Awight has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/178396

Change subject: update twig
......................................................................

update twig

Change-Id: Ia9ce422c57cf893c4971de2c8b4d51858be846fe
---
M twig/twig/.travis.yml
M twig/twig/CHANGELOG
M twig/twig/doc/api.rst
M twig/twig/doc/deprecated.rst
M twig/twig/doc/filters/batch.rst
M twig/twig/doc/filters/convert_encoding.rst
M twig/twig/doc/filters/first.rst
M twig/twig/doc/filters/last.rst
M twig/twig/doc/filters/merge.rst
M twig/twig/doc/filters/nl2br.rst
M twig/twig/doc/filters/number_format.rst
M twig/twig/doc/filters/raw.rst
M twig/twig/doc/filters/slice.rst
M twig/twig/doc/filters/split.rst
M twig/twig/doc/filters/trim.rst
M twig/twig/doc/functions/date.rst
M twig/twig/doc/functions/dump.rst
M twig/twig/doc/functions/include.rst
M twig/twig/doc/functions/random.rst
M twig/twig/doc/functions/source.rst
M twig/twig/doc/functions/template_from_string.rst
M twig/twig/doc/index.rst
M twig/twig/doc/installation.rst
M twig/twig/doc/intro.rst
M twig/twig/doc/tags/autoescape.rst
M twig/twig/doc/tags/do.rst
M twig/twig/doc/tags/if.rst
M twig/twig/doc/tags/use.rst
M twig/twig/doc/templates.rst
D twig/twig/ext/twig/LICENSE
M twig/twig/ext/twig/php_twig.h
M twig/twig/ext/twig/twig.c
M twig/twig/lib/Twig/Compiler.php
M twig/twig/lib/Twig/Environment.php
M twig/twig/lib/Twig/Error.php
M twig/twig/lib/Twig/ExpressionParser.php
M twig/twig/lib/Twig/Extension/Core.php
M twig/twig/lib/Twig/Loader/Array.php
M twig/twig/lib/Twig/Loader/String.php
M twig/twig/lib/Twig/Node.php
M twig/twig/lib/Twig/Node/AutoEscape.php
M twig/twig/lib/Twig/Node/Block.php
M twig/twig/lib/Twig/Node/BlockReference.php
M twig/twig/lib/Twig/Node/Do.php
M twig/twig/lib/Twig/Node/Expression/Array.php
M twig/twig/lib/Twig/Node/Expression/AssignName.php
M twig/twig/lib/Twig/Node/Expression/Binary.php
M twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php
M twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
M twig/twig/lib/Twig/Node/Expression/Binary/In.php
M twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
M twig/twig/lib/Twig/Node/Expression/Binary/Power.php
M twig/twig/lib/Twig/Node/Expression/Binary/Range.php
M twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php
M twig/twig/lib/Twig/Node/Expression/BlockReference.php
M twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
M twig/twig/lib/Twig/Node/Expression/GetAttr.php
M twig/twig/lib/Twig/Node/Expression/Parent.php
M twig/twig/lib/Twig/Node/Flush.php
M twig/twig/lib/Twig/Node/For.php
M twig/twig/lib/Twig/Node/ForLoop.php
M twig/twig/lib/Twig/Node/If.php
M twig/twig/lib/Twig/Node/Import.php
M twig/twig/lib/Twig/Node/Include.php
M twig/twig/lib/Twig/Node/Macro.php
M twig/twig/lib/Twig/Node/Module.php
M twig/twig/lib/Twig/Node/Print.php
M twig/twig/lib/Twig/Node/Sandbox.php
M twig/twig/lib/Twig/Node/SandboxedModule.php
M twig/twig/lib/Twig/Node/SandboxedPrint.php
M twig/twig/lib/Twig/Node/Set.php
M twig/twig/lib/Twig/Node/Spaceless.php
M twig/twig/lib/Twig/Node/Text.php
M twig/twig/lib/Twig/NodeInterface.php
M twig/twig/lib/Twig/NodeVisitor/Optimizer.php
M twig/twig/lib/Twig/NodeVisitor/Sandbox.php
A twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php
A twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php
A twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php
M twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
M twig/twig/lib/Twig/Template.php
M twig/twig/test/Twig/Tests/EnvironmentTest.php
M twig/twig/test/Twig/Tests/Extension/CoreTest.php
M twig/twig/test/Twig/Tests/Extension/SandboxTest.php
M twig/twig/test/Twig/Tests/FileCachingTest.php
M twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test
M twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test
M twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test
M twig/twig/test/Twig/Tests/Fixtures/filters/date.test
M twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test
M twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
M twig/twig/test/Twig/Tests/Fixtures/filters/split.test
A twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test
M twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
M twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
A twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test
A twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test
A twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test
M twig/twig/test/Twig/Tests/IntegrationTest.php
M twig/twig/test/Twig/Tests/LexerTest.php
M twig/twig/test/Twig/Tests/NativeExtensionTest.php
M twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
M twig/twig/test/Twig/Tests/Node/IncludeTest.php
M twig/twig/test/Twig/Tests/Node/MacroTest.php
M twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
M twig/twig/test/Twig/Tests/TemplateTest.php
M twig/twig/test/Twig/Tests/escapingTest.php
107 files changed, 705 insertions(+), 320 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/crm/vendor 
refs/changes/96/178396/1

diff --git a/twig/twig/.travis.yml b/twig/twig/.travis.yml
index a8d71c2..1fbff75 100644
--- a/twig/twig/.travis.yml
+++ b/twig/twig/.travis.yml
@@ -5,6 +5,7 @@
   - 5.3
   - 5.4
   - 5.5
+  - 5.6
   - hhvm
 
 env:
diff --git a/twig/twig/CHANGELOG b/twig/twig/CHANGELOG
index 1cf54a7..33b32f8 100644
--- a/twig/twig/CHANGELOG
+++ b/twig/twig/CHANGELOG
@@ -1,3 +1,24 @@
+* 1.16.2 (2014-10-17)
+
+ * fixed timezone on dates as strings
+ * fixed 2-words test names when a custom node class is not used
+ * fixed macros when using an argument named like a PHP super global (like GET 
or POST)
+ * fixed date_modify when working with DateTimeImmutable
+ * optimized for loops
+ * fixed multi-byte characters handling in the split filter
+ * fixed a regression in the in operator
+ * fixed a regression in the slice filter
+
+* 1.16.1 (2014-10-10)
+
+ * improved error reporting in a sandboxed template
+ * fixed missing error file/line information under certain circumstances
+ * fixed wrong error line number in some error messages
+ * fixed the in operator to use strict comparisons
+ * sped up the slice filter
+ * fixed for mb function overload mb_substr acting different
+ * fixed the attribute() function when passing a variable for the arguments
+
 * 1.16.0 (2014-07-05)
 
  * changed url_encode to always encode according to RFC 3986
diff --git a/twig/twig/doc/api.rst b/twig/twig/doc/api.rst
index b00d61e..7756127 100644
--- a/twig/twig/doc/api.rst
+++ b/twig/twig/doc/api.rst
@@ -166,21 +166,6 @@
 
     $twig->render('@admin/index.html', array());
 
-``Twig_Loader_String``
-......................
-
-``Twig_Loader_String`` loads templates from strings. It's a dummy loader as
-the template reference is the template source code::
-
-    $loader = new Twig_Loader_String();
-    $twig = new Twig_Environment($loader);
-
-    echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
-
-This loader should only be used for unit testing as it has severe limitations:
-several tags, like ``extends`` or ``include`` do not make sense to use as the
-reference to the template is the template source code itself.
-
 ``Twig_Loader_Array``
 .....................
 
@@ -214,7 +199,7 @@
         'base.html' => '{% block content %}{% endblock %}',
     ));
     $loader2 = new Twig_Loader_Array(array(
-        'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ 
name }}{% endblock %}',
+        'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ 
name }}{% endblock %}',
         'base.html'  => 'Will never be loaded',
     ));
 
@@ -266,26 +251,6 @@
          * @param timestamp $time The last modification time of the cached 
template
          */
         function isFresh($name, $time);
-    }
-
-As an example, here is how the built-in ``Twig_Loader_String`` reads::
-
-    class Twig_Loader_String implements Twig_LoaderInterface
-    {
-        public function getSource($name)
-        {
-          return $name;
-        }
-
-        public function getCacheKey($name)
-        {
-          return $name;
-        }
-
-        public function isFresh($name, $time)
-        {
-          return false;
-        }
     }
 
 The ``isFresh()`` method must return ``true`` if the current cached template
diff --git a/twig/twig/doc/deprecated.rst b/twig/twig/doc/deprecated.rst
index 641f31e..30aaac1 100644
--- a/twig/twig/doc/deprecated.rst
+++ b/twig/twig/doc/deprecated.rst
@@ -23,7 +23,7 @@
 PEAR
 ----
 
-PEAR support has been discontinued in Twig 1.15.1, and no PEAR packages is
+PEAR support has been discontinued in Twig 1.15.1, and no PEAR packages are
 provided anymore. Use Composer instead.
 
 Filters
@@ -80,6 +80,12 @@
 * The ``sameas`` and ``divisibleby`` tests are deprecated in favor of ``same
   as`` and ``divisible by`` respectively.
 
+Nodes
+-----
+
+* As of Twig 1.x, ``Node::toXml()`` is deprecated and will be removed in Twig
+  2.0.
+
 Interfaces
 ----------
 
diff --git a/twig/twig/doc/filters/batch.rst b/twig/twig/doc/filters/batch.rst
index b0b9964..30dd782 100644
--- a/twig/twig/doc/filters/batch.rst
+++ b/twig/twig/doc/filters/batch.rst
@@ -2,7 +2,7 @@
 =========
 
 .. versionadded:: 1.12.3
-    The batch filter was added in Twig 1.12.3.
+    The ``batch`` filter was added in Twig 1.12.3.
 
 The ``batch`` filter "batches" items by returning a list of lists with the
 given number of items. If you provide a second parameter, it is used to fill
diff --git a/twig/twig/doc/filters/convert_encoding.rst 
b/twig/twig/doc/filters/convert_encoding.rst
index c417e12..f4ebe58 100644
--- a/twig/twig/doc/filters/convert_encoding.rst
+++ b/twig/twig/doc/filters/convert_encoding.rst
@@ -21,8 +21,8 @@
 Arguments
 ---------
 
-* ``from``: The input charset
 * ``to``:   The output charset
+* ``from``: The input charset
 
 .. _`iconv`:    http://php.net/iconv
 .. _`mbstring`: http://php.net/mbstring
diff --git a/twig/twig/doc/filters/first.rst b/twig/twig/doc/filters/first.rst
index 4295e83..674c1f9 100644
--- a/twig/twig/doc/filters/first.rst
+++ b/twig/twig/doc/filters/first.rst
@@ -2,7 +2,7 @@
 =========
 
 .. versionadded:: 1.12.2
-    The first filter was added in Twig 1.12.2.
+    The ``first`` filter was added in Twig 1.12.2.
 
 The ``first`` filter returns the first "element" of a sequence, a mapping, or
 a string:
diff --git a/twig/twig/doc/filters/last.rst b/twig/twig/doc/filters/last.rst
index 723c0b5..345b657 100644
--- a/twig/twig/doc/filters/last.rst
+++ b/twig/twig/doc/filters/last.rst
@@ -2,7 +2,7 @@
 ========
 
 .. versionadded:: 1.12.2
-    The last filter was added in Twig 1.12.2.
+    The ``last`` filter was added in Twig 1.12.2.
 
 The ``last`` filter returns the last "element" of a sequence, a mapping, or
 a string:
diff --git a/twig/twig/doc/filters/merge.rst b/twig/twig/doc/filters/merge.rst
index 05a2ae7..cb8b1b2 100644
--- a/twig/twig/doc/filters/merge.rst
+++ b/twig/twig/doc/filters/merge.rst
@@ -39,3 +39,9 @@
         {% set items = { 'apple': 'unknown' }|merge(items) %}
 
         {# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #}
+        
+.. note::
+
+    Internally, Twig uses the PHP `array_merge`_ function.
+
+.. _`array_merge`: http://php.net/array_merge
diff --git a/twig/twig/doc/filters/nl2br.rst b/twig/twig/doc/filters/nl2br.rst
index 694c672..5c923e1 100644
--- a/twig/twig/doc/filters/nl2br.rst
+++ b/twig/twig/doc/filters/nl2br.rst
@@ -2,7 +2,7 @@
 =========
 
 .. versionadded:: 1.5
-    The nl2br filter was added in Twig 1.5.
+    The ``nl2br`` filter was added in Twig 1.5.
 
 The ``nl2br`` filter inserts HTML line breaks before all newlines in a string:
 
diff --git a/twig/twig/doc/filters/number_format.rst 
b/twig/twig/doc/filters/number_format.rst
index 3e60691..3114e84 100644
--- a/twig/twig/doc/filters/number_format.rst
+++ b/twig/twig/doc/filters/number_format.rst
@@ -2,7 +2,7 @@
 =================
 
 .. versionadded:: 1.5
-    The number_format filter was added in Twig 1.5
+    The ``number_format`` filter was added in Twig 1.5
 
 The ``number_format`` filter formats numbers.  It is a wrapper around PHP's
 `number_format`_ function:
diff --git a/twig/twig/doc/filters/raw.rst b/twig/twig/doc/filters/raw.rst
index a9900c7..e5e5b12 100644
--- a/twig/twig/doc/filters/raw.rst
+++ b/twig/twig/doc/filters/raw.rst
@@ -10,3 +10,27 @@
     {% autoescape %}
         {{ var|raw }} {# var won't be escaped #}
     {% endautoescape %}
+
+.. note::
+
+    Be careful when using the ``raw`` filter inside expressions:
+
+    .. code-block:: jinja
+
+        {% autoescape %}
+            {% set hello = '<strong>Hello</strong>' %}
+            {% set hola = '<strong>Hola</strong>' %}
+
+            {{ false ? '<strong>Hola</strong>' : hello|raw }}
+            does not render the same as
+            {{ false ? hola : hello|raw }}
+            but renders the same as
+            {{ (false ? hola : hello)|raw }}
+        {% endautoescape %}
+
+    The first ternary statement is not escaped: ``hello`` is marked as being
+    safe and Twig does not escape static values (see
+    :doc:`escape<../tags/autoescape>`). In the second ternary statement, even
+    if ``hello`` is marked as safe, ``hola`` remains unsafe and so is the whole
+    expression. The third ternary statement is marked as safe and the result is
+    not escaped.
diff --git a/twig/twig/doc/filters/slice.rst b/twig/twig/doc/filters/slice.rst
index afc8300..a856664 100644
--- a/twig/twig/doc/filters/slice.rst
+++ b/twig/twig/doc/filters/slice.rst
@@ -2,7 +2,7 @@
 ===========
 
 .. versionadded:: 1.6
-    The slice filter was added in Twig 1.6.
+    The ``slice`` filter was added in Twig 1.6.
 
 The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
 
diff --git a/twig/twig/doc/filters/split.rst b/twig/twig/doc/filters/split.rst
index 5c70b46..bbc6d79 100644
--- a/twig/twig/doc/filters/split.rst
+++ b/twig/twig/doc/filters/split.rst
@@ -2,7 +2,7 @@
 =========
 
 .. versionadded:: 1.10.3
-    The split filter was added in Twig 1.10.3.
+    The ``split`` filter was added in Twig 1.10.3.
 
 The ``split`` filter splits a string by the given delimiter and returns a list
 of strings:
diff --git a/twig/twig/doc/filters/trim.rst b/twig/twig/doc/filters/trim.rst
index 0c5b32e..4ddb208 100644
--- a/twig/twig/doc/filters/trim.rst
+++ b/twig/twig/doc/filters/trim.rst
@@ -2,7 +2,7 @@
 ========
 
 .. versionadded:: 1.6.2
-    The trim filter was added in Twig 1.6.2.
+    The ``trim`` filter was added in Twig 1.6.2.
 
 The ``trim`` filter strips whitespace (or other characters) from the beginning
 and end of a string:
diff --git a/twig/twig/doc/functions/date.rst b/twig/twig/doc/functions/date.rst
index 9442c39..714e08c 100644
--- a/twig/twig/doc/functions/date.rst
+++ b/twig/twig/doc/functions/date.rst
@@ -15,7 +15,7 @@
         {# do something #}
     {% endif %}
 
-The argument must be in a format supported by the `date`_ function.
+The argument must be in one of PHP’s supported `date and time formats`_.
 
 You can pass a timezone as the second argument:
 
@@ -49,4 +49,4 @@
 * ``date``:     The date
 * ``timezone``: The timezone
 
-.. _`date`: http://www.php.net/date
+.. _`date and time formats`: http://php.net/manual/en/datetime.formats.php
diff --git a/twig/twig/doc/functions/dump.rst b/twig/twig/doc/functions/dump.rst
index 54f8d4e..a231f08 100644
--- a/twig/twig/doc/functions/dump.rst
+++ b/twig/twig/doc/functions/dump.rst
@@ -2,7 +2,7 @@
 ========
 
 .. versionadded:: 1.5
-    The dump function was added in Twig 1.5.
+    The ``dump`` function was added in Twig 1.5.
 
 The ``dump`` function dumps information about a template variable. This is
 mostly useful to debug a template that does not behave as expected by
diff --git a/twig/twig/doc/functions/include.rst 
b/twig/twig/doc/functions/include.rst
index 8feb0f1..33bd56d 100644
--- a/twig/twig/doc/functions/include.rst
+++ b/twig/twig/doc/functions/include.rst
@@ -2,7 +2,7 @@
 ===========
 
 .. versionadded:: 1.12
-    The include function was added in Twig 1.12.
+    The ``include`` function was added in Twig 1.12.
 
 The ``include`` function returns the rendered content of a template:
 
diff --git a/twig/twig/doc/functions/random.rst 
b/twig/twig/doc/functions/random.rst
index acbffe5..168e74f 100644
--- a/twig/twig/doc/functions/random.rst
+++ b/twig/twig/doc/functions/random.rst
@@ -2,7 +2,7 @@
 ==========
 
 .. versionadded:: 1.5
-    The random function was added in Twig 1.5.
+    The ``random`` function was added in Twig 1.5.
 
 .. versionadded:: 1.6
     String and integer handling was added in Twig 1.6.
diff --git a/twig/twig/doc/functions/source.rst 
b/twig/twig/doc/functions/source.rst
index defa5fb..8ff39c2 100644
--- a/twig/twig/doc/functions/source.rst
+++ b/twig/twig/doc/functions/source.rst
@@ -2,7 +2,7 @@
 ==========
 
 .. versionadded:: 1.15
-    The source function was added in Twig 1.15.
+    The ``source`` function was added in Twig 1.15.
 
 The ``source`` function returns the content of a template without rendering it:
 
diff --git a/twig/twig/doc/functions/template_from_string.rst 
b/twig/twig/doc/functions/template_from_string.rst
index 95d9256..ce6a60d 100644
--- a/twig/twig/doc/functions/template_from_string.rst
+++ b/twig/twig/doc/functions/template_from_string.rst
@@ -2,7 +2,7 @@
 ========================
 
 .. versionadded:: 1.11
-    The template_from_string function was added in Twig 1.11.
+    The ``template_from_string`` function was added in Twig 1.11.
 
 The ``template_from_string`` function loads a template from a string:
 
diff --git a/twig/twig/doc/index.rst b/twig/twig/doc/index.rst
index 3109c73..358bd73 100644
--- a/twig/twig/doc/index.rst
+++ b/twig/twig/doc/index.rst
@@ -5,15 +5,15 @@
     :maxdepth: 2
 
     intro
+    installation
     templates
     api
     advanced
     internals
+    deprecated
     recipes
     coding_standards
     tags/index
     filters/index
     functions/index
     tests/index
-    installation
-    deprecated
diff --git a/twig/twig/doc/installation.rst b/twig/twig/doc/installation.rst
index d402f8a..2d19f75 100644
--- a/twig/twig/doc/installation.rst
+++ b/twig/twig/doc/installation.rst
@@ -9,44 +9,26 @@
 Installing via Composer (recommended)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-1. Install Composer in your project:
+Install `Composer`_ and run the following command to get the latest version:
 
 .. code-block:: bash
 
-    curl -s http://getcomposer.org/installer | php
-
-2. Create a ``composer.json`` file in your project root:
-
-.. code-block:: javascript
-
-    {
-        "require": {
-            "twig/twig": "1.*"
-        }
-    }
-
-3. Install via Composer
-
-.. code-block:: bash
-
-    php composer.phar install
-
-.. note::
-    If you want to learn more about Composer, the ``composer.json`` file syntax
-    and its usage, you can read the `online documentation`_.
+    composer require twig/twig:~1.0
 
 Installing from the tarball release
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 1. Download the most recent tarball from the `download page`_
-2. Unpack the tarball
-3. Move the files somewhere in your project
+2. Verify the integrity of the tarball 
http://fabien.potencier.org/article/73/signing-project-releases
+3. Unpack the tarball
+4. Move the files somewhere in your project
 
 Installing the development version
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-1. Install Git
-2. ``git clone git://github.com/fabpot/Twig.git``
+.. code-block:: bash
+
+    git clone git://github.com/fabpot/Twig.git
 
 Installing the PEAR package
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -56,9 +38,10 @@
     Using PEAR for installing Twig is deprecated and Twig 1.15.1 was the last
     version published on the PEAR channel; use Composer instead.
 
-1. Install PEAR
-2. ``pear channel-discover pear.twig-project.org``
-3. ``pear install twig/Twig``
+.. code-block:: bash
+
+    pear channel-discover pear.twig-project.org
+    pear install twig/Twig
 
 Installing the C extension
 --------------------------
@@ -75,11 +58,11 @@
 
 .. code-block:: bash
 
-    $ cd ext/twig
-    $ phpize
-    $ ./configure
-    $ make
-    $ make install
+    cd ext/twig
+    phpize
+    ./configure
+    make
+    make install
 
 .. note::
 
@@ -87,9 +70,10 @@
     deprecated and newer versions of Twig are not available on the PEAR
     channel):
 
-    1. Install PEAR
-    2. ``pear channel-discover pear.twig-project.org``
-    3. ``pear install twig/CTwig``
+    .. code-block:: bash
+
+        pear channel-discover pear.twig-project.org
+        pear install twig/CTwig
 
 For Windows:
 
@@ -124,6 +108,6 @@
 ``Twig_Template::getAttribute()`` method.
 
 .. _`download page`: https://github.com/fabpot/Twig/tags
-.. _`online documentation`: http://getcomposer.org/doc
+.. _`Composer`: https://getcomposer.org/download/
 .. _`PHP documentation`: https://wiki.php.net/internals/windows/stepbystepbuild
 .. _`Zend Server FAQ`: http://www.zend.com/en/products/server/faq#faqD6
diff --git a/twig/twig/doc/intro.rst b/twig/twig/doc/intro.rst
index 8677d50..3a7c1d4 100644
--- a/twig/twig/doc/intro.rst
+++ b/twig/twig/doc/intro.rst
@@ -33,7 +33,7 @@
 
 .. code-block:: bash
 
-    composer require "twig/twig:1.*"
+    composer require "twig/twig:~1.0"
 
 .. note::
 
@@ -50,12 +50,14 @@
 
     require_once '/path/to/vendor/autoload.php';
 
-    $loader = new Twig_Loader_String();
+    $loader = new Twig_Loader_Array(
+        'index' => 'Hello {{ name }}!',
+    );
     $twig = new Twig_Environment($loader);
 
-    echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
+    echo $twig->render('index', array('name' => 'Fabien'));
 
-Twig uses a loader (``Twig_Loader_String``) to locate templates, and an
+Twig uses a loader (``Twig_Loader_Array``) to locate templates, and an
 environment (``Twig_Environment``) to store the configuration.
 
 The ``render()`` method loads the template passed as a first argument and
diff --git a/twig/twig/doc/tags/autoescape.rst 
b/twig/twig/doc/tags/autoescape.rst
index c5ff0c2..4208d1a 100644
--- a/twig/twig/doc/tags/autoescape.rst
+++ b/twig/twig/doc/tags/autoescape.rst
@@ -67,5 +67,17 @@
 
 .. note::
 
+    Twig does not escape static expressions:
+
+    .. code-block:: jinja
+
+        {% set hello = "<strong>Hello</strong>" %}
+        {{ hello }}
+        {{ "<strong>world</strong>" }}
+
+    Will be rendered "<strong>Hello</strong> **world**".
+
+.. note::
+
     The chapter :doc:`Twig for Developers<../api>` gives more information
     about when and how automatic escaping is applied.
diff --git a/twig/twig/doc/tags/do.rst b/twig/twig/doc/tags/do.rst
index eca63d0..1c344e3 100644
--- a/twig/twig/doc/tags/do.rst
+++ b/twig/twig/doc/tags/do.rst
@@ -2,7 +2,7 @@
 ======
 
 .. versionadded:: 1.5
-    The do tag was added in Twig 1.5.
+    The ``do`` tag was added in Twig 1.5.
 
 The ``do`` tag works exactly like the regular variable expression (``{{ ...
 }}``) just that it doesn't print anything:
diff --git a/twig/twig/doc/tags/if.rst b/twig/twig/doc/tags/if.rst
index d7a1451..273207d 100644
--- a/twig/twig/doc/tags/if.rst
+++ b/twig/twig/doc/tags/if.rst
@@ -41,3 +41,20 @@
     {% else %}
         Kenny looks okay --- so far
     {% endif %}
+
+.. note::
+
+    The rules to determine if an expression is ``true`` or ``false`` are the
+    same as in PHP; here are the edge cases rules:
+
+    ====================== ====================
+    Value                  Boolean evaluation
+    ====================== ====================
+    empty string           false
+    numeric zero           false
+    whitespace-only string true
+    empty array            false
+    null                   false
+    non-empty array        true
+    object                 true
+    ====================== ====================
diff --git a/twig/twig/doc/tags/use.rst b/twig/twig/doc/tags/use.rst
index e403632..a2f3af0 100644
--- a/twig/twig/doc/tags/use.rst
+++ b/twig/twig/doc/tags/use.rst
@@ -39,7 +39,8 @@
 
 .. code-block:: jinja
 
-    # blocks.html
+    {# blocks.html #}
+    
     {% block sidebar %}{% endblock %}
 
 In this example, the ``use`` statement imports the ``sidebar`` block into the
diff --git a/twig/twig/doc/templates.rst b/twig/twig/doc/templates.rst
index aff036d..82b6f0c 100644
--- a/twig/twig/doc/templates.rst
+++ b/twig/twig/doc/templates.rst
@@ -693,7 +693,7 @@
 
     .. code-block:: jinja
 
-        {% if phone matches '{^[\d\.]+$}' %}
+        {% if phone matches '/^[\\d\\.]+$/' %}
         {% endif %}
 
 Containment Operator
diff --git a/twig/twig/ext/twig/LICENSE b/twig/twig/ext/twig/LICENSE
deleted file mode 100644
index 3384cc5..0000000
--- a/twig/twig/ext/twig/LICENSE
+++ /dev/null
@@ -1,31 +0,0 @@
-Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
-
-Some rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
-
-    * The names of the contributors may not be used to endorse or
-      promote products derived from this software without specific
-      prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/twig/twig/ext/twig/php_twig.h b/twig/twig/ext/twig/php_twig.h
index aefbf04..e116b4c 100644
--- a/twig/twig/ext/twig/php_twig.h
+++ b/twig/twig/ext/twig/php_twig.h
@@ -15,7 +15,7 @@
 #ifndef PHP_TWIG_H
 #define PHP_TWIG_H
 
-#define PHP_TWIG_VERSION "1.16.0"
+#define PHP_TWIG_VERSION "1.16.2"
 
 #include "php.h"
 
diff --git a/twig/twig/ext/twig/twig.c b/twig/twig/ext/twig/twig.c
index 5cb923f..5c482be 100644
--- a/twig/twig/ext/twig/twig.c
+++ b/twig/twig/ext/twig/twig.c
@@ -830,7 +830,11 @@
                        } elseif (is_object($object)) {
                                $message = sprintf('Impossible to access a key 
"%s" on an object of class "%s" that does not implement ArrayAccess interface', 
$item, get_class($object));
                        } elseif (is_array($object)) {
-                               $message = sprintf('Key "%s" for array with 
keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
+                               if (empty($object)) {
+                                   $message = sprintf('Key "%s" does not exist 
as the array is empty', $arrayItem);
+                               } else {
+                                   $message = sprintf('Key "%s" for array with 
keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
+                               }
                        } elseif (Twig_Template::ARRAY_CALL === $type) {
                                $message = sprintf('Impossible to access a key 
("%s") on a %s variable ("%s")', $item, gettype($object), $object);
                        } else {
@@ -845,7 +849,11 @@
                        } else if (Z_TYPE_P(object) == IS_OBJECT) {
                                TWIG_RUNTIME_ERROR(template TSRMLS_CC, 
"Impossible to access a key \"%s\" on an object of class \"%s\" that does not 
implement ArrayAccess interface", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
                        } else if (Z_TYPE_P(object) == IS_ARRAY) {
-                               TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key 
\"%s\" for array with keys \"%s\" does not exist", item, 
TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
+                               if (0 == 
zend_hash_num_elements(Z_ARRVAL_P(object))) {
+                                       TWIG_RUNTIME_ERROR(template TSRMLS_CC, 
"Key \"%s\" does not exist as the array is empty", item);
+                               } else {
+                                       TWIG_RUNTIME_ERROR(template TSRMLS_CC, 
"Key \"%s\" for array with keys \"%s\" does not exist", item, 
TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
+                               }
                        } else {
                                char *type_name = zend_zval_type_name(object);
                                Z_ADDREF_P(object);
diff --git a/twig/twig/lib/Twig/Compiler.php b/twig/twig/lib/Twig/Compiler.php
index ee00519..93dc876 100644
--- a/twig/twig/lib/Twig/Compiler.php
+++ b/twig/twig/lib/Twig/Compiler.php
@@ -74,6 +74,7 @@
     {
         $this->lastLine = null;
         $this->source = '';
+        $this->debugInfo = array();
         $this->sourceOffset = 0;
         // source code starts at 1 (as we then increment it when we encounter 
new lines)
         $this->sourceLine = 1;
@@ -181,14 +182,14 @@
         } elseif (is_array($value)) {
             $this->raw('array(');
             $first = true;
-            foreach ($value as $key => $value) {
+            foreach ($value as $key => $v) {
                 if (!$first) {
                     $this->raw(', ');
                 }
                 $first = false;
                 $this->repr($key);
                 $this->raw(' => ');
-                $this->repr($value);
+                $this->repr($v);
             }
             $this->raw(')');
         } else {
@@ -267,4 +268,9 @@
 
         return $this;
     }
+
+    public function getVarName()
+    {
+        return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), 
true), false));
+    }
 }
diff --git a/twig/twig/lib/Twig/Environment.php 
b/twig/twig/lib/Twig/Environment.php
index d3ba9be..17e88ab 100644
--- a/twig/twig/lib/Twig/Environment.php
+++ b/twig/twig/lib/Twig/Environment.php
@@ -16,7 +16,7 @@
  */
 class Twig_Environment
 {
-    const VERSION = '1.16.0';
+    const VERSION = '1.16.2';
 
     protected $charset;
     protected $loader;
diff --git a/twig/twig/lib/Twig/Error.php b/twig/twig/lib/Twig/Error.php
index 6772887..5b253dd 100644
--- a/twig/twig/lib/Twig/Error.php
+++ b/twig/twig/lib/Twig/Error.php
@@ -229,6 +229,8 @@
 
         while ($e = array_pop($exceptions)) {
             $traces = $e->getTrace();
+            array_unshift($traces, array('file' => $e->getFile(), 'line' => 
$e->getLine()));
+
             while ($trace = array_shift($traces)) {
                 if (!isset($trace['file']) || !isset($trace['line']) || $file 
!= $trace['file']) {
                     continue;
diff --git a/twig/twig/lib/Twig/ExpressionParser.php 
b/twig/twig/lib/Twig/ExpressionParser.php
index 01594f7..f685bad 100644
--- a/twig/twig/lib/Twig/ExpressionParser.php
+++ b/twig/twig/lib/Twig/ExpressionParser.php
@@ -318,7 +318,7 @@
                     throw new Twig_Error_Syntax('The "attribute" function 
takes at least two arguments (the variable and the attributes)', $line, 
$this->parser->getFilename());
                 }
 
-                return new Twig_Node_Expression_GetAttr($args->getNode(0), 
$args->getNode(1), count($args) > 2 ? $args->getNode(2) : new 
Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
+                return new Twig_Node_Expression_GetAttr($args->getNode(0), 
$args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, 
Twig_Template::ANY_CALL, $line);
             default:
                 if (null !== $alias = 
$this->parser->getImportedSymbol('function', $name)) {
                     $arguments = new Twig_Node_Expression_Array(array(), 
$line);
diff --git a/twig/twig/lib/Twig/Extension/Core.php 
b/twig/twig/lib/Twig/Extension/Core.php
index 750ef0f..e71d741 100644
--- a/twig/twig/lib/Twig/Extension/Core.php
+++ b/twig/twig/lib/Twig/Extension/Core.php
@@ -173,7 +173,7 @@
 
             // array helpers
             new Twig_SimpleFilter('join', 'twig_join_filter'),
-            new Twig_SimpleFilter('split', 'twig_split_filter'),
+            new Twig_SimpleFilter('split', 'twig_split_filter', 
array('needs_environment' => true)),
             new Twig_SimpleFilter('sort', 'twig_sort_filter'),
             new Twig_SimpleFilter('merge', 'twig_array_merge'),
             new Twig_SimpleFilter('batch', 'twig_array_batch'),
@@ -298,8 +298,8 @@
     public function parseTestExpression(Twig_Parser $parser, 
Twig_NodeInterface $node)
     {
         $stream = $parser->getStream();
-        $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
-        $class = $this->getTestNodeClass($parser, $name, $node->getLine());
+        $name = $this->getTestName($parser, $node->getLine());
+        $class = $this->getTestNodeClass($parser, $name);
         $arguments = null;
         if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
             $arguments = $parser->getExpressionParser()->parseArguments(true);
@@ -308,32 +308,40 @@
         return new $class($node, $name, $arguments, 
$parser->getCurrentToken()->getLine());
     }
 
-    protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
+    protected function getTestName(Twig_Parser $parser, $line)
     {
+        $stream = $parser->getStream();
+        $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
         $env = $parser->getEnvironment();
         $testMap = $env->getTests();
-        $testName = null;
+
         if (isset($testMap[$name])) {
-            $testName = $name;
-        } elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
+            return $name;
+        }
+
+        if ($stream->test(Twig_Token::NAME_TYPE)) {
             // try 2-words tests
             $name = $name.' '.$parser->getCurrentToken()->getValue();
 
             if (isset($testMap[$name])) {
                 $parser->getStream()->next();
 
-                $testName = $name;
+                return $name;
             }
         }
 
-        if (null === $testName) {
-            $message = sprintf('The test "%s" does not exist', $name);
-            if ($alternatives = $env->computeAlternatives($name, 
array_keys($env->getTests()))) {
-                $message = sprintf('%s. Did you mean "%s"', $message, 
implode('", "', $alternatives));
-            }
-
-            throw new Twig_Error_Syntax($message, $line, 
$parser->getFilename());
+        $message = sprintf('The test "%s" does not exist', $name);
+        if ($alternatives = $env->computeAlternatives($name, 
array_keys($testMap))) {
+            $message = sprintf('%s. Did you mean "%s"', $message, implode('", 
"', $alternatives));
         }
+
+        throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
+    }
+
+    protected function getTestNodeClass(Twig_Parser $parser, $name)
+    {
+        $env = $parser->getEnvironment();
+        $testMap = $env->getTests();
 
         if ($testMap[$name] instanceof Twig_SimpleTest) {
             return $testMap[$name]->getNodeClass();
@@ -436,10 +444,10 @@
  *   {{ post.published_at|date("m/d/Y") }}
  * </pre>
  *
- * @param Twig_Environment             $env      A Twig_Environment instance
- * @param DateTime|DateInterval|string $date     A date
- * @param string                       $format   A format
- * @param DateTimeZone|string          $timezone A timezone
+ * @param Twig_Environment                               $env      A 
Twig_Environment instance
+ * @param DateTime|DateTimeInterface|DateInterval|string $date     A date
+ * @param string|null                                    $format   The target 
format, null to use the default
+ * @param DateTimeZone|string|null|false                 $timezone The target 
timezone, null to use the default, false to leave unchanged
  *
  * @return string The formatted date
  */
@@ -473,9 +481,12 @@
 function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
 {
     $date = twig_date_converter($env, $date, false);
-    $date->modify($modifier);
+    $resultDate = $date->modify($modifier);
 
-    return $date;
+    // This is a hack to ensure PHP 5.2 support and support for 
DateTimeImmutable
+    // DateTime::modify does not return the modified DateTime object < 5.3.0
+    // and DateTimeImmutable does not modify $date.
+    return null === $resultDate ? $date : $resultDate;
 }
 
 /**
@@ -487,32 +498,32 @@
  *    {% endif %}
  * </pre>
  *
- * @param Twig_Environment    $env      A Twig_Environment instance
- * @param DateTime|string     $date     A date
- * @param DateTimeZone|string $timezone A timezone
+ * @param Twig_Environment                       $env      A Twig_Environment 
instance
+ * @param DateTime|DateTimeInterface|string|null $date     A date
+ * @param DateTimeZone|string|null|false         $timezone The target 
timezone, null to use the default, false to leave unchanged
  *
  * @return DateTime A DateTime instance
  */
 function twig_date_converter(Twig_Environment $env, $date = null, $timezone = 
null)
 {
     // determine the timezone
-    if (!$timezone) {
-        $defaultTimezone = $env->getExtension('core')->getTimezone();
-    } elseif (!$timezone instanceof DateTimeZone) {
-        $defaultTimezone = new DateTimeZone($timezone);
-    } else {
-        $defaultTimezone = $timezone;
+    if (false !== $timezone) {
+        if (null === $timezone) {
+            $timezone = $env->getExtension('core')->getTimezone();
+        } elseif (!$timezone instanceof DateTimeZone) {
+            $timezone = new DateTimeZone($timezone);
+        }
     }
 
     // immutable dates
     if ($date instanceof DateTimeImmutable) {
-        return false !== $timezone ? $date->setTimezone($defaultTimezone) : 
$date;
+        return false !== $timezone ? $date->setTimezone($timezone) : $date;
     }
 
     if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
         $date = clone $date;
         if (false !== $timezone) {
-            $date->setTimezone($defaultTimezone);
+            $date->setTimezone($timezone);
         }
 
         return $date;
@@ -523,9 +534,9 @@
         $date = '@'.$date;
     }
 
-    $date = new DateTime($date, $defaultTimezone);
+    $date = new DateTime($date, $env->getExtension('core')->getTimezone());
     if (false !== $timezone) {
-        $date->setTimezone($defaultTimezone);
+        $date->setTimezone($timezone);
     }
 
     return $date;
@@ -672,7 +683,7 @@
 function twig_array_merge($arr1, $arr2)
 {
     if (!is_array($arr1) || !is_array($arr2)) {
-        throw new Twig_Error_Runtime('The merge filter only works with arrays 
or hashes.');
+        throw new Twig_Error_Runtime(sprintf('The merge filter only works with 
arrays or hashes; %s and %s given.', gettype($arr1), gettype($arr2)));
     }
 
     return array_merge($arr1, $arr2);
@@ -692,7 +703,15 @@
 function twig_slice(Twig_Environment $env, $item, $start, $length = null, 
$preserveKeys = false)
 {
     if ($item instanceof Traversable) {
-        $item = iterator_to_array($item, false);
+        if ($item instanceof IteratorAggregate) {
+            $item = $item->getIterator();
+        }
+
+        if ($start >= 0 && $length >= 0) {
+            return iterator_to_array(new LimitIterator($item, $start, $length 
=== null ? -1 : $length), $preserveKeys);
+        }
+
+        $item = iterator_to_array($item, $preserveKeys);
     }
 
     if (is_array($item)) {
@@ -702,10 +721,10 @@
     $item = (string) $item;
 
     if (function_exists('mb_get_info') && null !== $charset = 
$env->getCharset()) {
-        return mb_substr($item, $start, null === $length ? mb_strlen($item, 
$charset) - $start : $length, $charset);
+        return (string) mb_substr($item, $start, null === $length ? 
mb_strlen($item, $charset) - $start : $length, $charset);
     }
 
-    return null === $length ? substr($item, $start) : substr($item, $start, 
$length);
+    return (string) (null === $length ? substr($item, $start) : substr($item, 
$start, $length));
 }
 
 /**
@@ -788,13 +807,31 @@
  *
  * @return array The split string as an array
  */
-function twig_split_filter($value, $delimiter, $limit = null)
+function twig_split_filter(Twig_Environment $env, $value, $delimiter, $limit = 
null)
 {
-    if (empty($delimiter)) {
+    if (!empty($delimiter)) {
+        return null === $limit ? explode($delimiter, $value) : 
explode($delimiter, $value, $limit);
+    }
+
+    if (!function_exists('mb_get_info') || null === $charset = 
$env->getCharset()) {
         return str_split($value, null === $limit ? 1 : $limit);
     }
 
-    return null === $limit ? explode($delimiter, $value) : explode($delimiter, 
$value, $limit);
+    if ($limit <= 1) {
+        return preg_split('/(?<!^)(?!$)/u', $value);
+    }
+
+    $length = mb_strlen($value, $charset);
+    if ($length < $limit) {
+        return array($value);
+    }
+
+    $r = array();
+    for ($i = 0; $i < $length; $i += $limit) {
+        $r[] = mb_substr($value, $i, $limit, $charset);
+    }
+
+    return $r;
 }
 
 // The '_default' filter is used internally to avoid using the ternary operator
@@ -944,7 +981,7 @@
             static $htmlspecialcharsCharsets;
 
             if (null === $htmlspecialcharsCharsets) {
-                if ('hiphop' === substr(PHP_VERSION, -6)) {
+                if (defined('HHVM_VERSION')) {
                     $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' 
=> true);
                 } else {
                     $htmlspecialcharsCharsets = array(
diff --git a/twig/twig/lib/Twig/Loader/Array.php 
b/twig/twig/lib/Twig/Loader/Array.php
index ac56104..436edd8 100644
--- a/twig/twig/lib/Twig/Loader/Array.php
+++ b/twig/twig/lib/Twig/Loader/Array.php
@@ -17,6 +17,8 @@
  * source code of the template). If you don't want to see your cache grows out 
of
  * control, you need to take care of clearing the old cache file by yourself.
  *
+ * This loader should only be used for unit testing.
+ *
  * @author Fabien Potencier <[email protected]>
  */
 class Twig_Loader_Array implements Twig_LoaderInterface, 
Twig_ExistsLoaderInterface
diff --git a/twig/twig/lib/Twig/Loader/String.php 
b/twig/twig/lib/Twig/Loader/String.php
index 8ad9856..2099c09 100644
--- a/twig/twig/lib/Twig/Loader/String.php
+++ b/twig/twig/lib/Twig/Loader/String.php
@@ -12,9 +12,7 @@
 /**
  * Loads a template from a string.
  *
- * This loader should only be used for unit testing as it has many limitations
- * (for instance, the include or extends tag does not make any sense for a 
string
- * loader).
+ * This loader should NEVER be used. It only exists for Twig internal purposes.
  *
  * When using this loader with a cache mechanism, you should know that a new 
cache
  * key is generated each time a template content "changes" (the cache key 
being the
diff --git a/twig/twig/lib/Twig/Node.php b/twig/twig/lib/Twig/Node.php
index 978e766..20af544 100644
--- a/twig/twig/lib/Twig/Node.php
+++ b/twig/twig/lib/Twig/Node.php
@@ -69,6 +69,9 @@
         return implode("\n", $repr);
     }
 
+    /**
+     * @deprecated since 1.16.1 (to be removed in 2.0)
+     */
     public function toXml($asDom = false)
     {
         $dom = new DOMDocument('1.0', 'UTF-8');
diff --git a/twig/twig/lib/Twig/Node/AutoEscape.php 
b/twig/twig/lib/Twig/Node/AutoEscape.php
index 8f190e0..fcabf90 100644
--- a/twig/twig/lib/Twig/Node/AutoEscape.php
+++ b/twig/twig/lib/Twig/Node/AutoEscape.php
@@ -30,7 +30,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Block.php 
b/twig/twig/lib/Twig/Node/Block.php
index 50eb67e..989e4a0 100644
--- a/twig/twig/lib/Twig/Node/Block.php
+++ b/twig/twig/lib/Twig/Node/Block.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/BlockReference.php 
b/twig/twig/lib/Twig/Node/BlockReference.php
index 013e369..a05ea04 100644
--- a/twig/twig/lib/Twig/Node/BlockReference.php
+++ b/twig/twig/lib/Twig/Node/BlockReference.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Do.php b/twig/twig/lib/Twig/Node/Do.php
index c528066..9981bc1 100644
--- a/twig/twig/lib/Twig/Node/Do.php
+++ b/twig/twig/lib/Twig/Node/Do.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Array.php 
b/twig/twig/lib/Twig/Node/Expression/Array.php
index 1da785f..6cf7ca1 100644
--- a/twig/twig/lib/Twig/Node/Expression/Array.php
+++ b/twig/twig/lib/Twig/Node/Expression/Array.php
@@ -63,7 +63,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/AssignName.php 
b/twig/twig/lib/Twig/Node/Expression/AssignName.php
index 2ddea78..4d5dbdb 100644
--- a/twig/twig/lib/Twig/Node/Expression/AssignName.php
+++ b/twig/twig/lib/Twig/Node/Expression/AssignName.php
@@ -15,7 +15,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary.php 
b/twig/twig/lib/Twig/Node/Expression/Binary.php
index 9dd5de2..5c383d1 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary.php
@@ -19,7 +19,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php
index 5de6c72..93b3b96 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php
@@ -12,14 +12,14 @@
 {
     public function compile(Twig_Compiler $compiler)
     {
+        $left = $compiler->getVarName();
+        $right = $compiler->getVarName();
         $compiler
-            ->raw('(0 === substr_compare(')
+            ->raw(sprintf('(is_string($%s = ', $left))
             ->subcompile($this->getNode('left'))
-            ->raw(', ')
+            ->raw(sprintf(') && is_string($%s = ', $right))
             ->subcompile($this->getNode('right'))
-            ->raw(', -strlen(')
-            ->subcompile($this->getNode('right'))
-            ->raw(')))')
+            ->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, 
-strlen($%2$s))))', $left, $right))
         ;
     }
 
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
index 7fbd055..d3518b5 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
@@ -13,7 +13,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/In.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/In.php
index 788f937..1d485b6 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/In.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/In.php
@@ -13,7 +13,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
index f347b7b..8f215f1 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
@@ -13,7 +13,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/Power.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/Power.php
index b2c5904..6cd3a21 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/Power.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/Power.php
@@ -13,7 +13,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/Range.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/Range.php
index bea4f2a..fc102fe 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/Range.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/Range.php
@@ -13,7 +13,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php 
b/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php
index eb8c107..d2e30d6 100644
--- a/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php
+++ b/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php
@@ -12,12 +12,14 @@
 {
     public function compile(Twig_Compiler $compiler)
     {
+        $left = $compiler->getVarName();
+        $right = $compiler->getVarName();
         $compiler
-            ->raw('(0 === strpos(')
+            ->raw(sprintf('(is_string($%s = ', $left))
             ->subcompile($this->getNode('left'))
-            ->raw(', ')
+            ->raw(sprintf(') && is_string($%s = ', $right))
             ->subcompile($this->getNode('right'))
-            ->raw('))')
+            ->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, 
$%2$s)))', $left, $right))
         ;
     }
 
diff --git a/twig/twig/lib/Twig/Node/Expression/BlockReference.php 
b/twig/twig/lib/Twig/Node/Expression/BlockReference.php
index 647196e..4ddb2cf 100644
--- a/twig/twig/lib/Twig/Node/Expression/BlockReference.php
+++ b/twig/twig/lib/Twig/Node/Expression/BlockReference.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php 
b/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
index 00ac670..db06abb 100644
--- a/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
+++ b/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Expression/GetAttr.php 
b/twig/twig/lib/Twig/Node/Expression/GetAttr.php
index 55d9fcc..6ce6111 100644
--- a/twig/twig/lib/Twig/Node/Expression/GetAttr.php
+++ b/twig/twig/lib/Twig/Node/Expression/GetAttr.php
@@ -11,7 +11,7 @@
  */
 class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
 {
-    public function __construct(Twig_Node_Expression $node, 
Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, 
$lineno)
+    public function __construct(Twig_Node_Expression $node, 
Twig_Node_Expression $attribute, Twig_Node_Expression $arguments = null, $type, 
$lineno)
     {
         parent::__construct(array('node' => $node, 'attribute' => $attribute, 
'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 
'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
     }
@@ -32,20 +32,30 @@
 
         $compiler->raw(', ')->subcompile($this->getNode('attribute'));
 
-        if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== 
$this->getAttribute('type') || $this->getAttribute('is_defined_test') || 
$this->getAttribute('ignore_strict_check')) {
-            $compiler->raw(', ')->subcompile($this->getNode('arguments'));
+        // only generate optional arguments when needed (to make generated 
code more readable)
+        $needFourth = $this->getAttribute('ignore_strict_check');
+        $needThird = $needFourth || $this->getAttribute('is_defined_test');
+        $needSecond = $needThird || Twig_Template::ANY_CALL !== 
$this->getAttribute('type');
+        $needFirst = $needSecond || null !== $this->getNode('arguments');
 
-            if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || 
$this->getAttribute('is_defined_test') || 
$this->getAttribute('ignore_strict_check')) {
-                $compiler->raw(', ')->repr($this->getAttribute('type'));
+        if ($needFirst) {
+            if (null !== $this->getNode('arguments')) {
+                $compiler->raw(', ')->subcompile($this->getNode('arguments'));
+            } else {
+                $compiler->raw(', array()');
             }
+        }
 
-            if ($this->getAttribute('is_defined_test') || 
$this->getAttribute('ignore_strict_check')) {
-                $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 
'true' : 'false'));
-            }
+        if ($needSecond) {
+            $compiler->raw(', ')->repr($this->getAttribute('type'));
+        }
 
-            if ($this->getAttribute('ignore_strict_check')) {
-                $compiler->raw(', 
'.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
-            }
+        if ($needThird) {
+            $compiler->raw(', ')->repr($this->getAttribute('is_defined_test'));
+        }
+
+        if ($needFourth) {
+            $compiler->raw(', 
')->repr($this->getAttribute('ignore_strict_check'));
         }
 
         $compiler->raw(')');
diff --git a/twig/twig/lib/Twig/Node/Expression/Parent.php 
b/twig/twig/lib/Twig/Node/Expression/Parent.php
index dcf618c..a22ce03 100644
--- a/twig/twig/lib/Twig/Node/Expression/Parent.php
+++ b/twig/twig/lib/Twig/Node/Expression/Parent.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Flush.php 
b/twig/twig/lib/Twig/Node/Flush.php
index 0467ddc..20d6aab 100644
--- a/twig/twig/lib/Twig/Node/Flush.php
+++ b/twig/twig/lib/Twig/Node/Flush.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/For.php b/twig/twig/lib/Twig/Node/For.php
index d1ff371..c54a23c 100644
--- a/twig/twig/lib/Twig/Node/For.php
+++ b/twig/twig/lib/Twig/Node/For.php
@@ -33,7 +33,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/ForLoop.php 
b/twig/twig/lib/Twig/Node/ForLoop.php
index b884158..d330283 100644
--- a/twig/twig/lib/Twig/Node/ForLoop.php
+++ b/twig/twig/lib/Twig/Node/ForLoop.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/If.php b/twig/twig/lib/Twig/Node/If.php
index b42d107..980274e 100644
--- a/twig/twig/lib/Twig/Node/If.php
+++ b/twig/twig/lib/Twig/Node/If.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Import.php 
b/twig/twig/lib/Twig/Node/Import.php
index 99efc09..2306655 100644
--- a/twig/twig/lib/Twig/Node/Import.php
+++ b/twig/twig/lib/Twig/Node/Import.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Include.php 
b/twig/twig/lib/Twig/Node/Include.php
index 860aedf..0654888 100644
--- a/twig/twig/lib/Twig/Node/Include.php
+++ b/twig/twig/lib/Twig/Node/Include.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
@@ -60,40 +60,26 @@
 
     protected function addGetTemplate(Twig_Compiler $compiler)
     {
-        if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
-            $compiler
-                ->write("\$this->env->loadTemplate(")
-                ->subcompile($this->getNode('expr'))
-                ->raw(")")
-            ;
-        } else {
-            $compiler
-                ->write("\$template = \$this->env->resolveTemplate(")
-                ->subcompile($this->getNode('expr'))
-                ->raw(");\n")
-                ->write('$template')
-            ;
-        }
+        $method = $this->getNode('expr') instanceof 
Twig_Node_Expression_Constant ? 'loadTemplate' : 'resolveTemplate';
+        $compiler
+            ->write(sprintf('$this->env->%s(', $method))
+            ->subcompile($this->getNode('expr'))
+            ->raw(')')
+        ;
     }
 
     protected function addTemplateArguments(Twig_Compiler $compiler)
     {
-        if (false === $this->getAttribute('only')) {
-            if (null === $this->getNode('variables')) {
-                $compiler->raw('$context');
-            } else {
-                $compiler
-                    ->raw('array_merge($context, ')
-                    ->subcompile($this->getNode('variables'))
-                    ->raw(')')
-                ;
-            }
+        if (null === $this->getNode('variables')) {
+            $compiler->raw(false === $this->getAttribute('only') ? '$context' 
: 'array()');
+        } elseif (false === $this->getAttribute('only')) {
+            $compiler
+                ->raw('array_merge($context, ')
+                ->subcompile($this->getNode('variables'))
+                ->raw(')')
+            ;
         } else {
-            if (null === $this->getNode('variables')) {
-                $compiler->raw('array()');
-            } else {
-                $compiler->subcompile($this->getNode('variables'));
-            }
+            $compiler->subcompile($this->getNode('variables'));
         }
     }
 }
diff --git a/twig/twig/lib/Twig/Node/Macro.php 
b/twig/twig/lib/Twig/Node/Macro.php
index 8991061..ab7e8d2 100644
--- a/twig/twig/lib/Twig/Node/Macro.php
+++ b/twig/twig/lib/Twig/Node/Macro.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
@@ -37,7 +37,7 @@
         $pos = 0;
         foreach ($this->getNode('arguments') as $name => $default) {
             $compiler
-                ->raw('$_'.$name.' = ')
+                ->raw('$__'.$name.'__ = ')
                 ->subcompile($default)
             ;
 
@@ -64,7 +64,7 @@
                 $compiler
                     ->write('')
                     ->string($name)
-                    ->raw(' => $_'.$name)
+                    ->raw(' => $__'.$name.'__')
                     ->raw(",\n")
                 ;
             }
diff --git a/twig/twig/lib/Twig/Node/Module.php 
b/twig/twig/lib/Twig/Node/Module.php
index 3f80175..9f66b28 100644
--- a/twig/twig/lib/Twig/Node/Module.php
+++ b/twig/twig/lib/Twig/Node/Module.php
@@ -31,7 +31,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Print.php 
b/twig/twig/lib/Twig/Node/Print.php
index b0c41d1..4263536 100644
--- a/twig/twig/lib/Twig/Node/Print.php
+++ b/twig/twig/lib/Twig/Node/Print.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Sandbox.php 
b/twig/twig/lib/Twig/Node/Sandbox.php
index 8cf3ed4..8ca772b 100644
--- a/twig/twig/lib/Twig/Node/Sandbox.php
+++ b/twig/twig/lib/Twig/Node/Sandbox.php
@@ -24,7 +24,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/SandboxedModule.php 
b/twig/twig/lib/Twig/Node/SandboxedModule.php
index 0de4503..410332c 100644
--- a/twig/twig/lib/Twig/Node/SandboxedModule.php
+++ b/twig/twig/lib/Twig/Node/SandboxedModule.php
@@ -43,17 +43,53 @@
     {
         parent::compileDisplayFooter($compiler);
 
+        $tags = $filters = $functions = array();
+        foreach (array('tags', 'filters', 'functions') as $type) {
+            foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
+                if ($node instanceof Twig_Node) {
+                    ${$type}[$name] = $node->getLine();
+                } else {
+                    ${$type}[$node] = null;
+                }
+            }
+        }
+
         $compiler
             ->write("protected function checkSecurity()\n", "{\n")
             ->indent()
+            ->write("\$tags = ")->repr(array_filter($tags))->raw(";\n")
+            ->write("\$filters = ")->repr(array_filter($filters))->raw(";\n")
+            ->write("\$functions = 
")->repr(array_filter($functions))->raw(";\n\n")
+            ->write("try {\n")
+            ->indent()
             ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
             ->indent()
-            ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', 
\'', $this->usedTags)."'),\n")
-            ->write(!$this->usedFilters ? "array(),\n" : 
"array('".implode('\', \'', $this->usedFilters)."'),\n")
-            ->write(!$this->usedFunctions ? "array()\n" : 
"array('".implode('\', \'', $this->usedFunctions)."')\n")
+            ->write(!$tags ? "array(),\n" : "array('".implode("', '", 
array_keys($tags))."'),\n")
+            ->write(!$filters ? "array(),\n" : "array('".implode("', '", 
array_keys($filters))."'),\n")
+            ->write(!$functions ? "array()\n" : "array('".implode("', '", 
array_keys($functions))."')\n")
             ->outdent()
             ->write(");\n")
             ->outdent()
+            ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
+            ->indent()
+            ->write("\$e->setTemplateFile(\$this->getTemplateName());\n\n")
+            ->write("if (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) 
{\n")
+            ->indent()
+            ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
+            ->outdent()
+            ->write("} elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFilterError && 
isset(\$filters[\$e->getFilterName()])) {\n")
+            ->indent()
+            ->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
+            ->outdent()
+            ->write("} elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFunctionError && 
isset(\$functions[\$e->getFunctionName()])) {\n")
+            ->indent()
+            
->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n")
+            ->outdent()
+            ->write("}\n\n")
+            ->write("throw \$e;\n")
+            ->outdent()
+            ->write("}\n")
+            ->outdent()
             ->write("}\n\n")
         ;
     }
diff --git a/twig/twig/lib/Twig/Node/SandboxedPrint.php 
b/twig/twig/lib/Twig/Node/SandboxedPrint.php
index 73dfaa9..91872cc 100644
--- a/twig/twig/lib/Twig/Node/SandboxedPrint.php
+++ b/twig/twig/lib/Twig/Node/SandboxedPrint.php
@@ -29,7 +29,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Set.php b/twig/twig/lib/Twig/Node/Set.php
index 4c9c16c..407d147 100644
--- a/twig/twig/lib/Twig/Node/Set.php
+++ b/twig/twig/lib/Twig/Node/Set.php
@@ -39,7 +39,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Spaceless.php 
b/twig/twig/lib/Twig/Node/Spaceless.php
index 7555fa0..1478c59 100644
--- a/twig/twig/lib/Twig/Node/Spaceless.php
+++ b/twig/twig/lib/Twig/Node/Spaceless.php
@@ -26,7 +26,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/Node/Text.php b/twig/twig/lib/Twig/Node/Text.php
index 21bdcea..6863604 100644
--- a/twig/twig/lib/Twig/Node/Text.php
+++ b/twig/twig/lib/Twig/Node/Text.php
@@ -25,7 +25,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler)
     {
diff --git a/twig/twig/lib/Twig/NodeInterface.php 
b/twig/twig/lib/Twig/NodeInterface.php
index 43afd0d..8077349 100644
--- a/twig/twig/lib/Twig/NodeInterface.php
+++ b/twig/twig/lib/Twig/NodeInterface.php
@@ -21,7 +21,7 @@
     /**
      * Compiles the node to PHP.
      *
-     * @param Twig_Compiler A Twig_Compiler instance
+     * @param Twig_Compiler $compiler A Twig_Compiler instance
      */
     public function compile(Twig_Compiler $compiler);
 
diff --git a/twig/twig/lib/Twig/NodeVisitor/Optimizer.php 
b/twig/twig/lib/Twig/NodeVisitor/Optimizer.php
index 06f69db..3cc3312 100644
--- a/twig/twig/lib/Twig/NodeVisitor/Optimizer.php
+++ b/twig/twig/lib/Twig/NodeVisitor/Optimizer.php
@@ -28,6 +28,7 @@
     const OPTIMIZE_VAR_ACCESS  = 8;
 
     protected $loops = array();
+    protected $loopsTargets = array();
     protected $optimizers;
     protected $prependedNodes = array();
     protected $inABody = false;
@@ -174,6 +175,8 @@
             // disable the loop variable by default
             $node->setAttribute('with_loop', false);
             array_unshift($this->loops, $node);
+            array_unshift($this->loopsTargets, 
$node->getNode('value_target')->getAttribute('name'));
+            array_unshift($this->loopsTargets, 
$node->getNode('key_target')->getAttribute('name'));
         } elseif (!$this->loops) {
             // we are outside a loop
             return;
@@ -183,7 +186,13 @@
 
         // the loop variable is referenced for the current loop
         elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === 
$node->getAttribute('name')) {
+            $node->setAttribute('always_defined', true);
             $this->addLoopToCurrent();
+        }
+
+        // optimize access to loop targets
+        elseif ($node instanceof Twig_Node_Expression_Name && 
in_array($node->getAttribute('name'), $this->loopsTargets)) {
+            $node->setAttribute('always_defined', true);
         }
 
         // block reference
@@ -221,6 +230,8 @@
     {
         if ($node instanceof Twig_Node_For) {
             array_shift($this->loops);
+            array_shift($this->loopsTargets);
+            array_shift($this->loopsTargets);
         }
     }
 
diff --git a/twig/twig/lib/Twig/NodeVisitor/Sandbox.php 
b/twig/twig/lib/Twig/NodeVisitor/Sandbox.php
index fb27045..e5e3ff6 100644
--- a/twig/twig/lib/Twig/NodeVisitor/Sandbox.php
+++ b/twig/twig/lib/Twig/NodeVisitor/Sandbox.php
@@ -40,18 +40,18 @@
             return $node;
         } elseif ($this->inAModule) {
             // look for tags
-            if ($node->getNodeTag()) {
-                $this->tags[] = $node->getNodeTag();
+            if ($node->getNodeTag() && 
!isset($this->tags[$node->getNodeTag()])) {
+                $this->tags[$node->getNodeTag()] = $node;
             }
 
             // look for filters
-            if ($node instanceof Twig_Node_Expression_Filter) {
-                $this->filters[] = 
$node->getNode('filter')->getAttribute('value');
+            if ($node instanceof Twig_Node_Expression_Filter && 
!isset($this->filters[$node->getNode('filter')->getAttribute('value')])) {
+                
$this->filters[$node->getNode('filter')->getAttribute('value')] = $node;
             }
 
             // look for functions
-            if ($node instanceof Twig_Node_Expression_Function) {
-                $this->functions[] = $node->getAttribute('name');
+            if ($node instanceof Twig_Node_Expression_Function && 
!isset($this->functions[$node->getAttribute('name')])) {
+                $this->functions[$node->getAttribute('name')] = $node;
             }
 
             // wrap print to check __toString() calls
@@ -76,7 +76,7 @@
         if ($node instanceof Twig_Node_Module) {
             $this->inAModule = false;
 
-            return new Twig_Node_SandboxedModule($node, 
array_unique($this->filters), array_unique($this->tags), 
array_unique($this->functions));
+            return new Twig_Node_SandboxedModule($node, $this->filters, 
$this->tags, $this->functions);
         }
 
         return $node;
diff --git a/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php 
b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php
new file mode 100644
index 0000000..99faba9
--- /dev/null
+++ b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2009 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Exception thrown when a not allowed filter is used in a template.
+ *
+ * @author Martin Hasoň <[email protected]>
+ */
+class Twig_Sandbox_SecurityNotAllowedFilterError extends 
Twig_Sandbox_SecurityError
+{
+    private $filterName;
+
+    public function __construct($message, $functionName, $lineno = -1, 
$filename = null, Exception $previous = null)
+    {
+        parent::__construct($message, $lineno, $filename, $previous);
+        $this->filterName = $functionName;
+    }
+
+    public function getFilterName()
+    {
+        return $this->filterName;
+    }
+}
diff --git a/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php 
b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php
new file mode 100644
index 0000000..05cf488
--- /dev/null
+++ b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2009 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Exception thrown when a not allowed function is used in a template.
+ *
+ * @author Martin Hasoň <[email protected]>
+ */
+class Twig_Sandbox_SecurityNotAllowedFunctionError extends 
Twig_Sandbox_SecurityError
+{
+    private $functionName;
+
+    public function __construct($message, $functionName, $lineno = -1, 
$filename = null, Exception $previous = null)
+    {
+        parent::__construct($message, $lineno, $filename, $previous);
+        $this->functionName = $functionName;
+    }
+
+    public function getFunctionName()
+    {
+        return $this->functionName;
+    }
+}
diff --git a/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php 
b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php
new file mode 100644
index 0000000..b3bb5e8
--- /dev/null
+++ b/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2009 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Exception thrown when a not allowed tag is used in a template.
+ *
+ * @author Martin Hasoň <[email protected]>
+ */
+class Twig_Sandbox_SecurityNotAllowedTagError extends 
Twig_Sandbox_SecurityError
+{
+    private $tagName;
+
+    public function __construct($message, $tagName, $lineno = -1, $filename = 
null, Exception $previous = null)
+    {
+        parent::__construct($message, $lineno, $filename, $previous);
+        $this->tagName = $tagName;
+    }
+
+    public function getTagName()
+    {
+        return $this->tagName;
+    }
+}
diff --git a/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php 
b/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
index 66ee233..c4dd03d 100644
--- a/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
+++ b/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
@@ -63,19 +63,19 @@
     {
         foreach ($tags as $tag) {
             if (!in_array($tag, $this->allowedTags)) {
-                throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not 
allowed.', $tag));
+                throw new Twig_Sandbox_SecurityNotAllowedTagError(sprintf('Tag 
"%s" is not allowed.', $tag), $tag);
             }
         }
 
         foreach ($filters as $filter) {
             if (!in_array($filter, $this->allowedFilters)) {
-                throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is 
not allowed.', $filter));
+                throw new 
Twig_Sandbox_SecurityNotAllowedFilterError(sprintf('Filter "%s" is not 
allowed.', $filter), $filter);
             }
         }
 
         foreach ($functions as $function) {
             if (!in_array($function, $this->allowedFunctions)) {
-                throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is 
not allowed.', $function));
+                throw new 
Twig_Sandbox_SecurityNotAllowedFunctionError(sprintf('Function "%s" is not 
allowed.', $function), $function);
             }
         }
     }
diff --git a/twig/twig/lib/Twig/Template.php b/twig/twig/lib/Twig/Template.php
index 1e23e8b..63910da 100644
--- a/twig/twig/lib/Twig/Template.php
+++ b/twig/twig/lib/Twig/Template.php
@@ -379,7 +379,11 @@
                 } elseif (is_object($object)) {
                     $message = sprintf('Impossible to access a key "%s" on an 
object of class "%s" that does not implement ArrayAccess interface', $item, 
get_class($object));
                 } elseif (is_array($object)) {
-                    $message = sprintf('Key "%s" for array with keys "%s" does 
not exist', $arrayItem, implode(', ', array_keys($object)));
+                    if (empty($object)) {
+                        $message = sprintf('Key "%s" does not exist as the 
array is empty', $arrayItem);
+                    } else {
+                        $message = sprintf('Key "%s" for array with keys "%s" 
does not exist', $arrayItem, implode(', ', array_keys($object)));
+                    }
                 } elseif (Twig_Template::ARRAY_CALL === $type) {
                     $message = sprintf('Impossible to access a key ("%s") on a 
%s variable ("%s")', $item, gettype($object), $object);
                 } else {
diff --git a/twig/twig/test/Twig/Tests/EnvironmentTest.php 
b/twig/twig/test/Twig/Tests/EnvironmentTest.php
index a5fc878..b791e57 100644
--- a/twig/twig/test/Twig/Tests/EnvironmentTest.php
+++ b/twig/twig/test/Twig/Tests/EnvironmentTest.php
@@ -48,7 +48,7 @@
         // globals can be added after calling getGlobals
         $twig = new Twig_Environment(new Twig_Loader_String());
         $twig->addGlobal('foo', 'foo');
-        $globals = $twig->getGlobals();
+        $twig->getGlobals();
         $twig->addGlobal('foo', 'bar');
         $globals = $twig->getGlobals();
         $this->assertEquals('bar', $globals['foo']);
@@ -65,7 +65,7 @@
         // globals can be modified after extensions init
         $twig = new Twig_Environment(new Twig_Loader_String());
         $twig->addGlobal('foo', 'foo');
-        $globals = $twig->getGlobals();
+        $twig->getGlobals();
         $twig->getFunctions();
         $twig->addGlobal('foo', 'bar');
         $globals = $twig->getGlobals();
@@ -74,7 +74,7 @@
         // globals can be modified after extensions and runtime init
         $twig = new Twig_Environment(new Twig_Loader_String());
         $twig->addGlobal('foo', 'foo');
-        $globals = $twig->getGlobals();
+        $twig->getGlobals();
         $twig->getFunctions();
         $twig->initRuntime();
         $twig->addGlobal('foo', 'bar');
diff --git a/twig/twig/test/Twig/Tests/Extension/CoreTest.php 
b/twig/twig/test/Twig/Tests/Extension/CoreTest.php
index 5f3da18..b3b1cb0 100644
--- a/twig/twig/test/Twig/Tests/Extension/CoreTest.php
+++ b/twig/twig/test/Twig/Tests/Extension/CoreTest.php
@@ -130,6 +130,24 @@
     {
         twig_escape_filter(new Twig_Environment(), 'foo', 'bar');
     }
+
+    public function testTwigFirst()
+    {
+        $twig = new Twig_Environment();
+        $this->assertEquals('a', twig_first($twig, 'abc'));
+        $this->assertEquals(1, twig_first($twig, array(1, 2, 3)));
+        $this->assertSame('', twig_first($twig, null));
+        $this->assertSame('', twig_first($twig, ''));
+    }
+
+    public function testTwigLast()
+    {
+        $twig = new Twig_Environment();
+        $this->assertEquals('c', twig_last($twig, 'abc'));
+        $this->assertEquals(3, twig_last($twig, array(1, 2, 3)));
+        $this->assertSame('', twig_last($twig, null));
+        $this->assertSame('', twig_last($twig, ''));
+    }
 }
 
 function foo_escaper_for_test(Twig_Environment $env, $string, $charset)
diff --git a/twig/twig/test/Twig/Tests/Extension/SandboxTest.php 
b/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
index 1022338..fee35a0 100644
--- a/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
+++ b/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
@@ -33,13 +33,13 @@
             '1_basic9' => '{{ obj.foobar }}{{ obj.fooBar }}',
             '1_basic'  => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
             '1_layout' => '{% block content %}{% endblock %}',
-            '1_child'  => '{% extends "1_layout" %}{% block content %}{{ 
"a"|json_encode }}{% endblock %}',
+            '1_child'  => "{% extends \"1_layout\" %}\n{% block content %}\n{{ 
\"a\"|json_encode }}\n{% endblock %}",
         );
     }
 
     /**
      * @expectedException        Twig_Sandbox_SecurityError
-     * @expectedExceptionMessage Filter "json_encode" is not allowed in 
"1_child".
+     * @expectedExceptionMessage Filter "json_encode" is not allowed in 
"1_child" at line 3.
      */
     public function testSandboxWithInheritance()
     {
diff --git a/twig/twig/test/Twig/Tests/FileCachingTest.php 
b/twig/twig/test/Twig/Tests/FileCachingTest.php
index 8efc948..36cdd33 100644
--- a/twig/twig/test/Twig/Tests/FileCachingTest.php
+++ b/twig/twig/test/Twig/Tests/FileCachingTest.php
@@ -32,7 +32,7 @@
     public function testWritingCacheFiles()
     {
         $name = 'This is just text.';
-        $template = $this->env->loadTemplate($name);
+        $this->env->loadTemplate($name);
         $cacheFileName = $this->env->getCacheFilename($name);
 
         $this->assertTrue(file_exists($cacheFileName), 'Cache file does not 
exist.');
@@ -42,7 +42,7 @@
     public function testClearingCacheFiles()
     {
         $name = 'I will be deleted.';
-        $template = $this->env->loadTemplate($name);
+        $this->env->loadTemplate($name);
         $cacheFileName = $this->env->getCacheFilename($name);
 
         $this->assertTrue(file_exists($cacheFileName), 'Cache file does not 
exist.');
diff --git a/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test 
b/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test
index 026bd52..6679fbe 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test
@@ -6,4 +6,4 @@
 {% block bar %}
 {% endblock %}
 --EXCEPTION--
-Twig_Error_Runtime: Block "foobar" is not defined in trait "foo" in 
"index.twig".
+Twig_Error_Runtime: Block "foobar" is not defined in trait "foo" in 
"index.twig" at line 2.
diff --git a/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test 
b/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test
index d259d11..9ad5e5e 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test
@@ -4,9 +4,23 @@
 {{ 'foo' ends with 'o' ? 'OK' : 'KO' }}
 {{ not ('foo' ends with 'f') ? 'OK' : 'KO' }}
 {{ not ('foo' ends with 'foowaytoolong') ? 'OK' : 'KO' }}
+{{ 'foo' ends with '' ? 'OK' : 'KO' }}
+{{ '1' ends with true ? 'OK' : 'KO' }}
+{{ 1 ends with true ? 'OK' : 'KO' }}
+{{ 0 ends with false ? 'OK' : 'KO' }}
+{{ '' ends with false ? 'OK' : 'KO' }}
+{{ false ends with false ? 'OK' : 'KO' }}
+{{ false ends with '' ? 'OK' : 'KO' }}
 --DATA--
 return array()
 --EXPECT--
 OK
 OK
 OK
+OK
+KO
+KO
+KO
+KO
+KO
+KO
diff --git a/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test 
b/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test
index 1ae4f86..75d331e 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test
@@ -7,6 +7,11 @@
 {{ 'foo' starts      with 'f' ? 'OK' : 'KO' }}
 {{ 'foo' starts
 with 'f' ? 'OK' : 'KO' }}
+{{ 'foo' starts with '' ? 'OK' : 'KO' }}
+{{ '1' starts with true ? 'OK' : 'KO' }}
+{{ '' starts with false ? 'OK' : 'KO' }}
+{{ 'a' starts with false ? 'OK' : 'KO' }}
+{{ false starts with '' ? 'OK' : 'KO' }}
 --DATA--
 return array()
 --EXPECT--
@@ -15,3 +20,8 @@
 OK
 OK
 OK
+OK
+KO
+KO
+KO
+KO
diff --git a/twig/twig/test/Twig/Tests/Fixtures/filters/date.test 
b/twig/twig/test/Twig/Tests/Fixtures/filters/date.test
index d40bb04..d17e5e2 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/filters/date.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/filters/date.test
@@ -31,6 +31,13 @@
 {{ date6|date('e', false) }}
 
 {{ date7|date }}
+{{ date7|date(timezone='Europe/Paris') }}
+{{ date7|date(timezone='Asia/Hong_Kong') }}
+{{ date7|date(timezone=false) }}
+{{ date7|date(timezone='Indian/Mauritius') }}
+
+{{ '2010-01-28 15:00:00'|date(timezone="Europe/Paris") }}
+{{ '2010-01-28 15:00:00'|date(timezone="Asia/Hong_Kong") }}
 --DATA--
 date_default_timezone_set('Europe/Paris');
 return array(
@@ -40,7 +47,7 @@
     'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', 
'2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp 
is always GMT
     'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', 
'1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
     'date6' => new DateTime('2010-10-04 13:45', new 
DateTimeZone('America/New_York')),
-    'date7' => '2010-01-28T15:00:00+05:00',
+    'date7' => '2010-01-28T15:00:00+04:00',
     'timezone1' => new DateTimeZone('America/New_York'),
 )
 --EXPECT--
@@ -73,4 +80,11 @@
 Europe/Paris
 America/New_York
 
-January 28, 2010 11:00
+January 28, 2010 12:00
+January 28, 2010 12:00
+January 28, 2010 19:00
+January 28, 2010 15:00
+January 28, 2010 15:00
+
+January 28, 2010 15:00
+January 28, 2010 22:00
diff --git a/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test 
b/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test
index b89ceb3..4e18325 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test
@@ -8,6 +8,7 @@
 {{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
 {{ date1|date('d/m/Y H:i:s', timezone1) }}
 {{ date1|date('d/m/Y H:i:s') }}
+{{ date1|date_modify('+1 hour')|date('d/m/Y H:i:s') }}
 
 {{ date2|date('d/m/Y H:i:s P', 'Europe/Paris') }}
 {{ date2|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
@@ -27,6 +28,7 @@
 04/10/2010 19:45:00
 04/10/2010 07:45:00
 04/10/2010 13:45:00
+04/10/2010 14:45:00
 
 04/10/2010 19:45:00 +02:00
 05/10/2010 01:45:00 +08:00
diff --git a/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test 
b/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
index b37ad65..fb36a4e 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
@@ -19,6 +19,9 @@
 {{ '1234'|slice(1) }}
 {{ '1234'[1:] }}
 {{ '1234'[:1] }}
+
+{{ arr|slice(3)|join('') }}
+{{ arr[2:]|join('') }}
 --DATA--
 return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 
3, 4)))
 --EXPECT--
@@ -40,3 +43,6 @@
 234
 234
 1
+
+4
+34
\ No newline at end of file
diff --git a/twig/twig/test/Twig/Tests/Fixtures/filters/split.test 
b/twig/twig/test/Twig/Tests/Fixtures/filters/split.test
index ce8ec9c..a093ed7 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/filters/split.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/filters/split.test
@@ -5,6 +5,7 @@
 {{ foo|split(',')|join('-') }}
 {{ foo|split(',', 3)|join('-') }}
 {{ baz|split('')|join('-') }}
+{{ baz|split('', 1)|join('-') }}
 {{ baz|split('', 2)|join('-') }}
 {{ foo|split(',', -2)|join('-') }}
 --DATA--
@@ -14,5 +15,6 @@
 one-two-three-four-five
 one-two-three,four,five
 1-2-3-4-5
+1-2-3-4-5
 12-34-5
 one-two-three
\ No newline at end of file
diff --git a/twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test 
b/twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test
new file mode 100644
index 0000000..305e162
--- /dev/null
+++ b/twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test
@@ -0,0 +1,24 @@
+--TEST--
+"split" filter
+--CONDITION--
+function_exists('mb_get_info')
+--TEMPLATE--
+{{ "é"|split('', 10)|join('-') }}
+{{ foo|split(',')|join('-') }}
+{{ foo|split(',', 1)|join('-') }}
+{{ foo|split(',', 2)|join('-') }}
+{{ foo|split(',', 3)|join('-') }}
+{{ baz|split('')|join('-') }}
+{{ baz|split('', 1)|join('-') }}
+{{ baz|split('', 2)|join('-') }}
+--DATA--
+return array('foo' => 'Ä,é,Äほ', 'baz' => 'éÄßごa',)
+--EXPECT--
+é
+Ä-é-Äほ
+Ä,é,Äほ
+Ä-é,Äほ
+Ä-é-Äほ
+é-Ä-ß-ご-a
+é-Ä-ß-ご-a
+éÄ-ßご-a
\ No newline at end of file
diff --git a/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test 
b/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
index 472b74d..71b2038 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
@@ -4,13 +4,15 @@
 {{ attribute(obj, method) }}
 {{ attribute(array, item) }}
 {{ attribute(obj, "bar", ["a", "b"]) }}
+{{ attribute(obj, "bar", arguments) }}
 {{ attribute(obj, method) is defined ? 'ok' : 'ko' }}
 {{ attribute(obj, nonmethod) is defined ? 'ok' : 'ko' }}
 --DATA--
-return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => 
array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx')
+return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => 
array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx', 'arguments' => 
array('a', 'b'))
 --EXPECT--
 foo
 bar
 bar_a-b
+bar_a-b
 ok
 ko
diff --git a/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test 
b/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
index 788a2ab..7b9ccac 100644
--- a/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
+++ b/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
@@ -3,8 +3,11 @@
 --TEMPLATE--
 {{ include("foo.twig", sandboxed = true) }}
 --TEMPLATE(foo.twig)--
+
+
+{{ foo|e }}
 {{ foo|e }}
 --DATA--
 return array()
 --EXCEPTION--
-Twig_Sandbox_SecurityError: Filter "e" is not allowed in "index.twig" at line 
2.
+Twig_Sandbox_SecurityNotAllowedFilterError: Filter "e" is not allowed in 
"foo.twig" at line 4.
diff --git 
a/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test 
b/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test
new file mode 100644
index 0000000..df48578
--- /dev/null
+++ b/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test
@@ -0,0 +1,15 @@
+--TEST--
+Exception with bad line number
+--TEMPLATE--
+{% block content %}
+    {{ foo }}
+    {{ include("foo") }}
+{% endblock %}
+index
+--TEMPLATE(foo)--
+foo
+{{ foo.bar }}
+--DATA--
+return array('foo' => 'foo');
+--EXCEPTION--
+Twig_Error_Runtime: Impossible to access an attribute ("bar") on a string 
variable ("foo") in "foo" at line 3
diff --git 
a/twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test 
b/twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test
new file mode 100644
index 0000000..269a305
--- /dev/null
+++ b/twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test
@@ -0,0 +1,10 @@
+--TEST--
+Twig allows multi-word tests without a custom node class
+--TEMPLATE--
+{{ 'foo' is multi word ? 'yes' : 'no' }}
+{{ 'foo bar' is multi word ? 'yes' : 'no' }}
+--DATA--
+return array()
+--EXPECT--
+no
+yes
diff --git a/twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test 
b/twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test
new file mode 100644
index 0000000..5679462
--- /dev/null
+++ b/twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test
@@ -0,0 +1,14 @@
+--TEST--
+Super globals as macro arguments
+--TEMPLATE--
+{% import _self as macros %}
+
+{{ macros.foo('foo') }}
+
+{% macro foo(GET) %}
+    {{ GET }}
+{% endmacro %}
+--DATA--
+return array()
+--EXPECT--
+foo
diff --git a/twig/twig/test/Twig/Tests/IntegrationTest.php 
b/twig/twig/test/Twig/Tests/IntegrationTest.php
index ea00b02..70f9b80 100644
--- a/twig/twig/test/Twig/Tests/IntegrationTest.php
+++ b/twig/twig/test/Twig/Tests/IntegrationTest.php
@@ -157,6 +157,13 @@
         );
     }
 
+    public function getTests()
+    {
+        return array(
+            new Twig_SimpleTest('multi word', array($this, 'is_multi_word')),
+        );
+    }
+
     public function §Filter($value)
     {
         return "§{$value}§";
@@ -210,6 +217,11 @@
         return '<br />';
     }
 
+    public function is_multi_word($value)
+    {
+        return false !== strpos($value, ' ');
+    }
+
     public function getName()
     {
         return 'integration_test';
diff --git a/twig/twig/test/Twig/Tests/LexerTest.php 
b/twig/twig/test/Twig/Tests/LexerTest.php
index ab104f4..c4d7083 100644
--- a/twig/twig/test/Twig/Tests/LexerTest.php
+++ b/twig/twig/test/Twig/Tests/LexerTest.php
@@ -46,7 +46,6 @@
         $stream = $lexer->tokenize($template);
 
         $count = 0;
-        $tokens = array();
         while (!$stream->isEOF()) {
             $token = $stream->next();
             if ($type === $token->getType()) {
@@ -114,7 +113,7 @@
         $template = '{% raw %}'.str_repeat('*', 100000).'{% endraw %}';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
 
         // should not throw an exception
     }
@@ -124,7 +123,7 @@
         $template = '{{ '.str_repeat('x', 100000).' }}';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
 
         // should not throw an exception
     }
@@ -134,17 +133,13 @@
         $template = '{% '.str_repeat('x', 100000).' %}';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
 
         // should not throw an exception
     }
 
     public function testBigNumbers()
     {
-        if ('hiphop' === substr(PHP_VERSION, -6)) {
-            $this->markTestSkipped('hhvm thinks that the number is actually a 
T_CONSTANT_ENCAPSED_STRING!');
-        }
-
         $template = '{{ 922337203685477580700 }}';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
@@ -216,7 +211,7 @@
         $template = '{{ "bar #{x" }}';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
     }
 
     public function testStringWithNestedInterpolations()
@@ -281,7 +276,7 @@
 ';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
     }
 
     /**
@@ -300,6 +295,6 @@
 ';
 
         $lexer = new Twig_Lexer(new Twig_Environment());
-        $stream = $lexer->tokenize($template);
+        $lexer->tokenize($template);
     }
 }
diff --git a/twig/twig/test/Twig/Tests/NativeExtensionTest.php 
b/twig/twig/test/Twig/Tests/NativeExtensionTest.php
index 9519bdf..7de268c 100644
--- a/twig/twig/test/Twig/Tests/NativeExtensionTest.php
+++ b/twig/twig/test/Twig/Tests/NativeExtensionTest.php
@@ -23,7 +23,7 @@
         $d2 = new DateTime();
         $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 
'd2'));
 
-        if ('hiphop' === substr(PHP_VERSION, -6)) {
+        if (defined('HHVM_VERSION')) {
             $this->markTestSkipped('Skip under HHVM as the behavior is not the 
same as plain PHP (which is an edge case anyway)');
         }
 
diff --git a/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php 
b/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
index 62fb0d3..76cf5c6 100644
--- a/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
+++ b/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
@@ -46,7 +46,7 @@
         $attr = new Twig_Node_Expression_Constant('bar', 1);
         $args = new Twig_Node_Expression_Array(array(), 1);
         $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 
Twig_Template::ANY_CALL, 1);
-        $tests[] = array($node, sprintf('%s%s, "bar")', 
$this->getAttributeGetter(), $this->getVariableGetter('foo')));
+        $tests[] = array($node, sprintf('%s%s, "bar", array())', 
$this->getAttributeGetter(), $this->getVariableGetter('foo')));
 
         $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 
Twig_Template::ARRAY_CALL, 1);
         $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', 
$this->getAttributeGetter(), $this->getVariableGetter('foo')));
diff --git a/twig/twig/test/Twig/Tests/Node/IncludeTest.php 
b/twig/twig/test/Twig/Tests/Node/IncludeTest.php
index e8aa326..9afecef 100644
--- a/twig/twig/test/Twig/Tests/Node/IncludeTest.php
+++ b/twig/twig/test/Twig/Tests/Node/IncludeTest.php
@@ -59,8 +59,7 @@
         $node = new Twig_Node_Include($expr, null, false, false, 1);
         $tests[] = array($node, <<<EOF
 // line 1
-\$template = \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
-\$template->display(\$context);
+\$this->env->resolveTemplate(((true) ? ("foo") : ("foo")))->display(\$context);
 EOF
         );
 
diff --git a/twig/twig/test/Twig/Tests/Node/MacroTest.php 
b/twig/twig/test/Twig/Tests/Node/MacroTest.php
index 4d2f641..2a77ac7 100644
--- a/twig/twig/test/Twig/Tests/Node/MacroTest.php
+++ b/twig/twig/test/Twig/Tests/Node/MacroTest.php
@@ -46,11 +46,11 @@
         return array(
             array($node, <<<EOF
 // line 1
-public function getfoo(\$_foo = null, \$_bar = "Foo")
+public function getfoo(\$__foo__ = null, \$__bar__ = "Foo")
 {
     \$context = \$this->env->mergeGlobals(array(
-        "foo" => \$_foo,
-        "bar" => \$_bar,
+        "foo" => \$__foo__,
+        "bar" => \$__bar__,
     ));
 
     \$blocks = array();
diff --git a/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php 
b/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
index 421f210..bb9ffb7 100644
--- a/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
+++ b/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
@@ -84,11 +84,29 @@
 
     protected function checkSecurity()
     {
-        \$this->env->getExtension('sandbox')->checkSecurity(
-            array('upper'),
-            array('for'),
-            array('cycle')
-        );
+        \$tags = array();
+        \$filters = array();
+        \$functions = array();
+
+        try {
+            \$this->env->getExtension('sandbox')->checkSecurity(
+                array('upper'),
+                array('for'),
+                array('cycle')
+            );
+        } catch (Twig_Sandbox_SecurityError \$e) {
+            \$e->setTemplateFile(\$this->getTemplateName());
+
+            if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && 
isset(\$tags[\$e->getTagName()])) {
+                \$e->setTemplateLine(\$tags[\$e->getTagName()]);
+            } elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFilterError && 
isset(\$filters[\$e->getFilterName()])) {
+                \$e->setTemplateLine(\$filters[\$e->getFilterName()]);
+            } elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFunctionError && 
isset(\$functions[\$e->getFunctionName()])) {
+                \$e->setTemplateLine(\$functions[\$e->getFunctionName()]);
+            }
+
+            throw \$e;
+        }
     }
 
     public function getTemplateName()
@@ -143,11 +161,29 @@
 
     protected function checkSecurity()
     {
-        \$this->env->getExtension('sandbox')->checkSecurity(
-            array('upper'),
-            array('for'),
-            array('cycle')
-        );
+        \$tags = array();
+        \$filters = array();
+        \$functions = array();
+
+        try {
+            \$this->env->getExtension('sandbox')->checkSecurity(
+                array('upper'),
+                array('for'),
+                array('cycle')
+            );
+        } catch (Twig_Sandbox_SecurityError \$e) {
+            \$e->setTemplateFile(\$this->getTemplateName());
+
+            if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && 
isset(\$tags[\$e->getTagName()])) {
+                \$e->setTemplateLine(\$tags[\$e->getTagName()]);
+            } elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFilterError && 
isset(\$filters[\$e->getFilterName()])) {
+                \$e->setTemplateLine(\$filters[\$e->getFilterName()]);
+            } elseif (\$e instanceof 
Twig_Sandbox_SecurityNotAllowedFunctionError && 
isset(\$functions[\$e->getFunctionName()])) {
+                \$e->setTemplateLine(\$functions[\$e->getFunctionName()]);
+            }
+
+            throw \$e;
+        }
     }
 
     public function getTemplateName()
diff --git a/twig/twig/test/Twig/Tests/TemplateTest.php 
b/twig/twig/test/Twig/Tests/TemplateTest.php
index b6f5a67..e2f84ee 100644
--- a/twig/twig/test/Twig/Tests/TemplateTest.php
+++ b/twig/twig/test/Twig/Tests/TemplateTest.php
@@ -28,6 +28,7 @@
 
         $context = array(
             'string'          => 'foo',
+            'empty_array'     => array(),
             'array'           => array('foo' => 'foo'),
             'array_access'    => new Twig_TemplateArrayAccessObject(),
             'magic_exception' => new 
Twig_TemplateMagicPropertyObjectWithException(),
@@ -46,10 +47,12 @@
     {
         $tests = array(
             array('{{ string["a"] }}', 'Impossible to access a key ("a") on a 
string variable ("foo") in "%s" at line 1', false),
+            array('{{ empty_array["a"] }}', 'Key "a" does not exist as the 
array is empty in "%s" at line 1', false),
             array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does 
not exist in "%s" at line 1', false),
             array('{{ array_access["a"] }}', 'Key "a" in object with 
ArrayAccess of class "Twig_TemplateArrayAccessObject" does not exist in "%s" at 
line 1', false),
             array('{{ string.a }}', 'Impossible to access an attribute ("a") 
on a string variable ("foo") in "%s" at line 1', false),
             array('{{ string.a() }}', 'Impossible to invoke a method ("a") on 
a string variable ("foo") in "%s" at line 1', false),
+            array('{{ empty_array.a }}', 'Key "a" does not exist as the array 
is empty in "%s" at line 1', false),
             array('{{ array.a }}', 'Key "a" for array with keys "foo" does not 
exist in "%s" at line 1', false),
             array('{{ attribute(array, -10) }}', 'Key "-10" for array with 
keys "foo" does not exist in "%s" at line 1', false),
             array('{{ array_access.a }}', 'Method "a" for object 
"Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
@@ -368,7 +371,7 @@
         $tests = array_merge($tests, array(
             array(false, null, 42, 'a', array(), $anyType, false, 'Impossible 
to access an attribute ("a") on a integer variable ("42")'),
             array(false, null, "string", 'a', array(), $anyType, false, 
'Impossible to access an attribute ("a") on a string variable ("string")'),
-            array(false, null, array(), 'a', array(), $anyType, false, 'Key 
"a" for array with keys "" does not exist'),
+            array(false, null, array(), 'a', array(), $anyType, false, 'Key 
"a" does not exist as the array is empty'),
         ));
 
         // add twig_template_get_attributes tests
diff --git a/twig/twig/test/Twig/Tests/escapingTest.php 
b/twig/twig/test/Twig/Tests/escapingTest.php
index 34d2a2d..d581315 100644
--- a/twig/twig/test/Twig/Tests/escapingTest.php
+++ b/twig/twig/test/Twig/Tests/escapingTest.php
@@ -227,7 +227,7 @@
     /**
      * Convert a Unicode Codepoint to a literal UTF-8 character.
      *
-     * @param int Unicode codepoint in hex notation
+     * @param int $codepoint Unicode codepoint in hex notation
      * @return string UTF-8 literal string
      */
     protected function codepointToUtf8($codepoint)
@@ -301,7 +301,7 @@
 
     public function testCssEscapingEscapesOwaspRecommendedRanges()
     {
-        $immune = array(); // CSS has no exceptions to escaping ranges
+        // CSS has no exceptions to escaping ranges
         for ($chr=0; $chr < 0xFF; $chr++) {
             if ($chr >= 0x30 && $chr <= 0x39
             || $chr >= 0x41 && $chr <= 0x5A

-- 
To view, visit https://gerrit.wikimedia.org/r/178396
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia9ce422c57cf893c4971de2c8b4d51858be846fe
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/fundraising/crm/vendor
Gerrit-Branch: master
Gerrit-Owner: Awight <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to