Merge branch 'master' into ROL-2156
diff --git a/NOTICE.txt b/NOTICE.txt
index 203644e..2531be1 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -20,8 +20,3 @@
 Copyright (c) 2010-2014 Pivotal, Inc. All Rights Reserved.
 
 The product includes icons by Mark James (http://www.famfamfam.com/lab/icons)
-
-The product includes snippets of code from the JavaMail
-COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
-Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
-https://glassfish.java.net/public/CDDL+GPL_1_1.html
\ No newline at end of file
diff --git a/app/pom.xml b/app/pom.xml
index d077819..dc813e2 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.roller</groupId>
         <artifactId>roller-project</artifactId>
-        <version>6.0.1-SNAPSHOT</version>
+        <version>6.0.2-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/ajax/CommentDataServlet.java b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/ajax/CommentDataServlet.java
index 54f619a..af5eacf 100644
--- a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/ajax/CommentDataServlet.java
+++ b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/ajax/CommentDataServlet.java
@@ -66,7 +66,6 @@
                 Weblog weblog = c.getWeblogEntry().getWebsite();
                 if (weblog.hasUserPermission(rses.getAuthenticatedUser(), WeblogPermission.POST)) {
                     String content = Utilities.escapeHTML(c.getContent());
-                    content = WordUtils.wrap(content, 72);
                     content = StringEscapeUtils.escapeEcmaScript(content);
                     String json = "{ id: \"" + c.getId() + "\"," + "content: \"" + content + "\" }";
                     response.setStatus(HttpServletResponse.SC_OK);
diff --git a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/TemplateRemove.java b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/TemplateRemove.java
deleted file mode 100644
index 80ae5af..0000000
--- a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/TemplateRemove.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  The ASF licenses this file to You
- * under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.  For additional information regarding
- * copyright in this work, please see the NOTICE file in the top level
- * directory of this distribution.
- */
-
-package org.apache.roller.weblogger.ui.struts2.editor;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.roller.weblogger.WebloggerException;
-import org.apache.roller.weblogger.business.WeblogManager;
-import org.apache.roller.weblogger.business.WebloggerFactory;
-import org.apache.roller.weblogger.pojos.ThemeTemplate;
-import org.apache.roller.weblogger.pojos.Weblog;
-import org.apache.roller.weblogger.pojos.WeblogTemplate;
-import org.apache.roller.weblogger.pojos.WeblogTheme;
-import org.apache.roller.weblogger.ui.struts2.util.UIAction;
-import org.apache.roller.weblogger.util.Utilities;
-import org.apache.roller.weblogger.util.cache.CacheManager;
-import org.apache.struts2.convention.annotation.AllowedMethods;
-
-/**
- * Remove a template.
- */
-// TODO: make this work @AllowedMethods({"execute","remove","cancel"})
-public class TemplateRemove extends UIAction {
-
-    private static Log log = LogFactory.getLog(TemplateRemove.class);
-
-    // id of template to remove
-    private String removeId = null;
-
-    // template object that we will remove
-    private WeblogTemplate template = null;
-
-    public TemplateRemove() {
-        this.actionName = "templateRemove";
-        this.desiredMenu = "editor";
-        this.pageTitle = "editPages.title.removeOK";
-    }
-
-    @Override
-    public void myPrepare() {
-        if (StringUtils.isNotEmpty(getRemoveId())) {
-            try {
-                setTemplate(
-                    WebloggerFactory.getWeblogger().getWeblogManager().getTemplate(getRemoveId()));
-            } catch (WebloggerException ex) {
-                log.error("Error looking up template by id - " + getRemoveId(), ex);
-                addError("editPages.remove.notFound", getRemoveId());
-            }
-        }
-    }
-
-    /**
-     * Display the remove template confirmation.
-     */
-    @Override
-    public String execute() {
-        return "confirm";
-    }
-
-    /**
-     * Remove a new template.
-     */
-    public String remove() {
-
-        if (getTemplate() != null) {
-            try {
-                if (!getTemplate().isRequired()
-                    || !WeblogTheme.CUSTOM.equals(getActionWeblog().getEditorTheme())) {
-
-                    WeblogManager mgr = WebloggerFactory.getWeblogger().getWeblogManager();
-
-                    // if weblog template remove custom style sheet also
-                    if (getTemplate().getName().equals(WeblogTemplate.DEFAULT_PAGE)) {
-
-                        Weblog weblog = getActionWeblog();
-
-                        ThemeTemplate stylesheet = getActionWeblog().getTheme().getStylesheet();
-
-                        // Delete style sheet if the same name
-                        if (stylesheet != null
-                            && getActionWeblog().getTheme().getStylesheet() != null
-                            && stylesheet.getLink().equals(
-                            getActionWeblog().getTheme().getStylesheet().getLink())) {
-
-                            // Same so OK to delete
-                            WeblogTemplate css =
-                                mgr.getTemplateByLink(getActionWeblog(), stylesheet.getLink());
-
-                            if (css != null) {
-                                mgr.removeTemplate(css);
-                            }
-                        }
-                    }
-
-                    // notify cache
-                    CacheManager.invalidate(getTemplate());
-                    mgr.removeTemplate(getTemplate());
-                    WebloggerFactory.getWeblogger().flush();
-
-                    return SUCCESS;
-                } else {
-                    addError("editPages.remove.requiredTemplate");
-                }
-
-            } catch (Exception ex) {
-                log.error("Error removing page - " + getRemoveId(), ex);
-                addError("editPages.remove.error");
-            }
-        }
-
-        return "confirm";
-    }
-
-
-    @Override
-    public String cancel() {
-        return CANCEL;
-    }
-
-    public String getRemoveId() {
-        return removeId;
-    }
-
-    public void setRemoveId(String removeId) {
-        this.removeId = removeId;
-    }
-
-    public WeblogTemplate getTemplate() {
-        return template;
-    }
-
-    public void setTemplate(WeblogTemplate template) {
-        this.template = template;
-    }
-
-}
diff --git a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/Templates.java b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/Templates.java
index ff92a8a..d9eb4d9 100644
--- a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/Templates.java
+++ b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/Templates.java
@@ -23,14 +23,14 @@
 import org.apache.commons.logging.LogFactory;
 import org.apache.roller.util.RollerConstants;
 import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.business.WeblogManager;
 import org.apache.roller.weblogger.business.WebloggerFactory;
-import org.apache.roller.weblogger.pojos.CustomTemplateRendition;
+import org.apache.roller.weblogger.pojos.*;
 import org.apache.roller.weblogger.pojos.TemplateRendition.RenditionType;
 import org.apache.roller.weblogger.pojos.TemplateRendition.TemplateLanguage;
 import org.apache.roller.weblogger.pojos.ThemeTemplate.ComponentType;
-import org.apache.roller.weblogger.pojos.WeblogTemplate;
-import org.apache.roller.weblogger.pojos.WeblogTheme;
 import org.apache.roller.weblogger.ui.struts2.util.UIAction;
+import org.apache.roller.weblogger.util.cache.CacheManager;
 import org.apache.struts2.convention.annotation.AllowedMethods;
 
 import java.util.ArrayList;
@@ -58,6 +58,9 @@
     private String newTmplName = null;
     private ComponentType newTmplAction = null;
 
+    // id of template to remove
+    private String removeId = null;
+
     public Templates() {
         this.actionName = "templates";
         this.desiredMenu = "editor";
@@ -201,6 +204,68 @@
         return execute();
     }
 
+    /**
+     * Remove a new template.
+     */
+    public String remove() {
+
+        WeblogTemplate template = null;
+        try {
+            template = WebloggerFactory.getWeblogger().getWeblogManager().getTemplate(getRemoveId());
+        } catch (WebloggerException e) {
+            addError("Error deleting template - check Roller logs");
+        }
+
+        if (template != null) {
+            try {
+                if (!template.isRequired()
+                    || !WeblogTheme.CUSTOM.equals(getActionWeblog().getEditorTheme())) {
+
+                    WeblogManager mgr = WebloggerFactory.getWeblogger().getWeblogManager();
+
+                    // if weblog template remove custom style sheet also
+                    if (template.getName().equals(WeblogTemplate.DEFAULT_PAGE)) {
+
+                        Weblog weblog = getActionWeblog();
+
+                        ThemeTemplate stylesheet = getActionWeblog().getTheme().getStylesheet();
+
+                        // Delete style sheet if the same name
+                        if (stylesheet != null
+                            && getActionWeblog().getTheme().getStylesheet() != null
+                            && stylesheet.getLink().equals(
+                            getActionWeblog().getTheme().getStylesheet().getLink())) {
+
+                            // Same so OK to delete
+                            WeblogTemplate css =
+                                mgr.getTemplateByLink(getActionWeblog(), stylesheet.getLink());
+
+                            if (css != null) {
+                                mgr.removeTemplate(css);
+                            }
+                        }
+                    }
+
+                    // notify cache
+                    CacheManager.invalidate(template);
+                    mgr.removeTemplate(template);
+                    WebloggerFactory.getWeblogger().flush();
+
+                } else {
+                    addError("editPages.remove.requiredTemplate");
+                }
+
+            } catch (Exception ex) {
+                log.error("Error removing page - " + getRemoveId(), ex);
+                addError("editPages.remove.error");
+            }
+        } else {
+            addError("editPages.remove.error");
+        }
+
+        return execute();
+    }
+
     // validation when adding a new template
     private void myValidate() {
 
@@ -270,4 +335,11 @@
         this.newTmplAction = newTmplAction;
     }
 
+    public String getRemoveId() {
+        return removeId;
+    }
+
+    public void setRemoveId(String removeId) {
+        this.removeId = removeId;
+    }
 }
diff --git a/app/src/main/resources/struts.xml b/app/src/main/resources/struts.xml
index 63d5bb3..33ab4b3 100644
--- a/app/src/main/resources/struts.xml
+++ b/app/src/main/resources/struts.xml
@@ -221,6 +221,9 @@
             <param name="pageTitle">userAdmin.title.createNewUser</param>
             <result name="input" type="tiles">.UserEdit</result>
             <result name="success" type="tiles">.UserAdmin</result>
+            <result name="cancel" type="redirectAction">
+                <param name="actionName">userAdmin</param>
+            </result>
             <allowed-methods>execute,firstSave,save</allowed-methods>
         </action>
 
@@ -556,9 +559,9 @@
         <action name="templates"
                 class="org.apache.roller.weblogger.ui.struts2.editor.Templates">
             <result name="list" type="tiles">.Templates</result>
-            <allowed-methods>add,execute</allowed-methods>
+            <allowed-methods>add,remove,execute</allowed-methods>
         </action>
-        
+
         <action name="templateEdit"
                 class="org.apache.roller.weblogger.ui.struts2.editor.TemplateEdit">
             <result name="list" type="chain">templates</result>
diff --git a/app/src/main/webapp/WEB-INF/jsps/admin/GlobalConfig.jsp b/app/src/main/webapp/WEB-INF/jsps/admin/GlobalConfig.jsp
index 5f91f8d..fc34946 100644
--- a/app/src/main/webapp/WEB-INF/jsps/admin/GlobalConfig.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/admin/GlobalConfig.jsp
@@ -40,7 +40,7 @@
             <%-- special case for front page blog --%>
             <s:elseif test="#pd.name == 'site.frontpage.weblog.handle'">
                 <s:select name="%{#pd.name}" label="%{getText(#pd.key)}" value="%{properties[#pd.name].value}"
-                          list="weblogs" listKey="handle" listValueKey="name"/>
+                          list="weblogs" listKey="handle" listValueKey="handle"/>
             </s:elseif>
 
             <%-- "string" type means use a simple textbox --%>
diff --git a/app/src/main/webapp/WEB-INF/jsps/admin/UserEdit.jsp b/app/src/main/webapp/WEB-INF/jsps/admin/UserEdit.jsp
index 9478e9c..f9c65a6 100644
--- a/app/src/main/webapp/WEB-INF/jsps/admin/UserEdit.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/admin/UserEdit.jsp
@@ -21,11 +21,9 @@
 <%-- Titling, processing actions different between add and edit --%>
 <s:if test="actionName == 'createUser'">
     <s:set var="subtitleKey">userAdmin.subtitle.createNewUser</s:set>
-    <s:set var="mainAction">createUser</s:set>
 </s:if>
 <s:else>
     <s:set var="subtitleKey">userAdmin.subtitle.editUser</s:set>
-    <s:set var="mainAction">modifyUser</s:set>
 </s:else>
 
 <p class="subtitle">
@@ -51,27 +49,27 @@
     </s:if>
 
     <s:if test="actionName == 'modifyUser'">
-        <s:textfield name="bean.userName" size="30" maxlength="30"
+        <s:textfield name="bean.userName" size="30" maxlength="30" onkeyup="formChanged()"
                 label="%{getText('userSettings.username')}"
                 tooltip="%{getText('userSettings.tip.username')}"
                 readonly="true" cssStyle="background: #e5e5e5" />
     </s:if>
     <s:else>
-        <s:textfield name="bean.userName" size="30" maxlength="30"
+        <s:textfield name="bean.userName" size="30" maxlength="30" onkeyup="formChanged()"
                 label="%{getText('userSettings.username')}"
                 tooltip="%{getText('userAdmin.tip.username')}" />
     </s:else>
 
-    <s:textfield name="bean.screenName" size="30" maxlength="30"
+    <s:textfield id="bean_userName" name="bean.screenName" size="30" maxlength="30" onkeyup="formChanged()"
                 label="%{getText('userSettings.screenname')}"
                 tooltip="%{getText('userAdmin.tip.screenName')}" />
 
-    <s:textfield name="bean.fullName" size="30" maxlength="30"
+    <s:textfield id="bean_fullName" name="bean.fullName" size="30" maxlength="30" onkeyup="formChanged()"
                  label="%{getText('userSettings.fullname')}"
                  tooltip="%{getText('userAdmin.tip.fullName')}" />
 
     <s:if test="authMethod == 'ROLLERDB' || authMethod == 'DB_OPENID'">
-        <s:password name="bean.password" size="30" maxlength="30"
+        <s:password name="bean.password" size="30" maxlength="30" onkeyup="formChanged()"
                      label="%{getText('userSettings.password')}"
                      tooltip="%{getText('userAdmin.tip.password')}" />
     </s:if>
@@ -82,7 +80,7 @@
                      tooltip="%{getText('userAdmin.tip.openIdUrl')}" />
     </s:if>
 
-    <s:textfield name="bean.emailAddress" size="30" maxlength="30"
+    <s:textfield id="bean_email" name="bean.emailAddress" size="30" maxlength="255" onkeyup="formChanged()"
                  label="%{getText('userSettings.email')}"
                  tooltip="%{getText('userAdmin.tip.email')}" />
 
@@ -153,8 +151,49 @@
     <br />
 
     <div class="control">
-        <s:submit cssClass="btn btn-default" value="%{getText('generic.save')}" action="%{#mainAction}!save"/>
-        <s:submit cssClass="btn" value="%{getText('generic.cancel')}" action="modifyUser!cancel" />
+        <s:if test="actionName == 'createUser'">
+            <s:submit cssClass="btn btn-default" id="save_button"
+                      value="%{getText('generic.save')}" action="createUser!save"/>
+            <s:submit cssClass="btn"
+                      value="%{getText('generic.cancel')}" action="createUser!cancel" />
+        </s:if>
+        <s:else>
+            <s:submit cssClass="btn btn-default" id="save_button"
+                      value="%{getText('generic.save')}" action="modifyUser!save"/>
+            <s:submit cssClass="btn"
+                      value="%{getText('generic.cancel')}" action="modifyUser!cancel" />
+        </s:else>
     </div>
 
 </s:form>
+
+
+<script>
+
+    document.forms[0].elements[0].focus();
+    let saveButton;
+
+    $( document ).ready(function() {
+        saveButton = $("#save_button");
+        formChanged()
+    });
+
+    function formChanged() {
+        let userName = $("#bean_userName:first").val();
+        let fullName = $("#bean_fullName:first").val();
+        let email = $("#bean_email:first").val();
+
+        let valid = (userName && userName.trim().length > 0
+            && fullName && fullName.trim().length > 0
+            && email && email.trim().length > 0
+            && validateEmail(email));
+
+        if (valid) {
+            saveButton.attr("disabled", false);
+        } else {
+            saveButton.attr("disabled", true);
+        }
+    }
+
+</script>
+
diff --git a/app/src/main/webapp/WEB-INF/jsps/core/Register.jsp b/app/src/main/webapp/WEB-INF/jsps/core/Register.jsp
index 6f8fcef..0667e3d 100644
--- a/app/src/main/webapp/WEB-INF/jsps/core/Register.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/core/Register.jsp
@@ -42,8 +42,6 @@
 
         </div>
 
-        <%-- <s:text name="userRegister.tip.userName" /> --%>
-
     </s:if>
     <s:else>
         <s:textfield label="%{getText('userSettings.username')}"
@@ -65,7 +63,7 @@
     <s:textfield label="%{getText('userSettings.email')}"
                  tooltip="%{getText('userRegister.tip.email')}"
                  onkeyup="onChange()"
-                 name="bean.emailAddress" size="40" maxlength="40" />
+                 name="bean.emailAddress" size="40" maxlength="255" />
 
     <s:if test="authMethod != 'LDAP'">
 
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/Comments.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/Comments.jsp
index 7a329b9..2fe94d9 100644
--- a/app/src/main/webapp/WEB-INF/jsps/editor/Comments.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/editor/Comments.jsp
@@ -411,7 +411,7 @@
 
     function editComment(id) {
         // make sure we have the full comment
-        if ($("#link-" + id).size() > 0) readMoreComment(id, editComment);
+        if ($("#link-" + id).length > 0) readMoreComment(id, editComment);
 
         // save the original comment value
         comments[id] = $("#comment-" + id).html();
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/MembersInvite.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/MembersInvite.jsp
index f285705..4301f12 100644
--- a/app/src/main/webapp/WEB-INF/jsps/editor/MembersInvite.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/editor/MembersInvite.jsp
@@ -84,6 +84,7 @@
         var userName = $('#userList').children("option:selected").val();
         if (userName !== '') {
             $('#inviteButton').attr("disabled", false);
+            $('#userName').val(userName);
         }
     }
 
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/TemplateRemove.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/TemplateRemove.jsp
deleted file mode 100644
index 67d26cb..0000000
--- a/app/src/main/webapp/WEB-INF/jsps/editor/TemplateRemove.jsp
+++ /dev/null
@@ -1,55 +0,0 @@
-<%--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  The ASF licenses this file to You
-  under the Apache License, Version 2.0 (the "License"); you may not
-  use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.  For additional information regarding
-  copyright in this work, please see the NOTICE file in the top level
-  directory of this distribution.
---%>
-<%@ include file="/WEB-INF/jsps/taglibs-struts2.jsp" %>
-
-<p class="subtitle">
-    <s:text name="pageRemove.subtitle" />
-</p>
-
-<p>
-    <s:text name="pageRemove.youSure"> 
-        <s:param value="template.name" />
-    </s:text>
-    <br/>
-	<br/>
-	<span class="warning">
-		<s:text name="pageRemoves.youSureWarning" />
-	</span>
-</p>
-
-<p>
-    <s:text name="pageRemove.pageId" /> = [<s:property value="template.id" />]
-    <br />
-    <s:text name="pageRemove.pageName" /> = [<s:property value="template.name" />]
-</p>
-
-<table>
-    <tr>
-        <td>
-            <s:form action="templateRemove!remove">
-                <s:hidden name="salt" />
-
-                <s:hidden name="removeId" />
-                <s:hidden name="weblog" value="%{actionWeblog.handle}" />
-                
-                <s:submit value="%{getText('generic.yes')}" />&nbsp;
-                <s:submit value="%{getText('generic.no')}" action="templateRemove!cancel" />
-            </s:form>
-        </td>
-    </tr>
-</table>
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/Templates.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/Templates.jsp
index fefbab6..05bd6cb 100644
--- a/app/src/main/webapp/WEB-INF/jsps/editor/Templates.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/editor/Templates.jsp
@@ -30,7 +30,7 @@
     <p><s:text name="pagesForm.themesReminder"><s:param value="actionWeblog.editorTheme"/></s:text></p>
 </s:if>
 
-<s:form action="templateRemove!remove" theme="bootstrap" cssClass="form-horizontal">
+<s:form action="templates!remove" theme="bootstrap" cssClass="form-horizontal">
     <s:hidden name="salt"/>
     <s:hidden name="weblog" value="%{actionWeblog.handle}"/>
     <s:hidden name="removeId" id="removeId"/>
@@ -104,8 +104,7 @@
     function confirmTemplateDelete(templateId, templateName) {
         $('#removeId').val(templateId);
         if (window.confirm('<s:text name="pageRemove.confirm"/>: \'' + templateName + '\'?')) {
-            document.templateRemove.action = "<s:url action='templateRemove!remove' />";
-            document.templateRemove.submit();
+            document.getElementById("templates").submit();
         }
     }
 </script>
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/TemplatesSidebar.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/TemplatesSidebar.jsp
index 38e3df0..a5bdc60 100644
--- a/app/src/main/webapp/WEB-INF/jsps/editor/TemplatesSidebar.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/editor/TemplatesSidebar.jsp
@@ -20,7 +20,7 @@
 <h3><s:text name="pagesForm.addNewPage"/></h3>
 <hr size="1" noshade="noshade"/>
 
-<s:form action="templates!add" theme="bootstrap" cssClass="form-horizontal">
+<s:form action="templates!add" theme="bootstrap" cssClass="form-horizontal" id="templateAdd">
     <s:hidden name="salt"/>
     <s:hidden name="weblog"/>
 
diff --git a/app/src/main/webapp/WEB-INF/jsps/editor/WeblogConfig.jsp b/app/src/main/webapp/WEB-INF/jsps/editor/WeblogConfig.jsp
index 14a2a9a..8f5d083 100644
--- a/app/src/main/webapp/WEB-INF/jsps/editor/WeblogConfig.jsp
+++ b/app/src/main/webapp/WEB-INF/jsps/editor/WeblogConfig.jsp
@@ -63,7 +63,7 @@
               label="%{getText('createWebsite.locale')}"/>
 
     <s:select name="bean.timeZone" list="timeZonesList"
-              label="%{getText('createWebsite.timeZone')}"/>
+              label="%{getText('createWebsite.timezone')}"/>
 
     <s:checkbox name="bean.enableMultiLang"
                 label="%{getText('websiteSettings.enableMultiLang')}"/>
diff --git a/app/src/main/webapp/theme/scripts/searchhi.js b/app/src/main/webapp/theme/scripts/searchhi.js
index 8205281..e9aa08d 100644
--- a/app/src/main/webapp/theme/scripts/searchhi.js
+++ b/app/src/main/webapp/theme/scripts/searchhi.js
@@ -76,8 +76,8 @@
     // ensure this only executes when showing search results
     if (document.getElementById("searchAgain")) {
         var searchTerm = document.getElementById("q").value;
-        words = unescape(searchTerm.replace(/\+/g,' ')).split(/\s+/);
-        for (w=0;w<words.length;w++) {
+        var words = unescape(searchTerm.replace(/\+/g,' ')).split(/\s+/);
+        for (var w=0;w<words.length;w++) {
             highlightWord(document.getElementsByTagName("body")[0],words[w]);
         }
     }
diff --git a/app/src/test/java/org/apache/roller/planet/business/SubscriptionFunctionalTests.java b/app/src/test/java/org/apache/roller/planet/business/SubscriptionFunctionalTests.java
index df0ebf1..0febf3b 100644
--- a/app/src/test/java/org/apache/roller/planet/business/SubscriptionFunctionalTests.java
+++ b/app/src/test/java/org/apache/roller/planet/business/SubscriptionFunctionalTests.java
@@ -21,9 +21,7 @@
 import org.apache.roller.planet.pojos.Subscription;
 import org.apache.roller.weblogger.TestUtils;
 import org.apache.roller.weblogger.business.WebloggerFactory;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.*;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -31,6 +29,7 @@
 /**
  * Test Subscription functionality.
  */
+@TestMethodOrder(MethodOrderer.Alphanumeric.class)
 public class SubscriptionFunctionalTests  {
     
     private Planet testPlanet = null;
diff --git a/app/src/test/java/org/apache/roller/weblogger/business/WeblogStatsTest.java b/app/src/test/java/org/apache/roller/weblogger/business/WeblogStatsTest.java
index c52ec69..ddf6d06 100644
--- a/app/src/test/java/org/apache/roller/weblogger/business/WeblogStatsTest.java
+++ b/app/src/test/java/org/apache/roller/weblogger/business/WeblogStatsTest.java
@@ -21,9 +21,7 @@
 import org.apache.roller.util.RollerConstants;
 import org.apache.roller.weblogger.TestUtils;
 import org.apache.roller.weblogger.pojos.*;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.*;
 
 import java.util.List;
 import java.util.Map;
@@ -31,6 +29,8 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
+
+@TestMethodOrder(MethodOrderer.Alphanumeric.class)
 public class WeblogStatsTest  {
     
     private User user1, user2;
@@ -48,6 +48,9 @@
 
     @BeforeEach
     public void setUp() throws Exception {
+
+        TestUtils.setupWeblogger();
+
         // create weblog with three entries and two comments per entry
         user1 = TestUtils.setupUser("a_commentCountTestUser");
         user2 = TestUtils.setupUser("b_commentCountTestUser");
diff --git a/assembly-release/copy-files.sh b/assembly-release/copy-files.sh
deleted file mode 100644
index b84e15a..0000000
--- a/assembly-release/copy-files.sh
+++ /dev/null
@@ -1 +0,0 @@
-cp target/roller-release
diff --git a/assembly-release/copy-to-asf.sh b/assembly-release/copy-to-asf.sh
deleted file mode 100755
index b083fdb..0000000
--- a/assembly-release/copy-to-asf.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-cp target/roller-release-* ~/src.asf/roller-dist/dev/roller/roller-6.0/v6.0.0
-
diff --git a/assembly-release/pom.xml b/assembly-release/pom.xml
index 8f46c2c..e84530c 100644
--- a/assembly-release/pom.xml
+++ b/assembly-release/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.roller</groupId>
         <artifactId>roller-project</artifactId>
-        <version>6.0.1-SNAPSHOT</version>
+        <version>6.0.2-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
@@ -79,7 +79,7 @@
                     </dependency>
                 </dependencies>
                 <configuration>
-                    <sourceDirectory>../docs/adoc</sourceDirectory>
+                    <sourceDirectory>../docs</sourceDirectory>
                     <attributes>
                         <sourcedir>${project.build.sourceDirectory}</sourcedir>
                     </attributes>
diff --git a/assembly-release/sign-release.sh b/assembly-release/sign-release.sh
index 8f322dd..8c67c14 100755
--- a/assembly-release/sign-release.sh
+++ b/assembly-release/sign-release.sh
@@ -1,31 +1,31 @@
 #!/usr/bin/env bash
 
-export rcstring="-rc-1"
-export vstring="6.0.0"
+export rcstring=""
+export vstring="6.0.2-SNAPSHOT"
 
 # for rc releases we rename the release files
 if [ rcstring != "" ]; then
-    mv target/roller-release-${vstring}-source.tar.gz   target/roller-release-${vstring}${rcstring}-source.tar.gz
-    mv target/roller-release-${vstring}-source.zip      target/roller-release-${vstring}${rcstring}-source.zip
-    mv target/roller-release-${vstring}-standard.tar.gz target/roller-release-${vstring}${rcstring}-standard.tar.gz
-    mv target/roller-release-${vstring}-standard.zip    target/roller-release-${vstring}${rcstring}-standard.zip
+    mv target/apache-roller-${vstring}-source.tar.gz   target/apache-roller-${vstring}${rcstring}-source.tar.gz
+    mv target/apache-roller-${vstring}-source.zip      target/apache-roller-${vstring}${rcstring}-source.zip
+    mv target/apache-roller-${vstring}-binary.tar.gz target/apache-roller-${vstring}${rcstring}-binary.tar.gz
+    mv target/apache-roller-${vstring}-binary.zip    target/apache-roller-${vstring}${rcstring}-binary.zip
 fi
 
-gpg --armor --detach-sig target/roller-release-${vstring}${rcstring}-standard.tar.gz
-gpg --armor --detach-sig target/roller-release-${vstring}${rcstring}-standard.zip
-gpg --armor --detach-sig target/roller-release-${vstring}${rcstring}-source.tar.gz
-gpg --armor --detach-sig target/roller-release-${vstring}${rcstring}-source.zip
+gpg --armor --detach-sig target/apache-roller-${vstring}${rcstring}-binary.tar.gz
+gpg --armor --detach-sig target/apache-roller-${vstring}${rcstring}-binary.zip
+gpg --armor --detach-sig target/apache-roller-${vstring}${rcstring}-source.tar.gz
+gpg --armor --detach-sig target/apache-roller-${vstring}${rcstring}-source.zip
 
-gpg --print-md sha256 target/roller-release-${vstring}${rcstring}-standard.tar.gz > \
-target/roller-release-${vstring}${rcstring}-standard.tar.gz.sha256
+gpg --print-md sha256 target/apache-roller-${vstring}${rcstring}-binary.tar.gz > \
+target/apache-roller-${vstring}${rcstring}-binary.tar.gz.sha256
 
-gpg --print-md sha256 target/roller-release-${vstring}${rcstring}-standard.zip > \
-target/roller-release-${vstring}${rcstring}-standard.zip.sha256
+gpg --print-md sha256 target/apache-roller-${vstring}${rcstring}-binary.zip > \
+target/apache-roller-${vstring}${rcstring}-binary.zip.sha256
 
-gpg --print-md sha256 target/roller-release-${vstring}${rcstring}-source.tar.gz > \
-target/roller-release-${vstring}${rcstring}-source.tar.gz.sha256
+gpg --print-md sha256 target/apache-roller-${vstring}${rcstring}-source.tar.gz > \
+target/apache-roller-${vstring}${rcstring}-source.tar.gz.sha256
 
-gpg --print-md sha256 target/roller-release-${vstring}${rcstring}-source.zip > \
-target/roller-release-${vstring}${rcstring}-source.zip.sha256
+gpg --print-md sha256 target/apache-roller-${vstring}${rcstring}-source.zip > \
+target/apache-roller-${vstring}${rcstring}-source.zip.sha256
 
 
diff --git a/assembly-release/src/main/assembly/binary.xml b/assembly-release/src/main/assembly/binary.xml
index 994f3ed..ae75c95 100644
--- a/assembly-release/src/main/assembly/binary.xml
+++ b/assembly-release/src/main/assembly/binary.xml
@@ -48,11 +48,11 @@
             <outputDirectory>${artifact.artifactId}-${artifact.version}/docs</outputDirectory>
         </file>
         <file>
-            <source>../docs/roller-template-guide.pdf</source>
+            <source>target/generated-docs/roller-template-guide.pdf</source>
             <outputDirectory>${artifact.artifactId}-${artifact.version}/docs</outputDirectory>
         </file>
         <file>
-            <source>../docs/roller-user-guide.pdf</source>
+            <source>target/generated-docs/roller-user-guide.pdf</source>
             <outputDirectory>${artifact.artifactId}-${artifact.version}/docs</outputDirectory>
         </file>
     </files>
diff --git a/binary-includes/NOTICE.txt b/binary-includes/NOTICE.txt
index 0dd038d..2531be1 100644
--- a/binary-includes/NOTICE.txt
+++ b/binary-includes/NOTICE.txt
@@ -20,8 +20,3 @@
 Copyright (c) 2010-2014 Pivotal, Inc. All Rights Reserved.
 
 The product includes icons by Mark James (http://www.famfamfam.com/lab/icons)
-
-The product includes snippets of code from the JavaMail
-COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
-Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
-https://glassfish.java.net/public/CDDL+GPL_1_1.html
diff --git a/docs/README.md b/docs/README.md
index 01448e2..8036aaf 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,10 +1,10 @@
 # docs/README.md
 
-In this directory you'll find Roller docs in PDF and Open Office (ODR) format, various examples and test plans.
+In this directory you'll find Roller docs in AsciiDoc format, various examples and test plans.
 
-* `roller-install-guide.pdf` - How to install Roller
-* `roller-user-guide.pdf` - How to use Roller
-* `roller-template-guide.pdf` - How to create Roller templates and themes
+* `roller-install-guide.adoc` - How to install Roller
+* `roller-user-guide.adoc` - How to use Roller
+* `roller-template-guide.adoc` - How to create Roller templates and themes
 * `examples/` - example configuration and script files
 * `testing/` - Various test scripts
 
diff --git a/docs/before-and-after/entries.png b/docs/before-and-after/entries.png
deleted file mode 100644
index 4a87986..0000000
--- a/docs/before-and-after/entries.png
+++ /dev/null
Binary files differ
diff --git a/docs/before-and-after/entry-edit.png b/docs/before-and-after/entry-edit.png
deleted file mode 100644
index fcea48e..0000000
--- a/docs/before-and-after/entry-edit.png
+++ /dev/null
Binary files differ
diff --git a/docs/before-and-after/main-menu.png b/docs/before-and-after/main-menu.png
deleted file mode 100644
index 8c8d7fa..0000000
--- a/docs/before-and-after/main-menu.png
+++ /dev/null
Binary files differ
diff --git a/docs/before-and-after/media-file-view.png b/docs/before-and-after/media-file-view.png
deleted file mode 100644
index c958976..0000000
--- a/docs/before-and-after/media-file-view.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/customize-theme-1.png b/docs/images/customize-theme-1.png
new file mode 100644
index 0000000..26c7544
--- /dev/null
+++ b/docs/images/customize-theme-1.png
Binary files differ
diff --git a/docs/images/customize-theme-2.png b/docs/images/customize-theme-2.png
new file mode 100644
index 0000000..171c5f0
--- /dev/null
+++ b/docs/images/customize-theme-2.png
Binary files differ
diff --git a/docs/images/model-object.png b/docs/images/model-object.png
new file mode 100644
index 0000000..3b76f3d
--- /dev/null
+++ b/docs/images/model-object.png
Binary files differ
diff --git a/docs/images/template-edit.png b/docs/images/template-edit.png
new file mode 100644
index 0000000..d3b7aa6
--- /dev/null
+++ b/docs/images/template-edit.png
Binary files differ
diff --git a/docs/images/templates.png b/docs/images/templates.png
new file mode 100644
index 0000000..1c81bf3
--- /dev/null
+++ b/docs/images/templates.png
Binary files differ
diff --git a/docs/images/user-guide-1-welcome.png b/docs/images/user-guide-1-welcome.png
new file mode 100644
index 0000000..f76e4c6
--- /dev/null
+++ b/docs/images/user-guide-1-welcome.png
Binary files differ
diff --git a/docs/images/user-guide-10-categories.png b/docs/images/user-guide-10-categories.png
new file mode 100644
index 0000000..561e285
--- /dev/null
+++ b/docs/images/user-guide-10-categories.png
Binary files differ
diff --git a/docs/images/user-guide-11-blogroll.png b/docs/images/user-guide-11-blogroll.png
new file mode 100644
index 0000000..fec5984
--- /dev/null
+++ b/docs/images/user-guide-11-blogroll.png
Binary files differ
diff --git a/docs/images/user-guide-12-media.png b/docs/images/user-guide-12-media.png
new file mode 100644
index 0000000..1e8cc57
--- /dev/null
+++ b/docs/images/user-guide-12-media.png
Binary files differ
diff --git a/docs/images/user-guide-13-add-media.png b/docs/images/user-guide-13-add-media.png
new file mode 100644
index 0000000..e4fdbbf
--- /dev/null
+++ b/docs/images/user-guide-13-add-media.png
Binary files differ
diff --git a/docs/images/user-guide-14-upload-complete.png b/docs/images/user-guide-14-upload-complete.png
new file mode 100644
index 0000000..7691c36
--- /dev/null
+++ b/docs/images/user-guide-14-upload-complete.png
Binary files differ
diff --git a/docs/images/user-guide-15-edit-media.png b/docs/images/user-guide-15-edit-media.png
new file mode 100644
index 0000000..cbd2424
--- /dev/null
+++ b/docs/images/user-guide-15-edit-media.png
Binary files differ
diff --git a/docs/images/user-guide-17-api.png b/docs/images/user-guide-17-api.png
new file mode 100644
index 0000000..8616df7
--- /dev/null
+++ b/docs/images/user-guide-17-api.png
Binary files differ
diff --git a/docs/images/user-guide-18-comments.png b/docs/images/user-guide-18-comments.png
new file mode 100644
index 0000000..bd9eb6f
--- /dev/null
+++ b/docs/images/user-guide-18-comments.png
Binary files differ
diff --git a/docs/images/user-guide-2-registration.png b/docs/images/user-guide-2-registration.png
new file mode 100644
index 0000000..124096c
--- /dev/null
+++ b/docs/images/user-guide-2-registration.png
Binary files differ
diff --git a/docs/images/user-guide-20-design-menu.png b/docs/images/user-guide-20-design-menu.png
new file mode 100644
index 0000000..5357c97
--- /dev/null
+++ b/docs/images/user-guide-20-design-menu.png
Binary files differ
diff --git a/docs/images/user-guide-21-member.png b/docs/images/user-guide-21-member.png
new file mode 100644
index 0000000..0aaceb7
--- /dev/null
+++ b/docs/images/user-guide-21-member.png
Binary files differ
diff --git a/docs/images/user-guide-22-invite-member.png b/docs/images/user-guide-22-invite-member.png
new file mode 100644
index 0000000..f9c7f9b
--- /dev/null
+++ b/docs/images/user-guide-22-invite-member.png
Binary files differ
diff --git a/docs/images/user-guide-23-ping.png b/docs/images/user-guide-23-ping.png
new file mode 100644
index 0000000..dec1d52
--- /dev/null
+++ b/docs/images/user-guide-23-ping.png
Binary files differ
diff --git a/docs/images/user-guide-24-user-admin.png b/docs/images/user-guide-24-user-admin.png
new file mode 100644
index 0000000..d4ea17d
--- /dev/null
+++ b/docs/images/user-guide-24-user-admin.png
Binary files differ
diff --git a/docs/images/user-guide-25-user-admin.png b/docs/images/user-guide-25-user-admin.png
new file mode 100644
index 0000000..ab5fbd6
--- /dev/null
+++ b/docs/images/user-guide-25-user-admin.png
Binary files differ
diff --git a/docs/images/user-guide-26-site-setting.png b/docs/images/user-guide-26-site-setting.png
new file mode 100644
index 0000000..132a06d
--- /dev/null
+++ b/docs/images/user-guide-26-site-setting.png
Binary files differ
diff --git a/docs/images/user-guide-27-comments.png b/docs/images/user-guide-27-comments.png
new file mode 100644
index 0000000..cc297a5
--- /dev/null
+++ b/docs/images/user-guide-27-comments.png
Binary files differ
diff --git a/docs/images/user-guide-28-feed.png b/docs/images/user-guide-28-feed.png
new file mode 100644
index 0000000..c2c6ffe
--- /dev/null
+++ b/docs/images/user-guide-28-feed.png
Binary files differ
diff --git a/docs/images/user-guide-29-fileupload.png b/docs/images/user-guide-29-fileupload.png
new file mode 100644
index 0000000..d2e8d55
--- /dev/null
+++ b/docs/images/user-guide-29-fileupload.png
Binary files differ
diff --git a/docs/images/user-guide-3-webblog.png b/docs/images/user-guide-3-webblog.png
new file mode 100644
index 0000000..78a7bbe
--- /dev/null
+++ b/docs/images/user-guide-3-webblog.png
Binary files differ
diff --git a/docs/images/user-guide-30-ping.png b/docs/images/user-guide-30-ping.png
new file mode 100644
index 0000000..7cb9e69
--- /dev/null
+++ b/docs/images/user-guide-30-ping.png
Binary files differ
diff --git a/docs/images/user-guide-31-add-ping.png b/docs/images/user-guide-31-add-ping.png
new file mode 100644
index 0000000..fcfee4f
--- /dev/null
+++ b/docs/images/user-guide-31-add-ping.png
Binary files differ
diff --git a/docs/images/user-guide-32-planet-config.png b/docs/images/user-guide-32-planet-config.png
new file mode 100644
index 0000000..63165f0
--- /dev/null
+++ b/docs/images/user-guide-32-planet-config.png
Binary files differ
diff --git a/docs/images/user-guide-33-subscription.png b/docs/images/user-guide-33-subscription.png
new file mode 100644
index 0000000..fa2a218
--- /dev/null
+++ b/docs/images/user-guide-33-subscription.png
Binary files differ
diff --git a/docs/images/user-guide-4-statusbar.png b/docs/images/user-guide-4-statusbar.png
new file mode 100644
index 0000000..abb9a40
--- /dev/null
+++ b/docs/images/user-guide-4-statusbar.png
Binary files differ
diff --git a/docs/images/user-guide-5-statusbar-webblog.png b/docs/images/user-guide-5-statusbar-webblog.png
new file mode 100644
index 0000000..85d03b7
--- /dev/null
+++ b/docs/images/user-guide-5-statusbar-webblog.png
Binary files differ
diff --git a/docs/images/user-guide-6-navigation.png b/docs/images/user-guide-6-navigation.png
new file mode 100644
index 0000000..697e4a6
--- /dev/null
+++ b/docs/images/user-guide-6-navigation.png
Binary files differ
diff --git a/docs/images/user-guide-7-main-menu.png b/docs/images/user-guide-7-main-menu.png
new file mode 100644
index 0000000..6d7c1bb
--- /dev/null
+++ b/docs/images/user-guide-7-main-menu.png
Binary files differ
diff --git a/docs/images/user-guide-8-editor.png b/docs/images/user-guide-8-editor.png
new file mode 100644
index 0000000..af97960
--- /dev/null
+++ b/docs/images/user-guide-8-editor.png
Binary files differ
diff --git a/docs/images/user-guide-9-entries.png b/docs/images/user-guide-9-entries.png
new file mode 100644
index 0000000..9fc390e
--- /dev/null
+++ b/docs/images/user-guide-9-entries.png
Binary files differ
diff --git a/docs/images/user-guide-comments.png b/docs/images/user-guide-comments.png
new file mode 100644
index 0000000..e3fac14
--- /dev/null
+++ b/docs/images/user-guide-comments.png
Binary files differ
diff --git a/docs/images/user-guide-design-theme.png b/docs/images/user-guide-design-theme.png
new file mode 100644
index 0000000..ead07af
--- /dev/null
+++ b/docs/images/user-guide-design-theme.png
Binary files differ
diff --git a/docs/images/user-guide-formatting.png b/docs/images/user-guide-formatting.png
new file mode 100644
index 0000000..ee823f3
--- /dev/null
+++ b/docs/images/user-guide-formatting.png
Binary files differ
diff --git a/docs/images/user-guide-internationalization.png b/docs/images/user-guide-internationalization.png
new file mode 100644
index 0000000..10b7479
--- /dev/null
+++ b/docs/images/user-guide-internationalization.png
Binary files differ
diff --git a/docs/images/user-guide-media-directory.png b/docs/images/user-guide-media-directory.png
new file mode 100644
index 0000000..5580c53
--- /dev/null
+++ b/docs/images/user-guide-media-directory.png
Binary files differ
diff --git a/docs/images/user-guide-plugin.png b/docs/images/user-guide-plugin.png
new file mode 100644
index 0000000..a2fd9dd
--- /dev/null
+++ b/docs/images/user-guide-plugin.png
Binary files differ
diff --git a/docs/images/user-guide-podcast.png b/docs/images/user-guide-podcast.png
new file mode 100644
index 0000000..ab1b763
--- /dev/null
+++ b/docs/images/user-guide-podcast.png
Binary files differ
diff --git a/docs/images/user-guide-setting.png b/docs/images/user-guide-setting.png
new file mode 100644
index 0000000..a074627
--- /dev/null
+++ b/docs/images/user-guide-setting.png
Binary files differ
diff --git a/docs/images/user-guide-settings.png b/docs/images/user-guide-settings.png
new file mode 100644
index 0000000..719078d
--- /dev/null
+++ b/docs/images/user-guide-settings.png
Binary files differ
diff --git a/docs/images/user-guide-spam.png b/docs/images/user-guide-spam.png
new file mode 100644
index 0000000..302c450
--- /dev/null
+++ b/docs/images/user-guide-spam.png
Binary files differ
diff --git a/docs/adoc/roller-install-guide.adoc b/docs/roller-install-guide.adoc
similarity index 100%
rename from docs/adoc/roller-install-guide.adoc
rename to docs/roller-install-guide.adoc
diff --git a/docs/roller-install-guide.odt b/docs/roller-install-guide.odt
deleted file mode 100644
index eb8d53d..0000000
--- a/docs/roller-install-guide.odt
+++ /dev/null
Binary files differ
diff --git a/docs/roller-install-guide.pdf b/docs/roller-install-guide.pdf
deleted file mode 100644
index 376b33b..0000000
--- a/docs/roller-install-guide.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/roller-template-guide.adoc b/docs/roller-template-guide.adoc
new file mode 100644
index 0000000..a51d155
--- /dev/null
+++ b/docs/roller-template-guide.adoc
@@ -0,0 +1,2248 @@
+= Template Guide
+Apache Roller Weblogger
+:toc:
+:sectnums:
+:imagesdir: ./images
+
+== Overview
+
+This document is a Template Guide to the Apache Roller Weblogger, the
+Java-based and open source weblog server that is produced by the Apache
+Roller project of the Apache Software Foundation.
+
+
+=== Copyright and trademark information
+
+The contents of this document are subject to the terms of the Apache
+Software License.
+
+All trademarks within this document belong to legitimate owners.
+
+=== Feedback
+
+Please direct any comments or suggestions about this document to:
+dev@roller.apache.org
+
+== Introduction
+
+If you know a little about HTML and CSS, then you’ll find that it’s easy
+to customize the appearance, layout and content of your Roller-based
+weblog. You can change the appearance of any of your weblog’s pages and
+add as many new pages as you want. Any Roller user can do it through
+Roller’s web-based interface and it’s all done with Roller’s simple and
+easy-to-use template language. In this guide, we’ll tell you how. We’ll
+start by explaining how Roller’s weblog template system works then we’ll
+provide a reference to the objects and macros that you can use in your
+templates.
+
+NOTE: If you have only AUTHOR or LIMITED permissions within a weblog
+then you won’t have access to the Design -> Theme or
+Design -> Templates pages and you won’t be able to change or
+customize your theme. You need to have ADMIN permission within a weblog
+to be able to do the things described in this guide.
+
+NOTE: It is possible for a Roller site administrator to disable theme
+customization. So if you do have ADMIN permission in your weblog and you
+still don’t see the Design -> Templates page, perhaps your Roller
+site does not allow customization.
+
+== The Roller template system
+
+Each Roller weblog is defined by a set of page templates, which you can
+edit to customize the content, layout and appearance of your weblog.
+
+=== Page templates
+
+When you create a new Roller weblog you must pick a theme to define the
+new weblog’s appearance and layout. A theme is just a small set of
+templates, where each template contains HTML code, template language
+expressions and macros. What’s a template? A template for an HTML web
+page is simply an HTML web page with some Velocity code embedded inside.
+For example, this is a valid Roller template, with one Velocity
+expression:
+
+----
+<html>
+  <body>
+    My blog is named $model.weblog.name
+</body>
+</html>
+----
+
+The string "$model.weblog.name" is a template language expression and
+when Roller displays the template, that expression will be replaced with
+the name of the weblog.
+
+Note that *$model* is something special. Roller makes a set of objects,
+known as _models_, available to page templates. In the example above, we
+see only the $model object, but here are others. You’ll learn more about
+models in Section 5 and Section 6 provides a complete reference.
+
+=== The Velocity template language
+
+The simple template language that we use inside Roller page templates is
+called Velocity. It’s designed to be simple and easy for even
+non-programmers, but it’s also a simple programming language. You can
+set variables, use if-else conditional logic and create loops.
+
+For example, this Roller page template will list the categories
+available in your weblog except for the one named Music:
+
+----
+<html>
+  <body>
+    My blog is named $model.weblog.name. These are my categories:<br>
+    #foreach ($cat in $model.weblog.categories)
+      #if ($cat.name != "Music")
+        $cat.name<br>
+      #end
+    #end
+  </body>
+</html>
+----
+
+Velocity also supports the concepts of _macros_. A macro is essentially
+a Velocity method call. We use them in Roller to generate HTML. For
+example, as illustrated below, to display a bookmark folder you first
+retrieve if from the weblog and second pass it to the
+_#showBookmarkLinksList()_ macro to display it as an HTML _<ul>_ list.
+
+----
+<html>
+  <body>
+    <h2>Blogroll</h2>
+    #set($rootFolder = $model.weblog.getBookmarkFolder("/"))
+    #showBookmarkLinksList($rootFolder)
+  </body>
+</html>
+----
+
+You’ll learn more about macros in Section 5 and Section 8 provides a
+complete reference to the standard Roller macros. If you want more
+information on Velocity, see http://wiki.apache.org/velocity/.
+
+Now that we’ve covered the basic concepts of page templates and the
+Velocity template language, let’s dig into the details of editing
+templates.
+
+== Editing and creating page templates
+
+After you’ve used Roller *Design -> Themes* page to customize your
+weblog theme, you can edit and create page templates through the
+*Design -> Templates* page. We’ll show you how to do that, but first
+you need to understand how the required pages, found in every theme,
+work together to display a weblog.
+
+Every theme is different, but all themes must have two required pages –
+pages that you cannot rename or delete. These are the *Weblog* template,
+which defines the main page of your blog, and the *_day* template, which
+defines how each day’s worth of blog entries is displayed on your main
+page. Some themes also have a required page named *_css* which defines
+the CSS style code used by the weblog.
+
+First, let’s look at a simple Weblog template.
+
+=== The Weblog template
+
+Below is a simple Weblog page that displays all of the data that weblog
+typically contains including recent entries with paging to past entries,
+category link, feed links, a calendar and feed auto-discovery. Check the
+annotations for more detail.
+
+Listing 1: a typical Weblog template
+----
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title>$model.weblog.name : $model.weblogPage.name</title> #1
+  #showAutodiscoveryLinks($model.weblog) #2
+  <style type="text/css">#includeTemplate($model.weblog "_css")</style> #3
+</head>
+<body>
+  <table border="0" align="center" width="95%">
+    <tr>
+      <td class="entries" width="80%" valign="top">
+        <h1>$model.weblog.name</h1> #4
+        <p class="descrip">$model.weblog.description</p>
+        #set($rootCategory = $model.weblog.getWeblogCategory("nil")) #5
+        #showWeblogCategoryLinksList($rootCategory false false)<br>
+        #set($pager = $model.getWeblogEntriesPager()) #6
+        <div class="next-previous">
+          #if ($model.results) #7
+            #showWeblogSearchAgainForm($model.weblog)
+            #showNextPrevSearchControl($pager)
+          #else
+            #showNextPrevEntriesControl($pager) #8
+          #end
+        </div>
+        #showWeblogEntriesPager($pager) #9
+        #if ($model.permalink) #10
+          #showWeblogEntryComments($entry)
+          #showWeblogEntryCommentForm($entry)
+        #end
+      </td>
+      <td width="20%" valign="top">
+        <h2>Calendar</h2>
+        #showWeblogEntryCalendar($model.weblog "nil") #11
+        <h2>Feeds</h2>
+        #showAtomFeedsList($model.weblog) #12
+        <h2>Search</h2>
+        #showWeblogSearchForm($model.weblog false) #13
+        <h2>Links</h2>
+        #set($defaultFolder = $model.weblog.getBookmarkFolder("/")) #14
+        #showBookmarkLinksList($defaultFolder)
+        <h2>Navigation</h2>
+        #showPageMenu($model.weblog) #15
+        #showAuthorMenu(true) #16
+        <h2>Referrers</h2>
+        #set($refs = $model.weblog.getTodaysReferrers()) #17
+        #showReferrersList($refs 30 20)
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
+----
+
+The above template includes a good mix of Velocity expressions and
+statements. There’s a lot going on, so let’s explain it in detail.
+Here’s the point-by-point breakdown.
+
+
+. *HTML title* For the HTML title we use the weblog’s name, a colon
+and the name of the page template that is currently being displayed.
+. *Auto-discovery links*
+The __#showAutodiscoveryLinks() __macro adds
+the HTML _<link>_ elements required for RSS and Atom feed auto-discovery
+as well as RSD for weblog clients.
+. *Include CSS styles* Here we use the include the theme’s *_css*
+template directly in the page, right inside a pair of _<style>_ tags.
+. *Display a page title* Here we use the weblog’s name again in an
+_<h1>_ title.
+. *Category links list* Display a list of weblog category links.
+. *Get entries pager* Get the entries pager object so we can display
+entries and a paging control.
+. *Show search results control?* Show search results pager control if
+search in progress
+. **Else . . . ** Show normal entries pager control.
+. *Show entries* Show current page’s worth of entries (or search
+results). Calls on *_day* template to do the display of each day’s worth
+of entries.
+. *Show comments?* If we’re on a permalink page, then show comments
+and comments form
+. *Show the calendar* Show the standard weblog calendar.
+. *Show feed links* Show links to all available Atom entry feeds, one
+per category.
+. *Search form* Show the weblog search form, false indicates no
+category chooser.
+. *Display blogroll* Display contents of the default (main) bookmark
+folder.
+. *Show page menu* Display navigation bar of pages available in
+weblog.
+. *Show author menu* Display author’s menu, only visible to authorized
+users.
+. *Display today’s referrers* Display today’s referrer URL with hit
+counts.
+
+Note in point #9 that the display of the weblog entries is controlled by
+another template, the _day template. So next let’s take a look at that
+_day template.
+
+=== The _day template
+
+A theme’s _day template is responsible for displaying one day’s worth of
+weblog entries. Here’s a typical _day template, one that corresponds to
+the above Weblog template.
+
+Listing 2: a typical _day template
+
+----
+<div class="dayBox">
+  <div class="dayTitle">
+    $utils.formatDate($day, "EEEE MMM dd, yyyy") #1
+  </div>
+  #foreach($entry in $entries) #2
+    <div class="entryBox">
+      <p class="entryTitle">$entry.title</p> #3
+      <p class="entryContent">
+        #if($model.permalink) #4
+          $entry.displayContent
+        #else
+          $entry.displayContent($url.entry($entry.anchor))
+        #end
+      </p>
+      <p class="entryInfo">
+        Posted at
+        <a href="$url.entry($entry.anchor)"> #5
+          $utils.formatDate($entry.pubTime, "hh:mma MMM dd, yyyy")</a>
+        by $entry.creator.fullName in #6
+        <span class="category">$entry.category.name</span> &nbsp;|&nbsp; #7
+        #if
+          ($utils.isUserAuthorizedToAuthor($entry.website)) #8
+          <a href="$url.editEntry($entry.anchor)">Edit</a> &nbsp;|&nbsp;
+        #end
+        #if($entry.commentsStillAllowed || $entry.commentCount > 0) #9
+          #set($link = "$url.comments($entry.anchor)" )
+          <a href="$link" class="commentsLink">
+          Comments[$entry.commentCount]</a>
+        #end
+      </p>
+    </div>
+  #end
+</div>
+----
+
+And here’s a point-by-point description of the template language
+expressions and statements found in the above day template:
+
+. *Display day header.* For the day header, we display the current date
+in a long format.
+. *Loop through day’s entries.* Here we use a $foreach loop to iterate
+through the $entries collection
+. *Display entry title.* Display the entry title in a <div> so that it
+can be easily styled.
+. *Display entry content or summary.* If we’re on a permalink page, show
+the entry’s content. Otherwise, show the summary if a summary is
+available.
+. *Display entry permalink.* Display permanent link to the entry.
+. *Display entry author’s name.* Display the name of the author of the
+entry.
+. *Display entry category.* Display the name of the category associated
+with the entry.
+. *Show edit link.* If user is authorized, display link to edit the
+entry.
+. *Show comments link.* If comments are available or are still allowed,
+display link to entry comments.
+
+Now you’ve seen the required templates and you’ve seen most of the
+commonly used macros in action, let’s discuss the mechanics of
+customizing your theme.
+
+=== Customizing your theme
+
+When you start a Roller weblog and you pick a theme, your weblog uses a
+_shared_ copy of that theme. The page templates that define your theme
+are shared by all of the other users who have also picked that theme.
+Using a shared theme is nice because, when your Roller site
+administrator makes fixes and improvements to that shared theme, then
+you’ll get those automatically. But you can’t customize a shared theme.
+Before you can customize your theme, you’ve got to get your own copy of
+the theme’s page templates like so:
+
+
+1) *Go to the Design -> Theme page.*
+
+Login to Roller and go to your
+weblog’s *Design -> Theme* page and select the 'Custom Theme' option.
+
+image::customize-theme-1.png[]
+
+
+2) *Click on 'Update Theme' button*
+
+If the you are using 'Custom Theme' option, you will see the following note:
+
+_Since this is the first time using a custom theme, Roller will copy the templates from your existing Shared Theme so you can edit them._
+
+Click on 'Update Theme' button to proceed.
+When you do this, copies of the themes page templates will
+be copied into your weblog so you can edit them.
+
+image::customize-theme-2.png[]
+
+
+3) *Customize your theme by editing and creating page templates.*
+Go to the Design -> Templates page, edit your page templates and add new
+ones as needed – as described in the next section.
+
+And if you get tired of your customized theme, just use the
+*Design -> Theme* page to switch back to a shared theme – or pick
+another one to customize. Now let’s discuss editing and creating
+templates.
+
+=== Editing and creating page templates
+
+Once you’ve got the page templates copied into your weblog, you can do
+just about anything you want to your theme. You can use the
+*Design -> Templates* page, shown below, to create a new page, delete
+a page or choose a page to edit.
+
+image::templates.png[]
+
+Now might be a good time to describe the _page template properties_
+since you can see them in the table above. The properties are name,
+description. Let’s explain each:
+
+* *Name*: Each template has a name, which you can display in your
+templates. You can also use the _#includeTemplate()_ macro to include
+the contents of one page in another, by referring to the template by
+name.
+* *Description*: You can enter an option description for each page for
+display or just as a reminder to yourself as to the purpose of the page.
+
+For new templates that you add, you’ll be able to edit all of those
+properties using the *Design -> Template* page (shown
+below).
+
+image::template-edit.png[]
+
+But the rules for _required pages_ are different. The weblog pages named
+Weblog, _day and _css are considered to be required pages. You can
+change the template code for those pages but you cannot edit the name,
+link or any other properties.
+
+Now that you know how to edit and create page templates, let’s discuss
+how to use the models, objects and macros that Roller makes available to
+template authors.
+
+== Using models, objects and macros
+
+Roller makes weblog data available to page templates in the form of
+_models_ and _data_ __objects __and makes it easy for you to generate
+the HTML for your weblog by providing _macros_. Let’s explain these new
+terms.
+
+* *Model objects*: Model objects provide access to data from Roller and
+specifically from your Roller weblog. A model object returns data
+objects or collections or data objects. In Section 7, we’ll describe each model, it’s
+properties and methods.
+* *Data objects*: Data objects each represent an item of data within
+your Roller weblog, for example there is a _Weblog_ object that
+represents your weblog, _WeblogEntry_ objects which represent individual
+weblog entries and _Bookmark_ objects that represent items in your
+blogroll. In Section 8, we’ll describe each data object, it’s properties
+and methods.
+* *Macros*. A macro is Velocity routine that generates HTML based on a
+data object or a collection of data objects. In Section 9 we’ll describe
+each of Roller’s build-in macros.
+
+Let’s discuss how to access data via models and data objects.
+
+=== Accessing data via models and objects
+
+Models and data objects are objects and there are two ways to access
+data from objects. One way is to access an objects properties. Another
+is to call the object’s methods. Let’s talk about these two techniques.
+
+==== Accessing object properties
+
+To access an objects properties, you use a simple dot-notation. For
+example, if you want to display the Roller version number property of
+the *$config* model object, you do something like this in your page:
+
+<p>**$config.rollerVersion**</p>
+
+Or, if you’d like to save the Roller version number in a variable named
+$version, you’d do this:
+
+*#set( $version = $config.rollerVersion )*
+
+And some properties are themselves objects, which in turn have their own
+properties and methods. For example, you can get the Weblog object from
+the $model object and from the weblog object you can display the
+weblog’s name and description like so:
+
+<p>**$model.weblog.name**</a>
+
+<p>**$model.weblog.description**</a>
+
+==== Calling object methods
+
+Another way to access an object’s data is to call an objects’s methods.
+Methods are different from properties because they require parameters.
+You use the same simple dot-notation, but you must end the expression
+with a list of parameters in parentheses. For example, if you’d like to
+display an image from within your theme, you can use the $url model like
+so:
+
+<img='**$url.themeResource("basic", "background.gif")**'></a>
+
+Argument one is the name of the theme and argument two is the name of a
+file that exists in the theme’s directory. Note that a comma is used to
+separate the arguments.
+
+=== Calling macros
+
+In page templates, you get data from objects and you use template code
+to display that data as HTML. To help you along, Roller includes some
+macros which can be used to generate commonly used HTML constructs on
+your weblog. There are macros for displaying your weblog entries,
+displaying your blogroll and displaying a comment form.
+
+Calling a macro is a little different from calling a macro. A macro call
+starts with a # pound-sign, followed by the macro name and the macro
+parameters enclosed in parentheses. For example, you call the weblog
+calendar macro like so:
+
+*#showWeblogEntryCalendar($model.weblog "nil")*
+
+Argument one is the weblog for the calendar and argument two is the
+category, where "nil" indicates that no category is specified. Note
+that the arguments for a macro are separated by a space and NOT a comma
+as was the case for methods.
+
+=== A word about pagers
+
+There are many cases in a weblog when we want to display a large
+collection of values and we want that collection to be page-able – that
+is, we want a Next link to go to the next page of results and possibly a
+Previous link to go to the previous page. So in Roller, we’ve introduced
+the concept of a pager. A _pager_ is a special type of object that makes
+it easy to display a page-able collection of items within a page
+template. You can see a pager in action in Listing 1 above.
+
+You probably won’t need to use a pager object directly, since the macros
+do it for you. But if you do, here’s what a pager looks like:
+
+* $pager.homeLink – URL of the first page of results
+* $pager.homeName – Name to be displayed for that URL
+* $pager.nextLink – URL of the next page of results
+* $pager.nextName – Name to be displayed for that URL
+* $pager.prevLink – URL of the previous page of results
+* $pager.prevName – Name to be displayed for that URL
+* $pager.items – Collection of data objects; the current page of results
+
+There is also a WeblogEntryPager interface that provides some extra
+methods for next-collection paging. The collection methods exist because
+often, with weblog entries, we are paging through the entries that exist
+within one time period, a month for example. In that case. the nextLink
+point to the next page of results within that month and the
+nextCollectionLink points to the next months entries.
+
+* $pager.homeLink – URL of the first page of results
+* $pager.homeName – Name to be displayed for that URL
+* $pager.nextLink – URL of the next page of results
+* $pager.nextName – Name to be displayed for that URL
+* $pager.prevLink – URL of the previous page of results
+* $pager.prevName – Name to be displayed for that URL
+* $pager.nextCollectionLink – URL of next collection in sequence
+* $pager.nextCollectionName – Name to be displayed for that URL
+* $pager.prevCollectionLink – URL of previous collection in sequence
+* $pager.prevCollectionName – Name to be displayed for that URL
+* $pager.items – Collection of data objects; the current page of results
+
+== Model Object Reference
+
+This section covers the standard model objects available in all page
+templates:
+
+* $config – provides access to the Roller site configuration parameters
+* $model – provides access to data for one specific weblog
+* $url – for creating Roller URLs and URLs within one specific weblog
+* $utils – utility methods needed within page templates
+
+For each model, we’ll cover properties and methods.
+
+=== $config
+
+The $config model provides access to the Roller configuration data that
+you’ll need in your weblog.
+
+==== $config Properties
+
+|===
+|Property Name |Type |Description
+
+|$config.analyticsOverrideAllowed
+|Boolean
+|True if individual bloggers are allowed to override the default tracking code (if any) provided by the blog administrator.
+
+|$config.commentAutoFormat
+|Boolean
+|True if comments should be formatted with added line feeds.
+
+|$config.commentEmailNotify
+|Boolean
+|True if notification of new comments via email is enabled.
+
+|$config.commentEscapeHtml
+|Boolean
+|True if all HTML will be stripped of comments before display.
+
+|$config.defaultAnalyticsTrackin gCode
+|String
+|Default tracking code for web analytics software, if configured by the blog administrator (See Roller User’s Guide, Roller Administration chapter.)
+
+|$config.feedMaxSize
+|Integer
+|Maximum number of items displayed in RSS and Atom feeds.
+
+|$config.feedStyle
+|Boolean
+|True if feeds are displayed with user-friendly formatting (via XSL stylesheet).
+
+|$config.rollerVersion
+|String
+|Version number of Roller build.
+
+|$config.registrationEnabled
+|Boolean
+|True if new user registration is enabled.
+
+|$config.registrationURL
+|String
+|URL of new user registration site (if not using standard Roller registration).
+
+|$config.siteDescription
+|String
+|Description of this Roller site.
+
+|$config.siteEmail
+|String
+|Email address of this Roller site's administrator.
+
+|$config.siteName
+|String
+|Name of this Roller site.
+
+|$config.siteShortName
+|String
+|Short name of this Roller site.
+|===
+
+==== $config Methods
+
+The *$config* model also provides a set of methods for accessing
+properties by name. Generally, you should be able to get the
+configuration data you need from the properties above. You shouldn’t
+need to call these methods, but just so you know:
+
+* *boolean getBooleanProperty(String propertyName)* Returns the named
+runtime property as a booean.
+* *String getProperty(String propertyName)* Returns the named runtime
+property as a String.
+* *int getIntProperty(String propertyName)* Returns the named runtime
+property as an integer.
+
+=== $model
+
+The **$model** object provides you with access to all of the data
+objects that make up your weblog. You can get a pager object to access
+your weblog entries, the weblog entry referenced by the request, the
+category object referenced by the request and the weblog itself.
+
+The diagram below show the objects you can get from the *$model* and the
+collections of objects that you can get from those. See Section 7 for a
+complete reference to the data objects and their properties.
+
+image::model-object.png[]
+
+Now let’s the details of the $model object, starting with properties.
+
+==== $model Properties
+
+|===
+|Name |Type |Description
+
+|$model.commentForm
+|CommentForm
+|On a comment-page, this object will be populated with the comment form values. Values available are $model.commentForm.name, $model.commentForm.url and $model.commenForm.content.
+
+|$model.locale
+|String
+|Name of locale if one is specified in the URL.
+
+|$model.weblog
+|Weblog
+|Current weblog being displayed.
+
+|$model.weblogCategory
+|WeblogCategory
+|Weblog category specified by URL or null if not specified.
+
+|$model.weblogEntry
+|WeblogEntry
+|Weblog entry object specified by URL or null if none specified.
+
+|$model.weblogEntriesPager
+|Pager
+|Weblog entry pager for paging over entries specified by URL.
+
+|$model.weblogPage
+|PageTemplate
+|Weblog page object specified or implied by URL.
+
+|$model.permalink
+|Boolean
+|True if URL specifies one specific Weblog Entry permalink.
+
+|$model.searchResults
+|Boolean
+|True if displaying search results.
+
+|$model.tags
+|List of strings
+|List of tags specified by request.
+|===
+
+==== $model Search Properties
+
+If the URL indicates a search, then the pager returned by
+*$model.weblogEntriesPager* will return entries from the search and some additional properties will be available on the *$model* object:
+
+|===
+|Name |Type |Description
+
+|$model.categories
+|List of Strings
+|List of category names available in search.
+
+|$model.hits
+|Integer
+|Total number of hits found.
+
+|$model.limit
+|Integer
+|Max. number of search results displayed per page.
+
+|$model.offset
+|Integer
+|Offset into current page of search results.
+
+|$model.weblogSpecificSearch
+|Boolean
+|True if search is specific to one weblog.
+|===
+
+==== $model methods
+
+The *$model* object also provides a couple of methods:
+
+* *Pager getWeblogEntriesPager(String catPath)* Returns a pager that
+contains only entries from the specified category.
+* *String getRequestParameter(String paramName)* Returns a specific
+request parameter from the URL. This is only supported on custom pages
+and not on the default pages of a weblog (e.g. the Weblog page).
+
+=== $url
+
+To ensure that your URLs are formed correctly, you should use the *$url*
+model to form all URLs that point to the Roller site or to your weblog.
+Every possible type of Roller URL is supported:
+
+|===
+|Name |Type |Description
+
+|$url.absoluteSite
+|String
+|Absolute URL of Roller site.
+
+|$url.category(String catPath)
+|String
+|URL for one category within weblog.
+
+|$url.category(String catPath, int pageNum)
+|String
+|URL for one category within weblog, w/page.
+
+|$url.commentAuthenticator
+|String
+|URL of comment authenticator.
+
+|$url.comment(String anchor, String timeStamp)
+|String
+|URL of comment for entry specified by anchor.
+
+|$url.comments(String anchor)
+|String
+|URL of comments for entry specified by anchor.
+
+|$url.createEntry
+|String
+|URL for new-entry page in Roller UI.
+
+|$url.editEntry(String anchor)
+|String
+|URL for edit-single-entry page in Roller UI.
+
+|$url.date(String dateString)
+|String
+|URL for one specific 6 or 8 character date.
+
+|$url.date(String dateString, int pageNum)
+|String
+|URL for one specific 6 or 8 character date, w/page.
+
+|$url.editSettings
+|String
+|URL for edit-weblog-settings page in Roller UI.
+
+|$url.entry(String anchor)
+|String
+|URL for entry specified by anchor.
+
+|$url.feed.entries.atom
+|String
+|URL of entries feed (Atom).
+
+|$url.feed.entries.rss
+|String
+|URL of entries feed (RSS).
+
+|$url.feed.comments.atom
+|String
+|URL of comments feed (Atom).
+
+|$url.feed.comments.rss
+|String
+|URL of comments feed (RSS).
+
+|$url.home
+|String
+|URL of weblog.
+
+|$url.home(String locale)
+|String
+|URL to access weblog in one specific language
+
+|$url.home(String locale, int pageNum)
+|String
+|URL to access weblog in one specific language, with paging
+
+|$url.login
+|String
+|URL of login page.
+
+|$url.logout
+|String
+|URL of logout page.
+
+|$url.rsd
+|String
+|URL of Really Simple Discovery (RSD) service.
+
+|$url.page(String pageLink)
+|String
+|URL of page specified by pageLink.
+
+|$url.page(String pageLink, String dateString, String catPath, int pageNum)
+|String
+|URL of page specified by pageLink, dateString, catPath and pageNum.
+
+|$url.search
+|String
+|URL of search
+
+|$url.search(String query, String catPath, int pageNum)
+|String
+|URL of search for specific search string, catPath and pageNum.
+
+|$url.site
+|String
+|Relative URL of Roller site.
+
+|$url.resource(String filePath)
+|String
+|URL of uploaded file resource in weblog.
+
+|$url.themeResource(String theme, String file)
+|String
+|URL of a resource within a Roller theme.
+
+|$url.themeResource(String theme, String file, boolean abs)
+|String
+|Absolute URL of a resource within a Roller theme.
+
+|$url.trackback(String anchor)
+|String
+|Trackback URL for entry specified by anchor.
+|===
+
+=== $utils
+
+The *$utils* object provides all of the string manipulation methods
+you’ll ever need for your weblog, including methods for formatting
+dates, escapeing HTML, encoding URLs and even removing HTML entirely.
+Here’s a comprehensive list of the $utils methods:
+
+* **User getAuthenticatedUser() **Get the current user, or null if no
+use is logged in.
+* *String addNowFollow(String s)* Adds the nofollow attribute to any
+HTML links found within the string.
+* *String autoformat(String s)* Converts any line-breaks in the string
+with* <br>* tags.
+* *String decode(String s)* Decodes a string that has been URL encoded.
+* *String encode(String s)* Applies URL encoding to a string.
+* *String escapeHTML(String s)* Escapes any non-HTML characters found in
+the string.
+* *String escapeXML(String s)* Escapes any non-XML compatible characters
+found in the string.
+* *String formatDate(Date date, String fmt)* Formats a date object
+according to the format specified (see java.text.SimpleDateFormat)
+* *String formatIso8601Date(Date date)* Formats a date object using
+ISO-8601 date formatting.
+* *String formatRfc822Date(Data date)* Formats a date object using
+RFC-822 date formatting.
+* *boolean isEmpty(Object o)* Returns true if the object is null or if
+it is an empty string.
+* *boolean IsNotEmpty(Object o)* Returns true of the object is not null
+or is a non-empty string.
+* *String removeHTML(String s)* Remove all HTML markup from a string.
+* *String replace(String str, String target, String replacement)* In the
+string str, replace the target string with the replacement string.
+* *String toBase64(String s)* Convert a string to Base64 encoding.
+* *String transformToHTMLSubset(String s)* Transform any HTML in the
+string to a safe HTML subset.
+* *String truncate(String str, int lower, int upper, String append)*
+Truncate a string str so that it is between lower and upper characters
+in length and add the append string.
+* *String unescapeHTML(String s)* Unscape a string that has been HTML
+escaped.
+* *String unescapeXML(String s)* Unescape a string that has been XML
+escaped.
+
+That’s it for the $url model and for models in general. Let’s move on to
+the data objects.
+
+== Data Object Reference
+
+In this section we’ll list each of the properties and methods of the
+Roller data objects. These are:
+
+* *Bookmark*: A single link within a weblog’s web bookmark collection,
+exists with a Folder
+* *Bookmark Folder*: A Folder containing Bookmarks, tied to a weblog.
+* *Comment*: A Comment associated with a specific Weblog Entry
+* *Page Template*: An individual page template within a Weblog.
+* *Referrer*: A Referrer represents an external site that links to the
+Weblog
+* *User*: Represents a single user within the Roller site.
+* *Weblog*: a Weblog containing Weblog Entries, Page Templates, Bookmark
+Folders, etc.
+* *Weblog Entry*: an individual Weblog Entry
+* *Weblog Entry Attrbute*: a name value pair-associated with a Weblog
+Entry
+* *Weblog Category*: A category within a weblog, categories in Roller
+are hierarchical
+
+=== Bookmark
+
+|===
+|Name |Type |Description
+
+|$bookmark.description
+|String
+|Description of the bookmark
+
+|$bookmark.feedUrl
+|String
+|URL of the newsfeed associated with the bookmark
+
+|$bookmark.folder
+|BookmarkFolder
+|Parent folder of the bookmark
+
+|$bookmark.image
+|String
+|URL of image to be displayed for bookmark
+
+|$bookmark.name
+|String
+|Name of the bookmark
+
+|$bookmark.url
+|String
+|URL of the bookmark
+
+|$bookmark.priority
+|Integer
+|Numerical position of the bookmark in the list, higher number means lower in the list.
+|===
+
+=== BookmarkFolder
+
+|===
+|Name |Type |Description
+
+|$folder.bookmarks
+|List of Bookmarks
+|Bookmarks contained in folder.
+
+|$folder.name
+|String
+|Name of folder
+
+|$folder.website
+|Weblog
+|Weblog in which folder is contained
+|===
+
+=== Comment
+
+|===
+|Name |Type |Description
+
+|$comment.approved
+|Boolean
+|True if comment has been approved for display
+
+|$comment.content
+|String
+|Content of the comment
+
+|$comment.email
+|String
+|Email address of the commenter
+
+|$comment.name
+|String
+|Name of the commenter
+
+|$comment.notify
+|Boolean
+|True if commenter choose the 'please notify me via email' option
+
+|$comment.pending
+|Boolean
+|True if comment is waiting for approval
+
+|$comment.postTime
+|Date
+|Time that comment was created
+
+|$comment.remoteHost
+|String
+|Host name or IP address of commenter
+
+|$comment.spam
+|Boolean
+|True if comment is marked as spam
+
+|$comment.url
+|String
+|URL of the commenter
+
+|$comment.weblogEntry
+|WeblogEntry
+|Weblog entry with which comment is associated
+|===
+
+=== PageTemplate
+
+|===
+|Name |Type |Description
+
+|$page.contents
+|String
+|The content of the page template, typically HTML and Velocity code
+
+|$page.description
+|String
+|Description of the page
+
+|$page.lastModified
+|Date
+|Date that page properties or content was last modified
+
+|$page.link
+|String
+|String used to form URL to page
+
+|$page.name
+|String
+|Name of the page
+
+|$page.navbar
+|String
+|True if page should be included in page navigation menu
+
+|$page.hidden
+|String
+|True if page is NOT callable by URL
+|===
+
+=== TagStat
+
+|===
+|Name |Type |Description
+
+|$tagStat.name
+|String
+|Name of tag
+
+|$tagStat.count
+|Integer
+|Number of usages of tag within weblog or site (depending on context)
+
+|$tagStat.intensity
+|Integer
+|Relative intensity rating of tag (values 1 through 5)
+|===
+
+=== User
+
+|===
+|Name |Type |Description
+
+|$user.dateCreated
+|Date
+|Date that user was created
+
+|$user.emailAddress
+|String
+|User's email address
+
+|$user.fullName
+|String
+|User's full name
+
+|$user.screenName
+|String
+|User's screen name
+
+|$user.locale
+|String
+|User's locale
+
+|$user.timeZone
+|String
+|User's timezone
+
+|$user.userName
+|String
+|User's username (this will always return the user's screen- name unless the property user.privateUserNames is set to false in roller-custom.proprerties).
+|===
+
+=== Weblog
+
+|===
+|Name |Type |Description
+
+
+|$weblog.about
+|String
+|“About your blog” text
+
+|$weblog.active
+|Boolean
+|True if weblog is considered active
+
+|$weblog.allowComments
+|Boolean
+|True if comments are allowed in weblog
+
+|$weblog.analyticsCode
+|String
+|Web analytics tracking code for the weblog. Will be null if not configured at the blog level, see $config.defaultAnalyticsTrackingCode for the global tracking code for blogs which do not have this value set. See Weblog Settings - Web Analytics section of Roller User’s Guide.
+
+|$weblog.commentCount
+|Long
+|Total number of comments of approved in weblog
+
+|$weblog.creator
+|User
+|User who created this weblog
+
+|$weblog.dateCreated
+|Date
+|Date weblog was created
+
+|$weblog.emailAddress
+|String
+|Email address of weblog's managing editor
+
+|$weblog.emailComments
+|Boolean
+|True if email notification of comments is enabled
+
+|$weblog.emailFromAddress
+|String
+|Email address for from-address of notifications
+
+|$weblog.enableBloggerApi
+|Boolean
+|True if remote blogging API is enabled
+
+|$weblog.enabled
+|Boolean
+|True if weblog is enabled
+
+|$weblog.entryCount
+|Long
+|Total number of entries in weblog
+
+|$weblog.entryDisplayCount
+|Integer
+|Default number of entries to display in pagers
+
+|$weblog.handle
+|String
+|Simple string handle that uniquely identifies weblog
+
+|$weblog.lastModified
+|Date
+|Timestamp of last modification to weblog
+
+|$weblog.locale
+|String
+|Default locale used by weblog
+
+|$weblog.moderateComments
+|True
+|True if comment moderation is enabled in weblog
+
+|$weblog.name
+|String
+|Name of the weblog
+
+|$weblog.pages
+|List of PageTemplates
+|Page templates of weblog
+
+|$weblog.popularTags(int sinceDays, int length)
+|List of TagStat objects
+|Popular tags in past sinceDays number of days. Returns up to length number of objects.
+
+|$weblog.tagline
+|String
+|Weblog tagline (short description)
+
+|$weblog.timeZone
+|String
+|Timezone of the weblog
+
+|$weblog.todaysHits
+|Integer
+|Number of hits counted today
+
+|$weblog.weblogCategories
+|List of WeblogCategories
+|Weblog categories
+|===
+
+Weblog Methods
+
+* *WeblogEntry getWeblogEntry(String anchor)* Get an individual
+weblog entry by the entry’s anchor, which is unique within a weblog.
+* *List getRecentWeblogEntries(String cat, int max)* Get most recent
+WeblogEntries in the weblog up to the number max. You can specify a
+category name if you’d like only entries from one category (or "nil"
+for all categories).
+* *List getRecentComments(int max)* Get most recent Comments in the
+weblog up to the limit max.
+* *WeblogCategory getWeblogCategory(String name)* Get weblog category specified by name.
+* *PageTemplate getPageByName(String name)* Get page template specified
+by name.
+* *PageTemplate getPageByLink(String link)* Get page template specified by link.
+
+=== WeblogCategory
+
+|===
+|Name |Type |Description
+
+|$category.description
+|String
+|Description
+
+|$category.image
+|String
+|URL of image to be displayed for category
+
+|$category.inUse
+|Boolean
+|True if category is in use, i.e. if WeblogEntry objects use it
+
+|$category.name
+|String
+|Name of the category
+
+|$category.website
+|Weblog
+|Weblog that contains category
+|===
+
+=== WeblogEntry
+
+|===
+|Name |Type |Description
+
+|$entry.allowComments
+|Boolean
+|True if this weblog entry allows comments
+
+|$entry.anchor
+|String
+|Simple string that uniquely identifies post in weblog
+
+|$entry.categories
+|List of WeblogCategories
+|Weblog categories associated with this entry
+
+|$entry.category
+|WeblogCategory
+|Primary weblog category of this entry
+
+|$entry.commentDays
+|Integer
+|Number of days that comments are allowed
+
+|$entry.commentsStillAllowed
+|Boolean
+|True if comments are currently allowed
+
+|$entry.contentSrc
+|String
+|URL of entry content, if out-of-line
+
+|$entry.contentType
+|String
+|MIME content-type of entry
+
+|$entry.creator
+|User
+|User who created the entry
+
+|$entry.entryAttributes
+|List of EntryAttributes
+|Arbitrary name/value attributes associated with entry
+
+|$entry.pubTime
+|Date
+|Timestamp when entry was published
+
+|$entry.rightToLeft
+|Boolean
+|True if entry text is to be displayed right-to-left
+
+|$entry.searchDescription
+|String
+|Descriptive text that can be added to the weblog entry's HTML header for search engine optimization (SEO).
+
+|$entry.status
+|String
+|Status of entry (i.e. PUBLISHED)
+
+|$entry.summary
+|String
+|Raw summary text of entry
+
+|$entry.tags
+|List of WeblogEntryTags
+|Tags associated with entry
+
+|$entry.tagsAsString
+|String
+|Tags listed as a string
+
+|$entry.text
+|String
+|Raw content text of entry
+
+|$entry.transformedText
+|String
+|Content text of entry processed by plugins
+
+|$entry.transformedSummary
+|String
+|Summary text of entry processed by plugins
+
+|$entry.updateTime
+|Date
+|Timestamp of last modification to entry
+
+|$entry.website
+|Weblog
+|Entry's weblog
+|===
+
+WeblogEntry methods
+
+
+* *public String getDisplayContent()* Returns transformed text of entry
+or transformed summary if there is no entry.
+* *public String getDisplayContent(String readMoreLink)* If you pass in
+a non-null and non-empty entry permalink, then this method will return
+the transformed summary of the entry, or the text if there is no
+summary.
+* *public String findEntryAttribute(String name)* Returns the value of
+the entry attribute specified or null if no such attribute
+
+=== WeblogEntryTag
+
+A user can assign as many tags as they wish to each weblog entry.
+
+|===
+|Name |Type |Description
+
+|$tag.name
+|String
+|Weblog entry associated with this attribute
+
+|$tag.user
+|User
+|User who added the tag
+
+|$tag.weblogEntry
+|WeblogEntry
+|Weblog entry associated with tag
+
+|$tag.weblog
+|Weblog
+|Weblog associated with tag
+|===
+
+=== WeblogEntryAttribute
+
+Weblog entry attributes are name/value pairs that can be
+assigned to weblog entries. Currently, they’re only used to add podcasts
+to blog entries.
+
+== Macro Reference
+
+This section lists the macros that are available for use in Roller page
+templates, a brief description of how each works and where appropriate
+an outline of the generated HTML, which highlights the CSS classes
+defined.
+
+=== Entry macros
+
+`#showWeblogEntriesPager($pager)`
+
+Arguments:
+
+*$pager:* Pager object returned by a getWeblogEntriesPager() method
+
+Synopsis:
+
+Displays the weblog entries contained in the specified $pager object by
+calling your weblog’s _day template for each day’s worth of entries.
+
+Generated HTML and CSS classes used
+
+Depends entirely on contents of your weblog’s _day template.
+
+`#showNextPrevEntriesControl($pager)`
+
+Arguments:
+
+*$pager:* Pager object returned by a getWeblogEntriesPager() method
+
+Synopsis:
+
+Display the next/prev links of the specified $pager object.
+
+Generated HTML and CSS classes used
+
+Assuming you the page has prev and next links, the HTML will look
+something like the below. As you can see, no CSS classes are defined.
+
+----
+&laquo;
+<a href="..."> ...prev... </a> |
+<a href="..."> ...home...</a> |
+<a href="..."> ...next... </a>
+&raquo;
+----
+
+`#showEntryTags($entry)`
+
+Arguments:
+
+*$entry:* WeblogEntry object
+
+Synopsis:
+
+Display tags associated with one weblog entry as list of links to tag
+specific views of weblog.
+
+Generated HTML and CSS classes used
+
+No CSS classes are used, only a series of links like so:
+----
+<a href="…" rel="tag"> …tag name… </a>
+<a href="…" rel="tag"> …tag name… </a>
+----
+
+=== Comment macros
+
+`#showWeblogEntryComments($entry)`
+
+Arguments:
+
+*$entry:* WeblogEntry object
+
+Synopsis:
+
+Display the comments associated with the specified entry, not including
+those entries that are not approved for posting or that are marked as
+spam.
+
+Generated HTML and CSS classes used
+
+
+----
+<div class="comments" id="comments">
+  <div class="comments-head"> <!-- Comments title --> </div>
+  <div class="comment even" id="">
+  <!-- even like above or odd as below -->
+  <div class="comment odd" id="">
+    ...comment content...
+    <p class="comment-details">
+      ...comment details...
+      <a href="link to comment" class="entrypermalink" >#</a>
+    </p>
+  </div>
+</div>
+----
+
+`#showWeblogEntryCommentForm($entry)`
+
+Arguments:
+
+*$entry:* WeblogEntry object
+
+Synopsis:
+
+Display a comment form for adding a comment to the specified entry.
+
+Generated HTML and CSS classes used
+
+If comments are no longer allowed for the weblog entry in question, then
+only a status message is generated:
+
+----
+<span class="status"> …comments closed message… </span>
+----
+
+Otherwise we display the comment form.
+
+----
+<div class="comments-form">
+  <div class="comments-head"> ...comment form title...</div>
+  <span class="error"> ...error message... </span>
+  <span class="status"> ...status message... </span>
+  <form method="post" name="commentForm" ...>
+    <ul>
+      <li>
+        <label class="desc"> ...text field... </label>
+        <input type="text" name="name" class="text large" .../></li>
+      <li>
+        <input type="checkbox" class="checkbox" .../> <label class="choice"> ...checkbox field... </label>
+      </li>
+      <li>
+        <label class="desc"> ... </label>
+        <textarea name="content" class="textarea large" cols="" rows="">
+          <!-- Comment content -->
+        </textarea>
+      </li>
+      <li class="info">
+        <span class="comments-syntax-indicator">
+        <span class="disabled"> Disabled </span>
+          <!-- disabled as above or enabled as below --> <span class="enabled"> Enabled </span>
+        </span>
+      </li>
+      <li class="info">
+        <div id="commentAuthenticator"></div>
+      </li>
+      <li>
+        <input type="button" class="button" .../> <!-- preview button -->
+        <input type="submit" class="button" .../> <!-- preview button --> </li>
+    </ul>
+  </form>
+----
+
+=== List macros
+
+`#showWeblogEntryLinksList($entries)`
+
+Arguments:
+
+$entries: List of WeblogEntry objects to be displayed in a list inks
+
+Synopsis:
+
+Display a simple list of entries, with a title and link for each.
+
+Generated HTML and CSS classes used
+
+We use a simple HTML list:
+
+----
+<ul class="rEntriesList">
+<li class="recentposts"><a href="..."> ...title... </a></li>
+</ul>
+----
+
+`#showBookmarkLinksList($folderObj)`
+
+Arguments:
+
+$folderObj: Folder object from which bookmarks are to be shown
+
+Synopsis:
+
+Displays all bookmarks in a specified bookmark folder object.
+
+Generated HTML and CSS classes used
+
+We generate a simple nested list with different CSS classes for the <ul>
+list and <li> list item elements. The bookmark CSS class is prepended
+with the priority number of the bookmark.
+
+----
+<ul class="rFolder">
+  <li class="rFolderItem">
+    <a href="..." class="rBookmark10"/>...bookmark name... </a> </li>
+  <li class="rFolderItem">
+    <a href="..." class="rBookmark5"/>...bookmark name... </a>
+  </li>
+</ul>
+----
+
+`#showWeblogCategoryLinksList()`
+
+Synopsis:
+
+Displays the defined categories for a given weblog.
+
+Generated HTML and CSS classes used
+
+----
+<ul class="rCategory">
+  <li> ...unselected category name...</li>
+  <li class="selected"> ...selected category name...</li>
+</ul>
+----
+
+`#showMobileCategoryLinksList()`
+
+Synopsis:
+
+Displays the defined categories for a given weblog in a format better
+suited for mobile devices.
+
+Generated HTML and CSS classes used
+
+----
+<ul>
+  ...
+  <li class="ui-btn-active">
+  ...
+</ul>
+----
+
+=== Menu macros
+
+#showPageMenu($weblog)
+
+Arguments:
+
+*$weblog:* Show page menu for this weblog
+
+Synopsis:
+
+Display a page navigation menu that lists all pages in the weblog.
+
+Generated HTML and CSS classes used
+
+The page menu is displayed as a simple HTML list with separate CSS
+styles for list and list-items.
+
+----
+<ul class="rNavigationBar">
+  <li class="rNavItem">
+    <a href="..."> ...name... </a>
+  </li>
+</ul>
+----
+
+`#showAuthorMenu($vertical)`
+
+Arguments:
+
+*$vertical:* True to display vertical menu, false to display
+horizontal
+
+Synopsis:
+
+Display an authoring menu for the current weblog. If $vertical is true,
+then display a menu suitable for use in a narrow sidebar.
+
+Generated HTML and CSS classes used
+
+For a vertical menu, we use a simple HTML list:
+
+----
+<ul class="rMenu">
+  <li><a href="..."> ...menu item name... </a></li>
+</ul>
+----
+
+For a horizontal menu, we simply emit a series of pipe-separated links:
+
+----
+<a href="..."> ...menu item name... </a> &nbsp;|&nbsp;
+<a href="..."> ...menu item name... </a> &nbsp;|&nbsp;
+<a href="..."> ...menu item name... </a>
+----
+
+=== Search macros
+
+`#showWeblogSearchForm($weblog $withCats)`
+
+Arguments:
+
+*$weblog:* show search form for this Weblog object** $withCats: **set
+to true to display a category combo-box
+
+Show a search form for searching the weblog and, if $withCats is true
+show a category chooser.
+
+Generated HTML and CSS classes used
+
+----
+<form id="searchForm" style="margin: 0; padding: 0" ...>
+  ...form markup...
+</form>
+----
+
+`#showWeblogSearchAgainForm($weblog)`
+
+Arguments:
+
+*$weblog:* show search-again form for this Weblog object****
+
+Synopsis:
+
+Show search again form, suitable for display at the start of a page of
+search results.
+
+Generated HTML and CSS classes used
+
+----
+<div id="searchAgain">
+  <form>
+    ...form markup...
+  </form>
+</div>
+----
+
+`#showNextPrevSearchControl($pager)`
+
+Arguments:
+
+*$pager:* Pager returned by getWeblogEntriesPager() in the context of
+a search page
+
+Synopsis:
+
+Show special pager designed for paging through search results.
+
+Generated HTML and CSS classes used
+
+----
+<h3> ...search summary... </h3>
+&laquo;
+<a href="..."> ...prev... </a> |
+<a href="..."> ...home... </a> |
+<a href="..."> ...next... </a>
+&raquo;
+----
+
+=== Misc. macros
+
+`#showWeblogEntryCalendar($weblog $category)`
+
+Arguments:
+
+*$weblog:* Weblog object
+
+*$category:* Category restriction (or `nil' for no restriction)
+
+Synopsis:
+
+Show weblog entry calendar, optionally restricted by category name
+("nil" for no category)
+
+Generated HTML and CSS classes used
+
+A weblog entry calendar is displayed as a table with different CSS
+classes for <td>, <th>, <div> and links elements within, as illustrated
+below.
+
+----
+<table class="hCalendarTable" ...>
+  <tr>
+    <td colspan="7" class="hCalendarMonthYearRow">
+      <a href="..." class="hCalendarNavBar">&laquo; ...prev month...</a> |
+      <a href="..." class="hCalendarNavBar">&raquo; ...next month...</a></td>
+  </tr>
+  <tr>
+    <th class="hCalendarDayNameRow" align="center">Sun</th>
+    ...days of week...
+    <th class="hCalendarDayNameRow" align="center">Sat</th>
+  </tr>
+  <tr>
+    <td class="hCalendarDayNotInMonth">&nbsp;</td>
+    ...days of week...
+    <td class="hCalendarDay">
+      <div class="hCalendarDayTitle">1</div>
+    </td>
+    <td class="hCalendarDayLinked">
+      <div class="hCalendarDayTitle">
+        <a href="...">2</a>
+      </div>
+    </td>
+  </tr>
+  <tr class="hCalendarNextPrev">
+    <td colspan="7" align="center">
+      <a href="..." class="hCalendarNavBar">Today</a></td>
+  </tr>
+</table>
+----
+
+`#includeTemplate($weblog $pageName)`
+
+Arguments:
+
+*$weblog:* Weblog object from which page is to be included
+
+*$pageName:* Name of page to be included
+
+Synopsis:
+
+Parse and include a page template into current page.
+
+`#showAutodiscoveryLinks($weblog)`
+
+Arguments:
+
+*$weblog:* Weblog object
+
+Synopsis:
+
+Show the RSS, Atom and RSD auto-discovery links suitable for use within
+an HTML <head> element.
+
+Generated HTML and CSS classes used
+
+No style-able markup is produced.
+
+`showMetaDescription()`
+
+Arguments: None
+
+Synopsis:
+
+Adds a meta description tag, suitable for use in HTML header sections.
+This tag is frequently used by
+
+search engines to provide a short description for links returned. The
+description value will set to the
+
+weblog’s tagline (weblog.description) if on a multiple blog entry page
+or the weblog entry search description (weblogEntry.searchDescription)
+if on a single blog entry (permalink) page. If the relevant description
+value has not been configured no meta tag will be created.
+
+Generated HTML and CSS classes used
+
+No style-able markup is produced.
+
+`showAnalyticsTrackingCode($weblog)`
+
+Arguments:
+*$weblog:* Weblog object
+
+Synopsis:
+
+Adds either the blog-specific or blog server-level web analytics
+tracking code provided by such services as Google Analytics. The
+server-level default tracking code is used unless a blog-specific one
+has been configured. See the Roller User’s Guide - Weblog Settings and
+Roller Administration sections for information on where to configure the
+tracking codes within Roller. This tag is normally placed within the
+HTML header section.
+
+Generated HTML and CSS classes used
+
+No style-able markup is produced.
+
+`#showTrackbackAutodiscovery($entry)`
+
+Arguments:
+
+*$entry:* WeblogEntry object
+
+Synopsis:
+
+Show trackback autodiscovery code for a specified weblog entry, suitable
+for use within a day template.
+
+Generated HTML and CSS classes used
+
+No style-able markup is produced.
+
+`#showAtomFeedsList($weblog)`
+
+Arguments:
+
+$weblog: Weblog object
+
+Synopsis:
+
+Displays a list of links to a weblog’s Atom newsfeeds. One for entries
+and one for entries in each category that is defined in your weblog.
+
+Generated HTML and CSS classes used
+
+The feed list is displayed as a simple HTML list with separate styles
+for list and list-items.
+
+----
+<ul class="rFeeds">
+  <li> <a href="..."> ...feed name...</a> </li>
+</ul>
+----
+
+`#showRSSFeedsList($weblog)`
+
+$weblog: Weblog object
+
+Synopsis:
+
+Displays a list of links to a weblog’s RSS newsfeeds. One for entries
+and one for entries in each category that is defined in your weblog.
+
+Generated HTML and CSS classes used
+
+The feed list is displayed as a simple HTML list with separate styles
+for list and list-items.
+
+----
+<ul class="rFeeds">
+  <li><a href="..."> ...feed name... </a></li>
+</ul>
+----
+
+And that’s it for the Roller macros. Before we move on to additional
+models, let’s cover something you might want to do, but that doesn’t yet
+have a macro – creating a tag cloud.
+
+=== Displaying a Tag Cloud
+
+We don’t yet include a Tag Cloud macro in Roller because it’s so easy to
+create one yourself. Here’s what you do to display a tag cloud for your
+weblog. First, if you have not already done so, customize your theme.
+Next, you’ve got to get the tags you want to display from your weblog
+object. For example, to get your most 30 most often used tags for all
+time you’d do this:
+
+`#set($mytags = $model.weblog.getPopularTags(-1, 30))`
+
+Or if you want to only get tags used in the last 90 days you’d do this:
+
+`#set($mytags = $model.weblog.getPopularTags(90, 30))`
+
+Once you’ve got your tags, you can display them with a _foreach_ loop.
+For example, here’s a loop that displays each tag as a link to your
+weblog that displays only entries in that tag. It also gives each tag a
+CSS class that indicates the intensity of the tag, which indicates on a
+scale of zero to five how often-used the tag is.
+
+----
+#foreach ($tag in $mytags)
+  <a class="tag s${tag.intensity}" href="$url.tag($tag.name)" title="$tag.count">
+    $tag.name
+  </a>
+#end
+----
+
+Include that _#set_ statement and loop in your weblog template and
+you’ll see a tag cloud, but it all the tags will be displayed in the
+same size and font. If you’d like to vary the size of the tags based on
+how often they are used, then you’ll need to add some CSS. Edit your CSS
+template and add this to size often used tags larger than those less
+often used:
+
+----
+.s1 {font-size:60%;}
+.s2 {font-size:80%;}
+.s3 {font-size:100%;}
+.s4 {font-size:120%;}
+.s5 {font-size:140%;}
+----
+
+== Additional models
+
+There are some additional models that can be made available to Roller
+weblogs by a site administrator. These are the
+*$site* for accessing site-wide data,and the *planet* model for accessing Planet Roller data. Let’s start with the $site
+model.
+
+=== $site
+
+The *$site* model provides access to site-wide data: aggregations of
+webog entries from all weblogs, comments from all weblogs, lists of
+users, lists of weblogs, etc. – in short, everything you need to build
+an interesting community front page for Roller.
+
+==== $site Objects
+
+Site object
+
+|===
+|Name |Type |Description
+
+|$site.commentCount
+|Long
+|Total number of comments in entire site
+
+|$site.entryCount
+|Long
+|Total number of entries in entire site
+
+|$site.userCount
+|Long
+|Total number of users in entire site
+
+|$site.weblogCount
+|Long
+|Total number of weblogs in entire site
+|===
+
+For some SiteModel methods (e.g. hot-blogs, most commented, etc.) return
+a special type of object use to expressing a count with a short name, a
+long name and an internationalized type:
+
+*StatCount object*
+
+|===
+|Name |Type |Description
+
+|$stat.subjectNameLong
+|WeblogEntry
+|Long name of subject of statistic (e.g. name of a weblog)
+
+|$stat.subjectNameShort
+|String
+|Short name of subject of statistic (e.g. handle of a weblog)
+
+|$stat.count
+|Integer
+|Value of the statistic (i.e. number of hits)
+
+|$stat.typeKey
+|String
+|I18N key for type of the statistic
+|===
+
+==== $site Methods
+
+* *Pager getWeblogEntriesPager(int sinceDays, int max)* Get pager that
+returns WeblogEntry objects. Will only return entries created in last
+sinceDays number of days and never more than max items.
+* *Pager getWeblogEntriesPager(Weblog weblog, int sinceDays, int max)*
+Get pager that returns WeblogEntry objects from one specific weblog.
+Will only return entries created in last sinceDays number of days and
+never more than max items.
+* **Pager getWeblogEntriesPager(**[#anchor-27]##*Pager
+getWeblogEntriesPager(Weblog weblog, User user, int sinceDays, int max)*
+Get pager that returns WeblogEntry objects from one specific weblog and
+user. Will only return entries created in last sinceDays number of days
+and never more than max items.
+* *Pager getWeblogEntriesPager(Weblog weblog, User user, String
+category, int sinceDays, int max)* Get pager that returns WeblogEntry
+objects from one specific weblog and category. Will only return entries
+created in last sinceDays number of days and never more than max items.
+* *Pager getCommentsPager(int sinceDays, int max)* Get pager that
+returns Comment objects. Will only return comments created in last
+sinceDays number of days and never more than max items.
+* *Pager getUsersByLetterPager(String letter, int sinceDays, int max)*
+Get pager that returns User objects. Will only return users whose names
+start with letter, created in last sinceDays number of days and never
+more than max items.
+* *Pager getWeblogsByLetterPager(String letter, int sinceDays, int max)*
+Get pager that returns Weblog objects. Will return weblogs whose handles
+start with the provided (single) letter, created in last sinceDays
+number of days and never more than max items. If the provided letter
+parameter is more than one character only its first character will be
+used.
+* *Map getUserNameLetterMap()* Get map of User objects keyed by first
+letter.
+* *Map getWeblogHandleLetterMap()* Get map of Weblog objects keyed by
+first letter.
+* *List getUsersWeblogs(String userName)* Get list of all Weblog objects
+associated with a specified user.
+* *List getWeblogsUsers(String handle)* Get list of all User objects
+associated with a specified weblog.
+* *Weblog getWeblog(String handle)* Get Weblog object by handle.
+* *List getNewWeblogs(int sinceDays, int max)* Get newest Weblog
+objects, i.e. only those created in last sinceDays number of days.
+* *List getNewUsers(int sinceDays, int max)* Get newest User objects,
+i.e. only those created in last sinceDays number of days.
+* *List getHotWeblogs(int sinceDays, int max)* Get recent hot Weblogs in
+the form of StatCount objects, but only those updated in last sinceDays
+number of days.
+* *List getMostCommentedWeblogs(int sinceDays, int max)* Get most commented weblogs in the form of
+StatCount objects, but only those updated in last sinceDays number of
+days.
+* *List getMostCommentedWeblogEntries(List cats, int
+sinceDays, int max)* Get most commented WeblogEntries in the form of
+StatCount objects, but only those updated in last sinceDays number of
+days.
+
+=== $planet
+
+The *$planet* model makes Planet Roller data available to weblog pages.
+It allows you to display the main aggregation (i.e. the one named
+"external"), any custom group aggregation, a feed and ranked
+subscriptions.
+
+==== Configuring the planet model
+
+The PlanetModel is not enabled by default in Roller, so before you can
+use it in your weblogs you’ll need to enable it. To do that, you need to
+define some properties in your Roller configuration and specifically, in
+your _roller-custom.properties_ override file, which is explained in
+STEP 8 and Appendix B of the Roller Installation Guide.
+
+If you want to make the Planet model available in weblog pages then add
+the Planet model to the list of models specified by the
+_rendering.pageModels_ property by overriding the property in your
+_roller-custom.properties_ file like so:
+
+----
+rendering.pageModels=\
+org.apache.roller.ui.rendering.model.PageModel,\
+org.apache.roller.ui.rendering.model.ConfigModel,\
+org.apache.roller.ui.rendering.model.UtilitiesModel,\
+org.apache.roller.ui.rendering.model.URLModel,\
+org.apache.roller.ui.rendering.model.MessageModel,\
+org.apache.roller.ui.rendering.model.CalendarModel,\
+org.apache.roller.ui.rendering.model.MenuModel, \
+org.apache.roller.ui.rendering.model.PlanetModel
+----
+
+That’s just a copy of the property setting from the default Roller
+properties file, plus the Planet model (shown in bold). Actually,
+depending on where want to use the Planet Model in Roller, you’ll need
+to add the Planet model to a couple of different properties.
+
+To make Planet model available in all blogs, you’ll want to add it to
+these model list properties:
+
+* rendering.pageModels: to make it available in blog pages.
+* rendering.previewModels: to make it available when entries are
+previewed in the blog editor
+
+To make Planet model available in the front page blog only:
+
+* rendering.siteModels: to make the model available in site-wide blogs
+
+Now let’s discuss the objects available from the Planet model.
+
+==== $planet Objects
+
+The $planet model returns two types of objects that we haven’t seen
+before: the PlanetSubscription object, which represents a feed
+subscription, and PlanetEntry, which represents one entry from a feed.
+
+*PlanetSubscription object*
+
+|===
+|Name |Type |Description
+
+| $sub.author
+|String
+|Author, from feed header
+
+|$sub.feedURL
+|String
+|URL of the feed
+
+|$sub.inboundBlogs
+|Integer
+|Number of weblogs that link to this weblog (or 0 if no Technorati license available)
+
+|$sub.inboundLinks
+|Integer
+|Number of links to this weblog (or 0 if no Technorati license available)
+
+|$sub.lastUpdated
+|Date
+|Last update time, from feed header
+
+|$sub.name
+|String
+|Name of the feed
+
+|$sub.title
+|String
+|Title of the feed
+
+|$sub.URL
+|String
+|Same as feedURL
+|===
+
+*PlanetEntry object*
+
+|===
+|Name |Type |Description
+
+|$entry.author
+|String
+|Name of author of entry
+
+|$entry.category
+|WeblogCategory
+|Category of entry
+
+|$entry.creator
+|User
+|User object representing author
+
+|$entry.guid
+|String
+|Unique ID of entry
+
+|$entry.permalink
+|String
+|Permanent link to entry
+
+|$entry.pubTime
+|Date
+|Time entry was published
+
+|$entry.summary
+|String
+|Entry summary text
+
+|$entry.text
+|String
+|Entry content text
+
+|$entry.title
+|String
+|Entry title
+
+|$entry.updateTime
+|Date
+|Time entry was last updated
+
+|$entry.website
+|PlanetSubscription
+|Subscription to which entry belongs
+|===
+
+==== $planet Methods
+
+* *Pager getAggregationPager(int sinceDays, int max)* Get pager that
+returns PlanetEntry objects from the main aggregation. Will only return
+entries created in last sinceDays number of days and never more than max
+items.
+* *Pager getAggregationPager(String groupHandle, int sinceDays, int
+max)* Get pager that returns PlanetEntry objects from the specified
+group aggregation. Will only return entries created in last sinceDays
+number of days and never more than max items.
+* *Pager getFeedPager(String feedURL, int max)* Get pager that returns
+PlanetEntry objects from the specified feed, up to max items.
+* *List getRankedSubscriptions(int sinceDays, int max)* Get all
+PlanetSubscription objects ordered by Technorati ranking. Will only
+return subscriptions updated in last sinceDays number of days and never
+more than max items.
+* *List getRankedSubscriptions(String groupHandle, int sinceDays, int
+length)* Get PlanetSubscription objects in the specified group ordered
+by Technorati ranking. Will only return subscriptions updated in last
+sinceDays number of days and never more than max items.
diff --git a/docs/roller-template-guide.odt b/docs/roller-template-guide.odt
deleted file mode 100644
index 541eb86..0000000
--- a/docs/roller-template-guide.odt
+++ /dev/null
Binary files differ
diff --git a/docs/roller-template-guide.pdf b/docs/roller-template-guide.pdf
deleted file mode 100644
index 6ae010d..0000000
--- a/docs/roller-template-guide.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/roller-user-guide.adoc b/docs/roller-user-guide.adoc
new file mode 100644
index 0000000..343dc20
--- /dev/null
+++ b/docs/roller-user-guide.adoc
@@ -0,0 +1,1613 @@
+= User Guide
+Apache Roller Weblogger
+:toc:
+:sectnums:
+:imagesdir: ./images
+
+== Overview
+
+This document is a user guide to the Apache Roller Weblogger, the
+Java-based and open source weblog server that is produced by the Apache
+Roller project of the Apache Software Foundation.
+
+There are separate guides available on other topics; a Template Guide
+for those who wish to customize the layout and design of their weblog
+pages and an Installation Guide for those installing the Roller software
+on a web server.
+
+=== Copyright and trademark information
+
+The contents of this document are subject to the terms of the Apache
+Software License.
+
+All trademarks within this document belong to legitimate owners.
+
+=== Feedback
+
+Please direct any comments or suggestions about this document to:
+dev@roller.apache.org
+
+== Introduction
+
+This user guide describes how to use the Apache Roller Weblogger or
+Roller for short, a web application that can support a single user
+weblog, thousands of weblogs and/or group weblogs.
+
+You’ll learn how to register as a new user. You’ll learn how to create
+one or more weblogs for yourself or a group of your friends. You’ll
+learn how to create, edit and post weblog entries. We will also cover
+more advanced topics such as adjusting your weblog’s settings, how to
+customize your blogroller, how to manage weblog pings and more.
+
+First, let’s get some terminology out of the way because there’s a lot
+of jargon in weblogging. Here’s a list of some of the terms we use in
+this manual without a whole lot of background.
+
+* *Weblog*: A set of web pages and RSS/Atom feeds that display weblog
+entries written by one or more authors, uploaded images, bookmarks and
+comments posted by visitors. Weblog entries are displayed on the main
+page of the weblog and in the weblog’s feeds in reverse chronological
+order.
+* *Weblog entry*. A single weblog entry with a title, publication
+timestamp, summary, content and some settings that indicate if and when
+comments are allowed.
+* *Comment*. A comment posted by a visitor to a weblog and regarding one
+specific weblog post. A comment has an email address, a publication
+timestamp and some content.
+* *Trackback*. A comment posted by a remote weblog regarding one
+specific weblog post. Trackbacks are stored as comments by Roller.
+* *Templates*. Each Roller weblog is defined by a set of HTML and CSS
+templates that provide the layout and styles for the weblog. Normally
+templates are authored using Velocity template language, but other
+languages are possible via plugins (i.e. Groovy Server Pages, JRuby,
+etc.)
+* *Feed*. A feed is an XML representation of the most recent entries,
+comments or other data. Folks can subscribe to your feed to be alerted
+of new weblog entries and comments posted. Roller supports both RSS and
+Atom formats for feeds.
+* *Feed reader*. Software that makes it easy to subscribe to and read
+feeds, e.g. Google Reader, Net News Wire, Feed Demon, etc.
+* *Blog client*. Software that makes it easy to post to your weblog,
+e.g. Ecto and Mars Edit.
+
+With that out of the way, let’s get started blogging with Roller.
+
+== Getting started with Roller
+
+Getting started with Roller means different things to different people.
+If you are using an existing Roller server, then getting started means
+registering a new user and creating or joining a weblog. If that’s the
+case for you, skip ahead to section 3.2. If you just finished setting up
+your own Roller installation on your own web server, then getting
+started means a little bit more. You’ve got a little post installation
+work to do.
+
+=== Getting started with a new Roller installation
+
+Once you’ve got Roller up and running you will see a screen like the one
+below, which explains exactly what you’ve got to do to get started with
+Roller. First, create a new user so you can login. Second, login and
+create a weblog for yourself or one to server as the front page of the
+site or both. Third, designate which weblog is the front page weblog.
+
+image::user-guide-1-welcome.png[]
+
+**Creating the first user. **Your first step is to create a new user.
+Remember, the first user you create will be given administrative
+privileges. You might want to use the username "admin" or something
+similar. Later, you can login as the admin user when you need to change
+site-wide settings. If you wish, you can grant other users admin
+privileges so they can help out with admin duties. Let’s take a look at
+the user registration page. You can see the new user registration form
+in the next section.
+
+**Create the first weblog(s). **Next you should create at least one
+weblog. See section 3.2 below for some more information the create
+weblog page. If you are running a personal blog site, then you might
+want your weblog to serve as the front page of your site. In that case,
+create a weblog, use a normal weblog theme (i.e. not the Roller Homepage
+theme) and assign your weblog as the front page weblog of the site.
+
+If you are running a community weblog site with multiple weblogs, then
+you will probably want to create a weblog to serve as the front page of
+the site. Create a new weblog, name it "main" or "community" or
+something suitable because its name will appear in URLs. And we
+recommend that you use the Roller Homepage theme because it is specially
+designed to serve as a weblog community front page, aggregating all of
+the site’s weblogs together but having no content of its own.
+
+**Designate a front page weblog. **Once you’ve created a front page
+weblog, whether it be a personal weblog or a community aggregator, you
+need to tell Roller. So, select your front page weblog and, if you are
+running a community site then set the _Enable aggregated site-wide
+frontpage_ checkbox before you click Save.
+
+If you’ve read this far, you’ve probably created your own user and
+weblog and if so you can skip the next section.
+
+=== Creating a new user and weblog
+
+To create a new user use the Register link, which can be found in the
+top right of the Roller login page. That link will take you to the New
+User Registration page shown below.
+
+image::user-guide-2-registration.png[]
+
+The New User Registration form is pretty self-explanatory, but keep in
+mind that your username cannot be changed; it is your unique identifier
+in the system. But that’s OK because your screen name is the name that
+will be displayed on your weblog and in your feeds and you _can_ change
+it later if you wish.
+
+Instead of username and password, the Roller administrator may provide
+(or require) OpenID (http://openid.net/[http://openid.net])
+authentication. With OpenID you will not provide a password (as you will
+be logging into another system to authenticate) but just your OpenID
+account name, whose format will vary based on the OpenID provider. For
+example, using Google+ as your OpenID provider will result in an account
+name similar to https://profiles.google.com/&lt;numeric-ID &gt;, where the
+numeric identifier can be determined simply by Googling your name along
+with "google plus". (Note the OpenID string does _not_ use the
+plus.google.com domain returned by this query.)
+
+**Picking your language and timezone. **You can set your language of
+choice and timezone too, but these values don’t do much in Roller. The
+locale and timezone of your weblog are really what matter. The values
+you set here will be used as your defaults when you create your weblog.
+
+**Creating a weblog . **Once you’ve created a user, then log in and
+you’ll see the Roller Main Menu page and a greeting that reads:
+
+You’ve got a user account, but no weblog. Would you like to _create
+one_?
+
+Follow that link to create your first weblog. You’ll see the form below.
+
+image::user-guide-3-webblog.png[]
+
+The form is designed to be self-explanatory. Note that you can change
+everything later, except for the weblog handle, which is the unique
+identifier for your weblog.
+
+Now that you’ve got a user and a weblog, let’s discuss how to get around
+in the Roller interface.
+
+=== Getting around in Roller
+
+Once you’ve logged into Roller’s editor pages you should be able to find
+your way around using Roller’s tabbed menu. To provide a little extra
+assistance, Roller displays a status bar at the top of each editor page.
+
+For example, the status bar below indicates that you are logged in as
+user 'admin' and you are not editing a weblog. You can go directly to
+the front page of the site by clicking the first link on the right (it
+might not be labelled Front Page on your site), to the main menu with
+the second link and you can log out entirely by using the Logout.
+
+image::user-guide-4-statusbar.png[]
+
+For example, the status bar below indicates that you are logged in as
+user 'admin' and you are editing a weblog with the handle 'adminblog'.
+
+image::user-guide-5-statusbar-webblog.png[]
+
+If you are not logged into Roller then you can either access the login
+link directly or use a Login link from one of the weblogs on the site.
+The login link is of this form:
+
+_http://hostname/roller-ui/login-redirect.rol_
+
+Or this form if Roller is installed under its own context:
+
+_http://hostname/roller/roller-ui/login-redirect.rol_
+
+You probably won’t need to cut-and-paste that link because most weblogs
+display an author menu like so:
+
+image::user-guide-6-navigation.png[]
+
+Now that we’ve covered the basics of registering a new user, creating a
+new weblog and finding your way around let’s start blogging.
+
+== Creating and editing your weblog
+
+First, you log in to Roller. What happens next depends on the number of
+weblogs that you have. If you have one weblog, you’ll be taken directly
+to the *New Entry* page for that weblog.
+
+If you have more than one weblog or none at all, then you’ll be taken to
+the *Main Menu* page, shown below, so you can pick which weblog to edit
+and/or create new weblogs.
+
+image::user-guide-7-main-menu.png[]
+
+The main menu page lists all of your weblogs and for each, shows you
+links to its New Entry, Entries, Comments, Theme and Settings pages. You
+can also create a new weblog, edit your user profile.
+
+If you are logged in as a Global Administrator, you will also see a
+Server Admin link in the actions side-bar. And if you have Roller’s
+Planet aggregator enabled, then you will also see a Planet Admin link
+there as well.
+
+=== Creating and editing a weblog entry
+
+Use the *Create & Edit -> New Entry* page (also known as the Weblog
+editor page) to create, edit and publish weblog entries. Using this
+page, shown below in illustration 7, you can set entry title, category,
+content and summary. You can also set some advanced settings by
+expanding the _Plugins To Apply_ and _Advanced Settings_ controls at the
+bottom of the page. Let’s review those fields, buttons and settings.
+
+image::user-guide-8-editor.png[]
+
+==== Weblog editor fields
+
+Let’s discuss each of the fields on the New Entry page, so you know how
+to use them.
+
+* *Title* – Each weblog entry must have a title. Be careful when you
+pick your title, it will be used in the permalink (URL) for your weblog
+entry (up to the first five words of the blog title, separated by
+hyphens). For best results, _do_ use titles that are short and
+to-the-point. __Don’t __include any HTML in your titles, just plain text
+– if you want your titles to be bold, then customize your templates
+instead of embedding HTML in your titles.
++
+To generate a permalink different from the actual blog title, first type
+in the desired permalink, then hit Save As Draft which will create the
+permalink. Then change the blog title to whatever desired for the blog
+entry prior to publishing it—the permalink won’t change.
+* *Status* – This read-only field tells you about the current state of
+the weblog entry that you are editing. There are three possible status
+settings:
+
+* _Not Saved_ – the entry has never been saved
+* _Draft_ – the entry is saved as a draft and is not yet visible to your
+weblog’s readers
+* _Published_ – the entry has been published and is visible to your
+weblog’s readers
+* *Permalink* – this read-only field is the permalink link to your
+weblog entry. It is set the first time that you save an entry, based on
+the title at the time you save (see Title section above), and it cannot
+be changed later. As a workaround for getting a new permalink, the text
+of a blog entry can be copied to a new blog entry with the desired
+permalink and the published date set back to that of the original blog
+entry (Advanced settings). Once the new blog entry is published, then
+just delete the old blog entry with the undesired URL. However, be
+cautious about changing a permalink in this manner because all external
+links to original blog entry will be broken as a result.
+* *Category* – You can pick one category for your weblog entry.
+Categories are for folks who want to organize their weblog entries by
+subject. You can add and remove categories via the Categories page.
+* *Tags* – (optional) In addition to assigning each of your weblog
+entries to a category you can also tag them. You can assign a list of
+tags to each entry. You can use any tag name you want. Separate your
+tags with spaces. Currently, the only way to do multi-word tags is to
+use an underbar, for example to tag something with "apache roller" you
+would use the tag apache_roller. As you type, Roller may suggest tags
+that you’ve used before.
+* *Content* – This is the main body of your weblog entry, in HTML
+format. We try to make that easy by providing two ways to edit the
+content. Via the Settings page, you can pick either of these:
+* *Rich Text Editor (Xinha)* – a rich-text editor that’s designed to
+make editing HTML as easy as using MS Word or Open Office.
+* *Text Editor* – a plain-text editor that you can use to edit the raw
+HTML markup of your weblog entries. Don’t use this unless you know HTML.
+* *Summary* – (optional) If you wish, you can enter a short summary of
+your weblog post. If you do so, then the short summary will be displayed
+on the main page of your weblog and your readers will have to click a
+Read More link to get to the full-content. Some bloggers like to do this
+when they have very long post and they don’t want that long post to
+dominate the main page of their weblog.
+
+==== Weblog editor buttons
+
+Here’s a guide to the buttons that appear on the Weblog editor page.
+
+* *Post to weblog* – Using this button will publish your weblog entry
+and make it visible to the world. Make sure you’re happy with your post
+before you publish because once something is published on the web, and
+grabbed by the blog aggregators and search engines, _there’s really no
+way to un-publish_ it.
+* *Submit for review* – if you’re just a limited blogger, you won’t see
+the Post to weblog button because you cannot post to the web. Instead,
+you’ll see a Submit for review button which you can use to send your
+entry to the author/admin of the blog that you are working in. If they
+like the post, they can publish it – or they can return it to you for
+further edits.
+* *Save as draft* – this will save your weblog post for later editing,
+but will _not_ publish it to the web. When you’re working on a new
+weblog entry, use Save as draft often so you won’t lose your post in the
+event of internet connection loss or session time-out.
+* *Delete entry* – use this to delete the current weblog entry, you’ll
+be asked to confirm.
+* *Full preview* – You won’t see this button until you’ve saved your
+entry as a draft. It allows you to view, in a separate window, a preview
+of your entry, displayed using the layout and style of your blog.
+
+==== Weblog editor plugin settings
+
+If you expand the _Plugins to Apply_ control, you’ll see a set of
+check-boxes, one for each Weblog Entry Plugin that is available. Check
+the ones that you’d like to apply to your current weblog entry. If you
+have a favorite plugin, one that you want to use on every entry, then
+you can set it as a default on your weblog’s Settings page.
+
+image::user-guide-plugin.png[]
+
+==== Weblog editor advanced settings
+
+If you expand the _Advanced Settings_ control, you’ll see what’s below.
+
+image::user-guide-settings.png[]
+
+All of these are optional settings.
+
+* *Pub Time* – if you’d like to set the publication time of your weblog
+entry to a specific time, possibly one in the future, you can do so
+here.
+* *Allow comments for* – this setting allows you to turn comments on/off
+for your weblog entry and to limit the number of days that comments are
+allowed.
+* *Text reads left-to-right* – this settings allows you to set the reads
+left-to-right flag for a weblog entry. Currently, none of the stock
+Roller templates respect this setting.
+* Pinned to main – only Global Administrators will see this setting.
+It’s a way to indicate that a post is a __special announcement __that
+should be pinned to the top of the front-page of a weblog site. The
+front-page theme respects this setting.
+* *Enclosure URL*: if you’d like to include a audio, video or image file
+as a p__odcast__ in your weblog’s RSS feed, then enter the URL of that
+file here.
+
+=== Finding and editing weblog entries
+
+All of your weblog entries are saved in a database. Once your entries
+scroll off the front page or off the recent entries list of the weblog
+editor page, they are still available via next and previous links
+displayed on your weblog and via the weblog calendar that is included in
+most weblog themes.
+
+You can also access your entries via the Edit Entries page, which allows
+you to search entries via keyword, category, tags, date and status.
+
+image::user-guide-9-entries.png[]
+
+=== Managing categories
+
+Each weblog can define its own unique list of categories to be used for
+categorizing weblog entries, using the Categories page shown below. When
+you or another author of your weblog creates a new entry you _must_
+choose one of the categories you have defined.
+
+image::user-guide-10-categories.png[]
+
+You can use the Categories page to add new categories and to edit your
+existing ones. You can change category names if you wish. And you can
+also delete categories and if a category is in use you will be asked to
+re-categorize the entries in that category.
+
+You can also define icons for each category, but support for icon images
+has not been coded in most Roller themes, requiring you to do template
+customization if you wish to display them.
+
+=== Managing your weblog’s blogroll
+
+Roller makes it easy to maintain a _blogroll_, that is, a list of your
+favorite weblogs and web sites that is displayed in the sidebar of your
+weblog. Individual blogroll items are known as _bookmarks_. Use the *Create &
+Edit:Blogroll* page to add, edit and delete bookmarks and bookmark
+folders in your blogroll.
+
+image::user-guide-11-blogroll.png[]
+
+=== Uploading images and other files to your weblog
+
+If you’d like to upload images or other files for use in your weblog, go
+to your weblog’s *Create & Edit -> Media Files* page. From there you can
+upload files, browse and search files. You can also manage your files,
+organize them into directories and post them to your weblog.
+
+image::user-guide-12-media.png[]
+
+You can see the Media File View page above. Below we’ll discuss all of
+the things you can do with Media Files via the Media File View page and
+the new Media File browser that we’ve added to the Weblog Editor.
+
+==== How to upload files
+
+To upload files you follow the *Add Media File* link in the top right of
+the page. You will see the Media File Add page, which is pictured below.
+
+image::user-guide-13-add-media.png[]
+
+You can upload up to five files at a time and you can enter information
+about the images including title, description, copyright statement and
+tags. You can pick which directory should receive the uploaded images.
+
+You can also decide whether or not you want your images to be included
+in the Gallery, which means that they will be made available in the
+Media File Feed for your blog.
+
+After your file upload completes, Roller will show you the *Upload
+Complete* page (below) with the files that you uploaded and will offer
+to include them in a new weblog post for you. You can choose any or all
+of the images, or you can skip this step and return to the Media File
+View.
+
+image::user-guide-14-upload-complete.png[]
+
+==== How to edit and update files
+
+From the Media File View page, you can edit any Media File simply by
+clicking on it. When you click you will be shown the Media File Edit
+page (below). From this page, you can edit the same information that you
+entered when you uploaded the file.
+
+You can also upload a new version of the file. The file will maintain
+the same URL as before the update, so no worries about broken links. If
+the file is an image, a new thumbnail will be generated for you and
+image size information will be updated.
+
+image::user-guide-15-edit-media.png[]
+
+==== How to use Media File Directories
+
+You can use directories to organize your Media Files. You can move files
+around and not worry about breaking any links because directory and file
+names are not part of URLs.
+
+To create a new directory, enter a new directory name in the new
+directory control, and click the create button.
+
+image::user-guide-media-directory.png[]
+
+To navigate into a directory in the Media File View page, simply click
+on the directory.
+
+==== How to delete Media Files
+
+To delete Media Files, go to the *Media File View* page, select the
+checkboxes of the files you wish to delete and then click the Delete
+button. You will have to confirm the delete before it executes.
+
+==== How to delete Media File Directories
+
+To delete Media File Directories you must first empty them out. You can
+only delete directories that are empty.
+
+==== How to post media files to your weblog
+
+We explained above how to post images during the upload process. From
+the Blog entry edit page, click on the "Add Media File" link located
+above and to the right of the Content field. Roller will insert the
+media file at the cursor location in the content field. If there’s a
+problem with the insertion location, hit Ctrl-Z to undo the action and
+try again.
+
+==== How to post a podcast to your weblog
+
+Upon uploading a non-image media file, such as a podcast, Roller
+provides you an option to create a new blog entry with that media file
+(podcast). If chosen, Roller will include the media file in the post
+content and in the Enclosure URL field in the Advanced Settings section
+of the Blog Edit Entry page. The Enclosure URL field is used just for
+your blog’s RSS and Atom feeds, it will include the podcast as a feed
+enclosure (http://en.wikipedia.org/wiki/RSS_enclosure) to make it easy
+for podcast readers to fetch it.
+
+Alternatively, you can select an podcast from the Add Media File link
+referenced in the previous section, which will add its URL to the post
+content, and then copy that URL to the Enclosure URL field in the
+Advanced Settings section if you wish to add it to your blog’s RSS
+and/or Atom feeds.
+
+=== Podcasting with Roller
+
+Roller includes support for _podcasting_, a way to distribute files
+through your weblog’s newsfeed. Typically, folks use podcasting to
+distribute audio files, but the technique can be used to distribute any
+type of file. Specialized podcast client software downloads the audio
+files that are referenced in your newsfeed and copies them to an music
+player, such as an MP3 player.
+
+This section assumes that you want to upload your podcasts to some other
+server, one with lots of space and bandwidth, and not to Roller. If you
+want to upload your podcasts to Roller, then see *Section 4.5.7* for an
+explanation of posting a Media File to your weblog as a podcast.
+
+==== *How to create a podcast feed with Roller*
+
+In Roller a Podcast is like an attachment to a weblog entry. Here are
+the steps involved in Podcasting with Roller:
+
+* Record an interesting Podcast (that’s the hard part, by the way) and
+save your Podcast in MP3 format or whatever format you prefer.
+
+* Upload your Podcast to a web server somewhere and take note of your
+Podcast’s URL. For example, if you were to upload a file to Roller, then
+the URL might look something like this:
+
+_http://hostname/roller/yourname/resource/mycast.mp3_
+
+* Create a new Roller weblog entry announcing your new Podcast. You
+might want to provide a link to it so that those without a Podcast
+client can click to download it directly. For example:
+
+Hey now! I just created my first Podcast you can download it here: <a
+href="http://hostname/roller/yourname/resource/mycast.mp3">mycast.mp3</a>
+
+* And the most important step: in the lower-half of the weblog editor
+page, you’ll see an expandable control labelled _Advanced Settings_.
+Click on that to expand the control and paste in the URL of your
+podcast.
+
+* Once your blog post is ready, save it as a draft or publish it. Once
+you’ve done that you’ll see that the Advanced Settings control has
+picked up the content-type and file-size of your podcast. If not, then
+Roller could not access your podcast due to network problems or perhaps
+a bad URL. Make sure the URL is correct and save again. If your podcast
+is OK, you’ll see something like this:
+
+image::user-guide-podcast.png[]
+
+* Roller will add the podcast to your RSS newsfeed as an _<enclosure>_.
+You can check this by looking at your RSS newsfeed and any podcast
+software that is subscribed to your feed will pick it up automatically.
+
+<enclosure url="http://example.com/roller/nina/resource/mycast.mp3"
+
+type="audio/x-mpeg" length="3409127" />
+
+=== Using a weblog client with Roller
+
+Using a nice weblog client like Ecto or MarsEdit can make it easier for
+you to post to your Roller weblog. You can also post to your weblog
+remotely from services like Flickr.com and del.icio.us. This is possible
+because Roller supports a standard publishing protocols such as the
+MetaWeblog API and the Atom Publishing Protocol. Here’s how to set up a
+weblog client to post to Roller.
+
+Configuring a weblog client for use with Roller
+
+First, make sure to enable weblog client API support in your weblog via
+your weblog’s Weblog Settings page.
+
+image::user-guide-17-api.png[]
+
+Next, start your blogging client, find the preferences or account setup
+dialog. You’ll need to set the following parameters:
+
+* *Username*: your Roller username
+* *Password*: your Roller password
+* *BlogID*: the handle of your Roller weblog
+* *URL*: the URL of Roller’s web services end-point
+
+Note that you may not need to enter your BlogID because some blog
+clients will login to Roller and then present you with a list of the
+weblogs that are available to your user.
+
+*A blogs.sun.com example*. For example, if you have an account on
+blogs.sun.com, your username is fred and your blog’s handle is fredsblog
+(i.e. your weblog’s URL is _http://blogs.sun.com/fredsblog_), then your
+parameters would be:
+
+* *Username*: fred
+* *Password*: (your password)
+* *BlogID*: fredsblog
+* *URL*: http://blogs.sun.com/roller-services/xmlrpc
+
+You may not need to enter your BlogID because some blog clients will
+login to Roller and then present you with a list of the weblogs that are
+available to your user.
+
+*A jroller.com example*. If you have an account on jroller.com, your
+username is fred and your blog’s handle is fredsblog (i.e. your weblog’s
+URL is _http://jroller.com/fredsblog_), then your parameters would be:
+
+* *Username*: fred
+* *Password*: (your password)
+* *BlogID*: fredsblog
+* *URL*: http://jroller.com/roller-services/xmlrpc
+
+== Working with comments and trackbacks
+
+Roller supports weblog comments and _trackbacks_, which provide a way
+for other bloggers to add comments to your blog remotely. By default
+comments and trackbacks are enabled, but you can turn them off on your
+weblog’s Weblog Settings page of your weblog. Note that turning off
+comments will disable both comments and trackbacks.
+
+=== Comment notification via email
+
+If you’re going to leave comments turn on then take the time to read
+them, to respond where appropriate and, when you receive spam or other
+forms of offensive comments, delete them from your weblog. You can’t
+respond to comments if you don’t know when you get one, so make sure you
+enable email notification of comments. You can do that on the Weblog
+Settings page.
+
+If you’ve got email turned on then you’ll receive an email every time
+you get a new comment and the email will include the text of the
+comment, a link to the entry that was commented upon and a link to the
+comment management page, shown below, where you may choose to approve,
+mark as spam or even delete the new comment.
+
+=== Comment management
+
+You can use the Comments page to manage your weblog comments. You can
+mark comments as spam or delete them entirely. You can search comments
+by keyword, date and status. If you’ve got comment moderation turned on,
+you will use the Comments page to approve new comments.
+
+image::user-guide-18-comments.png[]
+
+*A word about status*
+
+You can’t edit comments, but you can mark them as spam or dis-approve
+them. Someday, Roller may provide some spam filtering based on data
+collected from comments marked as spam but currently, marking as spam
+and dis-approving of a comment do the same thing – they prevent the
+comment from being displayed on your weblog.
+
+*How to get to the Comments page*
+
+There are a couple of ways to get to the Comments page. You can use
+Roller’s tabbed menu to go there and manage comment across your entire
+weblog. If you’ve got email notification of new comments turned on, the
+you might arrive at the Comments page via a link sent to you in your
+email.
+
+You can also manage comments for just one weblog. When you are editing a
+weblog entry with comments you’ll see a link in the top-right corner of
+the weblog editor page like the one below, which you can use to access
+the entry’s comments.
+
+=== Comment moderation
+
+If you’d like to preview and approve comments before they are displayed
+on your weblog, then you’ll want to turn on _comment moderation_ via
+Weblog Settings page. When comment moderation is enabled, then each new
+comment will be marked as pending and unapproved and will not appear on
+your weblog. To check for new comments, go to the Comments page to check
+for and either approve or delete new comments. If you’ve got comment
+notification enabled, make sure you also enable comment notification so
+you’ll know when new comments arrive. To moderate comments, use the
+comment management page, described below.
+
+How to moderate comments
+
+* Review each new comment and decide if it is to be approved for
+display, marked as spam and hidden or deleted entirely.
+* Only comments that are marked as approved and are not spam will be
+displayed on your weblog. So set (or unset) the corresponding checkboxes
+for each comment, or leave them the way they are.
+* When you are done. Click the save changes button at the bottom of the
+page. You’ll see that comments that were pending are no longer pending
+and those that you marked for delete will be gone.
+
+=== Global comment management
+
+If your user has global administration privileges, then you can manage
+comments across the entire Roller site, including every weblog. To do
+this, go to the *Server Administration:Comments* page and you’ll see a
+page that is almost identical to the weblog-specific comment management
+page.
+
+Limitations of global comment management
+
+You can use this page to mark as spam or delete any comment in the
+system, however you cannot change the approval status of comments
+through this interface. Approving comments for display is the duty and
+responsibility of the individual webloggers, so comment approval is only
+available in the context of a weblog.
+
+=== *Preventing weblog spam*
+
+There are two forms of comment spam that can affect your weblog:
+
+** _Comment spam_: spam that arrives via the comment form on your
+weblog. Sometimes spam comments are added by a human and sometimes by a
+computer program known as a _spambot._
+** _Trackback spam_: spam that arrives via trackbacks sent by a spambot.
+
+Fortunately, there are counter-measures for each type of spam. Here are
+Roller’s built in spam prevention measures:
+
+* _Pluggable comment authentication_. By default, Roller asks each
+commenter a simple math question to ensure that they are a person and
+not a spam robot. Your site administrator can turn this off or replace
+it with another form of authentication.
+* _Pluggable comment validation_. Roller includes five comment
+validators below. Your site administrator can adjust the settings for
+these validators and can enable/disable them as needed by overriding
+Roller’s configuration properties (see the Installation Guide for more
+information).
+** Excess links validator will mark comments with more than three links
+as spam (default: on)
+** Excess size validator marks any comment with more than 1000
+characters as spam (default: on)
+** Blacklist validator marks comments containing any of your site’s
+designated bad words as spam (default: on)
+** Trackback verification validator will check incoming trackbacks to
+ensure that they link to you.
+** Akismet validator allows you to use the Akismet.com spam prevention
+service.
+* _Comment throttling_. If your site is being abused by a spam robot
+your site administrator can set up throttling, which will watch for
+abusers and ban IP addresses that are posting too many comments too
+quickly.
+
+But nothing beats comment moderation
+
+Even if you’ve got all of those measures enabled you should still enable
+email notification of comments so that you are constantly aware of new
+comments on your weblog. None of the measures are 100% effective. If you
+are really concerned about displaying offensive content on your weblog
+even for a short time, then enable comment moderation on your weblog.
+
+Roller uses a _blacklist_, a lists of words which are used to check
+incoming comments, trackbacks and requestors for spam URLs. If the name,
+URL or content of a comment or trackback includes one of the blacklist
+words or matches one of the expressions then that comment or trackback
+is marked as spam and is not displayed on your weblog, unless you use
+the comment management page to unmark it.
+
+Actually, there are three levels of blacklist:
+
+** Level 1 blacklist: This is the built-in blacklist, the one that comes
+with Roller. This can only be changed by somebody with root access to
+the Roller server itself.
+** Level 2 blacklist: This is the site wide blacklist, which can only be
+edited by a global administrator via the Server Admin page.
+** Level 3 blacklist: Weblog specific blacklist, which you control in
+the Weblog Settings page of your weblog.
+
+Incoming comments and trackbacks are checked against all three levels of
+blacklist. Incoming web page requests, however, are only checked against
+the levels 2 and 3 blacklist and will receive a 403 (forbidden) message
+if found.
+
+If you have a spam problem on your weblog and you’d like to add words to
+the blacklist, it’s probably better for you to ask your administrator to
+add the words to the level 2 blacklist for you. That way, every blogger
+on the site will benefit from the addition. If you must do it yourself,
+here’s how you do it:
+
+
+** Go to the Weblog Settings page and scroll down to the blacklist
+fields
+** Enter your spam words, one per line
+** Lines that begin with a left parenthesis will be treated as regular
+expressions (see the Java API documentation for
+_javax.util.regex.Pattern_ for a guide to regular expressions). Don’t
+try to use a regular expression unless you really know what you’re
+doing.
+
+=== Sending trackbacks
+
+If you are writing about something you read on another weblog, you want
+to let the author and readers of that weblog know that you are doing so,
+and that other weblog is trackback enabled, then you should send that
+weblog a trackback ping. Here’s a story that illustrates how trackback
+works:
+
+* You read an interesting blog entry on Otto’s blog. You notice that
+Otto’s blog entry has a trackback URL, so instead of leaving a comment
+on Otto’s blog you decide to comment by writing a blog entry in your own
+blog. You copy that trackback URL (using ALT-C, or right-click-copy, or
+whatever) cause you’ll need it later.
+
+* You go to your blog and write a new blog entry in response to Otto’s
+entry. Click the Post to Weblog button to publish your new entry. After
+you publish, scroll down on the New Entry page until you see the
+following text field and button:
+* Enter the trackback URL from Otto’s blog entry into the text field and
+click the Send Trackback button. Roller will respond by printing the
+response received from Otto’s blog server. If the trackback was
+successful, you should see something like this:
+* You should now see your trackback listed among the comments on Otto’s
+blog entry.
+
+== Choosing your weblog theme
+
+A weblog theme is a set of templates, style-sheets and image that
+determine how your weblog will be displayed. A theme can define both the
+layout and color-scheme of your weblog. You can pick from one of a
+number of predefined themes. Some themes will allow you to control
+design by using a stylesheet. Other themes require you to edit the
+templates that define the theme if you want to customize them.
+
+You can access Roller’s theme and template features for your weblog via
+the Design menu, shown below:
+
+image::user-guide-20-design-menu.png[]
+
+The Theme menu leads you to the theme chooser page, shown below. Using
+this page you can pick from one or more different themes for your
+weblog. If none of the themes are appealing to you, then speak to your
+site administrator about obtaining or developing some additional themes.
+The Roller Support project is one place where you can obtain additional
+themes (_http://roller.dev.java.net_, _not_ an Apache site).
+
+image::user-guide-design-theme.png[]
+
+For more information on customizing Roller themes refer to the Template
+Guide.
+
+== Managing your weblog preferences
+
+As a Roller user, you are free to customize the settings of your weblog
+as you wish. When you establish your Roller user account, you can choose
+one of the dozen or so stock themes for your website. Later, you can use
+the theme switcher to switch to a different theme. Or, if you know
+something about HTML and CSS you can customize the look-and-feel and
+layout of your weblog yourself by modifying the page templates that make
+up your site and by adding new pages. Best of all, you can do all of
+this through the web-based Roller Editor UI.
+
+=== Weblog settings
+
+The *Preferences:Settings* page allows you to set the configuration
+parameters for your weblog.
+
+Here is an explanation of each of the settings on the weblog
+*Preferences:Settings* page:
+
+==== *General settings*
+
+image::user-guide-settings.png[]
+
+* *Title* - The title of your weblog may include HTML, but the HTML will
+be stripped out in your RSS feed. You can access your title in a page
+template with the expression _#showWebsiteTitle()_
+
+* *Tagline* – Short description or sub title of your weblog. May include
+HTML, but the HTML will be stripped out in your RSS feed. You can access
+your tagline in a page template with the expression
+_#showWebsiteDescription()_.
+* *Icon* - The image file name (ex: thumbnail.jpg) or image url (ex:
+http://yoursite/thumbnail.com) that shows on some of the default themes.
+You’ll need to upload the image via the *Create & Edit:File Uploads* tab
+first.
+* About your blog – A more detailed description of the blog or blog
+author(s) that shows on some of the default themes.
+
+* *Email address of weblog owner*: Enter the email address that you
+would like people to use to contact the person in charge of your blog;
+usually that’s you. To thwart spammers, your email address will be
+obfuscated when displayed on your blog. Please enter a valid address,
+otherwise Roller’s email features will not work.
+
+* *Weblog editor page to be used* - Choose a weblog editor page, some
+are rich-text editors:
+
+** editor-text.jsp: Simple text editor, you must enter HTML
+** editor-rte.jsp: Rich text editor (works in Firefox and IE but not
+Safari)
+* **Weblog is active: **un-check this box to indicate that your weblog
+is no longer active and should not appear in hot-blog and other weblog
+listing on the site. You might want to do this if you take a very long
+vacation or if you have decided to stop updating your weblog for some
+other reason.
+* *Number of entries to display on weblog*: Enter the maximum number of
+entries to be displayed on your weblog.
+
+==== Internationalization Settings
+
+image::user-guide-internationalization.png[]
+
+* I publish my weblog in multiple languages: check this box if you blog
+in multiple languages and would like to specify a language locale for
+each of your weblog entries.
+* Show my weblog entries from all languages on my home page: check this
+box if you’d like your weblog’s main page to show your posts in all
+languages. If you don’t check it, then readers will only see weblog
+entries from your default locale.
+* Locale set the default locale for your weblog.
+* Timezone: the timezone to be used in your weblog.
+
+==== Comments and default comment settings
+
+image::user-guide-comments.png[]
+
+* *Allow comments for your weblog?* – Check this box to allow visitors
+to leave comments on your weblog.
+* *Moderate comments* – Check this box to enable comment moderation
+(i.e. you must approve each comment before it is displayed).
+
+Note the next two options are visible only if the Roller Administrator
+has enabled email notifications for user blogs (See Section 9.2, Roller
+Administration):
+
+* *Email notification of comments?* – Check this box to receive an email
+notification of each new comments.
+* *Default from e-mail address for comments* – This will be used as the
+from address in comment emails sent by Roller.
+* *By default, allow comments for new entries* – Check this box to
+enable comments on your weblog. You can also control comments on each
+individual weblog entry.
+* Default time to allow comments for new entries – Choose the default
+amount of time to allow comments for new blog entries. This setting may
+also be overridden using the Comment Settings section of the New Entry
+page.
+* *Apply comment defaults to all existing entries? *- If you check this
+box, when you click the Save button the comment defaults you have set
+will be applied to all existing comments.
+
+==== *Weblog client API*
+
+image::user-guide-17-api.png[]
+
+* *Enable Blogger API for your weblog* - Set to true to enable
+weblogging via the MetaWeblog API. This will allow you to use handy
+blogging clients like Ecto to post to your weblog.
+
+* *Category for posts received via Blogger API* - Choose the category
+for incoming posts made via the Blogger API. This only applies if you
+blogging client does not support categories
+
+==== *Formatting*
+
+image::user-guide-formatting.png[]
+
+* **Default entry formatters: **this is the list of plug-ins to be
+enabled by default on a new weblog entry.
+
+==== *Spam prevention*
+
+image::user-guide-spam.png[]
+
+* **Ignore incoming URLs that contain any of these words - **you can use
+this to filter out what commentors, trackbacks, and referrers (web page
+requestors) are accepted. See Section
+[link:#5.5.Preventing%20weblog%20spam%20%7Coutline[5.5]]for more
+information on spam prevention.
+
+==== Web Analytics
+
+If you wish to use Web Analytics software tools such as Google Analytics
+(a fuller list of services is here:
+http://en.wikipedia.org/wiki/List_of_web_analytics_software) to track
+blog readers you can place your tracking code (usually a JavaScript
+snippet including the <script> element that contains it) in this field.
+Then, add the “#showAnalyticsTrackingCode($model.weblog)” macro to an
+appropriate area in your blog’s template (the HTML <head/> section is
+a good place) and this tracking code will be active for your blog.
+(Most if not all of the blog templates pre-packaged with Roller
+will already have this macro present; it will not output anything
+if no tracking code is provided.)
+
+This option will be available only if it has been activated by the blog
+server administrator; alternatively, the tracking code can be directly
+placed within the blog template if your administrator has enabled
+template customization for blog owners. The blog server administrator
+may configure a blog server-level default tracking key that will hold
+for all blogs or alternatively just for blogs which haven’t overwritten
+this default key.
+
+=== Weblog members: managing a group blog
+
+To create a group blog, create a new weblog or log into an existing
+weblog that you’d like members to contribute to. Creating a weblog for
+group blogging is the same a creating a personal weblog (see section
+http://www.rollerweblogger.org/wiki/Wiki.jsp?page=UserGuide_2.x#ref-UserGuide_2.x-3[[3]]
+for instructions). Navigate to the *Members* menu item in the
+*Preferences* tab. The *Preferences:Members* page enables weblog admins
+to invite members to a group blog and manage the group blog user access.
+
+image::user-guide-21-member.png[]
+
+You can use the *Invite new member* link to invite any Roller user to
+join your weblog, but before you do you should understand the three
+different permission levels allowed for members of a weblog. They are:
+
+* *Admin*: an admin can create/edit weblog entries and publish them to
+the web. They can also manage the weblog by changing the theme, editing
+the page templates that define the look of the blog, and managing the
+users of the blog. Roller will grant you admin rights in any weblog you
+create. Admin users can see both the Create & Edit tab and the
+Preferences tab of Roller.
+* *Author*: author permission allows users to create entries, edit
+entries and upload files. But authors cannot change weblog settings,
+modify the theme or manage users. Authors can see the weblog Create &
+Edit tab, but not the weblog Preferences tab.
+
+* *Limited*: limited bloggers can create and edit blog entries and save
+them as drafts, but cannot publish them to the web.
+
+Select *Invite new member* from the right navigation to invite Admins,
+Authors, and Limited authors to join the group blog. You’ll need to know
+the users individual blog username to find them in the list of users.
+You may scroll through the list, but it’s best to begin typing their
+username to locate them. Set the users Permissions by selecting Admin,
+Author, or Limited. Click on *Send Invitation*. If Roller is not
+configured to talk to the mail server, you may get the following
+messages:
+
+User successfully invited.
+
+ERROR: Notification email(s) not sent, due to Roller configuration or
+mail server problem.
+
+As long as the first message is present, the invite is successful. The
+next time the user logs into the blog site, they will see the message
+show in the screenshot below asking them to accept or decline your
+invitation.
+
+Once a user is a member of your blog, you can change their permissions.
+Just click the appropriate radio button in the table and click the
+*Save* button. You can also remove users from the site, but note that
+you cannot reduce your own permissions or remove yourself from the
+weblog.
+
+*Accept or Decline a Group Blog Invitation*
+
+If you are invited to become a member of a group blog, an invitation
+will be present at the top of the Main Menu page. Example:
+
+image::user-guide-22-invite-member.png[]
+
+Click 'accept' to become a member of the group blog or 'decline' to turn
+down the invitation.
+
+*Contribute to a group blog*
+
+Once you’re a member of a group blog, contributing is as easy as
+creating blog entry content. To access the group blog, login, from the
+*Main Menu* navigate to the group blog you’d like to contribute to and
+select any of the following: New Entry, Edit Entries, Settings (weblog
+admins only).
+
+For users who participate in multiple weblogs it is important to note
+that the Main Menu page is how you switch between the various weblogs
+you can author to. The Main Menu will always show you what weblogs you
+are participating in and what privileges you have on each weblog.
+
+*Resign from a Group Blog*
+
+To resign from a group blog, login, on the Main Menu page, navigate to
+the blog information for which you wish to resign. Select 'Resign'.
+
+== Using weblog pings
+
+Weblog update pings provide a means for you to notify aggregation and
+indexing sites (for example Weblogs.com, Technorati and javablogs.com)
+that your weblog has changed so that they will pick up your latest
+content from your RSS feed.
+
+Roller supports the conventional XML-RPC weblog update ping mechanism
+used by many sites for such notifications.
+
+=== Registering with an Aggregator
+
+Generally speaking, aggregation sites first require you to register your
+weblog with their site. During this registration process you normally
+provide both the HTTP URL and the RSS feed URL for your weblog. This is
+important because the ping message conveys only the normal HTTP URL of
+your site, and the site will use that to lookup the registered RSS feed
+URL to fetch from.
+
+Aggregation sites that accept ping notifications generally publish the
+ping URL to use to ping their site on their (human-readable) web site.
+Once you have registered your site with an aggregator, you can set up
+your weblog to deliver pings to that site.
+
+=== Ping Targets, Common and Custom
+
+You can set up the Roller server to ping sites of your choice
+automatically whenever you post published updates to your weblog.
+
+Roller uses the term *ping target* to refer to a site, such as an
+aggregator, that accepts weblog update ping notifications. A ping target
+is configured with a (display) name and the ping URL needed to reach the
+site. Before you can send a ping to a site, you must configure a ping
+target in Roller for the site. Roller comes pre-shipped with multiple
+ping targets and the Roller administrator can configure additional ones
+as desired.
+
+=== Setting up Automated Pings
+
+Once a ping target has been configured for the site that you wish to
+ping, you can use the *Weblog:Pings* page (shown below) to enable
+automatic pings and send manual pings.
+
+image::user-guide-23-ping.png[]
+
+To enable automatic pings to a ping target, find the ping target on the
+page and click the *Enable* link in the Automatic column. The status
+indicator turns to *ON* and the link changes to *Disable* (as shown for
+some sites in the screenshot above). To disable automatic pings to a
+ping target click the *Disable* link in the Automatic column. The status
+indicator turns to *OFF* and the link changes to *Enable*.
+
+When you have enabled automatic pinging for a ping target, Roller will
+automatically send a ping to that site whenever you publish a new weblog
+entry or update a published weblog entry.
+
+NOTE: In actuality, Roller queues a request to send the ping and
+processes this request in the background, so that you can get on with
+your blogging. The ping queue is processed at an interval configured by
+the site administrator; this interval is 5 minutes in a default
+configuration. In case the aggregator site is temporarily unreachable,
+Roller will requeue your ping request and retry on subsequent passes
+through the queue; in a default configuration the ping is requeued for
+up to 3 ping attempts._
+
+=== Sending a Manual Ping
+
+You can also send a manual ping to a ping target using the *Send Ping
+Now* link listed for the target on the *Weblog:Pings* page. When you
+send a manual ping the ping is not queued, it is sent immediately and
+attempted only once. Roller shows you the response status (success or a
+failure message) that results from the ping.
+
+You do not need to enable automatic pinging in order to send manual
+pings. You can send a manual ping whether or not you have enabled
+automatic pinging for that target.
+
+You can use manual pings if you ping a site very rarely, or if you are
+feeling a bit impatient, and you don’t want to wait for the next queue
+processing interval.
+
+If you don’t find a ping target listed for the site you wish to ping,
+you can request that your administrator add a a new one for all blogs to
+have available. See Chapter 10 for more information on adding ping
+targets.
+
+=== More on Registering with an Aggregator
+
+When you register with an aggregator, you will usually need to provide
+two pieces of information as part of the registration, your blog’s base
+(HTML) url and your RSS feed (XML) URL. Make sure to read the
+aggregator’s documentation and help on registering.
+
+For Roller weblogs, you get your weblog’s base URL by viewing your
+weblog and taking the URL to the point just following your weblog’s
+handle. (In other words it should end with _page_/_handlenamehere_).
+
+The RSS feed URL for your whole feed can be obtained by substituting
+_page_ in your weblog’s URL with _RSS_. Most browsers will display this
+link in the status bar when you place your mouse over RSS badge (the
+little orange XML box) on your weblog page.
+
+You also have category-specific feeds, which are useful for registering
+with topical aggregators like *java.blogs*. To get a category-specific
+feed URL, just append _?catname=/categoryname_ substituting _name_ for
+the category name. The "basic" theme has some category RSS feeds just
+below the RSS badge in the right-hand vertical bar.
+
+Some aggregators can also scrape (read and parse the HTML of your
+weblog) to discover the feed URL automatically when provided with the
+HTML URL. The default Roller theme template pages include hints in the
+form of tags that many sites can use to determine the feed URL
+automatically.
+
+== Roller administration
+
+This section of the Roller user guide is for users with the global admin
+role. How do you get the admin role? The first user created in a Roller
+system gets that role and then can grant it to other users via the
+*Global Admin->User Admin* page, which just happens to be the first
+topic we’ll cover in the section.
+
+We’ll also describe how to configure Roller via the **Global
+Admin->Configuration **page and how to configure Roller’s custom ping
+facility via the *Global Admin->Ping Targets* page.
+
+=== Managing users
+
+The *Global Admin->User Admin* page, shown below, allows you to find
+users, edit users and create new users.
+
+image::user-guide-24-user-admin.png[]
+
+To find a user, just enter the user’s username in the username in the
+the Username field and click the edit button. If you don’t know the
+user’s username, then start typing what you think might be the first
+letters of her username or email address and the list-box will be
+populated with all users whose usernames or email addresses match. When
+you see the user you want in the list box, click her and then click the
+Edit button to edit her user information.
+
+You can also create a new user by clicking the *create a new user link*.
+
+When a user is loaded into the *Global Admin->User Admin* page, or when
+you create a new user, you’ll see the form shown below. You can set the
+user’s full name, email address, locale and timezone. You can also reset
+the user’s password, if you enter both a password and password
+confirmation fields.
+
+image::user-guide-25-user-admin.png[]
+
+You can also disable a user, which will prevent the user from logging
+into Roller.
+
+Or you can check the Administrator checkbox to grant grant the user
+Global Admin privileges.
+
+At the bottom of the page, there’s a *Users Weblogs* section, which you
+can use to edit any of the user’s weblogs. This feature is here to make
+it easy for Global Admin’s to help users who are having trouble with any
+of Roller’s features, so please use it for that reason only; don’t use
+it to invade your user’s privacy.
+
+NOTE: you can disable a user but there is no way to remove a user from
+Roller.
+
+=== Configuring Roller
+
+The *Global Admin->Configuration* page allows you to set Roller’s
+runtime configuration properties. It is a big page, so we will discuss
+each section separately below.
+
+image::user-guide-26-site-setting.png[]
+
+* *Site name*: name of the site, to be included in site-wide newsfeeds
+(RSS and Atom) and on the default front page of the Roller.
+* *Short name*: short name of the site, to be included as the link in
+the banner that appears at the top of every page in the Roller
+editor/admin UI.
+* *Site description*: description of site, to be included in site-wide
+newsfeeds (RSS and Atom) and on the default front page of the site.
+* *Site Administrator’s emailConfiguring Roller Address*: admin’s email address, to be
+include in side-side newsfeeds (RSS and Atom)
+* *Handle of weblog to serve as frontpage blog*: specify the weblog that
+is to be displayed as the frontpage of this Roller site.
+* *Enable aggregated frontpage feeds*: Set this to true if you would
+like the frontpage weblog’s RSS and Atom feeds to be an aggregation of
+all weblogs on the Roller site.
+* *Absolute URL to this site*: to be used as basis for creating absolute
+URLs. Required for Roller’s Planet aggregator feature.
+* *Suspend all ping processing*: Allows you to turn off all (outgoing)
+weblogs pings for all weblogs in the system.
+* *Enable debug mode*: currently not used.
+
+image::user-guide-27-comments.png[]
+
+* *Allow New Users*: Set this to enable the _register as new user_ link
+on the main page. If you turnoff user creation, you’ll only be able to
+create new users via the *Global Admin->User Admin* page.
+
+* *External registration URL*: Controls the URL of Roller’s "Register
+as new users" link. If you use an external system to create Roller
+users and blogs, set the URL of that system here.
+* Editor pages: this is the list of weblog editors to be provided to
+users.
+
+* *Allow weblog comments*: By un-setting this you can turn off weblog
+comments on all weblogs in the system.
+* *Allow trackbacks*: By un-setting this you can turn off incoming
+trackbacks on all weblogs in the system.
+* *Autoformat comments*: If this is on, Roller will auto-format comments
+by adding in line-breaks where appropriate.
+* *Escape comment HTML*: By setting this, you can disallow HTML in
+comments and thereby protect your site from malicious JavaScript and
+some forms of cross-site scripting.
+* *E-mail notification of comments*: set this to enable email
+notification of new comments. This won’t work unless you configured
+Roller properly for sending email as described in the Roller
+installation guide.
+* *Enable verification of trackback links*: Trackback verification
+checks each incoming trackback to verify that the site sending the
+trackback actually links to the specific weblog entry that is the target
+of the trackback.
+
+image::user-guide-28-feed.png[]
+
+* *Default number of entries*: default number of entries to appear in
+each newsfeed (RSS and Atom).
+* *Maximum number of entries*: maximum number of entries to be allowed
+in each newsfeed (RSS and Atom).
+* *Display styled newsfeeds for browsers*: Set to true to enable
+user-friendly RSS and Atom feed display, so that users don’t see raw XML
+when they load the feed in their browsers.
+
+image::user-guide-29-fileupload.png[]
+
+* *Enable File Uploads*: Are users allowed to upload files?
+* *Allowed Extensions*: Comma-separated list of file extensions that
+users are allowed to upload.
+* *Forbidden Extensions*: Comma-separated list of file extensions that
+users are NOT allowed to upload.
+* *Max File Size (MB)*: Maximum size of file that users are allowed to
+upload.
+* *Max Directory Size (MB)*: Total upload directory size per user.
+
+The We Analytics section allows you to provide a JavaScript snippet if
+you wish to activate Google Analytics or other tracking services. The
+value you place here will hold for all blogs, unless you enable the
+individual blog overriding option in this section; in the latter case
+the default key will be used only for blogs which don’t have their own
+defined. Note that even if individual overrides are disallowed bloggers
+can still place their own tracking code within their blog templates if
+you enable custom themes (in the "Theme Settings" section on this
+configuration page.)
+
+== Weblog update ping administration
+
+This section, intended for Roller administrators, describes how the
+Roller weblog update ping feature works and how to configure and
+administer it.
+
+=== Creating and editing common ping targets
+
+Common ping targets are ping targets that are shared by all users. You
+can create and edit common ping targets using the *Global Admin->Ping
+Targets* page.
+
+image::user-guide-30-ping.png[]
+
+You can create and edit common ping in the same way that regular users
+create and edit custom ping targets, but keep in mind that common ping
+targets are shared amongst all users, and that your changes affect all
+users using the ping target. Administrators should make sure to test new
+common ping targets after creating them.
+
+Before adding a ping target, the administrator must determine the proper
+ping URL for the site that you wish to ping. This information can be
+obtained from the aggregator’s web site or from another knowledgeable
+source.
+
+It can be hard to find the aggregator’s documentation for the specific
+ping URL to use to notify their site. Commonly aggregators list this on
+their web site under a topic providing help about registering your feed,
+or under a topic providing information for developers. Keep in mind that
+some aggregators only use periodic polling and do not accept ping
+notifications at all. If you can’t find any information about pinging on
+the aggregator’s web site, the site may not support pinging.
+
+Click the *Add New* button to add a new ping target. This will bring up
+a form with a *Name* field and a *Ping URL* field. Fill in both fields,
+and click the *Save* button.
+
+image::user-guide-31-add-ping.png[]
+
+Once the new ping target has been created, it will be listed for all
+blogs on their *Weblog:Pings* page with the default activation status
+defined by the administrator. From this page, individual users can
+override the ping target’s enable status for their own blog as well as
+send manual pings to the new target.
+
+=== How Roller Processes Weblog Update Pings
+
+Roller processes weblog update pings in the background. When a user
+updates his or her weblog, Roller automatically queues any required
+automated pings on a queue. Roller only keeps one ping queue entry for a
+given user weblog and ping target. Subsequent updates to a weblog
+occurring before the ping is processed will not cause additional pings
+to be queued.
+
+Roller makes a full pass through the ping queue at regular intervals.
+(Configuration of this interval is discussed below) In each pass, Roller
+will attempt to send every queued ping request once. If any send fails
+(and provided the failure appears to be a transient one), the ping
+request will be re-queued, until the ping succeeds or a configured
+number of attempts has been made. Note that when a ping request fails
+and is re-queued, it is processed again only on subsequent ping passes.
+If the number of attempts to reach a given ping target reaches the
+maximum without succeeding, then an error message is logged and the ping
+request is dropped.
+
+There is currently no mechanism for alerting users of failing ping
+targets (though we plan some improvements in subsequent releases to
+provide condition information on the weblog *Preferences->Pings* page,
+as well as a failure policy to deactivate persistently failing ping
+targets).
+
+=== Configuration Properties Controlling Ping Processing
+
+These properties control processing of the ping queue. They are
+configured in the __roller.properties __file.
+
+**pings.queueProcessingIntervalMins **The interval in minutes between
+ping queue processing runs. This must be a value in the range 0 to 120.
+The default value is 5 minutes. We think the default value should work
+for most sites, and is tolerable for most users. The number of users
+publishing or updating entries in a given interval determines the length
+of the queue, and Roller requires enough time in an interval to process
+the queue once. We think that for all but the largest and most active
+sites, it can probably be lowered as low as 1 minute if desired.
+*IMPORTANT*: The value 0 (zero) has a special meaning. If the processing
+interval is set to 0, ping queue processing is disabled on the server.
+This can be used to exclude all but one host from sending pings in a
+clustered environment where multiple Roller servers are sharing one
+database schema. *Make sure to retain one host in the cluster that does
+process the ping queue!* If multiple hosts in a cluster process the ping
+queue, you may send duplicate pings and failing ping requests may drop
+out of the queue sooner than the expected maximum (configured by the
+next parameter). If no hosts in a cluster process the ping queue, auto
+ping requests will accumulate in the queue and this will eventually
+cause the database to run out of space, so don’t try to use this as a
+way to disable ping features. You can use the properties described in
+the following sections to disable ping features.
+
+**pings.maxPingAttempts **The maximum number of ping attempts made
+before the ping request will no longer be requeued and will instead be
+dropped from the queue. The default value is 3. We think this value is
+fine for most sites.
+
+=== Suspending all ping processing
+
+Administrators can suspend all ping processing at runtime by checking
+the *Suspend ping processing?* checkbox under the *Site Settings*
+heading on the *Global Admin->Configuration* page and saving that form.
+
+When this checkbox is set, all ping processing is suspended. New
+automatic ping requests are not added to the queue, and existing entries
+on the queue are not processed. Manual pings are not sent either; they
+result in a message telling the user that ping processing has been
+suspended. Suspending ping processing is appropriate to temporarily stop
+all ping processing if problems are encountered.
+
+Unchecking the checkbox and saving allows normal ping processing to
+resume. Note, however, that autopings for weblogs that are updated while
+ping processing is suspended will never be queued and hence never sent,
+but pings queued before the suspension are sent once the suspension is
+lifted.
+
+=== Controlling and disabling ping usage
+
+Since use of a ping target causes an outbound network connection to the
+ping site, some administrators may not want to allow users to create
+their own custom ping targets. It is possible to enable or disable the
+use of custom ping targets across the whole site and also to disable all
+ping usage. The following two properties are used to control this.
+
+**pings.disallowCustomTargets. **This property controls whether users
+are allowed to create custom ping targets. If set to true, all existing
+custom ping targets are _removed_, and the *Weblog:Custom Ping Targets*
+page and the associated actions are disabled preventing any
+configuration of custom ping targets. *Note:* __Setting this to true
+this will cause the Roller server to __remove _any custom ping targets
+that users have created when Roller is next started._
+
+Administrators may also wish to disable ping functionality entirely. The
+following property, used in conjunction with the above property, can be
+used to do this.
+
+**pings.disablePingUsage. **This property controls whether users are
+allowed to set up automatic pings or send manual pings. If set to true,
+all existing autoping configurations are removed (i.e. disabled), the
+weblog *Preferences->Pings* page and associated actions are disabled,
+preventing any use of the ping features by regular users. *Note:*
+__Setting this to true will cause the Roller server to __remove _any
+autopings that users have configured when Roller is next started._
+
+If both of the above properties are set to true, all ping functionality
+is effectively disabled for regular users. The *Global Admin:Ping
+Targets* page is still accessible (to administrators); you can use that
+page to clear out any common targets if you wish. No user (including
+administrators) will be able to configure automatic pings or send pings.
+Ping queue processing continues but the queue will always be empty; you
+can safely disable ping queue processing (by setting the processing
+interval to zero) in this situation.
+
+=== Initialization of common ping targets
+
+The initial set of common ping targets is determined by the following
+configuration property.
+
+**pings.initialCommonTargets. **This value is used to initialize the set
+of common ping targets. The value consists of a comma-separated list of
+ping targets, where each ping target is specified in the form
+
+{{name}{url}}
+
+This value is used every time Roller starts _and finds an empty list of
+common ping targets._ Normally, this is only the first time Roller is
+started on a fresh or upgraded database; note, however, that if you
+really want to maintain an empty list of common ping targets, you will
+need to comment out this value or set it to an empty string.
+
+== Weblog Export
+
+Roller includes an optional weblog export feature that allows you to
+export your weblog entries and uploaded Media Files to a format that is
+compatible with both Wordpress and MovableType. You can use the *Create
+& Edit -> Export* menu to do this. When you click one of the Export
+buttons, you will be prompted to download the resulting file.
+
+*Enabling Weblog Export*
+
+Export is an optional feature that is disabled by default.
+
+If you do not see it in Roller, as your Roller admin to enable it by
+setting the _weblog.export.enabled_ property to _true_ in the
+**roller-custom.properties **file.
+
+== Planet Roller administration
+
+Roller includes an aggregator known as Planet Roller, which makes it
+possible for you to aggregate together weblogs from a Roller server with
+weblogs that are hosted elsewhere. You can create multiple aggregation
+groups each with its own set of feeds, you can display aggregation
+groups on your weblog pages and Roller provides an RSS feed for each
+group you create.
+
+Roller’s aggregator is not enabled by default. If you want to use it,
+you’ll have to ask your site administrator to enable and configure it
+for you. Please refer to the Roller Installation Guide for more
+information on that topic.
+
+=== Configuring Planet Roller
+
+If you’ve got Planet enabled, when you login as a global admin you’ll
+see a Planet Administration link on the Roller Main Menu page. Click
+that link to view the *Planet Admin->Configuration* page, shown below.
+
+image::user-guide-32-planet-config.png[]
+
+To configure Planet Roller, you must:
+
+* Ensure that your site has an absolute URL in the *Global
+Admin->Configuration* page in the Site Settings section.
+
+* If you are behind a proxy, you must enter proxy settings in the
+*Planet Admin->Configuration* page.
+
+=== Adding external weblogs to Planet Roller
+
+Planet Roller allows you to create multiple aggregation groups each
+containing a different set of feeds, but there is also a special group
+known the _external_ group that is managed by Roller. The external group
+includes all weblogs on your Roller server plus any externally hosted
+weblogs you choose to add. The RSS feed for the external group is
+available at /planetrss, so on a default Roller install its URL will be:
+
+http://localhost:8080/roller/planetrss
+
+This section describes how to add and remove weblogs using the *Planet
+Admin->Subscriptions* page, shown below.
+
+image::user-guide-33-subscription.png[]
+
+*Adding an external weblog to Planet Roller*
+
+To add an externally hosted weblog to the Planet, use the *Planet
+Admin->Subscriptions* page. Enter its title, newsfeed URL and website
+URL and click the Save button.
+
+NOTE: Planet Roller only supports Atom and RSS newsfeeds that include
+entry level date information. If you enter a subscription that does not
+include dates, Planet Roller will accept it, but you may not see entries
+from the feed because Roller will assume that its entries are at least
+one day old.
+
+Removing an external weblog from Planet Roller
+
+You can select an existing subscription and edit it or delete it. The
+change will not be evident on the front page until the next scheduled
+Refresh Entries task runs.
+
+=== Adding custom groups to Planet Roller
+
+You can also add custom aggregation groups and Planet Roller will
+provide an RSS newsfeed for each group you add. For example, if you add
+groups with the handles _music_ and _politics_, then you’ll get two
+feeds at URLs like this:
+
+http://localhost:8080/roller/planetrss?group=music
+
+http://localhost:8080/roller/planetrss?group=politics
+
+To add new custom groups just use the *Planet Admin->Custom Groups*
+page, shown below.
+
+To create a custom group
+
+Go to the *Planet Admin->Custom Groups* page and enter the title and
+enter a title for the group, one that is appropriate for display in the
+group’s RSS feed. Enter a handle a one word name for the group, which
+you’ll use to refer to the group in your page templates. When you’re
+done click the Save button
+
+You’ll see your new group appear in the Existing Custom Aggregation
+Groups table. Click on the Subscriptions icons for your new group and
+you’ll be taken to the *Planet Admin->Subscriptions* page so you can add
+feed subscriptions to the group.
+
+Enter the title, newsfeed URL and website URL for the feed you’d like to
+add and click the Save button to add it to the feeds list. Repeat once
+for each subscription you’d like to add to the group.
\ No newline at end of file
diff --git a/docs/roller-user-guide.odt b/docs/roller-user-guide.odt
deleted file mode 100644
index dcb059e..0000000
--- a/docs/roller-user-guide.odt
+++ /dev/null
Binary files differ
diff --git a/docs/roller-user-guide.pdf b/docs/roller-user-guide.pdf
deleted file mode 100644
index eb7bba4..0000000
--- a/docs/roller-user-guide.pdf
+++ /dev/null
Binary files differ
diff --git a/it-selenium/pom.xml b/it-selenium/pom.xml
index d1e485a..ea92031 100644
--- a/it-selenium/pom.xml
+++ b/it-selenium/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.roller</groupId>
         <artifactId>roller-project</artifactId>
-        <version>6.0.1-SNAPSHOT</version>
+        <version>6.0.2-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/pom.xml b/pom.xml
index e91a230..62970bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.roller</groupId>
     <artifactId>roller-project</artifactId>
-    <version>6.0.1-SNAPSHOT</version>
+    <version>6.0.2-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <prerequisites>
@@ -47,7 +47,7 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <derby.version>10.11.1.1</derby.version>
-        <roller.version>6.0.1-SNAPSHOT</roller.version>
+        <roller.version>6.0.2-SNAPSHOT</roller.version>
     </properties>
 
     <modules>
diff --git a/docs/examples/i18n/check-default-resource-file.py b/testing/i18n/check-default-resource-file.py
similarity index 100%
rename from docs/examples/i18n/check-default-resource-file.py
rename to testing/i18n/check-default-resource-file.py
diff --git a/docs/examples/i18n/compare-vs-default-file.py b/testing/i18n/compare-vs-default-file.py
similarity index 100%
rename from docs/examples/i18n/compare-vs-default-file.py
rename to testing/i18n/compare-vs-default-file.py
diff --git a/docs/testing/junit-cleartables-mysql.sql b/testing/junit-cleartables-mysql.sql
similarity index 100%
rename from docs/testing/junit-cleartables-mysql.sql
rename to testing/junit-cleartables-mysql.sql
diff --git a/docs/testing/roller-junit.properties b/testing/roller-junit.properties
similarity index 100%
rename from docs/testing/roller-junit.properties
rename to testing/roller-junit.properties
diff --git a/docs/testing/roller-load-test.jmx b/testing/roller-load-test.jmx
similarity index 100%
rename from docs/testing/roller-load-test.jmx
rename to testing/roller-load-test.jmx
diff --git a/docs/testing/test-plan.sxc b/testing/test-plan.sxc
similarity index 100%
rename from docs/testing/test-plan.sxc
rename to testing/test-plan.sxc
Binary files differ