In 2.3.27 release process: Merge branch '2.3-gae' into 2.3
diff --git a/build.xml b/build.xml
index fd73ab0..80584fa 100644
--- a/build.xml
+++ b/build.xml
@@ -33,7 +33,7 @@
 
   <!-- Maven project coordinates: -->
   <property name="mavenGroupId" value="org.freemarker" />
-  <property name="mavenArtifactId" value="freemarker-gae" />
+  <property name="mavenArtifactId" value="freemarker" />
   <!-- Ivy project coordinates: -->
   <property name="moduleOrg" value="org.freemarker" />
   <property name="moduleName" value="freemarker" />
@@ -835,7 +835,6 @@
   
   <name>Apache FreeMarker</name>
   <description>
-    Google App Engine compliant variation of FreeMarker.
     FreeMarker is a "template engine"; a generic tool to generate text output based on templates.
   </description>
   <url>http://freemarker.org/</url>
diff --git a/src/main/java/freemarker/core/FreeMarkerTree.java b/src/main/java/freemarker/core/FreeMarkerTree.java
index ed2005f..b98cae5 100644
--- a/src/main/java/freemarker/core/FreeMarkerTree.java
+++ b/src/main/java/freemarker/core/FreeMarkerTree.java
@@ -19,13 +19,8 @@
 
 package freemarker.core;
 
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-
 import javax.swing.JTree;
 import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreeNode;
 
 import freemarker.template.Template;
 
@@ -36,26 +31,13 @@
  */
 @Deprecated
 public class FreeMarkerTree extends JTree {
-    private static final long serialVersionUID = 1L;
 
-    private final Map nodeMap = new HashMap();
-    
     public FreeMarkerTree(Template template) {
-        setTemplate(template);
-    }
-
-    private TreeNode getNode(TemplateElement element) {
-        TreeNode n = (TreeNode) nodeMap.get(element);
-        if (n != null) {
-            return n;
-        }
-        n = new TemplateElementTreeNode(element);
-        nodeMap.put(element, n);
-        return n;
+        super(template.getRootTreeNode());
     }
 
     public void setTemplate(Template template) {
-        this.setModel(new DefaultTreeModel(getNode(template.getRootTreeNode())));
+        this.setModel(new DefaultTreeModel(template.getRootTreeNode()));
         this.invalidate();
     }
 
@@ -63,55 +45,10 @@
     public String convertValueToText(Object value, boolean selected,
                                      boolean expanded, boolean leaf, int row,
                                      boolean hasFocus) {
-        if (value instanceof TemplateElementTreeNode) {
-            return ((TemplateElementTreeNode) value).element.getDescription();
+        if (value instanceof TemplateElement) {
+            return ((TemplateElement) value).getDescription();
         }
         return value.toString();
     }
     
-    private class TemplateElementTreeNode implements TreeNode {
-        private final TemplateElement element;
-        
-        TemplateElementTreeNode(TemplateElement element) {
-            this.element = element;
-        }
-
-        public Enumeration children() {
-            final Enumeration e = element.children();
-            return new Enumeration() {
-                public boolean hasMoreElements() {
-                    return e.hasMoreElements();
-                }
-                public Object nextElement() {
-                    return getNode((TemplateElement) e.nextElement());
-                }
-            };
-        }
-
-        public boolean getAllowsChildren() {
-            return element.getAllowsChildren();
-        }
-
-        public TreeNode getChildAt(int childIndex) {
-            return getNode(element.getChildAt(childIndex));
-        }
-
-        public int getChildCount() {
-            return element.getChildCount();
-        }
-
-        public int getIndex(TreeNode node) {
-            return element.getIndex(((TemplateElementTreeNode) node).element);
-        }
-
-        public TreeNode getParent() {
-            return getNode(element.getParentElement());
-        }
-
-        public boolean isLeaf() {
-            return element.isLeaf();
-        }
-        
-        
-    }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/freemarker/core/TemplateElement.java b/src/main/java/freemarker/core/TemplateElement.java
index a8dedea..359363c 100644
--- a/src/main/java/freemarker/core/TemplateElement.java
+++ b/src/main/java/freemarker/core/TemplateElement.java
@@ -23,6 +23,8 @@
 import java.util.Collections;
 import java.util.Enumeration;
 
+import javax.swing.tree.TreeNode;
+
 import freemarker.template.SimpleSequence;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateNodeModel;
@@ -37,7 +39,7 @@
  *             it.
  */
 @Deprecated
-abstract public class TemplateElement extends TemplateObject {
+abstract public class TemplateElement extends TemplateObject implements TreeNode {
 
     private static final int INITIAL_REGULATED_CHILD_BUFFER_CAPACITY = 6;
 
@@ -192,7 +194,11 @@
         return !isLeaf();
     }
 
-    public int getIndex(TemplateElement node) {
+    /**
+     * @deprecated Starting from 2.4, we won't use {@link TreeNode} API, as it requires Swing.
+     */
+    @Deprecated
+    public int getIndex(TreeNode node) {
         for (int i = 0; i < childCount; i++) {
             if (childBuffer[i].equals(node)) {
                 return i;
@@ -216,10 +222,11 @@
     }
 
     /**
-     * @deprecated Internal API - even internally, use {@link #getChild(int)} instead.
+     * @deprecated This method will return {@link TemplateElement} starting from 2.4, as that doesn't require Swing;
+     * don't use it. Internally, use {@link #getChild(int)} instead.
      */
     @Deprecated
-    public TemplateElement getChildAt(int index) {
+    public TreeNode getChildAt(int index) {
         if (childCount == 0) {
             throw new IndexOutOfBoundsException("Template element has no children");
         }
@@ -244,10 +251,11 @@
     /**
      * The element whose child this element is, or {@code null} if this is the root node.
      * 
-     * @deprecated Don't use in internal code either; use {@link #getParentElement()} there.
+     * @deprecated This method will return {@link TemplateElement} starting from 2.4, as that doesn't require Swing;
+     * don't use it. Don't use in internal code either; use {@link #getParentElement()} there.
      */
     @Deprecated
-    public TemplateElement getParent() {
+    public TreeNode getParent() {
         return parent;
     }
     
diff --git a/src/main/java/freemarker/template/Template.java b/src/main/java/freemarker/template/Template.java
index 240e527..5c65c54 100644
--- a/src/main/java/freemarker/template/Template.java
+++ b/src/main/java/freemarker/template/Template.java
@@ -37,6 +37,8 @@
 import java.util.Map;
 import java.util.Vector;
 
+import javax.swing.tree.TreePath;
+
 import freemarker.cache.TemplateCache;
 import freemarker.cache.TemplateLoader;
 import freemarker.cache.TemplateLookupStrategy;
@@ -993,7 +995,7 @@
      * @deprecated Should only be used internally, and might will be removed later.
      */
     @Deprecated
-    public List containingElements(int column, int line) {
+    public TreePath containingElements(int column, int line) {
         final ArrayList elements = new ArrayList();
         TemplateElement element = rootElement;
         mainloop: while (element.contains(column, line)) {
@@ -1007,7 +1009,10 @@
             }
             break;
         }
-        return elements.isEmpty() ? null : elements;
+        if (elements.isEmpty()) {
+            return null;
+        }
+        return new TreePath(elements.toArray());
     }
 
     /**
diff --git a/src/main/resources/freemarker/version.properties b/src/main/resources/freemarker/version.properties
index 6223223..c9ddd18 100644
--- a/src/main/resources/freemarker/version.properties
+++ b/src/main/resources/freemarker/version.properties
@@ -58,11 +58,11 @@
 # - When the major version number is increased, major backward
 #   compatibility violations are allowed, but still should be avoided.
 # During Apache Incubation, "-incubating" is added to this string.
-version=2.3.27-nightly_@timestampInVersion@-incubating
+version=2.3.27-incubating
 # This exists as for Maven we use "-SNAPSHOT" for nightly releases,
 # and no _nightly_@timestampInVersion@. Also, "-incubating" is added
 # *before* "-SNAPSHOT". For final releases it's the same as "version".
-mavenVersion=2.3.27-incubating-SNAPSHOT
+mavenVersion=2.3.27-incubating
 
 # Version string that conforms to OSGi
 # ------------------------------------
@@ -76,7 +76,7 @@
 #   2.4.0.pre01
 #   2.4.0.nightly_@timestampInVersion@
 # During Apache Incubation, "-incubating" is added to this string.
-versionForOSGi=2.3.27.nightly_@timestampInVersion@-incubating
+versionForOSGi=2.3.27.stable-incubating
 
 # Version string that conforms to legacy MF
 # -----------------------------------------
@@ -95,10 +95,10 @@
 # "97 denotes "nightly", 98 denotes "pre", 99 denotes "rc" build.
 # In general, for the nightly/preview/rc Y of version 2.X, the versionForMf is
 # 2.X-1.(99|98).Y. Note the X-1.
-versionForMf=2.3.26.97
+versionForMf=2.3.27
 
 # The date of the build.
 # This should be automatically filled by the building tool (Ant).
 buildTimestamp=@timestampNice@
 
-isGAECompliant=true
+isGAECompliant=false
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index a66096e..1375135 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -27073,7 +27073,7 @@
       <section xml:id="versions_2_3_27">
         <title>2.3.27 (incubating at Apache)</title>
 
-        <para>Release date: FIXME</para>
+        <para>Release date: 2017-10-15 + release process</para>
 
         <para><emphasis role="bold">This is a stable, final
         release.</emphasis> The <quote>incubating</quote> suffix is required
diff --git a/src/test/java/freemarker/test/TreeView.java b/src/test/java/freemarker/test/TreeView.java
index 0c89f5f..83c0735 100644
--- a/src/test/java/freemarker/test/TreeView.java
+++ b/src/test/java/freemarker/test/TreeView.java
@@ -64,7 +64,7 @@
     }
 
     static void usage() {
-        System.err.println("little toy program to display a compiled template as a tree.");
-        System.err.println("Usage: java freemarker.test.TreeView <templatefile>");
+        System.err.println("Little toy program to display a compiled template as a tree.");
+        System.err.println("Usage: java freemarker.testcase.TreeView <templatefile>");
     }
 }