Merge remote-tracking branch 'origin/2.3-gae' into 2.3
diff --git a/build.xml b/build.xml
index b17349e..034f172 100644
--- a/build.xml
+++ b/build.xml
@@ -239,7 +239,7 @@
     <delete dir="build/src-main-java-filtered" />
     <mkdir dir="build/src-main-java-filtered" />
     <copy toDir="build/src-main-java-filtered">
-      <fileset dir="src/main/java" />
+      <fileset dir="src/main/java" excludes="**/AdhocTest*" />
     </copy>
     <replaceregexp
         flags="gs" encoding="utf-8"
diff --git a/src/ide-settings/IntelliJ-IDEA/Java-code-style-FreeMarker.xml b/src/ide-settings/IntelliJ-IDEA/Java-code-style-FreeMarker.xml
index 8d47cbe..cff7e8e 100644
--- a/src/ide-settings/IntelliJ-IDEA/Java-code-style-FreeMarker.xml
+++ b/src/ide-settings/IntelliJ-IDEA/Java-code-style-FreeMarker.xml
@@ -1,3 +1,21 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  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.
+-->
 <code_scheme name="FreeMarker" version="173">
   <option name="LINE_SEPARATOR" value="&#xA;" />
   <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index 5e143b1..30c9c9d 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -388,21 +388,12 @@
             throw new InternalError();
         }
         bi.key = key;
-        if (bi.isLazilyGeneratedTargetResultSupported()) {
-            target.enableLazilyGeneratedResult();
-        }
-        bi.target = target;
+        bi.setTarget(target);
         return bi;
     }
 
-    /**
-     * If the built-in supports a lazily generated value as its left operand (the target).
-     * Don't confuse this with what's allowed for result of the built-in itself; that's influenced by
-     * {@link Expression#enableLazilyGeneratedResult()} (and so
-     * {@link IntermediateStreamOperationLikeBuiltIn#isLazilyGeneratedTargetResultSupported()}).
-     */
-    protected boolean isLazilyGeneratedTargetResultSupported() {
-        return false;
+    protected void setTarget(Expression target) {
+        this.target = target;
     }
 
     @Override
diff --git a/src/main/java/freemarker/core/BuiltInWithDirectCallOptimization.java b/src/main/java/freemarker/core/BuiltInWithDirectCallOptimization.java
new file mode 100644
index 0000000..a92ae43
--- /dev/null
+++ b/src/main/java/freemarker/core/BuiltInWithDirectCallOptimization.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package freemarker.core;
+
+abstract class BuiltInWithDirectCallOptimization extends SpecialBuiltIn {
+
+    /**
+     * Called if the built-in is directly followed by a "(" (ignoring comments and white-space). This can be utilized
+     * for optimizations that only work correctly if the method returned by the built-in is a called immediately (as
+     * opposed to being stored in a variable and then called at an arbitrary later point in time).
+     */
+    protected abstract void setDirectlyCalled();
+
+}
diff --git a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
index 34ff1f0..cf70c31 100644
--- a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
+++ b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
@@ -485,8 +485,9 @@
     static class sizeBI extends BuiltIn {
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setTarget(Expression target) {
+            super.setTarget(target);
+            target.enableLazilyGeneratedResult();
         }
 
         private int countingLimit;
diff --git a/src/main/java/freemarker/core/BuiltInsForSequences.java b/src/main/java/freemarker/core/BuiltInsForSequences.java
index 2ba6b11..6d76e1d 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -143,8 +143,9 @@
     static class firstBI extends BuiltIn {
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setTarget(Expression target) {
+            super.setTarget(target);
+            target.enableLazilyGeneratedResult();
         }
 
         @Override
@@ -181,11 +182,11 @@
         
     }
 
-    static class joinBI extends BuiltIn {
+    static class joinBI extends BuiltInWithDirectCallOptimization {
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setDirectlyCalled() {
+            target.enableLazilyGeneratedResult();
         }
 
         private class BIMethodForCollection implements TemplateMethodModelEx {
@@ -295,11 +296,11 @@
         }
     }
 
-    static class seq_containsBI extends BuiltIn {
+    static class seq_containsBI extends BuiltInWithDirectCallOptimization {
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setDirectlyCalled() {
+            target.enableLazilyGeneratedResult();
         }
 
         private class BIMethodForCollection implements TemplateMethodModelEx {
@@ -367,15 +368,15 @@
     
     }
     
-    static class seq_index_ofBI extends BuiltIn {
+    static class seq_index_ofBI extends BuiltInWithDirectCallOptimization {
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setDirectlyCalled() {
+            target.enableLazilyGeneratedResult();
         }
 
         private class BIMethod implements TemplateMethodModelEx {
-            
+
             protected final TemplateSequenceModel m_seq;
             protected final TemplateCollectionModel m_col;
             protected final Environment m_env;
@@ -893,8 +894,9 @@
         }
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setTarget(Expression target) {
+            super.setTarget(target);
+            target.enableLazilyGeneratedResult();
         }
     }
     
@@ -941,8 +943,9 @@
         }
 
         @Override
-        protected boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
+        protected void setTarget(Expression target) {
+            super.setTarget(target);
+            target.enableLazilyGeneratedResult();
         }
 
         @Override
diff --git a/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java b/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java
index a270276..0d1378b 100644
--- a/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java
+++ b/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java
@@ -74,8 +74,9 @@
     }
 
     @Override
-    protected final boolean isLazilyGeneratedTargetResultSupported() {
-        return true;
+    protected void setTarget(Expression target) {
+        super.setTarget(target);
+        target.enableLazilyGeneratedResult();
     }
 
     protected List<Expression> getArgumentsAsList() {
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index a157871..363e8bc 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -2182,6 +2182,7 @@
     ArrayList<Expression> args = null;
     Token openParen;
     Token closeParen;
+    MethodCall methodCall;
 }
 {
     <BUILT_IN>
@@ -2236,6 +2237,7 @@
             return result;
         }
     }
+
     [
         LOOKAHEAD({
                 result instanceof BuiltInWithParseTimeParameters
@@ -2265,10 +2267,26 @@
             return result;
         }
     ]
+
+    [
+        LOOKAHEAD(<OPEN_PAREN>, { result instanceof BuiltInWithDirectCallOptimization })
+        methodCall = MethodArgs(result)
+        {
+            ((BuiltInWithDirectCallOptimization) result).setDirectlyCalled();
+            return methodCall;
+        }
+    ]
+
     {
+        if (result instanceof BuiltInWithDirectCallOptimization) {
+            // We had no (...)
+            return result;
+        }
+
         // Should have already return-ed
         throw new AssertionError("Unhandled " + SpecialBuiltIn.class.getName() + " subclass: " + result.getClass());
     }
+
 }
 
 // Only supported as the argument of certain built-ins, so it's not called inside Expression.
diff --git a/src/main/resources/freemarker/included.html b/src/main/resources/freemarker/included.html
deleted file mode 100644
index 36c9254..0000000
--- a/src/main/resources/freemarker/included.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<div class="code">
-<pre><code>SCRIPT_DIR=&quot;\
-  $(\
-    cd &quot;$(dirname &quot;${BASH_SRC_DIR[0]}&quot;)&quot; \
-    &gt;/dev/null 2&gt;&amp;1 \
-    &amp;&amp; pwd\
-  )&quot;
-SCRIPT_NAME=$(basename $0)</code></pre>
-</div>
\ No newline at end of file
diff --git a/src/main/resources/freemarker/version.properties b/src/main/resources/freemarker/version.properties
index 720be33..fff63bd 100644
--- a/src/main/resources/freemarker/version.properties
+++ b/src/main/resources/freemarker/version.properties
@@ -56,11 +56,11 @@
 #   continue working without modification or recompilation.
 # - When the major version number is increased, major backward
 #   compatibility violations are allowed, but still should be avoided.
-version=2.3.29-nightly_@timestampInVersion@
+version=2.3.29
 # This exists as for Maven we use "-SNAPSHOT" for nightly releases,
 # and no _nightly_@timestampInVersion@. For final releases it's the
 # same as "version".
-mavenVersion=2.3.29-SNAPSHOT
+mavenVersion=2.3.29
 
 # Version string that conforms to OSGi
 # ------------------------------------
@@ -73,7 +73,7 @@
 #   2.4.0.rc01
 #   2.4.0.pre01
 #   2.4.0.nightly_@timestampInVersion@
-versionForOSGi=2.3.29.nightly_@timestampInVersion@
+versionForOSGi=2.3.29.stable
 
 # Version string that conforms to legacy MF
 # -----------------------------------------
@@ -92,7 +92,7 @@
 # "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.28.97
+versionForMf=2.3.29
 
 # The date of the build.
 # This should be automatically filled by the building tool (Ant).
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 3681a02..4a6e917 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -20,7 +20,11 @@
 <book conformance="docgen" version="5.0" xml:lang="en"
       xmlns="http://docbook.org/ns/docbook"
       xmlns:xlink="http://www.w3.org/1999/xlink"
->
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:ns5="http://www.w3.org/1999/xhtml"
+      xmlns:ns4="http://www.w3.org/2000/svg"
+      xmlns:ns3="http://www.w3.org/1998/Math/MathML"
+      xmlns:ns="http://docbook.org/ns/docbook">
   <info>
     <title>Apache FreeMarker Manual</title>
 
@@ -844,6 +848,14 @@
               true of false depending on if <literal>user</literal> starts
               with the letter <quote>J</quote> or not.</para>
             </listitem>
+
+            <listitem>
+              <para><literal>animals?filter(it -&gt; it.protected)</literal>
+              gives the list of protected animals. To list protected animals
+              only, you could use <literal>&lt;#list animals?filter(it -&gt;
+              it.protected) as
+              animal&gt;<replaceable>...</replaceable>&lt;/#list&gt;</literal>.</para>
+            </listitem>
           </itemizedlist>
 
           <para>Built-in applications can be chained, like
@@ -1373,7 +1385,10 @@
               its size or retrieve its sub variables by index, but they can be
               still listed with the <link
               linkend="ref.directive.list"><literal>list</literal>
-              directive</link>.</para>
+              directive</link>. Furthermore, very often they can only be
+              listed once. (If you are a Java programmer,
+              <quote>iterable</quote> would be a more fitting name than
+              collection.)</para>
             </listitem>
           </itemizedlist>
 
@@ -2159,6 +2174,12 @@
               <literal>/=</literal>, <literal>%=</literal>,
               <literal>++</literal>, <literal>--</literal></para>
             </listitem>
+
+            <listitem>
+              <para><link linkend="dgui_template_exp_lambda">Local
+              lambdas</link>: <literal>x -&gt; x + 1</literal>, <literal>(x,
+              y) -&gt; x + y</literal></para>
+            </listitem>
           </itemizedlist>
 
           <para>See also: <link
@@ -3815,7 +3836,7 @@
             <warning>
               <para>If you have a composite expression after the
               <literal>!</literal>, like <literal>1 + x</literal>,
-              <emphasis>always</emphasis> use parenthesses, like
+              <emphasis>always</emphasis> use parentheses, like
               <literal>${x!(1 + y)}</literal> or <literal>${(x!1) +
               y)}</literal>, depending on which interpretation you meant.
               That's needed because due to a programming mistake in FreeMarker
@@ -3998,6 +4019,59 @@
           </note>
         </section>
 
+        <section xml:id="dgui_template_exp_lambda">
+          <title>Local lambdas</title>
+
+          <indexterm>
+            <primary>lambda</primary>
+          </indexterm>
+
+          <para>FreeMarker doesn't support general purpose lambdas (unlike
+          Java). The usage of lambdas is restricted to the parameters of
+          certain <link linkend="dgui_template_exp_builtin">built-ins</link>,
+          like: <link
+          linkend="ref_builtin_filter"><literal>filter</literal></link>, <link
+          linkend="ref_builtin_map"><literal>map</literal></link>, <link
+          linkend="ref_builtin_take_while"><literal>take_while</literal></link>,
+          <link
+          linkend="ref_builtin_drop_while"><literal>drop_while</literal></link>.</para>
+
+          <para>The reason of this restriction is that FreeMarker doesn't
+          implement binding/capturing variables that are referred from the
+          lambda, instead it ensures that the evaluation of the lambda happens
+          before the enclosing variable scope is ended. Hence, and to
+          differentiate them from <quote>real</quote> lambdas, these are
+          called <emphasis>local</emphasis> lambdas.</para>
+
+          <para>The syntax of lambdas is like
+          <literal>(<replaceable>name1</replaceable>,
+          <replaceable>name2</replaceable>, <replaceable>...</replaceable>,
+          <replaceable>nameN</replaceable>) -&gt;
+          <replaceable>expression</replaceable></literal>. If there's only a
+          single argument, the parentheses can be omitted:
+          <literal><replaceable>name1</replaceable> -&gt;
+          <replaceable>expression</replaceable></literal>.</para>
+
+          <para>As the right side of the <literal>-&gt;</literal> is just a
+          single expression, if you need complex logic there, you probably
+          want to move that into a <link
+          linkend="ref.directive.function">function</link>, as the you can use
+          directives like <literal>if</literal>, <literal>list</literal>, etc.
+          In that case though, you don't need a lambda expression, as all
+          built-ins that support a lambda parameter, also support passing in a
+          function directly. For example, instead of <literal>seq?map(it -&gt;
+          myMapper(it))</literal> you should just write
+          <literal>seq?map(myMapper)</literal>.</para>
+
+          <para>The argument specified in a lambda expression can hold the
+          missing (Java <literal>null</literal>) value. Reading a lambda
+          argument never falls back to higher scope, so a variable with
+          identical name will not interfere when accessing the lambda
+          parameter. Therefore something like <literal>seq?filter(it -&gt;
+          it??)</literal>, which filters out missing element from the
+          sequence, will work reliably.</para>
+        </section>
+
         <section xml:id="dgui_template_exp_parentheses">
           <title>Parentheses</title>
 
@@ -4163,6 +4237,12 @@
 
                 <td><literal>||</literal></td>
               </tr>
+
+              <tr>
+                <td>local lambda</td>
+
+                <td><literal>-&gt;</literal></td>
+              </tr>
             </tbody>
           </informaltable>
 
@@ -4999,10 +5079,11 @@
             <literal>x</literal> in <literal>&lt;#list xs as
             x&gt;<replaceable>...</replaceable>&lt;/#list&gt;</literal>), and
             they only exist between the start-tag and end-tag of the
-            directive. They are only visible directly between these tags, not
-            from macros or functions called from there. As such, they are
-            quite similar to local variables, but they can't be assigned to
-            directly.</para>
+            directive. (User defined directives, like macros, can also create
+            loop variables.) They are only visible directly between these
+            tags, not from macros or functions called from there. As such,
+            they are quite similar to local variables, but they can't be
+            assigned to directly.</para>
           </listitem>
 
           <listitem>
@@ -6441,14 +6522,17 @@
         beginning of the application (possibly servlet) life-cycle:</para>
 
         <programlisting role="unspecified">// Create your Configuration instance, and specify if up to what FreeMarker
-// version (here 2.3.27) do you want to apply the fixes that are not 100%
+// version (here 2.3.29) do you want to apply the fixes that are not 100%
 // backward-compatible. See the Configuration JavaDoc for details.
-Configuration cfg = new Configuration(Configuration.VERSION_2_3_27);
+Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
 
 // Specify the source where the template files come from. Here I set a
 // plain directory for it, but non-file-system sources are possible too:
 cfg.setDirectoryForTemplateLoading(new File("<replaceable>/where/you/store/templates</replaceable>"));
 
+// From here we will set the settings recommended for new projects. These
+// aren't the defaults for backward compatibilty.
+
 // Set the preferred charset template files are stored in. UTF-8 is
 // a good choice in most applications:
 cfg.setDefaultEncoding("UTF-8");
@@ -6460,8 +6544,11 @@
 // Don't log exceptions inside FreeMarker that it will thrown at you anyway:
 cfg.setLogTemplateExceptions(false);
 
-// Wrap unchecked exceptions thrown during template processing into TemplateException-s.
-cfg.setWrapUncheckedExceptions(true);</programlisting>
+// Wrap unchecked exceptions thrown during template processing into TemplateException-s:
+cfg.setWrapUncheckedExceptions(true);
+
+// Do not fall back to higher scopes when reading a null loop variable:
+cfg.setFallbackOnNullLoopVariable(false);</programlisting>
 
         <para>From now you should use this <emphasis>single</emphasis>
         configuration instance (i.e., its a singleton). Note however that if a
@@ -6733,12 +6820,14 @@
         /* You should do this ONLY ONCE in the whole application life-cycle:        */
 
         /* Create and adjust the configuration singleton */
-        Configuration cfg = new Configuration(Configuration.VERSION_2_3_27);
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
         cfg.setDirectoryForTemplateLoading(new File("<replaceable>/where/you/store/templates</replaceable>"));
+        // Recommended settings for new projects:
         cfg.setDefaultEncoding("UTF-8");
         cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
         cfg.setLogTemplateExceptions(false);
         cfg.setWrapUncheckedExceptions(true);
+        cfg.setFallbackOnNullLoopVariable(false);
 
         /* ------------------------------------------------------------------------ */
         /* You usually do these for MULTIPLE TIMES in the application life-cycle:   */
@@ -12666,6 +12755,11 @@
           </listitem>
 
           <listitem>
+            <para><link
+            linkend="ref_builtin_drop_while">drop_while</link></para>
+          </listitem>
+
+          <listitem>
             <para><link linkend="ref_builtin_esc">esc</link></para>
           </listitem>
 
@@ -12689,6 +12783,10 @@
           </listitem>
 
           <listitem>
+            <para><link linkend="ref_builtin_filter">filter</link></para>
+          </listitem>
+
+          <listitem>
             <para><link linkend="ref_builtin_first">first</link></para>
           </listitem>
 
@@ -12860,6 +12958,10 @@
           </listitem>
 
           <listitem>
+            <para><link linkend="ref_builtin_map">map</link></para>
+          </listitem>
+
+          <listitem>
             <para><link
             linkend="ref_builtin_markup_string">markup_string</link></para>
           </listitem>
@@ -13024,6 +13126,11 @@
           </listitem>
 
           <listitem>
+            <para><link
+            linkend="ref_builtin_take_while">take_while</link></para>
+          </listitem>
+
+          <listitem>
             <para><link linkend="ref_builtin_then">then</link></para>
           </listitem>
 
@@ -16958,6 +17065,439 @@
           be of any type and value.</para>
         </section>
 
+        <section xml:id="ref_builtin_drop_while">
+          <title>drop_while</title>
+
+          <indexterm>
+            <primary>drop_while built-in</primary>
+          </indexterm>
+
+          <indexterm>
+            <primary>sequence</primary>
+
+            <secondary>drop while</secondary>
+          </indexterm>
+
+          <para>Returns a new sequence that contains the elements from the
+          input sequence starting with from the first element that does
+          <emphasis>not</emphasis> match the parameter predicate (condition).
+          After that, all elements are included, regardless if they match the
+          predicate or not. See the <link
+          linkend="ref_builtin_filter"><literal>filter</literal>
+          built-in</link> for more details about parameters, and other
+          details, but note that the condition in <literal>filter</literal>
+          has opposite meaning (what to keep, instead of what to drop).</para>
+
+          <para>Example and comparison with <literal>filter</literal>:</para>
+
+          <programlisting role="template">&lt;#assign xs = [1, 2, -3, 4, -5, 6]&gt;
+
+Drop while positive:
+&lt;#list xs?drop_while(x -&gt; x &gt; 0) as x&gt;${x} &lt;/#list&gt;
+
+Filer for positives:
+&lt;#list xs?filter(x -&gt; x &gt; 0) as x&gt;${x} &lt;/#list&gt;</programlisting>
+
+          <programlisting role="output">Drop while positive:
+-3 4 -5 6 
+
+Filer for positives:
+1 2 4 6 </programlisting>
+
+          <para>As you can see, <literal>take_while</literal> has stopped
+          dropping the elements once it ran into the first element that didn't
+          match the predicate (<literal>x &gt; 0</literal>). On the other
+          hand, <literal>filter</literal> keeps the elements that match the
+          same predicate, and it doesn't stop.</para>
+
+          <para>See also: <link
+          linkend="ref_builtin_take_while"><literal>take_while</literal>
+          built-in</link></para>
+        </section>
+
+        <section xml:id="ref_builtin_filter">
+          <title>filter</title>
+
+          <indexterm>
+            <primary>filter built-in</primary>
+          </indexterm>
+
+          <indexterm>
+            <primary>sequence</primary>
+
+            <secondary>filter</secondary>
+          </indexterm>
+
+          <note>
+            <para>This built-in is available since 2.3.29</para>
+          </note>
+
+          <para>Returns a new sequence that only contains the elements for
+          which the parameter condition (the predicate) returns
+          <literal>true</literal>. For example:</para>
+
+          <programlisting role="template">&lt;#assign xs = [1, -2, 3, 4, -5]&gt;
+Positives:
+&lt;#list xs?<emphasis>filter(x -&gt; x &gt; 0)</emphasis> as x&gt;${x} &lt;/#list&gt;
+Negatives:
+&lt;#list xs?<emphasis>filter(x -&gt; x &lt; 0)</emphasis> as x&gt;${x} &lt;/#list&gt;</programlisting>
+
+          <programlisting role="output">Positives:
+1 3 4 
+Negatives:
+-2 -5 </programlisting>
+
+          <para>This built-in has a single required parameter, the predicate
+          (filter condition, what to keep). The predicate can be specified in
+          3 ways:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>As a single argument <link
+              linkend="dgui_template_exp_lambda">lambda expression</link>:
+              <literal><replaceable>element</replaceable> -&gt;
+              <replaceable>predicate</replaceable></literal>. In that,
+              <literal><replaceable>element</replaceable></literal> is the
+              variable name with which you can refer to the current element in
+              the <literal><replaceable>predicate</replaceable></literal>, and
+              the <literal><replaceable>predicate</replaceable></literal> is
+              an arbitrarily complex <link
+              linkend="dgui_template_exp">expression</link> that must return a
+              boolean value (<literal>true</literal> or
+              <literal>false</literal>). An example this was shown above. Note
+              again the predicates can be arbitrarily complex, like the
+              predicate in <literal>products?filter(product -&gt;
+              product.discounted &amp;&amp;
+              !user.hasBought(product))</literal>.</para>
+            </listitem>
+
+            <listitem>
+              <para>As a <link
+              linkend="ref_directive_function">function</link> or method that
+              has a single argument, and returns boolean. For example, the
+              <quote>Negatives</quote> example above could be implemented like
+              this:</para>
+
+              <programlisting role="template">&lt;#function negative(x)&gt;
+  &lt;#return x &lt; 0&gt;
+&lt;/#function&gt;
+
+<replaceable>...</replaceable>
+
+Negatives:
+&lt;#list xs<emphasis>?filter(negative)</emphasis> as x&gt;${x} &lt;/#list&gt;</programlisting>
+
+              <para>Note how we just referred to the function by name, and did
+              not call it. Similarly, if you have a Java object called
+              <literal>utils</literal> in the data-model, and it has a
+              <literal>boolean isNegative(Number n)</literal> method, then you
+              could use that like
+              <literal>xs?filter(utils.isNegative)</literal>.</para>
+            </listitem>
+          </itemizedlist>
+
+          <note>
+            <para>Remember, the condition (predicate) that you specify tells
+            <emphasis>what to keep</emphasis>, not what to filter out! That
+            is, the element will be in the result sequence when you return
+            <literal>true</literal>, not when you return
+            <literal>false</literal>. (It's like the <literal>WHERE</literal>
+            condition in SQL, if you know that.)</para>
+          </note>
+
+          <para>While <literal>filter</literal> is most often used in the
+          <link linkend="ref.directive.list"><literal>list</literal>
+          directive</link>, naturally it can be used anywhere where a filtered
+          sequence is needed, and so this works as well:</para>
+
+          <programlisting role="template">&lt;#assign negatives = xs?filter(x -&gt; x &lt; 0)&gt;
+Negatives:
+&lt;#list negatives as x&gt;${x} &lt;/#list&gt;</programlisting>
+
+          <para>Note however, that for a very long sequences, the above
+          solution can consume significantly more memory. That's because
+          <literal>&lt;list
+          <replaceable>seq</replaceable>?filter(<replaceable>pred</replaceable>)
+          <replaceable>...</replaceable>&gt;</literal> is optimized to do
+          filtering without building an intermediate filtered sequence, while
+          the n above example, <literal>assign</literal> will first build the
+          whole filtered sequence in memory, and we pass that filtered
+          sequence later to <literal>list</literal>. But again, this only
+          matters for very long sequences.</para>
+
+          <para>See also: <link
+          linkend="ref_builtin_take_while"><literal>take_while</literal>
+          built-in</link>, <link
+          linkend="ref_builtin_drop_while"><literal>drop_while</literal>
+          built-in</link></para>
+
+          <simplesect xml:id="topic.filterLazyEval">
+            <title>Lazy evaluation and its consequences</title>
+
+            <note>
+              <para>Identical rules apply to these built-ins as well: <link
+              linkend="ref_builtin_map"><literal>map(<replaceable>mapper</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_take_while"><literal>take_while(<replaceable>predicate</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_drop_while"><literal>drop_while(<replaceable>predicate</replaceable>)</literal></link>.</para>
+            </note>
+
+            <para>To optimize processing, <literal>filter</literal> might
+            delays fetching the elements of the input sequence, and applying
+            the predicate on them. But it's guaranteed that those operations
+            are not delayed past the point where the execution of the
+            directive or interpolation, whose parameter contains the
+            <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)</literal>,
+            is finished. Some examples:</para>
+
+            <itemizedlist>
+              <listitem>
+                <para>In the case of <literal>&lt;list
+                <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)
+                <replaceable>...</replaceable>&gt;<replaceable>nested
+                content</replaceable>&lt;/#list&gt;</literal>, when the
+                execution enters the <literal><replaceable>nested
+                content</replaceable></literal>, it's not true that all
+                elements of <literal><replaceable>seq</replaceable></literal>
+                was already consumed and filtered. Consuming and filtering
+                <literal><replaceable>seq</replaceable></literal> is instead
+                done bit by bit as <literal>list</literal> repeats the nested
+                content. But it's guaranteed that past the
+                <literal>&lt;/#list&gt;</literal> tag (the end of the
+                execution of the <literal>list</literal> directive), there are
+                no delayed readings of
+                <literal><replaceable>seq</replaceable></literal>, or delayed
+                evaluation of the
+                <literal><replaceable>predicate</replaceable></literal>. So
+                avoid changing a such variable (or other system state) in the
+                nested content of <literal>list</literal>, which influences
+                the result of the
+                <literal><replaceable>predicate</replaceable></literal>. Doing
+                so could change the filtering for the rest of the
+                <literal><replaceable>seq</replaceable></literal>.</para>
+              </listitem>
+
+              <listitem>
+                <para>In the case of <literal>&lt;#assign
+                <replaceable>filteredSeq</replaceable> =
+                <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)&gt;</literal>
+                it's guaranteed that all elements of
+                <literal><replaceable>seq</replaceable></literal> were
+                processed, and thus
+                <literal><replaceable>predicate</replaceable></literal> won't
+                be evaluated after the <literal>assign</literal>
+                directive.</para>
+              </listitem>
+
+              <listitem>
+                <para>In the case of
+                <literal>${<replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)?join(',
+                ')}</literal> it's guaranteed that all elements of
+                <literal><replaceable>seq</replaceable></literal> were
+                processed, and thus
+                <literal><replaceable>predicate</replaceable></literal> won't
+                be evaluated after the <literal>assign</literal>
+                directive.</para>
+              </listitem>
+            </itemizedlist>
+
+            <para>Inside <link linkend="dgui_template_exp">expressions</link>
+            however, there's no promise regarding when the elements are
+            consumed and when the predicate is evaluated. Like in the case of
+            <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate1</replaceable>)?filter(<replaceable>predicate2</replaceable>)</literal>,
+            it's not guaranteed that
+            <literal><replaceable>predicate1</replaceable></literal> will only
+            be evaluated before
+            <literal><replaceable>predicate2</replaceable></literal>. (Most
+            likely they will be called alternately:
+            <literal><replaceable>predicate1</replaceable></literal> for the
+            1st element, then
+            <literal><replaceable>predicate2</replaceable></literal> for the
+            1st element, then
+            <literal><replaceable>predicate1</replaceable></literal> for the
+            2nd element, then
+            <literal><replaceable>predicate2</replaceable></literal> for the
+            2nd element, and so on.)</para>
+
+            <para>If you pass a filtered sequence to a
+            <emphasis>custom</emphasis> directive (a macro) or function or
+            method, as in <literal>&lt;@<replaceable>myMacro</replaceable>
+            <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)
+            /&gt;</literal> or
+            <literal><replaceable>myFunction</replaceable>(<replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>))</literal>,
+            then it's guaranteed that the filtering is not delayed past the
+            point when the custom directive/function/method is invoked. That
+            is, your macro/function/method will aways receive a fully
+            constructed filtered sequence.</para>
+
+            <para>Also note that in it's <emphasis>not</emphasis> guaranteed
+            that all elements of the input sequence will be read, and
+            therefore that the predicate will be evaluated for all elements.
+            Some examples of such cases:</para>
+
+            <itemizedlist>
+              <listitem>
+                <para>You may <link
+                linkend="ref.directive.list.break"><literal>break</literal></link>
+                out from <literal>&lt;list
+                <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)
+                <replaceable>...</replaceable>&gt;</literal> before it reaches
+                the last element, in which case the rest of the
+                <literal><replaceable>seq</replaceable></literal> elements
+                won't be fetched and filtered.</para>
+              </listitem>
+
+              <listitem>
+                <para>In the case of
+                <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)[2]</literal>,
+                which reads the 3rd element of the filtered sequence,
+                FreeMarker stops fetching and filtering the elements of
+                <literal><replaceable>seq</replaceable></literal> when we have
+                found the 3rd element that matches the
+                <literal><replaceable>predicate</replaceable></literal>.</para>
+              </listitem>
+
+              <listitem>
+                <para>In the case of
+                <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)?size
+                != 0</literal>, which tells whether the filtered sequence is
+                non-empty, we stop fetching and filtering the elements of
+                <literal><replaceable>seq</replaceable></literal> when we have
+                found the 1st element that matches the
+                <literal><replaceable>predicate</replaceable></literal>.
+                (That's certainly surprising as <literal>?size</literal> needs
+                to process the whole sequence to tell the size. But in this
+                case FreeMarker notices that we don't really need the exact
+                size.)</para>
+              </listitem>
+            </itemizedlist>
+
+            <para>If you are a Java programmer, note how the
+            <literal>filter</literal> built-in differs from Java
+            <literal>Stream.filter</literal>. <literal>Stream.filter</literal>
+            is <quote>lazy</quote>, while FreeMarker <literal>filter</literal>
+            is basically <quote>eager</quote>, and is only <quote>lazy</quote>
+            in special cases, and within a limited scope. Thus, unlike in
+            Java, calling <literal>filter</literal> is not always free. In
+            particular, if you assign a filtered sequence to a variable, or
+            pass it to a custom directive/function/method, the filtered
+            sequence will be created eagerly.</para>
+          </simplesect>
+
+          <simplesect xml:id="topic.filterLongInput">
+            <title>Filtering very long input that you don't hold in
+            memory</title>
+
+            <note>
+              <para>Identical rules apply to these built-ins as well: <link
+              linkend="ref_builtin_map"><literal>map(<replaceable>mapper</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_take_while"><literal>take_while(<replaceable>predicate</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_drop_while"><literal>drop_while(<replaceable>predicate</replaceable>)</literal></link>.</para>
+            </note>
+
+            <para>Some applications, particularly those that render huge
+            tables, use <link linkend="dgui_datamodel_container">sequence-like
+            values</link> in the data-model that are not held in memory at
+            once, instead they are like a stream of elements that you can only
+            read in the order as they are given to you (on the Java side these
+            are <literal>java.util.Iterator</literal>-s, or
+            <literal>java.util.Iterables</literal>, or the like). These will
+            have <quote>collection</quote> type in the template language,
+            which is like a restricted sequence.</para>
+
+            <para><literal>filter</literal> works with collection input too.
+            As you have seen earlier, <literal>filter</literal> might stores
+            the entire filtered sequence in the memory, which in this case
+            sounds concerning, because if the input was too big to fit into
+            the memory (hence it wasn't exposed as a sequence), then the
+            filtered collection can be too big as well. For that reason, if
+            the input is not a sequence (but a collection),
+            <literal>filter</literal> never collects its result into the
+            memory, and never fetches and processes the input elements until
+            they are really needed (<quote>lazy</quote> behavior). Furthermore
+            the result of <literal>filter</literal> is then a collection, not
+            a sequence, therefor sequence operations (like
+            <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>)
+            will not work on it.</para>
+
+            <para>Unlike with sequence input, any operation that would cause
+            collecting the whole filtered result into the memory will now
+            fail. Let's see that through examples. Let's say we have
+            <literal>hugeTable</literal> in the data-model, which is not a
+            sequence, but still a collection (probably an
+            <literal>Iterator</literal> in Java). Then, consider:</para>
+
+            <programlisting role="template">&lt;#-- Works: --&gt;
+&lt;#list hugeTable?filter(<replaceable>predicate</replaceable>) as row&gt;<replaceable>nested content</replaceable>&lt;/#list&gt;</programlisting>
+
+            <para>This works fine, since <literal>list</literal> doesn't
+            require collecting the result into the memory</para>
+
+            <para>Consider this:</para>
+
+            <programlisting role="template">&lt;#-- Fails if hugeTable is not a sequence, just a collection: --&gt;
+&lt;#assign filteredHugeTable = hugeTable?filter(<replaceable>predicate</replaceable>)&gt;</programlisting>
+
+            <para>This fails, as filtering can't be postponed beyond the
+            containing directive (<literal>assign</literal>), so FreeMareker
+            had to put the entire filtered result into
+            <literal>filteredHugeTable</literal>. If, however, you know that
+            <literal>filteredHugeTable</literal> won't be too big, you can
+            explicitly collect the result into a sequence via the <link
+            linkend="ref_builtin_sequence"><literal>sequence</literal>
+            built-in</link>:</para>
+
+            <programlisting role="template">&lt;#-- Works, but be sure filtredHugeTable fits into the memory: --&gt;
+&lt;#assign filteredHugeTable = hugeTable?filter(predicate)<emphasis>?sequence</emphasis>&gt;</programlisting>
+
+            <para>Naturally, applying the <literal>sequence</literal> built-in
+            allows all sequence operations, such as
+            <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>,
+            <literal><replaceable>seq</replaceable>[<replaceable>range</replaceable>]</literal>,
+            or
+            <literal><replaceable>seq</replaceable>?<replaceable>size</replaceable></literal>.
+            If these operations are directly applied on a sequence that was
+            converted from a collection, then FreeMarker optimizes out
+            actually creating the sequence in memory. So these won't consume
+            much memory regardless of the size of the filtered
+            <literal>hugeTable</literal>:</para>
+
+            <itemizedlist>
+              <listitem>
+                <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence[index]</literal>:
+                FreeMarker will just fetch and drop the elements till it
+                reaches the element at the desired position.</para>
+              </listitem>
+
+              <listitem>
+                <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence[0..9]</literal>:
+                FreeMarker will just collect the first 10 elements.</para>
+              </listitem>
+
+              <listitem>
+                <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence?size</literal>:
+                In this case the whole <literal>hugeTable</literal> will be
+                fetched, which is possibly slow, but the fetched elements are
+                still not collected into the memory, as they only need to be
+                counted.</para>
+              </listitem>
+            </itemizedlist>
+          </simplesect>
+
+          <simplesect xml:id="topic.filterMissing">
+            <title>Filtering missing (null) values</title>
+
+            <para>The argument to a lambda expression can hold the missing
+            (Java <literal>null</literal>) value, and reading such value will
+            not fall back to a higher scope. Thus, something like
+            <literal>seq?filter(it -&gt; it??)</literal>, which filters out
+            missing element from the sequence, will work reliably.</para>
+          </simplesect>
+        </section>
+
         <section xml:id="ref_builtin_first">
           <title>first</title>
 
@@ -17057,6 +17597,40 @@
           die with error if the sequence is empty.</para>
         </section>
 
+        <section xml:id="ref_builtin_map">
+          <title>map</title>
+
+          <indexterm>
+            <primary>map built-in</primary>
+          </indexterm>
+
+          <indexterm>
+            <primary>sequence</primary>
+
+            <secondary>filter</secondary>
+          </indexterm>
+
+          <para>Returns an new sequence where all elements are replaced with
+          the result of the parameter lambda, function, or method. For
+          example, you have a list of user objects in
+          <literal>users</literal>, but instead you need a list of user names
+          in variable, then you could do this:</para>
+
+          <programlisting role="template">&lt;#assign userNames = users?map(user -&gt; user.name)&gt;</programlisting>
+
+          <para>The parameter work like the parameter of the with <link
+          linkend="ref_builtin_filter"><literal>filter</literal>
+          built-in</link> (so see there), except that the
+          lambda/function/method you specify can return values of any
+          type.</para>
+
+          <para>Regarding lazy evaluation, and handling of very long inputs,
+          it also <link linkend="topic.filterLazyEval">works on the same
+          way</link> as the <link
+          linkend="ref_builtin_filter"><literal>filter</literal>
+          built-in</link>.</para>
+        </section>
+
         <section xml:id="ref_builtin_min_max">
           <title>min, max</title>
 
@@ -17110,11 +17684,6 @@
           </indexterm>
 
           <note>
-            <para>This built-in is available since FreeMarker 2.3.1. It
-            doesn't exist in 2.3.</para>
-          </note>
-
-          <note>
             <para>The <literal>seq_</literal> prefix is required in the
             built-in name to differentiate it from the <link
             linkend="ref_builtin_contains"><literal>contains</literal>
@@ -17406,6 +17975,51 @@
 - Fox, Amanda: 25 years old
 - Smith, Joe: 40 years old</programlisting>
         </section>
+
+        <section xml:id="ref_builtin_take_while">
+          <title>take_while</title>
+
+          <indexterm>
+            <primary>take_while built-in</primary>
+          </indexterm>
+
+          <indexterm>
+            <primary>sequence</primary>
+
+            <secondary>take while</secondary>
+          </indexterm>
+
+          <para>Returns a sequence that only contains the elements of the
+          input sequence which are before the first element that doesn't match
+          the parameter predicate (filter condition). This is very similar to
+          the <link linkend="ref_builtin_filter"><literal>filter</literal>
+          built-in</link>, so see further details there.</para>
+
+          <para>Example and comparison with <literal>filter</literal>:</para>
+
+          <programlisting role="template">&lt;#assign xs = [1, 2, -3, 4, -5, 6]&gt;
+
+Take while positive:
+&lt;#list xs<emphasis>?take_while</emphasis>(x -&gt; x &gt; 0) as x&gt;${x} &lt;/#list&gt;
+
+Filer for positives:
+&lt;#list xs?filter(x -&gt; x &gt; 0) as x&gt;${x} &lt;/#list&gt;</programlisting>
+
+          <programlisting role="output">Take while positive:
+1 2 
+
+Filer for positives:
+1 2 4 6 </programlisting>
+
+          <para>As you can see, <literal>take_while</literal> has stopped at
+          the first number that didn't match the predicate (<literal>x &gt;
+          0</literal>), while <literal>filter</literal> has continued finding
+          further matches.</para>
+
+          <para>See also: <link
+          linkend="ref_builtin_drop_while"><literal>drop_while</literal>
+          built-in</link></para>
+        </section>
       </section>
 
       <section xml:id="ref_builtins_hash">
@@ -18994,8 +19608,9 @@
           support operations like <literal>xs[index]</literal> and
           <literal>xs?size</literal>. Also, the resulting value is listable
           for multiple times, even if the original value was backed by a
-          <literal>java.util.Iterator</literal>. This built-in is typically
-          used to work around data-model problems, in case you can't fix the
+          <literal>java.util.Iterator</literal> (which gives error when you
+          try to list it for the 2nd time). This built-in is typically used to
+          work around data-model problems, in case you can't fix the
           data-model itself. If you can, always fix the data-model instead
           (give a <literal>java.util.List</literal> or array to the template
           instead of a more restricted object, like a
@@ -19006,10 +19621,13 @@
           returns that as is. If the value is not something that the <link
           linkend="ref.directive.list"><literal>list</literal>
           directive</link> could list, then template processing will be
-          aborted with error. Otherwise, it fetches all the values, and stores
-          them into a sequence. Be careful if you can have a huge number of
-          items, as all of them will be held in memory on the same
-          time.</para>
+          aborted with error. Otherwise, it usually fetches all the values,
+          and stores them into a sequence. Be careful if you can have a huge
+          number of items, as all of them will be held in memory on the same
+          time. However, in some special cases fetching and/or storing all
+          elements is avoided; see about the <link
+          linkend="ref_builtin_sequence_optimizations">optimizations</link>
+          later.</para>
 
           <para>You should convert a value with <literal>sequence</literal>
           only once. If you need the resulting sequence at multiple places,
@@ -19032,6 +19650,39 @@
 Again:
 &lt;#list usersSeq as user&gt;...&lt;/#list&gt;
 </programlisting>
+
+          <simplesect xml:id="ref_builtin_sequence_optimizations">
+            <title>Optimizations</title>
+
+            <para>Since version 2.3.29, if the result of the
+            <literal>sequence</literal> built-in is directly the input of to
+            the <link
+            linkend="dgui_template_exp_var_sequence"><literal>[<replaceable>index</replaceable>]</literal></link>
+            or <link
+            linkend="dgui_template_exp_seqenceop_slice"><literal>[<replaceable>range</replaceable>]</literal></link>
+            operator, or of <literal>?size</literal>, or of
+            <literal>?first</literal>, or a chain of these operations, then
+            the elements will not be collected into the memory, and only as
+            many elements as strictly necessary will be fetched. For example
+            <literal>anIterator?sequence[1]</literal> will just fetch the
+            first 2 items (instead of building a sequence that contains all
+            the elements, and then getting the 2nd element from that). Or, if
+            you write <literal>anIterator?sequence?size</literal>, it will
+            just skip through all elements to count them, but won't store them
+            in memory.</para>
+
+            <para>The optimizations will only work within the same chain of
+            built-in calls, so for example in <literal>&lt;#assign seq =
+            anIterator?sequence&gt;${seq[1]}</literal> the
+            <literal>?sequence</literal> step will collect all the elements
+            into the memory, as <literal>anIterator?sequence</literal> and
+            <literal>seq[1]</literal> are separated. On the other hand, the
+            optimizations will work in
+            <literal>anIterator?sequence[10..]?size</literal>, as both
+            <literal>[<replaceable>range</replaceable>]</literal> and
+            <literal>?size</literal> supports it, and they are directly
+            chained together.</para>
+          </simplesect>
         </section>
       </section>
     </chapter>
@@ -21081,9 +21732,9 @@
     <replaceable>Part repeated for each key-value pair</replaceable>
 &lt;/#list&gt;</literal></programlisting>
 
-          <para>But these are just cases of the generic forms, which are shown
-          below. Note that for simplicity we only show the generic forms for
-          sequence listing; simply replace <quote><literal>as
+          <para>But these are just special cases of the generic forms, which
+          are shown below. Note that for simplicity we only show the generic
+          forms for sequence listing; simply replace <quote><literal>as
           <replaceable>item</replaceable></literal></quote> with
           <quote><literal>as <replaceable>key</replaceable>,
           <replaceable>value</replaceable></literal></quote> to get the
@@ -21396,6 +22047,16 @@
               <primary>break directive</primary>
             </indexterm>
 
+            <note>
+              <para><literal>break</literal> is deprecated for most use cases,
+              as it doesn't work well with <literal>&lt;#sep&gt;</literal> and
+              <literal><replaceable>item</replaceable>?has_next</literal>.
+              Instead, use <link
+              linkend="ref_builtin_take_while"><literal><replaceable>sequence</replaceable>?take_while(<replaceable>predicate</replaceable>)</literal></link>
+              to cut the sequence before you list it. See also examples <link
+              linkend="ref_list_skipping">here.</link></para>
+            </note>
+
             <para>You can exit the iteration at any point with the
             <literal>break</literal> directive. For example:</para>
 
@@ -21436,10 +22097,11 @@
             <literal>break</literal>-able directive.</para>
 
             <para>Using <literal>break</literal> together with
-            <literal>sep</literal> is generally a bad idea, as
-            <literal>sep</literal> can't know if you will skip the rest of
-            items with <literal>break</literal>, and then you end up with a
-            separator after the item printed last.</para>
+            <literal>sep</literal> or <literal>?has_next</literal> is
+            generally a bad idea, as these can't know if you will skip the
+            rest of items with a <literal>break</literal>. To solve such
+            situations see <link linkend="ref_list_skipping">these
+            examples</link>.</para>
 
             <para>Just like <literal>else</literal> and
             <literal>items</literal>, <literal>break</literal> must be
@@ -21457,8 +22119,22 @@
             </indexterm>
 
             <note>
+              <para><literal>continue</literal> is deprecated for most use
+              cases, as it doesn't work well with
+              <literal>&lt;#sep&gt;</literal>,
+              <literal><replaceable>item</replaceable>?has_next</literal>,
+              <literal><replaceable>item</replaceable>?count</literal>,
+              <literal><replaceable>item</replaceable>?index</literal>,
+              <literal><replaceable>item</replaceable>?item_parity</literal>,
+              etc. Instead, use <link
+              linkend="ref_builtin_filter"><literal><replaceable>sequence</replaceable>?filter(<replaceable>predicate</replaceable>)</literal></link>
+              to remove unwanted elements. See also examples <link
+              linkend="ref_list_skipping">here.</link></para>
+            </note>
+
+            <note>
               <para>The <literal>continue</literal> directive exists since
-              FreeMarker 2.3.27</para>
+              FreeMarker 2.3.27.</para>
             </note>
 
             <para>You can skip the rest of the iteration body (the section
@@ -21496,10 +22172,12 @@
             <para>When you call <literal>continue</literal>, the
             <literal>sep</literal> directive will not be executed for that
             iteration. Using <literal>continue</literal> together with
-            <literal>sep</literal> is generally a bad idea, as
-            <literal>sep</literal> can't know if you will skip the rest of the
-            items, and then you end up with a separator after the item printed
-            last.</para>
+            <literal>sep</literal> is generally a bad idea anyway, also
+            <literal>?has_next</literal>, <literal>?count</literal>,
+            <literal>?index</literal>, <literal>?item_parity</literal>, etc.
+            will not work as you certainly wanted if you completely skip
+            items. To solve such situations see <link
+            linkend="ref_list_skipping">these examples</link>.</para>
 
             <para>Just like <literal>break</literal>,
             <literal>continue</literal> must be literally inside body of the
@@ -21574,6 +22252,78 @@
             1}</literal>.</para>
           </section>
 
+          <section xml:id="ref_list_skipping">
+            <title>Skipping items conditionally</title>
+
+            <para>If you need to skip certain element in a list, it's
+            generally a bad idea to use <link
+            linkend="ref.directive.if"><literal>if</literal> directive</link>
+            for that, because then <literal>&lt;#sep&gt;</literal>,
+            <literal><replaceable>item</replaceable>?has_next</literal>,
+            <literal><replaceable>item</replaceable>?count</literal>,
+            <literal><replaceable>item</replaceable>?index</literal>,
+            <literal><replaceable>item</replaceable>?item_parity</literal>,
+            etc., will not be usable, as FreeMarker doesn't know what items
+            were and will be actually displayed. Instead, you should try to
+            remove the unwanted items from the sequence that you will list,
+            and then list it (since 2.3.29). Here are some typical examples
+            with and without <literal>if</literal>.</para>
+
+            <simplesect>
+              <title>Filtering</title>
+
+              <para>In this example, you want to show the recommended products
+              from <literal>products</literal>. Here's the wrong solution with
+              <literal>if</literal>:</para>
+
+              <programlisting role="template">&lt;#-- WRONG solution! The row parity classes will be possibly messed up: --&gt;
+&lt;#list products as product&gt;
+   &lt;#<emphasis>if product.recommended</emphasis>&gt;
+     &lt;div class="${product<emphasis>?item_parity</emphasis>}Row"&gt;${product.name}&lt;/div&gt;
+   &lt;/#if&gt;
+&lt;/#list&gt;</programlisting>
+
+              <para>Here's the good solution that uses the <link
+              linkend="ref_builtin_filter"><literal>filter</literal>
+              built-in</link>:</para>
+
+              <programlisting role="template">&lt;#-- Good solution: --&gt;
+&lt;#list products<emphasis>?filter(p -&gt; p.recommended)</emphasis> as product&gt;
+  &lt;div class="${product?item_parity}Row"&gt;${product.name}&lt;/div&gt;
+&lt;/#list&gt;</programlisting>
+            </simplesect>
+
+            <simplesect>
+              <title>Stop listing when a certain element is found</title>
+
+              <para>Let's say you have a list of lines in
+              <literal>lines</literal>, and you need to stop at the first
+              empty line (if there's any). Furthermore you need to
+              <literal>&lt;br&gt;</literal> between the elements. Here's the
+              wrong solution with <literal>if</literal> and
+              <literal>break</literal>:</para>
+
+              <programlisting role="template">&lt;#-- WRONG solution! &lt;br&gt; might be added after the last printed line: --&gt;
+&lt;#list lines as line&gt;
+   &lt;#if line == ''&gt;
+     &lt;#break&gt;
+   &lt;/#if&gt;
+   ${line}&lt;#sep&gt;&lt;br&gt;
+&lt;/#list&gt;</programlisting>
+
+              <para>Here's the good solution that uses the <link
+              linkend="ref_builtin_take_while"><literal>take_while</literal>
+              built-in</link> (note that the condition is inverted compared to
+              the <literal>if</literal>+<literal>break</literal>
+              solution):</para>
+
+              <programlisting role="template">&lt;#-- Good solution: --&gt;
+&lt;#list lines?take_while(line -&gt; line != '') as line&gt;
+   ${line}&lt;#sep&gt;&lt;br&gt;
+&lt;/#list&gt;</programlisting>
+            </simplesect>
+          </section>
+
           <section xml:id="ref_list_nesting">
             <title>Nesting loops into each other</title>
 
@@ -21617,6 +22367,40 @@
   Outer again: 2</programlisting>
           </section>
 
+          <section xml:id="ref_list_missing_element">
+            <title>Treatment of missing (null) elements</title>
+
+            <para>As you know by now, the <literal>list</literal> directive
+            will repeat its nested content for each element of the listed
+            value. However, it's technically possible that you have holes
+            (missing values, Java <literal>null</literal>-s) in the list of
+            elements. The nested content will executed for these
+            <quote>holes</quote> as well, but then the loop variable (the
+            variable whose name you specify after the <literal>as</literal>
+            keyword) will be missing. When FreeMarker finds that there's no
+            variable with the given name in the loop variable scope, it will
+            just fall back to a higher scopes to find it. However, this
+            fallback behavior can be problematic in this case.
+            Consider:</para>
+
+            <programlisting role="template">&lt;#list xs as x&gt;
+  ${x!'Missing'}
+&lt;/#list&gt;</programlisting>
+
+            <para>Here, the intent of the author is to print
+            <quote>Missing</quote> for the missing elements (hopes) of
+            <literal>xs</literal>. But if accidentally there's an
+            <literal>x</literal> variable in a higher scope, like in the
+            data-model, then <literal>x</literal> will evaluate to that in
+            case the currently listed element is missing, and so it won't
+            default to <quote>Missing</quote>. To solve that, the programmers
+            should set the <literal>fallback_on_null_loop_variable</literal>
+            configuration setting to <literal>false</literal>. (Unfortunately,
+            the default must be <literal>true</literal> for backward
+            compatibility.) In that case no fallback will occur if a loop
+            variable is missing.</para>
+          </section>
+
           <section xml:id="ref_list_java_notes">
             <title>Notes for Java programmers</title>
 
@@ -27888,31 +28672,38 @@
       <section xml:id="versions_2_3_29">
         <title>2.3.29</title>
 
-        <para>Release date: [FIXME]</para>
+        <para>Release date: 2019-08-09 + release process</para>
 
         <section>
           <title>Changes on the FTL side</title>
 
           <itemizedlist>
             <listitem>
-              <para>Added new built-ins:
-              <literal>?filter(<replaceable>predicate</replaceable>)</literal>,
-              <literal>?map(<replaceable>mapper</replaceable>)</literal>,
-              <literal>?take_while(<replaceable>predicate</replaceable>)</literal>,
-              <literal>?drop_while(<replaceable>predicate</replaceable>)</literal>.
-              These allow using lambda expression, like
+              <para>Added new built-ins: <link
+              linkend="ref_builtin_filter"><literal>?filter(<replaceable>predicate</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_map"><literal>?map(<replaceable>mapper</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_take_while"><literal>?take_while(<replaceable>predicate</replaceable>)</literal></link>,
+              <link
+              linkend="ref_builtin_drop_while"><literal>?drop_while(<replaceable>predicate</replaceable>)</literal></link>.
+              These allow using lambda expressions, like
               <literal>users?filter(user -&gt; user.superuser)</literal> or
               <literal>users?map(user -&gt; user.name)</literal>, or accept a
-              functions/method as parameter. (Lambda expressions are also new
+              functions/method as parameter. Lambda expressions are also new
               in this release, but they can only be used in said built-ins, so
-              they aren't like in Java for example.) These built-ins are
-              generally eager, that is, they immediately build a new sequence.
-              However at selected places, most notably when used as
-              <literal>&lt;#list <replaceable>...</replaceable>&gt;</literal>
-              directive parameter, they are working in lazy mode instead, that
-              is, they won't built the a new sequence, just stream through the
-              existing one and apply the filter or mapping element by element.
-              [TODO: document and link documentation]</para>
+              they aren't like in Java for example, and also, unlike the
+              similar Java methods, these built-ins aren't lazy in general,
+              only in specific cases (see more <link
+              linkend="topic.filterLazyEval">here</link>). The main goal of
+              adding these built-ins was to allow conditionally skipping
+              elements in the <literal>list</literal> directive without nested
+              <literal>if</literal>-s that interfere with the <link
+              linkend="ref.directive.sep"><literal>sep</literal>
+              directive</link>, and the <link
+              linkend="ref_builtins_loop_var">loop variable built-ins</link>
+              (see examples <link
+              linkend="ref_list_skipping">here</link>).</para>
             </listitem>
 
             <listitem>
@@ -27937,23 +28728,17 @@
               <literal><replaceable>seq</replaceable>?size</literal>,
               <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>,
               <literal><replaceable>seq</replaceable>[<replaceable>range</replaceable>]</literal>,
-              and with some built-ins (<literal>filter</literal>,
+              and with some other built-ins (<literal>filter</literal>,
               <literal>map</literal>, <literal>join</literal>, etc.) to spare
               collecting all the elements into the memory when possible. For
-              example <literal>anIterator?sequence[1]</literal> now will just
-              fetch the first 2 items, instead of building a sequence that
-              contains all the elements, and then getting the 2nd element from
-              that. Or, if you write
-              <literal>anIterator?sequence?size</literal>, it will just skip
-              through all elements to count them, but won't store them in
-              memory. These optimizations only work within the same chain of
-              built-in calls, so for example in <literal>&lt;#assign seq =
-              anIterator?sequence&gt;${seq[1]}</literal> will still collect
-              all the elements into the memory, as
-              <literal>anIterator?sequence</literal> and
-              <literal>seq[1]</literal> are separated. [TODO: document this at
-              <link linkend="ref_builtin_sequence">ref_builtin_sequence</link>
-              too]</para>
+              example <literal>anIterator?sequence[1]</literal> will now just
+              fetch the first 2 items, while earlier it has built a sequence
+              that contains all the elements, only to get the 2nd element from
+              that. Or, <literal>anIterator?sequence?size</literal> will now
+              just count the elements, without collecting them into the
+              memory. See <link
+              linkend="ref_builtin_sequence_optimizations">the
+              reference</link> for more details.</para>
             </listitem>
 
             <listitem>
@@ -28002,14 +28787,14 @@
               <literal>${<replaceable>aBoolean</replaceable>}</literal> will
               behave as
               <literal>${<replaceable>aBoolean</replaceable>?c}</literal>.
-              This should be only used if you are generating output for
+              This should only be used if you are generating output for
               non-human (computer) consumption only. If your output has pieces
               for human audience too, it's still recommended to use
               <literal>${<replaceable>aBoolean</replaceable>?c}</literal>
               where <literal>true</literal>/<literal>false</literal> output is
               needed, and either not set the <literal>boolean_format</literal>
               at all, or set it to something that's appropriate for everyday
-              uses (like <literal>"yes,no"</literal>).</para>
+              users (like <literal>"yes,no"</literal>).</para>
             </listitem>
 
             <listitem>
@@ -28032,16 +28817,23 @@
             <listitem>
               <para>If the result of
               <literal><replaceable>seq</replaceable>?size</literal> is
-              compared to an integer literal in a template, like in
-              <literal><replaceable>seq</replaceable>?size != 0</literal>, or
-              <literal><replaceable>seq</replaceable>?size &lt; 1</literal>,
-              and to decide the answer it's enough to know if
-              <literal><replaceable>seq</replaceable></literal> is an empty
-              sequence or collection (i.e., the exact size isn't needed), and
-              said value implements
+              compared to an integer <emphasis>literal</emphasis> in a
+              template, like in <literal><replaceable>seq</replaceable>?size
+              != 0</literal>, or <literal><replaceable>seq</replaceable>?size
+              &lt; 1</literal>, and to decide the answer it's enough to know
+              if <literal><replaceable>seq</replaceable></literal> is empty or
+              not (i.e., the exact size isn't needed), and
+              <literal><replaceable>seq</replaceable></literal> implements
               <literal>TemplateCollectionModelEx</literal>, FreeMarker will
               call <literal>TemplateCollectionModelEx.isEmpty()</literal>
-              instead of <literal>size()</literal>.</para>
+              instead of <literal>size()</literal>. Furthermore, if
+              <literal><replaceable>seq</replaceable></literal> is the result
+              of <literal>?filter</literal>, or of a similar built-ins that
+              can provide lazily generated result, it will do counting to
+              figure out the size (rather than constructing the whole sequence
+              in memory), and will limit how far it counts based on what
+              literal the result of <literal>?size</literal> is compared
+              with.</para>
             </listitem>
 
             <listitem>
@@ -28049,8 +28841,8 @@
               <literal>TemplateModelUtils.wrapAsHashUnion(ObjectWrapper,
               List&lt;?&gt;)</literal> and
               <literal>wrapAsHashUnion(ObjectWrapper, Object...)</literal>,
-              which meant to be used when you want to compose a data-model
-              from multiple objects in a way so that their entries
+              which is useful when you want to compose the data-model from
+              multiple objects in a way so that their entries
               (<literal>Map</literal> key-value pairs, bean properties, etc.)
               appear together on the top level of the data-model.</para>
             </listitem>
diff --git a/src/test/java/freemarker/core/LambdaParsingTest.java b/src/test/java/freemarker/core/LambdaParsingTest.java
new file mode 100644
index 0000000..92df5d6
--- /dev/null
+++ b/src/test/java/freemarker/core/LambdaParsingTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package freemarker.core;
+
+import org.junit.Test;
+
+import freemarker.test.TemplateTest;
+
+public class LambdaParsingTest extends TemplateTest {
+
+    @Test
+    public void testPrecedence() throws Exception {
+        assertOutput("${[1, 2, 3]?filter(it -> it == 1 || it == 3)?join(', ')}", "1, 3");
+    }
+
+}
diff --git a/src/test/java/freemarker/core/LazilyGeneratedCollectionTest.java b/src/test/java/freemarker/core/LazilyGeneratedCollectionTest.java
index fbbf226..0dee5f4 100644
--- a/src/test/java/freemarker/core/LazilyGeneratedCollectionTest.java
+++ b/src/test/java/freemarker/core/LazilyGeneratedCollectionTest.java
@@ -265,6 +265,28 @@
         assertOutput("${seqLong?filter(x->true)[2..*3]?size}", "[size][get 0][get 1][get 2][get 3][get 4]3");
     }
 
+    @Test
+    public void testNonDirectCalledBuiltInsAreNotLazy() throws Exception {
+        assertOutput("" +
+                "<#assign changing = 1>" +
+                "<#assign method = [1, 2]?filter(it -> it != changing)?join>" +
+                "<#assign changing = 2>" +
+                "${method(', ')}",
+                "2");
+        assertOutput("" +
+                "<#assign changing = 1>" +
+                "<#assign method = [1, 2]?filter(it -> it != changing)?seq_contains>" +
+                "<#assign changing = 2>" +
+                "${method(2)?c}",
+                "true");
+        assertOutput("" +
+                "<#assign changing = 1>" +
+                "<#assign method = [1, 2]?filter(it -> it != changing)?seq_index_of>" +
+                "<#assign changing = 2>" +
+                "${method(2)}",
+                "0");
+    }
+
     public static abstract class ListContainingTemplateModel {
         protected final List<Number> elements;
 
diff --git a/src/test/java/freemarker/core/MapBiTest.java b/src/test/java/freemarker/core/MapBiTest.java
index 3e70c0f..927ea52 100644
--- a/src/test/java/freemarker/core/MapBiTest.java
+++ b/src/test/java/freemarker/core/MapBiTest.java
@@ -165,6 +165,11 @@
                 "<#function tenTimes(x)><#assign s += '${x};'><#return x * 10></#function>" +
                 "${(1..3)?map(tenTimes)?seqIndexOf(20)} ${s}", "1 1;2;");
 
+        assertOutput("" +
+                "<#assign s = ''>" +
+                "<#function tenTimes(x)><#assign s += '${x};'><#return x * 10></#function>" +
+                "${[1, 2, 3, 2, 5]?map(tenTimes)?seqLastIndexOf(20)} ${s}", "3 1;2;3;2;5;");
+
         // For these this test can't check that there was no sequence built, but at least we know they are working:
         assertOutput("${(1..3)?map(it -> it * 10)?min}", "10");
         assertOutput("${(1..3)?map(it -> it * 10)?max}", "30");
diff --git a/src/test/resources/freemarker/test/templatesuite/templates/range-lazy.ftl b/src/test/resources/freemarker/test/templatesuite/templates/range-lazy.ftl
index 4fe96e1..02f5710 100644
--- a/src/test/resources/freemarker/test/templatesuite/templates/range-lazy.ftl
+++ b/src/test/resources/freemarker/test/templatesuite/templates/range-lazy.ftl
@@ -1,3 +1,22 @@
+<#--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  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.
+-->
+
 <#assign s="012">
 <#assign seq=[0, 1, 2]>