--- a/adm/style/acp_database.html
+++ b/adm/style/acp_database.html
@@ -14,7 +14,7 @@
 		<legend>{L_RESTORE_OPTIONS}</legend>
 	<dl>
 		<dt><label for="file">{L_SELECT_FILE}{L_COLON}</label></dt>
-		<dd><select id="file" name="file" size="10"><!-- BEGIN files --><option value="{files.FILE}"<!-- IF files.S_LAST_ROW --> selected="selected"<!-- ENDIF -->>{files.NAME}</option><!-- END files --></select></dd>
+		<dd><select id="file" name="file" size="10"><!-- BEGIN files --><option value="{files.FILE}"<!-- IF files.S_FIRST_ROW --> selected="selected"<!-- ENDIF -->>{files.NAME}</option><!-- END files --></select></dd>
 	</dl>
 
 	<p class="submit-buttons">
--- a/adm/style/acp_main.html
+++ b/adm/style/acp_main.html
@@ -14,7 +14,11 @@
 
 	<p>{L_ADMIN_INTRO}</p>
 
-	<!-- IF S_VERSIONCHECK_FAIL -->
+	<!-- IF S_UPDATE_INCOMPLETE -->
+		<div class="errorbox">
+			<p>{L_UPDATE_INCOMPLETE} <a href="{U_VERSIONCHECK}">{L_MORE_INFORMATION}</a></p>
+		</div>
+	<!-- ELSEIF S_VERSIONCHECK_FAIL -->
 		<div class="errorbox notice">
 			<p>{L_VERSIONCHECK_FAIL}</p>
 			<p>{VERSIONCHECK_FAIL_REASON}</p>
--- a/adm/style/acp_posting_buttons.html
+++ b/adm/style/acp_posting_buttons.html
@@ -63,6 +63,7 @@
 		<!-- ENDIF -->
 		<!-- ENDIF -->
 	</select>
+	<!-- EVENT acp_posting_buttons_custom_tags_before -->
 	<!-- BEGIN custom_tags -->
 	<input type="button" class="button2" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{custom_tags.BBCODE_HELPLINE}" />
 	<!-- END custom_tags -->
--- a/adm/style/acp_update.html
+++ b/adm/style/acp_update.html
@@ -6,11 +6,16 @@
 
 <p>{L_VERSION_CHECK_EXPLAIN}</p>
 
+<!-- IF S_UPDATE_INCOMPLETE -->
+	<div class="errorbox">
+		<p>{L_UPDATE_INCOMPLETE} {L_UPDATE_INCOMPLETE_MORE}</p>
+	</div>
+<!-- ENDIF -->
 <!-- IF S_UP_TO_DATE -->
 	<div class="successbox">
 		<p>{L_VERSION_UP_TO_DATE_ACP} - <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
 	</div>
-<!-- ELSE -->
+<!-- ELSEIF not S_UPDATE_INCOMPLETE -->
 	<div class="errorbox">
 		<p>{L_VERSION_NOT_UP_TO_DATE_ACP} - <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
 	</div>
@@ -18,10 +23,21 @@
 
 <fieldset>
 	<legend></legend>
+	<!-- IF not S_UPDATE_INCOMPLETE -->
 	<dl>
 		<dt><label>{L_CURRENT_VERSION}</label></dt>
 		<dd><strong>{CURRENT_VERSION}</strong></dd>
 	</dl>
+	<!-- ELSE -->
+	<dl>
+		<dt><label>{L_FILES_VERSION}</label></dt>
+		<dd><strong>{FILES_VERSION}</strong></dd>
+	</dl>
+	<dl>
+		<dt><label>{L_DATABASE_VERSION}</label></dt>
+		<dd><strong>{CURRENT_VERSION}</strong></dd>
+	</dl>
+	<!-- ENDIF -->
 </fieldset>
 
 <!-- BEGIN updates_available -->
@@ -38,6 +54,11 @@
 	</fieldset>
 <!-- END updates_available -->
 
+<!-- IF S_UPDATE_INCOMPLETE -->
+	{INCOMPLETE_INSTRUCTIONS}
+	<br>
+<!-- ENDIF -->
+
 <!-- IF not S_UP_TO_DATE -->
 	{UPDATE_INSTRUCTIONS}
 	<br /><br />
--- a/composer.lock
+++ b/composer.lock
@@ -1,10 +1,11 @@
 {
     "_readme": [
         "This file locks the dependencies of your project to a known state",
-        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
     "hash": "33fa9de480a8a9c8f7e3f2926cd4c034",
+    "content-hash": "2d9c1857e65554ceb4cfa435495df188",
     "packages": [
         {
             "name": "lusitanian/oauth",
@@ -109,17 +110,17 @@
         },
         {
             "name": "symfony/config",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Config",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "1324aed10a750ed5a0446a71d95e321bf5d3bd24"
+                "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/1324aed10a750ed5a0446a71d95e321bf5d3bd24",
-                "reference": "1324aed10a750ed5a0446a71d95e321bf5d3bd24",
+                "url": "https://api.github.com/repos/symfony/config/zipball/16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
+                "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
                 "shasum": ""
             },
             "require": {
@@ -156,21 +157,21 @@
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:06"
+            "time": "2016-05-30 08:14:41"
         },
         {
             "name": "symfony/console",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Console",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "cc386594e19024e53e81ee7b6d6c37c221864c4e"
+                "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/cc386594e19024e53e81ee7b6d6c37c221864c4e",
-                "reference": "cc386594e19024e53e81ee7b6d6c37c221864c4e",
+                "url": "https://api.github.com/repos/symfony/console/zipball/20c12c6d6c5a087a66d4e77999451713a92a3507",
+                "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507",
                 "shasum": ""
             },
             "require": {
@@ -212,21 +213,21 @@
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 09:20:54"
+            "time": "2016-05-26 08:04:58"
         },
         {
             "name": "symfony/debug",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Debug",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
-                "reference": "a6f7b78e406658897f689fa8b00a06205446bebd"
+                "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/a6f7b78e406658897f689fa8b00a06205446bebd",
-                "reference": "a6f7b78e406658897f689fa8b00a06205446bebd",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/863d29c31a1ddfcf1faedf5f8362f392e3261632",
+                "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632",
                 "shasum": ""
             },
             "require": {
@@ -274,21 +275,21 @@
             ],
             "description": "Symfony Debug Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 13:04:09"
+            "time": "2016-03-30 09:02:35"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/DependencyInjection",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "7cbda8ce5b5e4bd865401cf243070708e1f9a5e6"
+                "reference": "06265ee128644eb70356bd72ab28c9ded6618d19"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7cbda8ce5b5e4bd865401cf243070708e1f9a5e6",
-                "reference": "7cbda8ce5b5e4bd865401cf243070708e1f9a5e6",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/06265ee128644eb70356bd72ab28c9ded6618d19",
+                "reference": "06265ee128644eb70356bd72ab28c9ded6618d19",
                 "shasum": ""
             },
             "require": {
@@ -333,21 +334,21 @@
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-08 16:58:37"
+            "time": "2016-05-30 08:31:06"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/EventDispatcher",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "b2d9d812e21d6e00983061d49ee61a82f54cace7"
+                "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b2d9d812e21d6e00983061d49ee61a82f54cace7",
-                "reference": "b2d9d812e21d6e00983061d49ee61a82f54cace7",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fd6d162d97bf3e6060622e5c015af39ca72e33bc",
+                "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc",
                 "shasum": ""
             },
             "require": {
@@ -390,21 +391,21 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:06"
+            "time": "2016-04-04 09:22:54"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Filesystem",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "56f6725f520a357e19deaef6558c3d223046b843"
+                "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/56f6725f520a357e19deaef6558c3d223046b843",
-                "reference": "56f6725f520a357e19deaef6558c3d223046b843",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
+                "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
                 "shasum": ""
             },
             "require": {
@@ -440,21 +441,21 @@
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-10 16:50:02"
+            "time": "2016-04-12 15:20:10"
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/HttpFoundation",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40"
+                "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40",
-                "reference": "f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
+                "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
                 "shasum": ""
             },
             "require": {
@@ -494,21 +495,21 @@
             ],
             "description": "Symfony HttpFoundation Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-12 16:03:08"
+            "time": "2016-05-13 15:22:39"
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/HttpKernel",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "a704146970a1ff261c05e865b636bcc5d95f1b5b"
+                "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a704146970a1ff261c05e865b636bcc5d95f1b5b",
-                "reference": "a704146970a1ff261c05e865b636bcc5d95f1b5b",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/57e0329236e8edf2b0e683043c604f7c9aba9398",
+                "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398",
                 "shasum": ""
             },
             "require": {
@@ -570,20 +571,20 @@
             ],
             "description": "Symfony HttpKernel Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-13 16:38:02"
+            "time": "2016-05-30 08:41:10"
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.1.1",
+            "version": "v1.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "1289d16209491b584839022f29257ad859b8532d"
+                "reference": "dff51f72b0706335131b00a7f49606168c582594"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
-                "reference": "1289d16209491b584839022f29257ad859b8532d",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594",
                 "shasum": ""
             },
             "require": {
@@ -595,7 +596,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1-dev"
+                    "dev-master": "1.2-dev"
                 }
             },
             "autoload": {
@@ -629,21 +630,21 @@
                 "portable",
                 "shim"
             ],
-            "time": "2016-01-20 09:13:37"
+            "time": "2016-05-18 14:26:46"
         },
         {
             "name": "symfony/routing",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Routing",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "9f464f27cb127232f5c32d5a736fe769e5249442"
+                "reference": "5b8a2bb7569df81401171829498809e90d6e446c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/9f464f27cb127232f5c32d5a736fe769e5249442",
-                "reference": "9f464f27cb127232f5c32d5a736fe769e5249442",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/5b8a2bb7569df81401171829498809e90d6e446c",
+                "reference": "5b8a2bb7569df81401171829498809e90d6e446c",
                 "shasum": ""
             },
             "require": {
@@ -691,21 +692,21 @@
             ],
             "description": "Symfony Routing Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:06"
+            "time": "2016-05-29 10:13:06"
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Yaml",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe"
+                "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe",
-                "reference": "d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
+                "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
                 "shasum": ""
             },
             "require": {
@@ -741,20 +742,20 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:08"
+            "time": "2016-05-30 08:10:17"
         },
         {
             "name": "twig/twig",
-            "version": "v1.24.0",
+            "version": "v1.24.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig.git",
-                "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
+                "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
-                "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512",
+                "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512",
                 "shasum": ""
             },
             "require": {
@@ -802,7 +803,7 @@
             "keywords": [
                 "templating"
             ],
-            "time": "2016-01-25 21:22:18"
+            "time": "2016-05-30 09:11:59"
         }
     ],
     "packages-dev": [
@@ -1421,21 +1422,24 @@
         },
         {
             "name": "phpunit/php-timer",
-            "version": "1.0.7",
+            "version": "1.0.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
-                "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3"
             },
+            "require-dev": {
+                "phpunit/phpunit": "~4|~5"
+            },
             "type": "library",
             "autoload": {
                 "classmap": [
@@ -1458,7 +1462,7 @@
             "keywords": [
                 "timer"
             ],
-            "time": "2015-06-21 08:01:12"
+            "time": "2016-05-12 18:03:57"
         },
         {
             "name": "phpunit/php-token-stream",
@@ -1863,16 +1867,16 @@
         },
         {
             "name": "sebastian/environment",
-            "version": "1.3.5",
+            "version": "1.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
-                "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
                 "shasum": ""
             },
             "require": {
@@ -1909,20 +1913,20 @@
                 "environment",
                 "hhvm"
             ],
-            "time": "2016-02-26 18:40:46"
+            "time": "2016-05-17 03:18:57"
         },
         {
             "name": "sebastian/exporter",
-            "version": "1.2.1",
+            "version": "1.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
+                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
-                "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
+                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
                 "shasum": ""
             },
             "require": {
@@ -1930,12 +1934,13 @@
                 "sebastian/recursion-context": "~1.0"
             },
             "require-dev": {
+                "ext-mbstring": "*",
                 "phpunit/phpunit": "~4.4"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.2.x-dev"
+                    "dev-master": "1.3.x-dev"
                 }
             },
             "autoload": {
@@ -1975,7 +1980,7 @@
                 "export",
                 "exporter"
             ],
-            "time": "2015-06-21 07:55:53"
+            "time": "2016-06-17 09:04:28"
         },
         {
             "name": "sebastian/recursion-context",
@@ -2067,19 +2072,20 @@
         },
         {
             "name": "squizlabs/php_codesniffer",
-            "version": "2.5.1",
+            "version": "2.6.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
-                "reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8"
+                "reference": "4edb770cb853def6e60c93abb088ad5ac2010c83"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6731851d6aaf1d0d6c58feff1065227b7fda3ba8",
-                "reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8",
+                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4edb770cb853def6e60c93abb088ad5ac2010c83",
+                "reference": "4edb770cb853def6e60c93abb088ad5ac2010c83",
                 "shasum": ""
             },
             "require": {
+                "ext-simplexml": "*",
                 "ext-tokenizer": "*",
                 "ext-xmlwriter": "*",
                 "php": ">=5.1.2"
@@ -2140,11 +2146,11 @@
                 "phpcs",
                 "standards"
             ],
-            "time": "2016-01-19 23:39:10"
+            "time": "2016-07-13 23:29:13"
         },
         {
             "name": "symfony/browser-kit",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/BrowserKit",
             "source": {
                 "type": "git",
@@ -2202,7 +2208,7 @@
         },
         {
             "name": "symfony/css-selector",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/CssSelector",
             "source": {
                 "type": "git",
@@ -2256,17 +2262,17 @@
         },
         {
             "name": "symfony/dom-crawler",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/DomCrawler",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "507dca599566359a4489aa732612347ff65b9a51"
+                "reference": "b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/507dca599566359a4489aa732612347ff65b9a51",
-                "reference": "507dca599566359a4489aa732612347ff65b9a51",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d",
+                "reference": "b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d",
                 "shasum": ""
             },
             "require": {
@@ -2308,21 +2314,21 @@
             ],
             "description": "Symfony DomCrawler Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:08"
+            "time": "2016-04-06 13:13:46"
         },
         {
             "name": "symfony/finder",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Finder",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "24cbc57da78ef7d05250c657b18b1ddcb1298bdf"
+                "reference": "dce4b58434fc1cbd66e3006e539bb53074dfea82"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/24cbc57da78ef7d05250c657b18b1ddcb1298bdf",
-                "reference": "24cbc57da78ef7d05250c657b18b1ddcb1298bdf",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/dce4b58434fc1cbd66e3006e539bb53074dfea82",
+                "reference": "dce4b58434fc1cbd66e3006e539bb53074dfea82",
                 "shasum": ""
             },
             "require": {
@@ -2358,21 +2364,21 @@
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-09 12:50:31"
+            "time": "2016-05-13 14:58:35"
         },
         {
             "name": "symfony/process",
-            "version": "v2.3.39",
+            "version": "v2.3.42",
             "target-dir": "Symfony/Component/Process",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "12b5d095f70d2dd706c181e51106005e008e5ca8"
+                "reference": "89aced1438655ad81fc828c2e2e555e9b88fef3b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/12b5d095f70d2dd706c181e51106005e008e5ca8",
-                "reference": "12b5d095f70d2dd706c181e51106005e008e5ca8",
+                "url": "https://api.github.com/repos/symfony/process/zipball/89aced1438655ad81fc828c2e2e555e9b88fef3b",
+                "reference": "89aced1438655ad81fc828c2e2e555e9b88fef3b",
                 "shasum": ""
             },
             "require": {
@@ -2408,7 +2414,7 @@
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-04 07:12:06"
+            "time": "2016-03-31 08:39:43"
         }
     ],
     "aliases": [],
--- a/config/feed.yml
+++ b/config/feed.yml
@@ -25,6 +25,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.forums:
@@ -38,6 +39,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.news:
@@ -51,6 +53,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.overall:
@@ -64,6 +67,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.topic:
@@ -77,6 +81,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.topics:
@@ -90,6 +95,7 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
 
     feed.topics_active:
@@ -103,4 +109,5 @@ services:
             - @user
             - @auth
             - @content.visibility
+            - @dispatcher
             - %core.php_ext%
--- a/cron.php
+++ b/cron.php
@@ -55,6 +55,18 @@ if ($cron_lock->acquire())
 	$task = $cron->find_task($cron_type);
 	if ($task)
 	{
+		/**
+		 * This event enables you to catch the task before it runs
+		 *
+		 * @event core.cron_run_before
+		 * @var	\phpbb\cron\task\wrapper	task	Current Cron task
+		 * @since 3.1.8-RC1
+		 */
+		$vars = array(
+			'task',
+		);
+		extract($phpbb_dispatcher->trigger_event('core.cron_run_before', compact($vars)));
+
 		if ($task->is_parametrized())
 		{
 			$task->parse_parameters($request);
--- a/docs/CHANGELOG.html
+++ b/docs/CHANGELOG.html
@@ -50,6 +50,7 @@
 <ol>
 	<li><a href="#changelog">Changelog</a>
 	<ul>
+		<li><a href="#v319">Changes since 3.1.9</a></li>
 		<li><a href="#v318">Changes since 3.1.8</a></li>
 		<li><a href="#v317pl1">Changes since 3.1.7-PL1</a></li>
 		<li><a href="#v317">Changes since 3.1.7</a></li>
@@ -118,7 +119,88 @@
 
 <div class="content">
 
-			<a name="v318"></a><h3>Changes since 3.1.8</h3>
+	<a name="v319"></a><h3>Changes since 3.1.9</h3>
+
+	<h4>Bug</h4>
+	<ul>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11446">PHPBB3-11446</a>] - Use sql_in_set as designed and consistent with the rest of phpBB code in phpbb_notification_manager</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12230">PHPBB3-12230</a>] - Do not auto remove user group when Newly Registered Users group was disabled</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12925">PHPBB3-12925</a>] - Use plural for permanent delete posts/topics confirmation</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14109">PHPBB3-14109</a>] - MySQL InnoDB does not support multiple index definitions on the same query.</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14291">PHPBB3-14291</a>] - Function send_file_to_browser() endlessly overwrites 'filesize' in ATTACHMENTS_TABLE</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14610">PHPBB3-14610</a>] - Q&amp;A CAPTCHA logs error when it has been solved</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14615">PHPBB3-14615</a>] - delete avatar triggers the new min max value in the HTML5 inputs</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14616">PHPBB3-14616</a>] - Auto-prune fails on large forums</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14631">PHPBB3-14631</a>] - 3.1.9 DB cli update crashes with PHP Fatal error: Call to undefined function phpbb\truncate_string()</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14654">PHPBB3-14654</a>] - Imagemagick &gt; ImageMagick</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14661">PHPBB3-14661</a>] - Fix a typo in twig.php</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14673">PHPBB3-14673</a>] - Missing Language Variable</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14683">PHPBB3-14683</a>] - Typos in operators in some email templates</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14703">PHPBB3-14703</a>] - module.add adds a module to the wrong parent</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14704">PHPBB3-14704</a>] - Remove unused language files and corresponding  functions</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14721">PHPBB3-14721</a>] - New registrants choosing old deleted usernames get linked to old accounts with namechange</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14742">PHPBB3-14742</a>] - Improvements to migrator</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14745">PHPBB3-14745</a>] - &quot;U_NOTIFICATION_SETTINGS&quot; contains an HTML entity but is printed in a plaintext email</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14755">PHPBB3-14755</a>] - Error in MCP Move posts</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14782">PHPBB3-14782</a>] - Quick Links &gt; Your Posts gives mysql error</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14788">PHPBB3-14788</a>] - Update developer list to reflect team changes</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14796">PHPBB3-14796</a>] - Log table is using constant in log delete method</li>
+	</ul>
+	<h4>Improvement</h4>
+	<ul>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13709">PHPBB3-13709</a>] - Fallback to english in email templates by extensions</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13716">PHPBB3-13716</a>] - Check phpBB version constant against config version</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13865">PHPBB3-13865</a>] - Complement core event search_modify_param</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14184">PHPBB3-14184</a>] - Missing info on SMTP mail function option</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14429">PHPBB3-14429</a>] - core.obtain_users_online_string_modify</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14466">PHPBB3-14466</a>] - Add an event to cron.php</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14469">PHPBB3-14469</a>] - [Template] - &lt;!-- EVENT viewforum_topicrow_before --&gt;</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14516">PHPBB3-14516</a>] - [Template] - memberlist_email_before</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14581">PHPBB3-14581</a>] - Add core events relating to soft delete</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14592">PHPBB3-14592</a>] - [PHP] - core.search_backend_search_after</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14596">PHPBB3-14596</a>] - Prevent installs of 3.1 on PHP 7</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14624">PHPBB3-14624</a>] - Add event to ucp_profile in signature section</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14630">PHPBB3-14630</a>] - Add event to ucp_pm_compose</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14638">PHPBB3-14638</a>] - [PHP] - multiple UCP subscription events for form data and template variables</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14643">PHPBB3-14643</a>] - Select newest file in restore list</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14652">PHPBB3-14652</a>] - Typo birthdays</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14664">PHPBB3-14664</a>] - Fix PHPDoc comment in cron manager</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14672">PHPBB3-14672</a>] - Add template event to viewforum</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14685">PHPBB3-14685</a>] - PHP event for altering announcements sql</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14687">PHPBB3-14687</a>] - Modify viewforum_modify_topicrow</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14688">PHPBB3-14688</a>] - Add core events to the feeds</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14689">PHPBB3-14689</a>] - Build 3.2.x API docs</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14695">PHPBB3-14695</a>] - Add posting_editor_subject_prepend/append template events</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14712">PHPBB3-14712</a>] - Add search.php core event to allow modifying the forum select list</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14713">PHPBB3-14713</a>] - Add core event to the admin function get_forum_list()</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14715">PHPBB3-14715</a>] - Add template events in posting_topic_review &amp; mcp_topic</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14720">PHPBB3-14720</a>] - Add global javascript variable 'phpbb' to jshint settings</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14727">PHPBB3-14727</a>] - Event core.search_modify_submit_parameters</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14738">PHPBB3-14738</a>] - Add core events to improve modifying forum lists</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14747">PHPBB3-14747</a>] - Add topic_last_poster_id and topic_last_post_time to Event core.modify_posting_auth</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14762">PHPBB3-14762</a>] - Add core event to session.php to alter IP address</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14781">PHPBB3-14781</a>] - Add core event to the function group_user_attributes()</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14783">PHPBB3-14783</a>] - Event - ACP Posting Buttons Before Custom BBCodes</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14784">PHPBB3-14784</a>] - missing rewrite for lighttpd</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14785">PHPBB3-14785</a>] - [Template event] - overall_header_headerbar_append</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14787">PHPBB3-14787</a>] - Add more parameters to the core.search_modify_url_parameters event</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14789">PHPBB3-14789</a>] - Add missing link hash and form token checks to ACP</li>
+	</ul>
+	<h4>New Feature</h4>
+	<ul>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13978">PHPBB3-13978</a>] - [PHP] - User control panel - on signature change</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14484">PHPBB3-14484</a>] - Support extensions in UI tests</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14506">PHPBB3-14506</a>] - [Template] - mcp_move_before</li>
+	</ul>
+	<h4>Task</h4>
+	<ul>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12133">PHPBB3-12133</a>] - Update list of browsers supporting filename* in Content-Disposition</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14538">PHPBB3-14538</a>] - Update composer dependencies</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14598">PHPBB3-14598</a>] - Phing Sniffer Testing Use Statements in DocBlocks</li>
+		<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14743">PHPBB3-14743</a>] - Remove PHP7 from test matrix in 3.1.x</li>
+	</ul>
+
+	<a name="v318"></a><h3>Changes since 3.1.8</h3>
 
 	<h4>Bug</h4>
 	<ul>
--- a/docs/CREDITS.txt
+++ b/docs/CREDITS.txt
@@ -1,6 +1,6 @@
 /**
 *
-* phpBB © Copyright phpBB Limited 2003-2014
+* phpBB © Copyright phpBB Limited 2003-2016
 * http://www.phpbb.com
 *
 * phpBB is free software. You can redistribute it and/or modify it
@@ -20,13 +20,13 @@
 
 phpBB Project Manager:   Marshalrusty (Yuriy Rusko)
 
-phpBB Lead Developer:    naderman (Nils Adermann)
+phpBB Product Manager:   naderman (Nils Adermann)
+
+phpBB Lead Developer:    Marc (Marc Alexander)
 
 phpBB Developers:        bantu (Andreas Fischer)
                          CHItA (Máté Bartus)
-                         dhruv.goel92 (Dhruv Goel)
                          Elsensee (Oliver Schramm)
-                         marc1706 (Marc Alexander)
                          nickvergessen (Joas Schilling)
                          Nicofuma (Tristan Darricau)
                          prototech (Cesar Gallegos)
@@ -54,6 +54,7 @@ phpBB Developers:        A_Jelly_Doughnut (Josh Woody) [01/2010 - 11/2010]
                          ckwalsh (Cullen Walsh)        [01/2010 - 07/2011]
                          DavidMJ (David M.)            [12/2005 - 08/2009]
                          dhn (Dominik Dröscher)        [05/2007 - 01/2011]
+                         dhruv.goel92 (Dhruv Goel)     [04/2013 - 05/2016]
                          EXreaction (Nathan Guse)      [07/2012 - 05/2014]
                          GrahamJE (Graham Eames)       [09/2005 - 11/2006]
                          igorw (Igor Wiedler)          [08/2010 - 02/2013]
--- a/docs/INSTALL.html
+++ b/docs/INSTALL.html
@@ -160,7 +160,7 @@
 			<li>zlib Compression support</li>
 			<li>Remote FTP support</li>
 			<li>XML support</li>
-			<li>Imagemagick support</li>
+			<li>ImageMagick support</li>
 			<li>GD Support</li>
 		</ul>
 		</li>
--- a/docs/events.md
+++ b/docs/events.md
@@ -343,6 +343,13 @@ acp_posting_buttons_before
 * Since: 3.1.0-b4
 * Purpose: Add content before BBCode posting buttons in the ACP
 
+acp_posting_buttons_custom_tags_before
+===
+* Locations:
+    + adm/style/acp_posting_buttons.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before the custom BBCodes in the ACP
+
 acp_profile_contact_before
 ===
 * Locations:
@@ -843,6 +850,14 @@ mcp_front_latest_unapproved_before
 * Since: 3.1.3-RC1
 * Purpose: Add content before latest unapproved posts list
 
+mcp_move_before
+===
+* Locations:
+    + styles/prosilver/template/mcp_move.html
+    + styles/subsilver2/template/mcp_move.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before move topic/post form
+
 mcp_post_additional_options
 ===
 * Locations:
@@ -867,6 +882,22 @@ mcp_topic_options_before
 * Since: 3.1.6-RC1
 * Purpose: Add some options (field, checkbox, ...) before the subject field when split a subject
 
+mcp_topic_postrow_post_details_after
+===
+* Locations:
+    + styles/prosilver/template/mcp_topic.html
+    + styles/subsilver2/template/mcp_topic.html
+* Since: 3.1.10-RC1
+* Purpose: Add content after post details in topic moderation
+
+mcp_topic_postrow_post_details_before
+===
+* Locations:
+    + styles/prosilver/template/mcp_topic.html
+    + styles/subsilver2/template/mcp_topic.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before post details in topic moderation
+
 mcp_topic_topic_title_after
 ===
 * Locations:
@@ -951,6 +982,14 @@ memberlist_body_username_prepend
 * Purpose: Add information before every username in the memberlist. Works in
 all display modes (leader, group and normal memberlist).
 
+memberlist_email_before
+===
+* Locations:
+    + styles/prosilver/template/memberlist_email.html
+    + styles/subsilver2/template/memberlist_email.html
+* Since: 3.1.10-RC1
+* Purpose: Allow adding customizations before the memberlist_email form.
+
 memberlist_search_fields_after
 ===
 * Locations:
@@ -1336,6 +1375,20 @@ overall_header_head_append
 * Since: 3.1.0-a1
 * Purpose: Add asset calls directly before the `</head>` tag
 
+overall_header_headerbar_after
+===
+* Locations:
+    + styles/prosilver/template/overall_header.html
+* Since: 3.1.10-RC1
+* Purpose: Add content at the end of the headerbar
+
+overall_header_headerbar_before
+===
+* Locations:
+    + styles/prosilver/template/overall_header.html
+* Since: 3.1.10-RC1
+* Purpose: Add content at the beginning of the headerbar
+
 overall_header_navbar_before
 ===
 * Locations:
@@ -1487,6 +1540,14 @@ posting_editor_subject_after
 * Since: 3.1.0-a2
 * Purpose: Add field (e.g. textbox) to the posting screen after the subject
 
+posting_editor_subject_append
+===
+* Locations:
+    + styles/prosilver/template/posting_editor.html
+    + styles/subsilver2/template/posting_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add field, text, etc. to the posting after the subject text box
+
 posting_editor_subject_before
 ===
 * Locations:
@@ -1495,6 +1556,14 @@ posting_editor_subject_before
 * Since: 3.1.0-a2
 * Purpose: Add field (e.g. textbox) to the posting screen before the subject
 
+posting_editor_subject_prepend
+===
+* Locations:
+    + styles/prosilver/template/posting_editor.html
+    + styles/subsilver2/template/posting_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add field, text, etc. to the posting before the subject text box
+
 posting_editor_submit_buttons
 ===
 * Locations:
@@ -1556,6 +1625,22 @@ posting_preview_poll_after
 * Since: 3.1.7-RC1
 * Purpose: Add content after the poll preview block
 
+posting_topic_review_row_post_details_after
+===
+* Locations:
+    + styles/prosilver/template/posting_topic_review.html
+    + styles/subsilver2/template/posting_topic_review.html
+* Since: 3.1.10-RC1
+* Purpose: Add content after post details in topic review
+
+posting_topic_review_row_post_details_before
+===
+* Locations:
+    + styles/prosilver/template/posting_topic_review.html
+    + styles/subsilver2/template/posting_topic_review.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before post details in topic review
+
 posting_topic_title_after
 ===
 * Locations:
@@ -1853,6 +1938,18 @@ topiclist_row_append
 * Changed: 3.1.6-RC1 Added event to mcp_forum.html
 * Purpose: Add content into topic rows (inside the elements containing topic titles)
 
+topiclist_row_topic_title_after
+===
+* Locations:
+    + styles/prosilver/template/search_results.html
+    + styles/prosilver/template/viewforum_body.html
+    + styles/prosilver/template/mcp_forum.html
+    + styles/subsilver2/template/search_results.html
+    + styles/subsilver2/template/viewforum_body.html
+    + styles/subsilver2/template/mcp_forum.html
+* Since: 3.1.10-RC1
+* Purpose: Add content into topic rows (after the elements containing the topic titles)
+
 ucp_agreement_terms_after
 ===
 * Locations:
@@ -2227,6 +2324,14 @@ viewforum_body_topic_row_prepend
 * Since: 3.1.7-RC1
 * Purpose: Add content at the end of the topic list item.
 
+viewforum_body_topicrow_row_before
+===
+* Locations:
+    + styles/prosilver/template/viewforum_body.html
+    + styles/subsilver2/template/viewforum_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before list of topics.
+
 viewforum_buttons_bottom_before
 ===
 * Locations:
--- a/docs/lighttpd.sample.conf
+++ b/docs/lighttpd.sample.conf
@@ -1,7 +1,7 @@
 # Sample lighttpd configuration file for phpBB.
 # Global settings have been removed, copy them
 # from your system's lighttpd.conf.
-# Tested with lighttpd 1.4.26
+# Tested with lighttpd 1.4.35
 
 # If you want to use the X-Sendfile feature,
 # uncomment the 'allow-x-send-file' for the fastcgi
@@ -16,6 +16,7 @@
 server.modules += ( 
 	"mod_access",
 	"mod_fastcgi",
+	"mod_rewrite",
 	"mod_accesslog"
 )
 
@@ -49,7 +50,15 @@ $HTTP["host"] == "www.myforums.com" {
 	$HTTP["url"] =~ "/\.htaccess|/\.htpasswd|/\.htgroups" {
 		url.access-deny = ( "" )
 	}
-
+	
+	# The following 3 lines will rewrite URLs passed through the front controller
+	# to not require app.php in the actual URL. In other words, a controller is
+	# by default accessed at /app.php/my/controller, but can also be accessed at
+	# /my/controller
+	url.rewrite-if-not-file = (
+	   "^/(.*)$" => "/app.php/$1"
+	)
+	
 	fastcgi.server = ( ".php" => 
 		((
 			"bin-path" => "/usr/bin/php-cgi",
--- a/feed.php
+++ b/feed.php
@@ -84,6 +84,20 @@ $feed->open();
 // Iterate through items
 while ($row = $feed->get_item())
 {
+	/**
+	* Event to modify the feed row
+	*
+	* @event core.feed_modify_feed_row
+	* @var	int		forum_id	Forum ID
+	* @var	string	mode		Feeds mode (forums|topics|topics_new|topics_active|news)
+	* @var	array	row			Array with feed data
+	* @var	int		topic_id	Topic ID
+	*
+	* @since 3.1.10-RC1
+	*/
+	$vars = array('forum_id', 'mode', 'row', 'topic_id');
+	extract($phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars)));
+
 	// BBCode options to correctly disable urls, smilies, bbcode...
 	if ($feed->get('options') === NULL)
 	{
--- a/includes/acp/acp_board.php
+++ b/includes/acp/acp_board.php
@@ -449,7 +449,7 @@ class acp_board
 
 						'legend2'				=> 'SMTP_SETTINGS',
 						'smtp_delivery'			=> array('lang' => 'USE_SMTP',				'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),
-						'smtp_host'				=> array('lang' => 'SMTP_SERVER',			'validate' => 'string',	'type' => 'text:25:50', 'explain' => false),
+						'smtp_host'				=> array('lang' => 'SMTP_SERVER',			'validate' => 'string',	'type' => 'text:25:50', 'explain' => true),
 						'smtp_port'				=> array('lang' => 'SMTP_PORT',				'validate' => 'int:0:99999',	'type' => 'number:0:99999', 'explain' => true),
 						'smtp_auth_method'		=> array('lang' => 'SMTP_AUTH_METHOD',		'validate' => 'string',	'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true),
 						'smtp_username'			=> array('lang' => 'SMTP_USERNAME',			'validate' => 'string',	'type' => 'text:25:255', 'explain' => true),
--- a/includes/acp/acp_database.php
+++ b/includes/acp/acp_database.php
@@ -39,6 +39,9 @@ class acp_database
 		$action	= request_var('action', '');
 		$submit = (isset($_POST['submit'])) ? true : false;
 
+		$form_key = 'acp_database';
+		add_form_key($form_key);
+
 		$template->assign_vars(array(
 			'MODE'	=> $mode
 		));
@@ -62,6 +65,11 @@ class acp_database
 							trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
 						}
 
+						if (!check_form_key($form_key))
+						{
+							trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+						}
+
 						$store = $download = $structure = $schema_data = false;
 
 						if ($where == 'store_and_download' || $where == 'store')
--- a/includes/acp/acp_forums.php
+++ b/includes/acp/acp_forums.php
@@ -842,9 +842,26 @@ class acp_forums
 			ORDER BY left_id";
 		$result = $db->sql_query($sql);
 
-		if ($row = $db->sql_fetchrow($result))
+		$rowset = array();
+		while ($row = $db->sql_fetchrow($result))
+		{
+			$rowset[(int) $row['forum_id']] = $row;
+		}
+		$db->sql_freeresult($result);
+
+		/**
+		* Modify the forum list data
+		*
+		* @event core.acp_manage_forums_modify_forum_list
+		* @var	array	rowset	Array with the forums list data
+		* @since 3.1.10-RC1
+		*/
+		$vars = array('rowset');
+		extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_modify_forum_list', compact($vars)));
+
+		if (!empty($rowset))
 		{
-			do
+			foreach ($rowset as $row)
 			{
 				$forum_type = $row['forum_type'];
 
@@ -888,7 +905,6 @@ class acp_forums
 					'U_SYNC'			=> $url . '&amp;action=sync')
 				);
 			}
-			while ($row = $db->sql_fetchrow($result));
 		}
 		else if ($this->parent_id)
 		{
@@ -904,7 +920,7 @@ class acp_forums
 				'U_SYNC'			=> $url . '&amp;action=sync')
 			);
 		}
-		$db->sql_freeresult($result);
+		unset($rowset);
 
 		$template->assign_vars(array(
 			'ERROR_MSG'		=> (sizeof($errors)) ? implode('<br />', $errors) : '',
--- a/includes/acp/acp_icons.php
+++ b/includes/acp/acp_icons.php
@@ -40,6 +40,10 @@ class acp_icons
 		$action = (isset($_POST['edit'])) ? 'edit' : $action;
 		$action = (isset($_POST['import'])) ? 'import' : $action;
 		$icon_id = request_var('id', 0);
+		$submit = $request->is_set_post('submit', false);
+
+		$form_key = 'acp_icons';
+		add_form_key($form_key);
 
 		$mode = ($mode == 'smilies') ? 'smilies' : 'icons';
 
@@ -325,6 +329,11 @@ class acp_icons
 			case 'create':
 			case 'modify':
 
+				if (!check_form_key($form_key))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				// Get items to create/modify
 				$images = (isset($_POST['image'])) ? array_keys(request_var('image', array('' => 0))) : array();
 
@@ -513,6 +522,11 @@ class acp_icons
 				{
 					$order = 0;
 
+					if (!check_form_key($form_key))
+					{
+						trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+					}
+
 					if (!($pak_ary = @file($phpbb_root_path . $img_path . '/' . $pak)))
 					{
 						trigger_error($user->lang['PAK_FILE_NOT_READABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -698,7 +712,7 @@ class acp_icons
 
 				$template->assign_vars(array(
 					'MESSAGE_TITLE'		=> $user->lang['EXPORT_' . $lang],
-					'MESSAGE_TEXT'		=> sprintf($user->lang['EXPORT_' . $lang . '_EXPLAIN'], '<a href="' . $this->u_action . '&amp;action=send">', '</a>'),
+					'MESSAGE_TEXT'		=> sprintf($user->lang['EXPORT_' . $lang . '_EXPLAIN'], '<a href="' . $this->u_action . '&amp;action=send&amp;hash=' . generate_link_hash('acp_icons') . '">', '</a>'),
 
 					'S_USER_NOTICE'		=> true,
 					)
@@ -710,6 +724,11 @@ class acp_icons
 
 			case 'send':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_icons'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = "SELECT *
 					FROM $table
 					ORDER BY {$fields}_order";
@@ -811,6 +830,11 @@ class acp_icons
 			case 'move_up':
 			case 'move_down':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_icons'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				// Get current order id...
 				$sql = "SELECT {$fields}_order as current_order
 					FROM $table
@@ -928,8 +952,8 @@ class acp_icons
 				'EMOTION'		=> (isset($row['emotion'])) ? $row['emotion'] : '',
 				'U_EDIT'		=> $this->u_action . '&amp;action=edit&amp;id=' . $row[$fields . '_id'],
 				'U_DELETE'		=> $this->u_action . '&amp;action=delete&amp;id=' . $row[$fields . '_id'],
-				'U_MOVE_UP'		=> $this->u_action . '&amp;action=move_up&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start,
-				'U_MOVE_DOWN'	=> $this->u_action . '&amp;action=move_down&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start,
+				'U_MOVE_UP'		=> $this->u_action . '&amp;action=move_up&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start . '&amp;hash=' . generate_link_hash('acp_icons'),
+				'U_MOVE_DOWN'	=> $this->u_action . '&amp;action=move_down&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start . '&amp;hash=' . generate_link_hash('acp_icons'),
 			));
 
 			if (!$spacer && !$row['display_on_posting'])
--- a/includes/acp/acp_language.php
+++ b/includes/acp/acp_language.php
@@ -244,6 +244,11 @@ class acp_language
 			break;
 
 			case 'install':
+				if (!check_link_hash($request->variable('hash', ''), 'acp_language'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$lang_iso = request_var('iso', '');
 				$lang_iso = basename($lang_iso);
 
@@ -423,7 +428,7 @@ class acp_language
 					'ISO'			=> htmlspecialchars($lang_ary['iso']),
 					'LOCAL_NAME'	=> htmlspecialchars($lang_ary['local_name'], ENT_COMPAT, 'UTF-8'),
 					'NAME'			=> htmlspecialchars($lang_ary['name'], ENT_COMPAT, 'UTF-8'),
-					'U_INSTALL'		=> $this->u_action . '&amp;action=install&amp;iso=' . urlencode($lang_ary['iso']))
+					'U_INSTALL'		=> $this->u_action . '&amp;action=install&amp;iso=' . urlencode($lang_ary['iso']) . '&amp;hash=' . generate_link_hash('acp_language'))
 				);
 			}
 		}
--- a/includes/acp/acp_main.php
+++ b/includes/acp/acp_main.php
@@ -453,6 +453,12 @@ class acp_main
 			$template->assign_var('S_VERSION_UP_TO_DATE', true);
 		}
 
+		// Incomplete update?
+		if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<'))
+		{
+			$template->assign_var('S_UPDATE_INCOMPLETE', true);
+		}
+
 		/**
 		* Notice admin
 		*
--- a/includes/acp/acp_modules.php
+++ b/includes/acp/acp_modules.php
@@ -46,6 +46,9 @@ class acp_modules
 		$user->add_lang('acp/modules');
 		$this->tpl_name = 'acp_modules';
 
+		$form_key = 'acp_modules';
+		add_form_key($form_key);
+
 		// module class
 		$this->module_class = $mode;
 
@@ -119,6 +122,11 @@ class acp_modules
 					trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
 				}
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_modules'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT *
 					FROM ' . MODULES_TABLE . "
 					WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
@@ -150,6 +158,11 @@ class acp_modules
 					trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
 				}
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_modules'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT *
 					FROM ' . MODULES_TABLE . "
 					WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
@@ -273,6 +286,11 @@ class acp_modules
 
 				if ($submit)
 				{
+					if (!check_form_key($form_key))
+					{
+						trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+					}
+
 					if (!$module_data['module_langname'])
 					{
 						trigger_error($user->lang['NO_MODULE_LANGNAME'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
@@ -460,12 +478,12 @@ class acp_modules
 					'S_ACP_MODULE_MANAGEMENT'	=> ($this->module_class == 'acp' && ($row['module_basename'] == 'modules' || $row['module_langname'] == 'ACP_MODULE_MANAGEMENT')) ? true : false,
 
 					'U_MODULE'			=> $this->u_action . '&amp;parent_id=' . $row['module_id'],
-					'U_MOVE_UP'			=> $url . '&amp;action=move_up',
-					'U_MOVE_DOWN'		=> $url . '&amp;action=move_down',
+					'U_MOVE_UP'			=> $url . '&amp;action=move_up&amp;hash=' . generate_link_hash('acp_modules'),
+					'U_MOVE_DOWN'		=> $url . '&amp;action=move_down&amp;hash=' . generate_link_hash('acp_modules'),
 					'U_EDIT'			=> $url . '&amp;action=edit',
 					'U_DELETE'			=> $url . '&amp;action=delete',
-					'U_ENABLE'			=> $url . '&amp;action=enable',
-					'U_DISABLE'			=> $url . '&amp;action=disable')
+					'U_ENABLE'			=> $url . '&amp;action=enable&amp;hash=' . generate_link_hash('acp_modules'),
+					'U_DISABLE'			=> $url . '&amp;action=disable&amp;hash=' . generate_link_hash('acp_modules'))
 				);
 			}
 			while ($row = $db->sql_fetchrow($result));
@@ -484,8 +502,8 @@ class acp_modules
 
 				'U_EDIT'			=> $url . '&amp;action=edit',
 				'U_DELETE'			=> $url . '&amp;action=delete',
-				'U_ENABLE'			=> $url . '&amp;action=enable',
-				'U_DISABLE'			=> $url . '&amp;action=disable')
+				'U_ENABLE'			=> $url . '&amp;action=enable&amp;hash=' . generate_link_hash('acp_modules'),
+				'U_DISABLE'			=> $url . '&amp;action=disable&amp;hash=' . generate_link_hash('acp_modules'))
 			);
 		}
 		$db->sql_freeresult($result);
--- a/includes/acp/acp_permission_roles.php
+++ b/includes/acp/acp_permission_roles.php
@@ -366,6 +366,11 @@ class acp_permission_roles
 			case 'move_up':
 			case 'move_down':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_permission_roles'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT role_order
 					FROM ' . ACL_ROLES_TABLE . "
 					WHERE role_id = $role_id";
@@ -440,8 +445,8 @@ class acp_permission_roles
 
 				'U_EDIT'			=> $this->u_action . '&amp;action=edit&amp;role_id=' . $row['role_id'],
 				'U_REMOVE'			=> $this->u_action . '&amp;action=remove&amp;role_id=' . $row['role_id'],
-				'U_MOVE_UP'			=> $this->u_action . '&amp;action=move_up&amp;role_id=' . $row['role_id'],
-				'U_MOVE_DOWN'		=> $this->u_action . '&amp;action=move_down&amp;role_id=' . $row['role_id'],
+				'U_MOVE_UP'			=> $this->u_action . '&amp;action=move_up&amp;role_id=' . $row['role_id'] . '&amp;hash=' . generate_link_hash('acp_permission_roles'),
+				'U_MOVE_DOWN'		=> $this->u_action . '&amp;action=move_down&amp;role_id=' . $row['role_id'] . '&amp;hash=' . generate_link_hash('acp_permission_roles'),
 				'U_DISPLAY_ITEMS'	=> ($row['role_id'] == $display_item) ? '' : $this->u_action . '&amp;display_item=' . $row['role_id'] . '#assigned_to')
 			);
 
--- a/includes/acp/acp_profile.php
+++ b/includes/acp/acp_profile.php
@@ -53,6 +53,9 @@ class acp_profile
 		$error = array();
 		$s_hidden_fields = '';
 
+		$form_key = 'acp_profile';
+		add_form_key($form_key);
+
 		if (!$field_id && in_array($action, array('delete','activate', 'deactivate', 'move_up', 'move_down', 'edit')))
 		{
 			trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -161,6 +164,11 @@ class acp_profile
 
 			case 'activate':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_profile'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT lang_id
 					FROM ' . LANG_TABLE . "
 					WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
@@ -201,6 +209,11 @@ class acp_profile
 
 			case 'deactivate':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_profile'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . "
 					SET field_active = 0
 					WHERE field_id = $field_id";
@@ -230,6 +243,11 @@ class acp_profile
 			case 'move_up':
 			case 'move_down':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_profile'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT field_order
 					FROM ' . PROFILE_FIELDS_TABLE . "
 					WHERE field_id = $field_id";
@@ -579,6 +597,11 @@ class acp_profile
 
 				if (!sizeof($error))
 				{
+					if (!check_form_key($form_key))
+					{
+						trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+					}
+
 					if (($step == 3 && (sizeof($this->lang_defs['iso']) == 1 || $save)) || ($action == 'edit' && $save))
 					{
 						$this->save_profile_field($cp, $field_type, $action);
@@ -735,12 +758,12 @@ class acp_profile
 				'FIELD_TYPE'		=> $profile_field->get_name(),
 
 				'L_ACTIVATE_DEACTIVATE'		=> $user->lang[$active_lang],
-				'U_ACTIVATE_DEACTIVATE'		=> $this->u_action . "&amp;action=$active_value&amp;field_id=$id",
+				'U_ACTIVATE_DEACTIVATE'		=> $this->u_action . "&amp;action=$active_value&amp;field_id=$id" . '&amp;hash=' . generate_link_hash('acp_profile'),
 				'U_EDIT'					=> $this->u_action . "&amp;action=edit&amp;field_id=$id",
 				'U_TRANSLATE'				=> $this->u_action . "&amp;action=edit&amp;field_id=$id&amp;step=3",
 				'U_DELETE'					=> $this->u_action . "&amp;action=delete&amp;field_id=$id",
-				'U_MOVE_UP'					=> $this->u_action . "&amp;action=move_up&amp;field_id=$id",
-				'U_MOVE_DOWN'				=> $this->u_action . "&amp;action=move_down&amp;field_id=$id",
+				'U_MOVE_UP'					=> $this->u_action . "&amp;action=move_up&amp;field_id=$id" . '&amp;hash=' . generate_link_hash('acp_profile'),
+				'U_MOVE_DOWN'				=> $this->u_action . "&amp;action=move_down&amp;field_id=$id" . '&amp;hash=' . generate_link_hash('acp_profile'),
 
 				'S_NEED_EDIT'				=> $s_need_edit)
 			);
--- a/includes/acp/acp_reasons.php
+++ b/includes/acp/acp_reasons.php
@@ -282,6 +282,11 @@ class acp_reasons
 			case 'move_up':
 			case 'move_down':
 
+				if (!check_link_hash($request->variable('hash', ''), 'acp_reasons'))
+				{
+					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+				}
+
 				$sql = 'SELECT reason_order
 					FROM ' . REPORTS_REASONS_TABLE . "
 					WHERE reason_id = $reason_id";
@@ -383,8 +388,8 @@ class acp_reasons
 
 				'U_EDIT'		=> $this->u_action . '&amp;action=edit&amp;id=' . $row['reason_id'],
 				'U_DELETE'		=> (!$other_reason) ? $this->u_action . '&amp;action=delete&amp;id=' . $row['reason_id'] : '',
-				'U_MOVE_UP'		=> $this->u_action . '&amp;action=move_up&amp;id=' . $row['reason_id'],
-				'U_MOVE_DOWN'	=> $this->u_action . '&amp;action=move_down&amp;id=' . $row['reason_id'])
+				'U_MOVE_UP'		=> $this->u_action . '&amp;action=move_up&amp;id=' . $row['reason_id'] . '&amp;hash=' . generate_link_hash('acp_reasons'),
+				'U_MOVE_DOWN'	=> $this->u_action . '&amp;action=move_down&amp;id=' . $row['reason_id'] . '&amp;hash=' . generate_link_hash('acp_reasons'))
 			);
 		}
 		$db->sql_freeresult($result);
--- a/includes/acp/acp_search.php
+++ b/includes/acp/acp_search.php
@@ -54,6 +54,13 @@ class acp_search
 		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
 
 		$submit = (isset($_POST['submit'])) ? true : false;
+		$form_key = 'acp_search';
+		add_form_key($form_key);
+
+		if ($submit && !check_form_key($form_key))
+		{
+			trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+		}
 
 		$search_types = $this->get_search_types();
 
@@ -232,7 +239,7 @@ class acp_search
 
 	function index($id, $mode)
 	{
-		global $db, $user, $auth, $template, $cache;
+		global $db, $user, $auth, $template, $cache, $request;
 		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
 
 		$action = request_var('action', '');
@@ -244,6 +251,15 @@ class acp_search
 			$this->state = array();
 			$this->save_state();
 		}
+		$submit = $request->is_set_post('submit', false);
+
+		$form_key = 'acp_search';
+		add_form_key($form_key);
+
+		if (!check_form_key($form_key) && in_array($action, array('delete', 'create')))
+		{
+			trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+		}
 
 		if ($action)
 		{
--- a/includes/acp/acp_update.php
+++ b/includes/acp/acp_update.php
@@ -62,5 +62,17 @@ class acp_update
 
 			'UPDATE_INSTRUCTIONS'	=> sprintf($user->lang['UPDATE_INSTRUCTIONS'], $update_link),
 		));
+
+		// Incomplete update?
+		if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<'))
+		{
+			$database_update_link = append_sid($phpbb_root_path . 'install/database_update.' . $phpEx);
+
+			$template->assign_vars(array(
+				'S_UPDATE_INCOMPLETE'		=> true,
+				'FILES_VERSION'				=> PHPBB_VERSION,
+				'INCOMPLETE_INSTRUCTIONS'	=> $user->lang('UPDATE_INCOMPLETE_EXPLAIN', $database_update_link),
+			));
+		}
 	}
 }
--- a/includes/acp/acp_users.php
+++ b/includes/acp/acp_users.php
@@ -2274,6 +2274,12 @@ class acp_users
 						{
 							trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
 						}
+
+						if (!check_link_hash($request->variable('hash', ''), 'acp_users'))
+						{
+							trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+						}
+
 						group_user_attributes($action, $group_id, $user_id);
 
 						if ($action == 'default')
@@ -2431,8 +2437,8 @@ class acp_users
 					{
 						$template->assign_block_vars('group', array(
 							'U_EDIT_GROUP'		=> append_sid("{$phpbb_admin_path}index.$phpEx", "i=groups&amp;mode=manage&amp;action=edit&amp;u=$user_id&amp;g={$data['group_id']}&amp;back_link=acp_users_groups"),
-							'U_DEFAULT'			=> $this->u_action . "&amp;action=default&amp;u=$user_id&amp;g=" . $data['group_id'],
-							'U_DEMOTE_PROMOTE'	=> $this->u_action . '&amp;action=' . (($data['group_leader']) ? 'demote' : 'promote') . "&amp;u=$user_id&amp;g=" . $data['group_id'],
+							'U_DEFAULT'			=> $this->u_action . "&amp;action=default&amp;u=$user_id&amp;g=" . $data['group_id'] . '&amp;hash=' . generate_link_hash('acp_users'),
+							'U_DEMOTE_PROMOTE'	=> $this->u_action . '&amp;action=' . (($data['group_leader']) ? 'demote' : 'promote') . "&amp;u=$user_id&amp;g=" . $data['group_id'] . '&amp;hash=' . generate_link_hash('acp_users'),
 							'U_DELETE'			=> $this->u_action . "&amp;action=delete&amp;u=$user_id&amp;g=" . $data['group_id'],
 							'U_APPROVE'			=> ($group_type == 'pending') ? $this->u_action . "&amp;action=approve&amp;u=$user_id&amp;g=" . $data['group_id'] : '',
 
--- a/includes/constants.php
+++ b/includes/constants.php
@@ -28,7 +28,7 @@ if (!defined('IN_PHPBB'))
 */
 
 // phpBB Version
-define('PHPBB_VERSION', '3.1.9');
+define('PHPBB_VERSION', '3.1.10');
 
 // QA-related
 // define('PHPBB_QA', 1);
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -4334,6 +4334,30 @@ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum'
 			}
 		}
 	}
+
+	/**
+	* Modify online userlist data
+	*
+	* @event core.obtain_users_online_string_before_modify
+	* @var	array	online_users		Array with online users data
+	*									from obtain_users_online()
+	* @var	int		item_id				Restrict online users to item id
+	* @var	string	item				Restrict online users to a certain
+	*									session item, e.g. forum for
+	*									session_forum_id
+	* @var	array	rowset				Array with online users data
+	* @var	array	user_online_link	Array with online users items (usernames)
+	* @since 3.1.10-RC1
+	*/
+	$vars = array(
+		'online_users',
+		'item_id',
+		'item',
+		'rowset',
+		'user_online_link',
+	);
+	extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_before_modify', compact($vars)));
+
 	$online_userlist = implode(', ', $user_online_link);
 
 	if (!$online_userlist)
--- a/includes/functions_admin.php
+++ b/includes/functions_admin.php
@@ -65,7 +65,7 @@ function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = ar
 */
 function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $only_acl_post = false, $return_array = false)
 {
-	global $db, $user, $auth;
+	global $db, $user, $auth, $phpbb_dispatcher;
 
 	// This query is identical to the jumpbox one
 	$sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id
@@ -73,16 +73,33 @@ function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl =
 		ORDER BY left_id ASC';
 	$result = $db->sql_query($sql, 600);
 
+	$rowset = array();
+	while ($row = $db->sql_fetchrow($result))
+	{
+		$rowset[(int) $row['forum_id']] = $row;
+	}
+	$db->sql_freeresult($result);
+
 	$right = 0;
 	$padding_store = array('0' => '');
 	$padding = '';
 	$forum_list = ($return_array) ? array() : '';
 
+	/**
+	* Modify the forum list data
+	*
+	* @event core.make_forum_select_modify_forum_list
+	* @var	array	rowset	Array with the forums list data
+	* @since 3.1.10-RC1
+	*/
+	$vars = array('rowset');
+	extract($phpbb_dispatcher->trigger_event('core.make_forum_select_modify_forum_list', compact($vars)));
+
 	// Sometimes it could happen that forums will be displayed here not be displayed within the index page
 	// This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
 	// If this happens, the padding could be "broken"
 
-	while ($row = $db->sql_fetchrow($result))
+	foreach ($rowset as $row)
 	{
 		if ($row['left_id'] < $right)
 		{
@@ -133,8 +150,7 @@ function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl =
 			$forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>';
 		}
 	}
-	$db->sql_freeresult($result);
-	unset($padding_store);
+	unset($padding_store, $rowset);
 
 	return $forum_list;
 }
@@ -201,7 +217,7 @@ function group_select_options($group_id, $exclude_ids = false, $manage_founder =
 */
 function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
 {
-	global $db, $auth;
+	global $db, $auth, $phpbb_dispatcher;
 	static $forum_rows;
 
 	if (!isset($forum_rows))
@@ -256,6 +272,16 @@ function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only =
 		}
 	}
 
+	/**
+	* Modify the forum list data
+	*
+	* @event core.get_forum_list_modify_data
+	* @var	array	rowset	Array with the forum list data
+	* @since 3.1.10-RC1
+	*/
+	$vars = array('rowset');
+	extract($phpbb_dispatcher->trigger_event('core.get_forum_list_modify_data', compact($vars)));
+
 	return $rowset;
 }
 
@@ -2531,7 +2557,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
 /**
 * Prune function
 */
-function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true)
+function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true, $prune_limit = 0)
 {
 	global $db, $phpbb_dispatcher;
 
@@ -2583,9 +2609,19 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
 	* @var int		prune_flags		The prune flags
 	* @var bool		auto_sync		Whether or not to perform auto sync
 	* @var string	sql_and			SQL text appended to where clause
+	* @var int		prune_limit		The prune limit
 	* @since 3.1.3-RC1
+	* @changed 3.1.10-RC1			Added prune_limit
 	*/
-	$vars = array('forum_id', 'prune_mode', 'prune_date', 'prune_flags', 'auto_sync', 'sql_and');
+	$vars = array(
+		'forum_id',
+		'prune_mode',
+		'prune_date',
+		'prune_flags',
+		'auto_sync',
+		'sql_and',
+		'prune_limit',
+	);
 	extract($phpbb_dispatcher->trigger_event('core.prune_sql', compact($vars)));
 
 	$sql = 'SELECT topic_id
@@ -2593,7 +2629,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
 		WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
 			AND poll_start = 0
 			$sql_and";
-	$result = $db->sql_query($sql);
+	$result = $db->sql_query_limit($sql, $prune_limit);
 
 	$topic_list = array();
 	while ($row = $db->sql_fetchrow($result))
@@ -2610,7 +2646,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
 				AND poll_start > 0
 				AND poll_last_vote < $prune_date
 				$sql_and";
-		$result = $db->sql_query($sql);
+		$result = $db->sql_query_limit($sql, $prune_limit);
 
 		while ($row = $db->sql_fetchrow($result))
 		{
@@ -2643,12 +2679,15 @@ function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_fr
 		$prune_date = time() - ($prune_days * 86400);
 		$next_prune = time() + ($prune_freq * 86400);
 
-		prune($forum_id, $prune_mode, $prune_date, $prune_flags, true);
+		$result = prune($forum_id, $prune_mode, $prune_date, $prune_flags, true, 300);
 
-		$sql = 'UPDATE ' . FORUMS_TABLE . "
-			SET prune_next = $next_prune
-			WHERE forum_id = $forum_id";
-		$db->sql_query($sql);
+		if ($result['topics'] == 0 && $result['posts'] == 0)
+		{
+			$sql = 'UPDATE ' . FORUMS_TABLE . "
+				SET prune_next = $next_prune
+				WHERE forum_id = $forum_id";
+			$db->sql_query($sql);
+		}
 
 		add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
 	}
--- a/includes/functions_content.php
+++ b/includes/functions_content.php
@@ -150,7 +150,7 @@ function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key,
 */
 function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false, $force_display = false)
 {
-	global $config, $auth, $template, $user, $db, $phpbb_path_helper;
+	global $config, $auth, $template, $user, $db, $phpbb_path_helper, $phpbb_dispatcher;
 
 	// We only return if the jumpbox is not forced to be displayed (in case it is needed for functionality)
 	if (!$config['load_jumpbox'] && $force_display === false)
@@ -163,16 +163,33 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list
 		ORDER BY left_id ASC';
 	$result = $db->sql_query($sql, 600);
 
+	$rowset = array();
+	while ($row = $db->sql_fetchrow($result))
+	{
+		$rowset[(int) $row['forum_id']] = $row;
+	}
+	$db->sql_freeresult($result);
+
 	$right = $padding = 0;
 	$padding_store = array('0' => 0);
 	$display_jumpbox = false;
 	$iteration = 0;
 
+	/**
+	* Modify the jumpbox forum list data
+	*
+	* @event core.make_jumpbox_modify_forum_list
+	* @var	array	rowset	Array with the forums list data
+	* @since 3.1.10-RC1
+	*/
+	$vars = array('rowset');
+	extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_forum_list', compact($vars)));
+
 	// Sometimes it could happen that forums will be displayed here not be displayed within the index page
 	// This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
 	// If this happens, the padding could be "broken"
 
-	while ($row = $db->sql_fetchrow($result))
+	foreach ($rowset as $row)
 	{
 		if ($row['left_id'] < $right)
 		{
@@ -205,20 +222,21 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list
 			continue;
 		}
 
+		$tpl_ary = array();
 		if (!$display_jumpbox)
 		{
-			$template->assign_block_vars('jumpbox_forums', array(
+			$tpl_ary[] = array(
 				'FORUM_ID'		=> ($select_all) ? 0 : -1,
 				'FORUM_NAME'	=> ($select_all) ? $user->lang['ALL_FORUMS'] : $user->lang['SELECT_FORUM'],
 				'S_FORUM_COUNT'	=> $iteration,
 				'LINK'			=> $phpbb_path_helper->append_url_params($action, array('f' => $forum_id)),
-			));
+			);
 
 			$iteration++;
 			$display_jumpbox = true;
 		}
 
-		$template->assign_block_vars('jumpbox_forums', array(
+		$tpl_ary[] = array(
 			'FORUM_ID'		=> $row['forum_id'],
 			'FORUM_NAME'	=> $row['forum_name'],
 			'SELECTED'		=> ($row['forum_id'] == $forum_id) ? ' selected="selected"' : '',
@@ -227,7 +245,25 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list
 			'S_IS_LINK'		=> ($row['forum_type'] == FORUM_LINK) ? true : false,
 			'S_IS_POST'		=> ($row['forum_type'] == FORUM_POST) ? true : false,
 			'LINK'			=> $phpbb_path_helper->append_url_params($action, array('f' => $row['forum_id'])),
-		));
+		);
+
+		/**
+		 * Modify the jumpbox before it is assigned to the template
+		 *
+		 * @event core.make_jumpbox_modify_tpl_ary
+		 * @var	array	row				The data of the forum
+		 * @var	array	tpl_ary			Template data of the forum
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'row',
+			'tpl_ary',
+		);
+		extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_tpl_ary', compact($vars)));
+
+		$template->assign_block_vars_array('jumpbox_forums', $tpl_ary);
+
+		unset($tpl_ary);
 
 		for ($i = 0; $i < $padding; $i++)
 		{
@@ -235,8 +271,7 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list
 		}
 		$iteration++;
 	}
-	$db->sql_freeresult($result);
-	unset($padding_store);
+	unset($padding_store, $rowset);
 
 	$url_parts = $phpbb_path_helper->get_url_parts($action);
 
--- a/includes/functions_download.php
+++ b/includes/functions_download.php
@@ -166,7 +166,7 @@ function send_file_to_browser($attachment, $upload_dir, $category)
 	}
 
 	// Make sure the database record for the filesize is correct
-	if ($size > 0 && $size != $attachment['filesize'])
+	if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false)
 	{
 		// Update database record
 		$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
@@ -284,7 +284,7 @@ function header_filename($file)
 
 	// There be dragons here.
 	// Not many follows the RFC...
-	if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Safari') !== false || strpos($user_agent, 'Konqueror') !== false)
+	if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false)
 	{
 		return "filename=" . rawurlencode($file);
 	}
--- a/includes/functions_messenger.php
+++ b/includes/functions_messenger.php
@@ -231,6 +231,13 @@ class messenger
 			$template_lang = basename($config['default_lang']);
 		}
 
+		$ext_template_paths = array(
+			array(
+				'name' 		=> $template_lang . '_email',
+				'ext_path' 	=> 'language/' . $template_lang . '/email' . $template_dir_prefix,
+			),
+		);
+
 		if ($template_path)
 		{
 			$template_paths = array(
@@ -246,23 +253,38 @@ class messenger
 				$template_path . $template_dir_prefix,
 			);
 
+			$board_language = basename($config['default_lang']);
+
 			// we can only specify default language fallback when the path is not a custom one for which we
 			// do not know the default language alternative
-			if ($template_lang !== basename($config['default_lang']))
+			if ($template_lang !== $board_language)
 			{
 				$fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
-				$fallback_template_path .= basename($config['default_lang']) . '/email';
+				$fallback_template_path .= $board_language . '/email';
 
 				$template_paths[] = $fallback_template_path . $template_dir_prefix;
+
+				$ext_template_paths[] = array(
+					'name'		=> $board_language . '_email',
+					'ext_path'	=> 'language/' . $board_language . '/email' . $template_dir_prefix,
+				);
+			}
+			// If everything fails just fall back to en template
+			if ($template_lang !== 'en' && $board_language !== 'en')
+			{
+				$fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
+				$fallback_template_path .= 'en/email';
+
+				$template_paths[] = $fallback_template_path . $template_dir_prefix;
+
+				$ext_template_paths[] = array(
+					'name'		=> 'en_email',
+					'ext_path'	=> 'language/en/email' . $template_dir_prefix,
+				);
 			}
 		}
 
-		$this->set_template_paths(array(
-			array(
-				'name' 		=> $template_lang . '_email',
-				'ext_path' 	=> 'language/' . $template_lang . '/email' . $template_dir_prefix,
-			),
-		), $template_paths);
+		$this->set_template_paths($ext_template_paths, $template_paths);
 
 		$this->template->set_filenames(array(
 			'body'		=> $template_file . '.txt',
--- a/includes/functions_posting.php
+++ b/includes/functions_posting.php
@@ -702,7 +702,7 @@ function create_thumbnail($source, $destination, $mimetype)
 
 	$used_imagick = false;
 
-	// Only use imagemagick if defined and the passthru function not disabled
+	// Only use ImageMagick if defined and the passthru function not disabled
 	if ($config['img_imagick'] && function_exists('passthru'))
 	{
 		if (substr($config['img_imagick'], -1) !== '/')
--- a/includes/functions_user.php
+++ b/includes/functions_user.php
@@ -119,19 +119,29 @@ function user_update_name($old_name, $new_name)
 	global $config, $db, $cache, $phpbb_dispatcher;
 
 	$update_ary = array(
-		FORUMS_TABLE			=> array('forum_last_poster_name'),
-		MODERATOR_CACHE_TABLE	=> array('username'),
-		POSTS_TABLE				=> array('post_username'),
-		TOPICS_TABLE			=> array('topic_first_poster_name', 'topic_last_poster_name'),
+		FORUMS_TABLE			=> array(
+			'forum_last_poster_id'	=> 'forum_last_poster_name',
+		),
+		MODERATOR_CACHE_TABLE	=> array(
+			'user_id'	=> 'username',
+		),
+		POSTS_TABLE				=> array(
+			'poster_id'	=> 'post_username',
+		),
+		TOPICS_TABLE			=> array(
+			'topic_poster'			=> 'topic_first_poster_name',
+			'topic_last_poster_id'	=> 'topic_last_poster_name',
+		),
 	);
 
 	foreach ($update_ary as $table => $field_ary)
 	{
-		foreach ($field_ary as $field)
+		foreach ($field_ary as $id_field => $name_field)
 		{
 			$sql = "UPDATE $table
-				SET $field = '" . $db->sql_escape($new_name) . "'
-				WHERE $field = '" . $db->sql_escape($old_name) . "'";
+				SET $name_field = '" . $db->sql_escape($new_name) . "'
+				WHERE $name_field = '" . $db->sql_escape($old_name) . "'
+					AND $id_field <> " . ANONYMOUS;
 			$db->sql_query($sql);
 		}
 	}
@@ -3076,7 +3086,7 @@ function remove_default_rank($group_id, $user_ids)
 */
 function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false)
 {
-	global $db, $auth, $phpbb_root_path, $phpEx, $config, $phpbb_container;
+	global $db, $auth, $phpbb_root_path, $phpEx, $config, $phpbb_container, $phpbb_dispatcher;
 
 	// We need both username and user_id info
 	$result = user_get_id_name($user_id_ary, $username_ary);
@@ -3207,6 +3217,28 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
 		break;
 	}
 
+	/**
+	* Event to perform additional actions on setting user group attributes
+	*
+	* @event core.user_set_group_attributes
+	* @var	int		group_id			ID of the group
+	* @var	string	group_name			Name of the group
+	* @var	array	user_id_ary			IDs of the users to set group attributes
+	* @var	array	username_ary		Names of the users to set group attributes
+	* @var	array	group_attributes	Group attributes which were changed
+	* @var	string	action				Action to perform over the group members
+	* @since 3.1.10-RC1
+	*/
+	$vars = array(
+		'group_id',
+		'group_name',
+		'user_id_ary',
+		'username_ary',
+		'group_attributes',
+		'action',
+	);
+	extract($phpbb_dispatcher->trigger_event('core.user_set_group_attributes', compact($vars)));
+
 	// Clear permissions cache of relevant users
 	$auth->acl_clear_prefetch($user_id_ary);
 
--- a/includes/mcp/mcp_forum.php
+++ b/includes/mcp/mcp_forum.php
@@ -273,7 +273,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
 			'TOPIC_ICON_IMG_WIDTH'	=> (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
 			'TOPIC_ICON_IMG_HEIGHT'	=> (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
 			'UNAPPROVED_IMG'		=> ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
-			'DELETED_IMG'			=> ($topic_deleted) ? $user->img('icon_topic_deleted', 'POSTS_DELETED') : '',
+			'DELETED_IMG'			=> ($topic_deleted) ? $user->img('icon_topic_deleted', 'TOPIC_DELETED') : '',
 
 			'TOPIC_AUTHOR'				=> get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
 			'TOPIC_AUTHOR_COLOUR'		=> get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
--- a/includes/mcp/mcp_main.php
+++ b/includes/mcp/mcp_main.php
@@ -877,11 +877,12 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
 		}
 
 		$template->assign_vars(array(
-			'S_SHADOW_TOPICS'		=> $only_shadow,
-			'S_SOFTDELETED'			=> $only_softdeleted,
-			'S_TOPIC_MODE'			=> true,
-			'S_ALLOWED_DELETE'		=> $auth->acl_get('m_delete', $forum_id),
-			'S_ALLOWED_SOFTDELETE'	=> $auth->acl_get('m_softdelete', $forum_id),
+			'S_SHADOW_TOPICS'					=> $only_shadow,
+			'S_SOFTDELETED'						=> $only_softdeleted,
+			'S_TOPIC_MODE'						=> true,
+			'S_ALLOWED_DELETE'					=> $auth->acl_get('m_delete', $forum_id),
+			'S_ALLOWED_SOFTDELETE'				=> $auth->acl_get('m_softdelete', $forum_id),
+			'DELETE_TOPIC_PERMANENTLY_EXPLAIN'	=> $user->lang('DELETE_TOPIC_PERMANENTLY', sizeof($topic_ids)),
 		));
 
 		$l_confirm = (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
@@ -1116,9 +1117,10 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
 		}
 
 		$template->assign_vars(array(
-			'S_SOFTDELETED'			=> $only_softdeleted,
-			'S_ALLOWED_DELETE'		=> $auth->acl_get('m_delete', $forum_id),
-			'S_ALLOWED_SOFTDELETE'	=> $auth->acl_get('m_softdelete', $forum_id),
+			'S_SOFTDELETED'						=> $only_softdeleted,
+			'S_ALLOWED_DELETE'					=> $auth->acl_get('m_delete', $forum_id),
+			'S_ALLOWED_SOFTDELETE'				=> $auth->acl_get('m_softdelete', $forum_id),
+			'DELETE_POST_PERMANENTLY_EXPLAIN'	=> $user->lang('DELETE_POST_PERMANENTLY', sizeof($post_ids)),
 		));
 
 		$l_confirm = (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS';
--- a/includes/ucp/ucp_main.php
+++ b/includes/ucp/ucp_main.php
@@ -35,7 +35,7 @@ class ucp_main
 
 	function main($id, $mode)
 	{
-		global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+		global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
 		global $request;
 
 		switch ($mode)
@@ -215,6 +215,14 @@ class ucp_main
 
 				$unwatch = (isset($_POST['unwatch'])) ? true : false;
 
+				/**
+				 * Read and potentially modify the post data used to remove subscriptions to forums/topics
+				 *
+				 * @event core.ucp_main_subscribed_post_data
+				 * @since 3.1.10-RC1
+				 */
+				$phpbb_dispatcher->dispatch('core.ucp_main_subscribed_post_data');
+
 				if ($unwatch)
 				{
 					if (check_form_key('ucp_front_subscribed'))
@@ -300,6 +308,20 @@ class ucp_main
 						$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
 					}
 
+					/**
+					 * Modify the query used to retrieve a list of subscribed forums
+					 *
+					 * @event core.ucp_main_subscribed_forums_modify_query
+					 * @var array	sql_array	       The subscribed forums query
+					 * @var array   forbidden_forums   The list of forbidden forums
+					 * @since 3.1.10-RC1
+					 */
+					$vars = array(
+						'sql_array',
+						'forbidden_forums',
+					);
+					extract($phpbb_dispatcher->trigger_event('core.ucp_main_subscribed_forums_modify_query', compact($vars)));
+
 					$sql = $db->sql_build_query('SELECT', $sql_array);
 					$result = $db->sql_query($sql);
 
@@ -341,7 +363,7 @@ class ucp_main
 							$last_post_time = $last_post_url = '';
 						}
 
-						$template->assign_block_vars('forumrow', array(
+						$template_vars = array(
 							'FORUM_ID'				=> $forum_id,
 							'FORUM_IMG_STYLE'		=> $folder_image,
 							'FORUM_FOLDER_IMG'		=> $user->img($folder_image, $folder_alt),
@@ -360,8 +382,36 @@ class ucp_main
 							'S_UNREAD_FORUM'		=> $unread_forum,
 
 							'U_LAST_POST'			=> $last_post_url,
-							'U_VIEWFORUM'			=> append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']))
+							'U_VIEWFORUM'			=> append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id'])
+						);
+
+						/**
+						 * Add template variables to a subscribed forum row.
+						 *
+						 * @event core.ucp_main_subscribed_forum_modify_template_vars
+						 * @var array	template_vars	Array containing the template variables for the row
+						 * @var array   row    	        Array containing the subscribed forum row data
+						 * @var int     forum_id        Forum ID
+						 * @var string  folder_image	Folder image
+						 * @var string  folder_alt      Alt text for the folder image
+						 * @var bool    unread_forum    Whether the forum has unread content or not
+						 * @var string  last_post_time  The time of the most recent post, expressed as a formatted date string
+						 * @var string  last_post_url   The URL of the most recent post in the forum
+						 * @since 3.1.10-RC1
+						 */
+						$vars = array(
+							'template_vars',
+							'row',
+							'forum_id',
+							'folder_image',
+							'folder_alt',
+							'unread_forum',
+							'last_post_time',
+							'last_post_url',
 						);
+						extract($phpbb_dispatcher->trigger_event('core.ucp_main_subscribed_forum_modify_template_vars', compact($vars)));
+
+						$template->assign_block_vars('forumrow', $template_vars);
 					}
 					$db->sql_freeresult($result);
 				}
@@ -643,7 +693,7 @@ class ucp_main
 	*/
 	function assign_topiclist($mode = 'subscribed', $forbidden_forum_ary = array())
 	{
-		global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_container;
+		global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_container, $request, $phpbb_dispatcher;
 
 		$table = ($mode == 'subscribed') ? TOPICS_WATCH_TABLE : BOOKMARKS_TABLE;
 		$start = request_var('start', 0);
@@ -664,6 +714,23 @@ class ucp_main
 				AND i.user_id = ' . $user->data['user_id'] . '
 				AND ' . $db->sql_in_set('t.forum_id', $forbidden_forum_ary, true, true),
 		);
+
+		/**
+		 * Modify the query used to retrieve the count of subscribed/bookmarked topics
+		 *
+		 * @event core.ucp_main_topiclist_count_modify_query
+		 * @var array	sql_array	          The subscribed/bookmarked topics query
+		 * @var array   forbidden_forum_ary   The list of forbidden forums
+		 * @var string  mode                  The type of topic list ('subscribed' or 'bookmarks')
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'sql_array',
+			'forbidden_forum_ary',
+			'mode',
+		);
+		extract($phpbb_dispatcher->trigger_event('core.ucp_main_topiclist_count_modify_query', compact($vars)));
+
 		$sql = $db->sql_build_query('SELECT', $sql_array);
 		$result = $db->sql_query($sql);
 		$topics_count = (int) $db->sql_fetchfield('topics_count');
@@ -732,6 +799,22 @@ class ucp_main
 			$sql_array['SELECT'] .= ', tp.topic_posted';
 		}
 
+		/**
+		 * Modify the query used to retrieve the list of subscribed/bookmarked topics
+		 *
+		 * @event core.ucp_main_topiclist_modify_query
+		 * @var array	sql_array	          The subscribed/bookmarked topics query
+		 * @var array   forbidden_forum_ary   The list of forbidden forums
+		 * @var string  mode                  The type of topic list ('subscribed' or 'bookmarks')
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'sql_array',
+			'forbidden_forum_ary',
+			'mode',
+		);
+		extract($phpbb_dispatcher->trigger_event('core.ucp_main_topiclist_modify_query', compact($vars)));
+
 		$sql = $db->sql_build_query('SELECT', $sql_array);
 		$result = $db->sql_query_limit($sql, $config['topics_per_page'], $start);
 
@@ -796,7 +879,7 @@ class ucp_main
 			$view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params);
 
 			// Send vars to template
-			$template->assign_block_vars('topicrow', array(
+			$template_vars = array(
 				'FORUM_ID'					=> $forum_id,
 				'TOPIC_ID'					=> $topic_id,
 				'FIRST_POST_TIME'			=> $user->format_date($row['topic_time']),
@@ -838,7 +921,41 @@ class ucp_main
 				'U_LAST_POST'			=> append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'],
 				'U_VIEW_TOPIC'			=> $view_topic_url,
 				'U_VIEW_FORUM'			=> append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
-			));
+			);
+
+			/**
+			 * Add template variables to a subscribed/bookmarked topic row.
+			 *
+			 * @event core.ucp_main_topiclist_topic_modify_template_vars
+			 * @var array	template_vars	Array containing the template variables for the row
+			 * @var array   row    	        Array containing the subscribed/bookmarked topic row data
+			 * @var int     forum_id        ID of the forum containing the topic
+			 * @var int     topic_id        Topic ID
+			 * @var int     replies         Number of replies in the topic
+			 * @var string  topic_type      Topic type
+			 * @var string  folder_img      Folder image
+			 * @var string  folder_alt      Alt text for the folder image
+			 * @var array   icons           Array containing topic icons
+			 * @var bool    unread_topic    Whether the topic has unread content or not
+			 * @var string  view_topic_url  The URL of the topic
+			 * @since 3.1.10-RC1
+			 */
+			$vars = array(
+				'template_vars',
+				'row',
+				'forum_id',
+				'topic_id',
+				'replies',
+				'topic_type',
+				'folder_img',
+				'folder_alt',
+				'icons',
+				'unread_topic',
+				'view_topic_url',
+			);
+			extract($phpbb_dispatcher->trigger_event('core.ucp_main_topiclist_topic_modify_template_vars', compact($vars)));
+
+			$template->assign_block_vars('topicrow', $template_vars);
 
 			$pagination->generate_template_pagination(append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . "&amp;t=$topic_id"), 'topicrow.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true);
 		}
--- a/includes/ucp/ucp_pm_compose.php
+++ b/includes/ucp/ucp_pm_compose.php
@@ -751,6 +751,34 @@ function compose_pm($id, $mode, $action, $user_folders = array())
 		$enable_urls 		= (isset($_POST['disable_magic_url'])) ? 0 : 1;
 		$enable_sig			= (!$config['allow_sig'] ||!$config['allow_sig_pm']) ? false : ((isset($_POST['attach_sig'])) ? true : false);
 
+		/**
+		* Modify private message
+		*
+		* @event core.ucp_pm_compose_modify_parse_before
+		* @var	bool	enable_bbcode		Whether or not bbcode is enabled
+		* @var	bool	enable_smilies		Whether or not smilies are enabled
+		* @var	bool	enable_urls			Whether or not urls are enabled
+		* @var	bool	enable_sig			Whether or not signature is enabled
+		* @var	string	subject				PM subject text
+		* @var	object	message_parser		The message parser object
+		* @var	bool	submit				Whether or not the form has been sumitted
+		* @var	bool	preview				Whether or not the signature is being previewed
+		* @var	array	error				Any error strings
+		* @since 3.1.10-RC1
+		*/
+		$vars = array(
+			'enable_bbcode',
+			'enable_smilies',
+			'enable_urls',
+			'enable_sig',
+			'subject',
+			'message_parser',
+			'submit',
+			'preview',
+			'error',
+		);
+		extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_parse_before', compact($vars)));
+
 		if ($submit)
 		{
 			$status_switch	= (($enable_bbcode+1) << 8) + (($enable_smilies+1) << 4) + (($enable_urls+1) << 2) + (($enable_sig+1) << 1);
--- a/includes/ucp/ucp_profile.php
+++ b/includes/ucp/ucp_profile.php
@@ -479,6 +479,32 @@ class ucp_profile
 					{
 						$message_parser = new parse_message($signature);
 
+						/**
+						* Modify user signature on editing profile in UCP
+						*
+						* @event core.ucp_profile_modify_signature
+						* @var	bool	enable_bbcode		Whether or not bbcode is enabled
+						* @var	bool	enable_smilies		Whether or not smilies are enabled
+						* @var	bool	enable_urls			Whether or not urls are enabled
+						* @var	string	signature			Users signature text
+						* @var	object	message_parser		The message parser object
+						* @var	array	error				Any error strings
+						* @var	bool	submit				Whether or not the form has been sumitted
+						* @var	bool	preview				Whether or not the signature is being previewed
+						* @since 3.1.10-RC1
+						*/
+						$vars = array(
+							'enable_bbcode',
+							'enable_smilies',
+							'enable_urls',
+							'signature',
+							'message_parser',
+							'error',
+							'submit',
+							'preview',
+						);
+						extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature', compact($vars)));
+
 						// Allowing Quote BBCode
 						$message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, $config['allow_sig_links'], true, 'sig');
 
@@ -505,6 +531,16 @@ class ucp_profile
 								'user_sig_bbcode_bitfield'	=> $message_parser->bbcode_bitfield
 							);
 
+							/**
+							* Modify user registration data before submitting it to the database
+							*
+							* @event core.ucp_profile_modify_signature_sql_ary
+							* @var	array	sql_ary		Array with user signature data to submit to the database
+							* @since 3.1.10-RC1
+							*/
+							$vars = array('sql_ary');
+							extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature_sql_ary', compact($vars)));
+
 							$sql = 'UPDATE ' . USERS_TABLE . '
 								SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 								WHERE user_id = ' . $user->data['user_id'];
--- a/index.php
+++ b/index.php
@@ -184,8 +184,8 @@ if ($config['load_birthdays'] && $config['allow_birthdays'] && $auth->acl_gets('
 	* Event to modify the birthdays list
 	*
 	* @event core.index_modify_birthdays_list
-	* @var	array	birthdays		Array with the users birhtdays data
-	* @var	array	rows			Array with the birhtdays SQL query result
+	* @var	array	birthdays		Array with the users birthdays data
+	* @var	array	rows			Array with the birthdays SQL query result
 	* @since 3.1.7-RC1
 	*/
 	$vars = array('birthdays', 'rows');
--- a/language/en/acp/attachments.php
+++ b/language/en/acp/attachments.php
@@ -117,7 +117,7 @@ $lang = array_merge($lang, array(
 
 	'IMAGE_LINK_SIZE'			=> 'Image link dimensions',
 	'IMAGE_LINK_SIZE_EXPLAIN'	=> 'Display image attachment as an inline text link if image is larger than this. To disable this behaviour, set the values to 0px by 0px.',
-	'IMAGICK_PATH'				=> 'Imagemagick path',
+	'IMAGICK_PATH'				=> 'ImageMagick path',
 	'IMAGICK_PATH_EXPLAIN'		=> 'Full path to the imagemagick convert application, e.g. <samp>/usr/bin/</samp>.',
 
 	'MAX_ATTACHMENTS'				=> 'Maximum number of attachments per post',
@@ -153,7 +153,7 @@ $lang = array_merge($lang, array(
 	'REMOVE_DISALLOWED_IPS'			=> 'Remove or un-exclude <em>disallowed</em> IPs/hostnames',
 	'RESYNC_FILES_STATS_CONFIRM'	=> 'Are you sure you wish to resynchronise file statistics?',
 
-	'SEARCH_IMAGICK'				=> 'Search for Imagemagick',
+	'SEARCH_IMAGICK'				=> 'Search for ImageMagick',
 	'SECURE_ALLOW_DENY'				=> 'Allow/Deny list',
 	'SECURE_ALLOW_DENY_EXPLAIN'		=> 'Change the default behaviour when secure downloads are enabled of the Allow/Deny list to that of a <strong>whitelist</strong> (Allow) or a <strong>blacklist</strong> (Deny).',
 	'SECURE_DOWNLOADS'				=> 'Enable secure downloads',
--- a/language/en/acp/board.php
+++ b/language/en/acp/board.php
@@ -570,6 +570,7 @@ $lang = array_merge($lang, array(
 	'SMTP_PORT'						=> 'SMTP server port',
 	'SMTP_PORT_EXPLAIN'				=> 'Only change this if you know your SMTP server is on a different port.',
 	'SMTP_SERVER'					=> 'SMTP server address',
+	'SMTP_SERVER_EXPLAIN'			=> 'Note that you have to provide the protocol that your server uses. If you are using SSL, this has to be "ssl://your.mailserver.com"',
 	'SMTP_SETTINGS'					=> 'SMTP settings',
 	'SMTP_USERNAME'					=> 'SMTP username',
 	'SMTP_USERNAME_EXPLAIN'			=> 'Only enter a username if your SMTP server requires it.',
--- a/language/en/acp/search.php
+++ b/language/en/acp/search.php
@@ -54,7 +54,7 @@ $lang = array_merge($lang, array(
 	'DELETING_INDEX_IN_PROGRESS_EXPLAIN'	=> 'The search backend is currently cleaning its index. This can take a few minutes.',
 
 	'FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE'	=> 'The MySQL fulltext backend can only be used with MySQL4 and above.',
-	'FULLTEXT_MYSQL_NOT_SUPPORTED'			=> 'MySQL fulltext indexes can only be used with MyISAM or InnoDB tables. MySQL 5.6.4 or later is required for fulltext indexes on InnoDB tables.',
+	'FULLTEXT_MYSQL_NOT_SUPPORTED'			=> 'MySQL fulltext indexes can only be used with MyISAM or InnoDB tables. MySQL 5.6.8 or later is required for fulltext indexes on InnoDB tables.',
 	'FULLTEXT_MYSQL_TOTAL_POSTS'			=> 'Total number of indexed posts',
 	'FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'	=> 'Words with at least this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.',
 	'FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'	=> 'Words with no more than this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.',
--- a/language/en/email/forum_notify.txt
+++ b/language/en/email/forum_notify.txt
@@ -2,7 +2,7 @@ Subject: Forum post notification - "{FORUM_NAME}"
 
 Hello {USERNAME},
 
-You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}"<!-- IF AUTHOR_NAME !== '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic.
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}"<!-- IF AUTHOR_NAME != '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic.
 
 {U_NEWEST_POST}
 
--- a/language/en/email/newtopic_notify.txt
+++ b/language/en/email/newtopic_notify.txt
@@ -2,7 +2,7 @@ Subject: New topic notification - "{FORUM_NAME}"
 
 Hello {USERNAME},
 
-You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic<!-- IF AUTHOR_NAME !== '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic<!-- IF AUTHOR_NAME != '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
 
 {U_FORUM}
 
--- a/language/en/email/short/newtopic_notify.txt
+++ b/language/en/email/short/newtopic_notify.txt
@@ -2,7 +2,7 @@ Subject: New topic notification - "{FORUM_NAME}"
 
 Hello {USERNAME},
 
-You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic<!-- IF AUTHOR_NAME !== '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic<!-- IF AUTHOR_NAME != '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
 
 {U_FORUM}
 
--- a/language/en/email/short/topic_notify.txt
+++ b/language/en/email/short/topic_notify.txt
@@ -2,7 +2,7 @@ Subject: Topic reply notification - "{TOPIC_TITLE}"
 
 Hello {USERNAME},
 
-You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply<!-- IF AUTHOR_NAME !== '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
+You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply<!-- IF AUTHOR_NAME != '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
 
 If you want to view the newest post made since your last visit, click the following link:
 {U_NEWEST_POST}
--- a/language/en/email/topic_notify.txt
+++ b/language/en/email/topic_notify.txt
@@ -2,7 +2,7 @@ Subject: Topic reply notification - "{TOPIC_TITLE}"
 
 Hello {USERNAME},
 
-You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply<!-- IF AUTHOR_NAME !== '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. No more notifications will be sent until you visit the topic.
+You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply<!-- IF AUTHOR_NAME != '' --> by {AUTHOR_NAME}<!-- ENDIF --> since your last visit. No more notifications will be sent until you visit the topic.
 
 If you want to view the newest post made since your last visit, click the following link:
 {U_NEWEST_POST}
--- a/language/en/install.php
+++ b/language/en/install.php
@@ -44,7 +44,7 @@ $lang = array_merge($lang, array(
 	'ADMIN_TEST'				=> 'Check administrator settings',
 	'ADMIN_USERNAME'			=> 'Administrator username',
 	'ADMIN_USERNAME_EXPLAIN'	=> 'Please enter a username between 3 and 20 characters in length.',
-	'APP_MAGICK'				=> 'Imagemagick support [ Attachments ]',
+	'APP_MAGICK'				=> 'ImageMagick support [ Attachments ]',
 	'AUTHOR_NOTES'				=> 'Author notes<br />» %s',
 	'AVAILABLE'					=> 'Available',
 	'AVAILABLE_CONVERTORS'		=> 'Available convertors',
@@ -282,7 +282,7 @@ $lang = array_merge($lang, array(
 	'NOT_UNDERSTAND'			=> 'Could not understand %s #%d, table %s (“%s”)',
 	'NO_CONVERTORS'				=> 'No convertors are available for use.',
 	'NO_CONVERT_SPECIFIED'		=> 'No convertor specified.',
-	'NO_LOCATION'				=> 'Cannot determine location. If you know Imagemagick is installed, you may specify the location later within your administration control panel',
+	'NO_LOCATION'				=> 'Cannot determine location. If you know ImageMagick is installed, you may specify the location later within your administration control panel',
 	'NO_TABLES_FOUND'			=> 'No tables found.',
 
 	'OVERVIEW_BODY'				=> 'Welcome to phpBB3!<br /><br />phpBB® is the most widely used open source bulletin board solution in the world. phpBB3 is the latest installment in a package line started in 2000. Like its predecessors, phpBB3 is feature-rich, user-friendly, and fully supported by the phpBB Team. phpBB3 greatly improves on what made phpBB2 popular, and adds commonly requested features that were not present in previous versions. We hope it exceeds your expectations.<br /><br />This installation system will guide you through installing phpBB3, updating to the latest version of phpBB3 from past releases, as well as converting to phpBB3 from a different discussion board system (including phpBB2). For more information, we encourage you to read <a href="../docs/INSTALL.html">the installation guide</a>.<br /><br />To read the phpBB3 license or learn about obtaining support and our stance on it, please select the respective options from the side menu. To continue, please select the appropriate tab above.',
@@ -301,10 +301,10 @@ $lang = array_merge($lang, array(
 	'PHP_REGISTER_GLOBALS_EXPLAIN'	=> 'phpBB will still run if this setting is enabled, but if possible, it is recommended that register_globals is disabled on your PHP install for security reasons.',
 	'PHP_SAFE_MODE'					=> 'Safe mode',
 	'PHP_SETTINGS'					=> 'PHP version and settings',
-	'PHP_SETTINGS_EXPLAIN'			=> '<strong>Required</strong> - You must be running at least version 5.3.3 of PHP in order to install phpBB. If <var>safe mode</var> is displayed below your PHP installation is running in that mode. This will impose limitations on remote administration and similar features.',
+	'PHP_SETTINGS_EXPLAIN'			=> '<strong>Required</strong> - You must be running at least version 5.3.3 of PHP (PHP 7 is not supported) in order to install phpBB. If <var>safe mode</var> is displayed below your PHP installation is running in that mode. This will impose limitations on remote administration and similar features.',
 	'PHP_URL_FOPEN_SUPPORT'			=> 'PHP setting <var>allow_url_fopen</var> is enabled',
 	'PHP_URL_FOPEN_SUPPORT_EXPLAIN'	=> '<strong>Optional</strong> - This setting is optional, however certain phpBB functions like off-site avatars will not work properly without it.',
-	'PHP_VERSION_REQD'				=> 'PHP version >= 5.3.3',
+	'PHP_VERSION_REQD'				=> 'PHP version: >= 5.3.3, < 7.0.0-dev',
 	'POST_ID'						=> 'Post ID',
 	'PREFIX_FOUND'					=> 'A scan of your tables has shown a valid installation using <strong>%s</strong> as table prefix.',
 	'PREPROCESS_STEP'				=> 'Executing pre-processing functions/queries',
@@ -400,6 +400,7 @@ $lang = array_merge($lang, array(
 	'DATABASE_UPDATE_CONTINUE'			=> 'Continue database update',
 	'DATABASE_UPDATE_INFO_OLD'			=> 'The database update file within the install directory is outdated. Please make sure you uploaded the correct version of the file.',
 	'DATABASE_UPDATE_NOT_COMPLETED'		=> 'The database update has not yet completed.',
+	'DATABASE_VERSION'					=> 'Database version',
 	'DELETE_USER_REMOVE'				=> 'Delete user and remove posts',
 	'DELETE_USER_RETAIN'				=> 'Delete user but keep posts',
 	'DESTINATION'						=> 'Destination file',
@@ -439,6 +440,7 @@ $lang = array_merge($lang, array(
 	'FILES_NOT_MODIFIED_EXPLAIN'	=> 'The following files are not modified and represent the original phpBB files from the version you want to update from.',
 	'FILES_UP_TO_DATE'				=> 'Already updated files',
 	'FILES_UP_TO_DATE_EXPLAIN'		=> 'The following files are already up to date and do not need to be updated.',
+	'FILES_VERSION'					=> 'Files Version',
 	'FTP_SETTINGS'					=> 'FTP settings',
 	'FTP_UPDATE_METHOD'				=> 'FTP upload',
 
@@ -486,6 +488,7 @@ $lang = array_merge($lang, array(
 	'OLD_UPDATE_FILES'		=> 'Update files are out of date. The update files found are for updating from phpBB %1$s to phpBB %2$s but the latest version of phpBB is %3$s.',
 
 	'PACKAGE_UPDATES_TO'				=> 'Current package updates to version',
+	'PACKAGE_VERSION'					=> 'Package version installed',
 	'PERFORM_DATABASE_UPDATE'			=> 'Perform database update',
 	'PERFORM_DATABASE_UPDATE_EXPLAIN'	=> 'Below you will find a button to the database update script. The database update can take a while, so please do not stop the execution if it seems to hang. After the database update has been performed just follow the instructions to continue the update process.',
 	'PREVIOUS_VERSION'					=> 'Previous version',
@@ -530,6 +533,12 @@ $lang = array_merge($lang, array(
 	'UPDATE_DATABASE_SCHEMA'		=> 'Updating database schema',
 	'UPDATE_FILES'					=> 'Update files',
 	'UPDATE_FILES_NOTICE'			=> 'Please make sure you have updated your board files too, this file is only updating your database.',
+	'UPDATE_INCOMPLETE'				=> 'Your phpBB installation has not been correctly updated.',
+	'UPDATE_INCOMPLETE_MORE'		=> 'Please read the information below in order to fix this error.',
+	'UPDATE_INCOMPLETE_EXPLAIN'		=> '<h1>Incomplete update</h1>
+
+		<p>We noticed that the last update of your phpBB installation hasn’t been completed. Visit the <a href="%1$s" title="%1$s">database_update script</a> and run it. If it is missing, please <a href="https://www.phpbb.com/downloads/" title="phpBB downloads">download your package version</a>, upload the "install" folder to your phpBB root directory (where your config.php file is) and <a href="%1$s" title="%1$s">run the database update script</a>.</p>',
+
 	'UPDATE_INSTALLATION'			=> 'Update phpBB installation',
 	'UPDATE_INSTALLATION_EXPLAIN'	=> 'With this option, it is possible to update your phpBB installation to the latest version.<br />During the process all of your files will be checked for their integrity. You are able to review all differences and files before the update.<br /><br />The file update itself can be done in two different ways.</p><h2>Manual Update</h2><p>With this update you only download your personal set of changed files to make sure you do not lose your file modifications you may have done. After you downloaded this package you need to manually upload the files to their correct position under your phpBB root directory. Once done, you are able to do the file check stage again to see if you moved the files to their correct location.</p><h2>Automatic Update with FTP</h2><p>This method is similar to the first one but without the need to download the changed files and uploading them on your own. This will be done for you. In order to use this method you need to know your FTP login details since you will be asked for them. Once finished you will be redirected to the file check again to make sure everything got updated correctly.<br /><br />',
 	'UPDATE_INSTRUCTIONS'			=> '
--- a/language/en/migrator.php
+++ b/language/en/migrator.php
@@ -50,6 +50,7 @@ $lang = array_merge($lang, array(
 	'MIGRATION_NOT_FULFILLABLE'			=> 'The migration "%1$s" is not fulfillable, missing migration "%2$s".',
 	'MIGRATION_NOT_VALID'				=> '%s is not a valid migration.',
 	'MIGRATION_SCHEMA_DONE'				=> 'Installed Schema: %1$s; Time: %2$.2f seconds',
+	'MIGRATION_SCHEMA_IN_PROGRESS'		=> 'Installing Schema: %1$s; Time: %2$.2f seconds',
 	'MIGRATION_SCHEMA_RUNNING'			=> 'Installing Schema: %s.',
 
 	'MIGRATION_INVALID_DATA_MISSING_CONDITION'		=> 'A migration is invalid. An if statement helper is missing a condition.',
@@ -60,9 +61,12 @@ $lang = array_merge($lang, array(
 	'MIGRATION_INVALID_DATA_UNDEFINED_METHOD'		=> 'A migration is invalid. An undefined migration tool method was encountered.',
 
 	'MODULE_ERROR'						=> 'An error occurred while creating a module: %s',
+	'MODULE_EXISTS'						=> 'A module already exists: %s',
+	'MODULE_EXIST_MULTIPLE'				=> 'Several modules with the given parent module langname already exist: %s. Try using before/after keys to clarify the module placement.',
 	'MODULE_INFO_FILE_NOT_EXIST'		=> 'A required module info file is missing: %2$s',
 	'MODULE_NOT_EXIST'					=> 'A required module does not exist: %s',
 
+	'PARENT_MODULE_FIND_ERROR'			=> 'Unable to determine the parent module identifier: %s',
 	'PERMISSION_NOT_EXIST'				=> 'The permission setting "%s" unexpectedly does not exist.',
 
 	'ROLE_NOT_EXIST'					=> 'The permission role "%s" unexpectedly does not exist.',
--- a/language/en/posting.php
+++ b/language/en/posting.php
@@ -90,14 +90,20 @@ $lang = array_merge($lang, array(
 	'DELETE_PERMANENTLY'		=> 'Delete permanently',
 	'DELETE_POST_CONFIRM'		=> 'Are you sure you want to delete this post?',
 	'DELETE_POST_PERMANENTLY_CONFIRM'	=> 'Are you sure you want to <strong>permanently</strong> delete this post?',
-	'DELETE_POST_PERMANENTLY'	=> 'Permanently delete this post so it can not be recovered',
+	'DELETE_POST_PERMANENTLY'	=> array(
+		1	=> 'Permanently delete this post so it can not be recovered',
+		2	=> 'Permanently delete %1$d posts so they can not be recovered',
+	),
 	'DELETE_POSTS_CONFIRM'		=> 'Are you sure you want to delete these posts?',
 	'DELETE_POSTS_PERMANENTLY_CONFIRM'	=> 'Are you sure you want to <strong>permanently</strong> delete these posts?',
 	'DELETE_REASON'				=> 'Reason for deletion',
 	'DELETE_REASON_EXPLAIN'		=> 'The specified reason for deletion will be visible to moderators.',
 	'DELETE_POST_WARN'			=> 'Delete this post',
 	'DELETE_TOPIC_CONFIRM'		=> 'Are you sure you want to delete this topic?',
-	'DELETE_TOPIC_PERMANENTLY'	=> 'Permanently delete this topic so it can not be recovered',
+	'DELETE_TOPIC_PERMANENTLY'	=> array(
+		1	=> 'Permanently delete this topic so it can not be recovered',
+		2	=> 'Permanently delete %1$d topics so they can not be recovered',
+	),
 	'DELETE_TOPIC_PERMANENTLY_CONFIRM'	=> 'Are you sure you want to <strong>permanently</strong> delete this topic?',
 	'DELETE_TOPICS_CONFIRM'		=> 'Are you sure you want to delete these topics?',
 	'DELETE_TOPICS_PERMANENTLY_CONFIRM'	=> 'Are you sure you want to <strong>permanently</strong> delete these topics?',
--- a/phpbb/avatar/driver/gravatar.php
+++ b/phpbb/avatar/driver/gravatar.php
@@ -52,8 +52,8 @@ class gravatar extends \phpbb\avatar\driver\driver
 	public function prepare_form($request, $template, $user, $row, &$error)
 	{
 		$template->assign_vars(array(
-			'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', 0),
-			'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', 0),
+			'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', ''),
+			'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', ''),
 			'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
 		));
 
--- a/phpbb/avatar/driver/remote.php
+++ b/phpbb/avatar/driver/remote.php
@@ -36,8 +36,8 @@ class remote extends \phpbb\avatar\driver\driver
 	public function prepare_form($request, $template, $user, $row, &$error)
 	{
 		$template->assign_vars(array(
-			'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', 0),
-			'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', 0),
+			'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', ''),
+			'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', ''),
 			'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '',
 		));
 
--- a/phpbb/captcha/plugins/qa.php
+++ b/phpbb/captcha/plugins/qa.php
@@ -222,7 +222,11 @@ class qa
 	{
 		global $phpbb_log, $template, $user;
 
-		if ($this->is_solved() || empty($this->question_text) || !count($this->question_ids))
+		if ($this->is_solved())
+		{
+			return false;
+		}
+		else if (empty($this->question_text) || !count($this->question_ids))
 		{
 			/** @var \phpbb\log\log_interface $phpbb_log */
 			$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
@@ -231,10 +235,10 @@ class qa
 		else
 		{
 			$template->assign_vars(array(
-				'QA_CONFIRM_QUESTION'		=> $this->question_text,
-				'QA_CONFIRM_ID'				=> $this->confirm_id,
-				'S_CONFIRM_CODE'			=> true,
-				'S_TYPE'					=> $this->type,
+				'QA_CONFIRM_QUESTION'	=> $this->question_text,
+				'QA_CONFIRM_ID'			=> $this->confirm_id,
+				'S_CONFIRM_CODE'		=> true,
+				'S_TYPE'				=> $this->type,
 			));
 
 			return 'captcha_qa.html';
--- a/phpbb/content_visibility.php
+++ b/phpbb/content_visibility.php
@@ -417,13 +417,46 @@ class content_visibility
 			return array();
 		}
 
+		if (!function_exists('truncate_string'))
+		{
+			include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
+		}
+
 		$data = array(
 			'post_visibility'		=> (int) $visibility,
 			'post_delete_user'		=> (int) $user_id,
 			'post_delete_time'		=> ((int) $time) ?: time(),
 			'post_delete_reason'	=> truncate_string($reason, 255, 255, false),
 		);
-
+		/**
+		 * Perform actions right before the query to change post visibility
+		 *
+		 * @event core.set_post_visibility_before_sql
+		 * @var			int			visibility		Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+		 * @var			array		post_id			Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
+		 * @var			int			topic_id		Topic of the post IDs to be modified.
+		 * @var			int			forum_id		Forum ID that the topic_id resides in.
+		 * @var			int			user_id			User ID doing this action.
+		 * @var			int			timestamp		Timestamp of this action.
+		 * @var			string		reason			Reason specified by the user for this change.
+		 * @var			bool		is_starter		Are we changing the topic's starter?
+		 * @var			bool		is_latest		Are we changing the topic's latest post?
+		 * @var			array		data			The data array for this action.
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'visibility',
+			'post_id',
+			'topic_id',
+			'forum_id',
+			'user_id',
+			'timestamp',
+			'reason',
+			'is_starter',
+			'is_latest',
+			'data',
+		);
+		extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars)));
 		$sql = 'UPDATE ' . $this->posts_table . '
 			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
 			WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
@@ -580,7 +613,35 @@ class content_visibility
 				WHERE topic_id = ' . (int) $topic_id;
 			$this->db->sql_query($sql);
 		}
-
+		/**
+		 * Perform actions after all steps to changing post visibility
+		 *
+		 * @event core.set_post_visibility_after
+		 * @var			int			visibility		Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+		 * @var			array		post_id			Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
+		 * @var			int			topic_id		Topic of the post IDs to be modified.
+		 * @var			int			forum_id		Forum ID that the topic_id resides in.
+		 * @var			int			user_id			User ID doing this action.
+		 * @var			int			timestamp		Timestamp of this action.
+		 * @var			string		reason			Reason specified by the user for this change.
+		 * @var			bool		is_starter		Are we changing the topic's starter?
+		 * @var			bool		is_latest		Are we changing the topic's latest post?
+		 * @var			array		data			The data array for this action.
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'visibility',
+			'post_id',
+			'topic_id',
+			'forum_id',
+			'user_id',
+			'timestamp',
+			'reason',
+			'is_starter',
+			'is_latest',
+			'data',
+		);
+		extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars)));
 		return $data;
 	}
 
@@ -628,6 +689,11 @@ class content_visibility
 			}
 		}
 
+		if (!function_exists('truncate_string'))
+		{
+			include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
+		}
+
 		// Note, we do not set a reason for the posts, just for the topic
 		$data = array(
 			'topic_visibility'		=> (int) $visibility,
@@ -635,7 +701,31 @@ class content_visibility
 			'topic_delete_time'		=> ((int) $time) ?: time(),
 			'topic_delete_reason'	=> truncate_string($reason, 255, 255, false),
 		);
-
+		/**
+		 * Perform actions right before the query to change topic visibility
+		 *
+		 * @event core.set_topic_visibility_before_sql
+		 * @var			int			visibility			Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+		 * @var			int			topic_id			Topic of the post IDs to be modified.
+		 * @var			int			forum_id			Forum ID that the topic_id resides in.
+		 * @var			int			user_id				User ID doing this action.
+		 * @var			int			timestamp			Timestamp of this action.
+		 * @var			string		reason				Reason specified by the user for this change.
+		 * @var			bool		force_update_all	Force an update on all posts within the topic, regardless of their current approval state.
+		 * @var			array		data				The data array for this action.
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'visibility',
+			'topic_id',
+			'forum_id',
+			'user_id',
+			'timestamp',
+			'reason',
+			'force_update_all',
+			'data',
+		);
+		extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars)));
 		$sql = 'UPDATE ' . $this->topics_table . '
 			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
 			WHERE topic_id = ' . (int) $topic_id;
@@ -660,7 +750,31 @@ class content_visibility
 		{
 			$this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true);
 		}
-
+		/**
+		 * Perform actions after all steps to changing topic visibility
+		 *
+		 * @event core.set_topic_visibility_after
+		 * @var			int			visibility			Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+		 * @var			int			topic_id			Topic of the post IDs to be modified.
+		 * @var			int			forum_id			Forum ID that the topic_id resides in.
+		 * @var			int			user_id				User ID doing this action.
+		 * @var			int			timestamp			Timestamp of this action.
+		 * @var			string		reason				Reason specified by the user for this change.
+		 * @var			bool		force_update_all	Force an update on all posts within the topic, regardless of their current approval state.
+		 * @var			array		data				The data array for this action.
+		 * @since 3.1.10-RC1
+		 */
+		$vars = array(
+			'visibility',
+			'topic_id',
+			'forum_id',
+			'user_id',
+			'timestamp',
+			'reason',
+			'force_update_all',
+			'data',
+		);
+		extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars)));
 		return $data;
 	}
 
--- a/phpbb/cron/manager.php
+++ b/phpbb/cron/manager.php
@@ -110,7 +110,7 @@ class manager
 	* Web runner uses this method to resolve names to tasks.
 	*
 	* @param string				$name Name of the task to look up.
-	* @return \phpbb\cron\task\task	A task corresponding to the given name, or null.
+	* @return \phpbb\cron\task\wrapper	A wrapped task corresponding to the given name, or null.
 	*/
 	public function find_task($name)
 	{
--- /dev/null
+++ b/phpbb/db/migration/data/v31x/add_log_time_index.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class add_log_time_index extends \phpbb\db\migration\migration
+{
+	static public function depends_on()
+	{
+		return array(
+			'\phpbb\db\migration\data\v31x\v319',
+		);
+	}
+
+	public function update_schema()
+	{
+		return array(
+			'add_index' => array(
+				$this->table_prefix . 'log' => array(
+					'log_time'	=> array('log_time'),
+				),
+			),
+		);
+	}
+
+	public function revert_schema()
+	{
+		return array(
+			'drop_keys' => array(
+				$this->table_prefix . 'log' => array(
+					'log_time',
+				),
+			),
+		);
+	}
+}
--- /dev/null
+++ b/phpbb/db/migration/data/v31x/v3110.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class v3110 extends \phpbb\db\migration\migration
+{
+	public function effectively_installed()
+	{
+		return phpbb_version_compare($this->config['version'], '3.1.10', '>=');
+	}
+
+	static public function depends_on()
+	{
+		return array(
+			'\phpbb\db\migration\data\v31x\v3110rc1',
+		);
+	}
+
+	public function update_data()
+	{
+		return array(
+			array('config.update', array('version', '3.1.10')),
+		);
+	}
+}
--- /dev/null
+++ b/phpbb/db/migration/data/v31x/v3110rc1.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class v3110rc1 extends \phpbb\db\migration\migration
+{
+	public function effectively_installed()
+	{
+		return phpbb_version_compare($this->config['version'], '3.1.10-RC1', '>=');
+	}
+
+	static public function depends_on()
+	{
+		return array(
+			'\phpbb\db\migration\data\v31x\v319',
+		);
+	}
+
+	public function update_data()
+	{
+		return array(
+			array('config.update', array('version', '3.1.10-RC1')),
+		);
+	}
+}
--- a/phpbb/db/migration/helper.php
+++ b/phpbb/db/migration/helper.php
@@ -81,4 +81,36 @@ class helper
 
 		return $steps;
 	}
+
+	/**
+	 * Reverse the update steps from an array of data changes
+	 *
+	 * 'If' statements and custom methods will be skipped, for all
+	 * other calls the reverse method of the tool class will be called
+	 *
+	 * @param array $steps Update changes from migration
+	 *
+	 * @return array
+	 */
+	public function reverse_update_data($steps)
+	{
+		$reversed_array = array();
+
+		foreach ($steps as $step)
+		{
+			$parts = explode('.', $step[0]);
+			$parameters = $step[1];
+
+			$class = $parts[0];
+			$method = isset($parts[1]) ? $parts[1] : false;
+
+			if ($class !== 'if' && $class !== 'custom')
+			{
+				array_unshift($parameters, $method);
+				$reversed_array[] = array($class . '.reverse', $parameters);
+			}
+		}
+
+		return array_reverse($reversed_array);
+	}
 }
--- a/phpbb/db/migration/tool/config.php
+++ b/phpbb/db/migration/tool/config.php
@@ -150,6 +150,11 @@ class config implements \phpbb\db\migration\tool\tool_interface
 					$arguments[0],
 				);
 			break;
+
+			case 'reverse':
+				// Reversing a reverse is just the call itself
+				$call = array_shift($arguments);
+			break;
 		}
 
 		if ($call)
--- a/phpbb/db/migration/tool/config_text.php
+++ b/phpbb/db/migration/tool/config_text.php
@@ -115,6 +115,11 @@ class config_text implements \phpbb\db\migration\tool\tool_interface
 					$arguments[] = '';
 				}
 			break;
+
+			case 'reverse':
+				// Reversing a reverse is just the call itself
+				$call = array_shift($arguments);
+			break;
 		}
 
 		if ($call)
--- a/phpbb/db/migration/tool/module.php
+++ b/phpbb/db/migration/tool/module.php
@@ -36,6 +36,9 @@ class module implements \phpbb\db\migration\tool\tool_interface
 	/** @var string */
 	protected $modules_table;
 
+	/** @var array */
+	protected $module_categories = array();
+
 	/**
 	* Constructor
 	*
@@ -87,30 +90,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
 		$parent_sql = '';
 		if ($parent !== false)
 		{
-			// Allows '' to be sent as 0
-			$parent = $parent ?: 0;
-
-			if (!is_numeric($parent))
-			{
-				$sql = 'SELECT module_id
-					FROM ' . $this->modules_table . "
-					WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
-						AND module_class = '" . $this->db->sql_escape($class) . "'";
-				$result = $this->db->sql_query($sql);
-				$module_id = $this->db->sql_fetchfield('module_id');
-				$this->db->sql_freeresult($result);
-
-				if (!$module_id)
-				{
-					return false;
-				}
-
-				$parent_sql = 'AND parent_id = ' . (int) $module_id;
-			}
-			else
-			{
-				$parent_sql = 'AND parent_id = ' . (int) $parent;
-			}
+			$parent = $this->get_parent_module_id($parent, $module);
+			$parent_sql = 'AND parent_id = ' . (int) $parent;
 		}
 
 		$sql = 'SELECT module_id
@@ -171,15 +152,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
 	*/
 	public function add($class, $parent = 0, $data = array())
 	{
-		// Allows '' to be sent as 0
-		$parent = $parent ?: 0;
-
 		// allow sending the name as a string in $data to create a category
 		if (!is_array($data))
 		{
 			$data = array('module_langname' => $data);
 		}
 
+		$parent = $data['parent_id'] = $this->get_parent_module_id($parent, $data);
+
 		if (!isset($data['module_langname']))
 		{
 			// The "automatic" way
@@ -210,31 +190,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
 		}
 
 		// The "manual" way
-		if (!is_numeric($parent))
-		{
-			$sql = 'SELECT module_id
-				FROM ' . $this->modules_table . "
-				WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
-					AND module_class = '" . $this->db->sql_escape($class) . "'";
-			$result = $this->db->sql_query($sql);
-			$module_id = $this->db->sql_fetchfield('module_id');
-			$this->db->sql_freeresult($result);
-
-			if (!$module_id)
-			{
-				throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
-			}
-
-			$parent = $data['parent_id'] = $module_id;
-		}
-		else if (!$this->exists($class, false, $parent))
+		if (!$this->exists($class, false, $parent))
 		{
 			throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
 		}
 
 		if ($this->exists($class, $parent, $data['module_langname']))
 		{
-			return;
+			throw new \phpbb\db\migration\exception('MODULE_EXISTS', $module_id);
 		}
 
 		if (!class_exists('acp_modules'))
@@ -373,26 +336,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
 			$parent_sql = '';
 			if ($parent !== false)
 			{
-				// Allows '' to be sent as 0
-				$parent = ($parent) ?: 0;
-
-				if (!is_numeric($parent))
-				{
-					$sql = 'SELECT module_id
-						FROM ' . $this->modules_table . "
-						WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
-							AND module_class = '" . $this->db->sql_escape($class) . "'";
-					$result = $this->db->sql_query($sql);
-					$module_id = $this->db->sql_fetchfield('module_id');
-					$this->db->sql_freeresult($result);
-
-					// we know it exists from the module_exists check
-					$parent_sql = 'AND parent_id = ' . (int) $module_id;
-				}
-				else
-				{
-					$parent_sql = 'AND parent_id = ' . (int) $parent;
-				}
+				$parent = $this->get_parent_module_id($parent, $module);
+				$parent_sql = 'AND parent_id = ' . (int) $parent;
 			}
 
 			$module_ids = array();
@@ -454,6 +399,11 @@ class module implements \phpbb\db\migration\tool\tool_interface
 			case 'remove':
 				$call = 'add';
 			break;
+
+			case 'reverse':
+				// Reversing a reverse is just the call itself
+				$call = array_shift($arguments);
+			break;
 		}
 
 		if ($call)
@@ -487,4 +437,110 @@ class module implements \phpbb\db\migration\tool\tool_interface
 
 		return array_pop($module);
 	}
+
+	/**
+	* Get the list of installed module categories
+	*	key - module_id
+	*	value - module_langname
+	*
+	* @return null
+	*/
+	protected function get_categories_list()
+	{
+		// Select the top level categories
+		// and 2nd level [sub]categories which exist for ACP only
+		$sql = 'SELECT m2.module_id, m2.module_langname
+			FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
+			WHERE m1.parent_id = 0
+				AND (m1.module_id = m2.module_id
+				OR m2.module_class = 'acp' AND m2.parent_id = m1.module_id)
+			ORDER BY m1.module_id, m2.module_id ASC";
+
+		$result = $this->db->sql_query($sql);
+		while ($row = $this->db->sql_fetchrow($result))
+		{
+			$this->module_categories[(int) $row['module_id']] = $row['module_langname'];
+		}
+		$this->db->sql_freeresult($result);
+	}
+
+	/**
+	* Get parent module id
+	*
+	* @param string|int $parent_id The parent module_id|module_langname
+	* @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
+	* @return int The parent module_id
+	* @throws \phpbb\db\migration\exception
+	*/
+	public function get_parent_module_id($parent_id, $data = '')
+	{
+		// Allow '' to be sent as 0
+		$parent_id = $parent_id ?: 0;
+
+		// If automatic adding is in action, convert array back to string to simplify things
+		if (is_array($data) && sizeof($data) == 1)
+		{
+			$data = $data['module_langname'];
+		}
+
+		if (!is_numeric($parent_id))
+		{
+			// Refresh the $module_categories array
+			$this->get_categories_list();
+
+			// Search for the parent module_langname
+			$ids = array_keys($this->module_categories, $parent_id);
+
+			switch (sizeof($ids))
+			{
+				// No parent with the given module_langname exist
+				case 0:
+					throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
+				break;
+
+				// Return the module id
+				case 1:
+					$parent_id = (int) $ids[0];
+				break;
+
+				// Several modules with the given module_langname were found
+				// Try to determine the parent_id by the neighbour module parent
+				default:
+					if (is_array($data) && (isset($data['before']) || isset($data['after'])))
+					{
+						$neighbour_module_langname = isset($data['before']) ? $data['before'] : $data['after'];
+						$sql = 'SELECT parent_id
+							FROM ' . $this->modules_table . "
+							WHERE module_langname = '" . $this->db->sql_escape($neighbour_module_langname) . "'
+								AND " . $this->db->sql_in_set('parent_id', $ids);
+						$result = $this->db->sql_query($sql);
+						$parent_id = (int) $this->db->sql_fetchfield('parent_id');
+						if (!$parent_id)
+						{
+							throw new \phpbb\db\migration\exception('PARENT_MODULE_FIND_ERROR', $data['parent_id']);
+						}
+					}
+					else if (!empty($data) && !is_array($data))
+					{
+						// The module_langname is set, checking for the module existance
+						// As more than 1 parents were found already, there's no way for null parent_id here
+						$sql = 'SELECT m2.module_id as module_parent_id
+							FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
+							WHERE " . ((is_numeric($data)) ? 'm1.module_id = ' . (int) $data : "m1.module_langname = '" . $this->db->sql_escape($data)) . "'
+								AND m2.module_id = m1.parent_id
+								AND " . $this->db->sql_in_set('m2.module_id', $ids);
+						$result = $this->db->sql_query($sql);
+						$parent_id = (int) $this->db->sql_fetchfield('module_parent_id');
+					}
+					else
+					{
+						//Unable to get the parent module id, throwing an exception
+						throw new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
+					}
+				break;
+			}
+		}
+
+		return $parent_id;
+	}
 }
--- a/phpbb/db/migration/tool/permission.php
+++ b/phpbb/db/migration/tool/permission.php
@@ -637,6 +637,11 @@ class permission implements \phpbb\db\migration\tool\tool_interface
 					$arguments[0],
 				);
 			break;
+
+			case 'reverse':
+				// Reversing a reverse is just the call itself
+				$call = array_shift($arguments);
+			break;
 		}
 
 		if ($call)
--- a/phpbb/db/migrator.php
+++ b/phpbb/db/migrator.php
@@ -80,14 +80,14 @@ class migrator
 	*
 	* @var array
 	*/
-	public $last_run_migration = false;
+	protected $last_run_migration = false;
 
 	/**
 	 * The output handler. A null handler is configured by default.
 	 *
 	 * @var migrator_output_handler_interface
 	 */
-	public $output_handler;
+	protected $output_handler;
 
 	/**
 	* Constructor of the database migrator
@@ -152,6 +152,7 @@ class migrator
 				$this->migration_state[$migration['migration_name']] = $migration;
 
 				$this->migration_state[$migration['migration_name']]['migration_depends_on'] = unserialize($migration['migration_depends_on']);
+				$this->migration_state[$migration['migration_name']]['migration_data_state'] = !empty($migration['migration_data_state']) ? unserialize($migration['migration_data_state']) : '';
 			}
 		}
 
@@ -161,6 +162,19 @@ class migrator
 	}
 
 	/**
+	 * Get an array with information about the last migration run.
+	 *
+	 * The array contains 'name', 'class' and 'state'. 'effectively_installed' is set
+	 * and set to true if the last migration was effectively_installed.
+	 *
+	 * @return array
+	 */
+	public function get_last_run_migration()
+	{
+		return $this->last_run_migration;
+	}
+
+	/**
 	* Sets the list of available migration class names to the given array.
 	*
 	* @param array $class_names An array of migration class names
@@ -297,38 +311,70 @@ class migrator
 
 		if (!$state['migration_schema_done'])
 		{
-			$this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE);
+			$verbosity = empty($state['migration_data_state']) ?
+				migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+			$this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), $verbosity);
 
 			$this->last_run_migration['task'] = 'process_schema_step';
+
+			$total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+				$state['migration_data_state']['_total_time'] : 0.0;
 			$elapsed_time = microtime(true);
+
 			$steps = $this->helper->get_schema_steps($migration->update_schema());
 			$result = $this->process_data_step($steps, $state['migration_data_state']);
+
 			$elapsed_time = microtime(true) - $elapsed_time;
+			$total_time += $elapsed_time;
+
+			if (is_array($result))
+			{
+				$result['_total_time'] = $total_time;
+			}
 
 			$state['migration_data_state'] = ($result === true) ? '' : $result;
 			$state['migration_schema_done'] = ($result === true);
 
-			$this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+			if ($state['migration_schema_done'])
+			{
+				$this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+			}
+			else
+			{
+				$this->output_handler->write(array('MIGRATION_SCHEMA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE);
+			}
 		}
 		else if (!$state['migration_data_done'])
 		{
 			try
 			{
-				$this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE);
+				$verbosity = empty($state['migration_data_state']) ?
+					migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+				$this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), $verbosity);
 
 				$this->last_run_migration['task'] = 'process_data_step';
 
+				$total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+					$state['migration_data_state']['_total_time'] : 0.0;
 				$elapsed_time = microtime(true);
+
 				$result = $this->process_data_step($migration->update_data(), $state['migration_data_state']);
+
 				$elapsed_time = microtime(true) - $elapsed_time;
+				$total_time += $elapsed_time;
+
+				if (is_array($result))
+				{
+					$result['_total_time'] = $total_time;
+				}
 
 				$state['migration_data_state'] = ($result === true) ? '' : $result;
 				$state['migration_data_done'] = ($result === true);
 				$state['migration_end_time'] = ($result === true) ? time() : 0;
 
-				if ($state['migration_schema_done'])
+				if ($state['migration_data_done'])
 				{
-					$this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+					$this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
 				}
 				else
 				{
@@ -337,10 +383,12 @@ class migrator
 			}
 			catch (\phpbb\db\migration\exception $e)
 			{
-				// Revert the schema changes
+				// Reset data state and revert the schema changes
+				$state['migration_data_state'] = '';
+				$this->set_migration_state($name, $state);
+
 				$this->revert_do($name);
 
-				// Rethrow exception
 				throw $e;
 			}
 		}
@@ -416,19 +464,11 @@ class migrator
 
 		if ($state['migration_data_done'])
 		{
-			if ($state['migration_data_state'] !== 'revert_data')
-			{
-				$result = $this->process_data_step($migration->update_data(), $state['migration_data_state'], true);
-
-				$state['migration_data_state'] = ($result === true) ? 'revert_data' : $result;
-			}
-			else
-			{
-				$result = $this->process_data_step($migration->revert_data(), '', false);
+			$steps = array_merge($this->helper->reverse_update_data($migration->update_data()), $migration->revert_data());
+			$result = $this->process_data_step($steps, $state['migration_data_state']);
 
-				$state['migration_data_state'] = ($result === true) ? '' : $result;
-				$state['migration_data_done'] = ($result === true) ? false : true;
-			}
+			$state['migration_data_state'] = ($result === true) ? '' : $result;
+			$state['migration_data_done'] = ($result === true) ? false : true;
 
 			$this->set_migration_state($name, $state);
 		}
@@ -446,8 +486,13 @@ class migrator
 					WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
 				$this->db->sql_query($sql);
 
+				$this->last_run_migration = false;
 				unset($this->migration_state[$name]);
 			}
+			else
+			{
+				$this->set_migration_state($name, $state);
+			}
 		}
 
 		return true;
@@ -464,7 +509,12 @@ class migrator
 	*/
 	protected function process_data_step($steps, $state, $revert = false)
 	{
-		$state = ($state) ? unserialize($state) : false;
+		if (sizeof($steps) === 0)
+		{
+			return true;
+		}
+
+		$state = is_array($state) ? $state : false;
 
 		// reverse order of steps if reverting
 		if ($revert === true)
@@ -472,54 +522,45 @@ class migrator
 			$steps = array_reverse($steps);
 		}
 
-		foreach ($steps as $step_identifier => $step)
+		$step = $last_result = 0;
+		if ($state)
 		{
-			$last_result = 0;
-			if ($state)
-			{
-				// Continue until we reach the step that matches the last step called
-				if ($state['step'] != $step_identifier)
-				{
-					continue;
-				}
-
-				// We send the result from last time to the callable function
-				$last_result = $state['result'];
+			$step = $state['step'];
 
-				// Set state to false since we reached the point we were at
-				$state = false;
-			}
+			// We send the result from last time to the callable function
+			$last_result = $state['result'];
+		}
 
-			try
+		try
+		{
+			// Result will be null or true if everything completed correctly
+			// Stop after each update step, to let the updater control the script runtime
+			$result = $this->run_step($steps[$step], $last_result, $revert);
+			if (($result !== null && $result !== true) || $step + 1 < sizeof($steps))
 			{
-				// Result will be null or true if everything completed correctly
-				$result = $this->run_step($step, $last_result, $revert);
-				if ($result !== null && $result !== true)
-				{
-					return serialize(array(
-						'result'	=> $result,
-						'step'		=> $step_identifier,
-					));
-				}
+				return array(
+					'result'	=> $result,
+					// Move on if the last call finished
+					'step'		=> ($result !== null && $result !== true) ? $step : $step + 1,
+				);
 			}
-			catch (\phpbb\db\migration\exception $e)
+		}
+		catch (\phpbb\db\migration\exception $e)
+		{
+			// We should try rolling back here
+			foreach ($steps as $reverse_step_identifier => $reverse_step)
 			{
-				// We should try rolling back here
-				foreach ($steps as $reverse_step_identifier => $reverse_step)
+				// If we've reached the current step we can break because we reversed everything that was run
+				if ($reverse_step_identifier == $step)
 				{
-					// If we've reached the current step we can break because we reversed everything that was run
-					if ($reverse_step_identifier == $step_identifier)
-					{
-						break;
-					}
-
-					// Reverse the step that was run
-					$result = $this->run_step($reverse_step, false, !$revert);
+					break;
 				}
 
-				// rethrow the exception
-				throw $e;
+				// Reverse the step that was run
+				$result = $this->run_step($reverse_step, false, !$revert);
 			}
+
+			throw $e;
 		}
 
 		return true;
@@ -587,6 +628,13 @@ class migrator
 					throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_STEP', $step);
 				}
 
+				if ($reverse)
+				{
+					// We might get unexpected results when trying
+					// to revert this, so just avoid it
+					return false;
+				}
+
 				$condition = $parameters[0];
 
 				if (!$condition)
@@ -664,6 +712,7 @@ class migrator
 	{
 		$migration_row = $state;
 		$migration_row['migration_depends_on'] = serialize($state['migration_depends_on']);
+		$migration_row['migration_data_state'] = !empty($state['migration_data_state']) ? serialize($state['migration_data_state']) : '';
 
 		if (isset($this->migration_state[$name]))
 		{
--- a/phpbb/db/migrator_output_handler_interface.php
+++ b/phpbb/db/migrator_output_handler_interface.php
@@ -15,11 +15,11 @@ namespace phpbb\db;
 
 interface migrator_output_handler_interface
 {
-	const VERBOSITY_QUIET        = 0;
-	const VERBOSITY_NORMAL       = 1;
-	const VERBOSITY_VERBOSE      = 2;
-	const VERBOSITY_VERY_VERBOSE = 3;
-	const VERBOSITY_DEBUG        = 4;
+	const VERBOSITY_QUIET        = 16;
+	const VERBOSITY_NORMAL       = 32;
+	const VERBOSITY_VERBOSE      = 64;
+	const VERBOSITY_VERY_VERBOSE = 128;
+	const VERBOSITY_DEBUG        = 256;
 
 	/**
 	 * Write output using the configured closure.
--- a/phpbb/event/kernel_exception_subscriber.php
+++ b/phpbb/event/kernel_exception_subscriber.php
@@ -34,6 +34,9 @@ class kernel_exception_subscriber implements EventSubscriberInterface
 	*/
 	protected $user;
 
+	/** @var \phpbb\request\type_cast_helper */
+	protected $type_caster;
+
 	/**
 	* Construct method
 	*
@@ -44,6 +47,7 @@ class kernel_exception_subscriber implements EventSubscriberInterface
 	{
 		$this->template = $template;
 		$this->user = $user;
+		$this->type_caster = new \phpbb\request\type_cast_helper();
 	}
 
 	/**
@@ -57,6 +61,7 @@ class kernel_exception_subscriber implements EventSubscriberInterface
 		$exception = $event->getException();
 
 		$message = $exception->getMessage();
+		$this->type_caster->set_var($message, $message, 'string', false, false);
 
 		if ($exception instanceof \phpbb\exception\exception_interface)
 		{
--- a/phpbb/feed/base.php
+++ b/phpbb/feed/base.php
@@ -39,6 +39,12 @@ abstract class base
 	/** @var \phpbb\auth\auth */
 	protected $auth;
 
+	/** @var \phpbb\content_visibility */
+	protected $content_visibility;
+
+	/** @var \phpbb\event\dispatcher_interface */
+	protected $phpbb_dispatcher;
+
 	/** @var string */
 	protected $phpEx;
 
@@ -79,10 +85,21 @@ abstract class base
 	* @param \phpbb\cache\driver\driver_interface	$cache	Cache object
 	* @param \phpbb\user						$user		User object
 	* @param \phpbb\auth\auth					$auth		Auth object
-	* @param \phpbb\content_visibility			$content_visibility		Auth object
+	* @param \phpbb\content_visibility			$content_visibility		Content visibility object
+	* @param \phpbb\event\dispatcher_interface	$phpbb_dispatcher		Event dispatcher object
 	* @param string								$phpEx		php file extension
 	*/
-	function __construct(\phpbb\feed\helper $helper, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, \phpbb\user $user, \phpbb\auth\auth $auth, \phpbb\content_visibility $content_visibility, $phpEx)
+	function __construct(
+		\phpbb\feed\helper $helper,
+		\phpbb\config\config $config,
+		\phpbb\db\driver\driver_interface $db,
+		\phpbb\cache\driver\driver_interface $cache,
+		\phpbb\user $user,
+		\phpbb\auth\auth $auth,
+		\phpbb\content_visibility $content_visibility,
+		\phpbb\event\dispatcher_interface $phpbb_dispatcher,
+		$phpEx
+	)
 	{
 		$this->config = $config;
 		$this->helper = $helper;
@@ -91,6 +108,7 @@ abstract class base
 		$this->user = $user;
 		$this->auth = $auth;
 		$this->content_visibility = $content_visibility;
+		$this->phpbb_dispatcher = $phpbb_dispatcher;
 		$this->phpEx = $phpEx;
 
 		$this->set_keys();
@@ -239,6 +257,21 @@ abstract class base
 				return false;
 			}
 
+			$sql_ary = $this->sql;
+
+			/**
+			* Event to modify the feed item sql
+			*
+			* @event core.feed_base_modify_item_sql
+			* @var	array	sql_ary		The SQL array to get the feed item data
+			*
+			* @since 3.1.10-RC1
+			*/
+			$vars = array('sql_ary');
+			extract($this->phpbb_dispatcher->trigger_event('core.feed_base_modify_item_sql', compact($vars)));
+			$this->sql = $sql_ary;
+			unset($sql_ary);
+
 			// Query database
 			$sql = $this->db->sql_build_query('SELECT', $this->sql);
 			$this->result = $this->db->sql_query_limit($sql, $this->num_items);
--- a/phpbb/log/log.php
+++ b/phpbb/log/log.php
@@ -402,7 +402,7 @@ class log implements \phpbb\log\log_interface
 			}
 		}
 
-		$sql = 'DELETE FROM ' . LOG_TABLE . "
+		$sql = 'DELETE FROM ' . $this->log_table . "
 					$sql_where";
 		$this->db->sql_query($sql);
 
--- a/phpbb/notification/manager.php
+++ b/phpbb/notification/manager.php
@@ -192,7 +192,7 @@ class manager
 			$sql = 'SELECT n.*, nt.notification_type_name
 				FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
 				WHERE n.user_id = ' . (int) $options['user_id'] .
-					(($options['notification_id']) ? ((is_array($options['notification_id'])) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : ' AND n.notification_id = ' . (int) $options['notification_id']) : '') . '
+					(($options['notification_id']) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : '') . '
 					AND nt.notification_type_id = n.notification_type_id
 					AND nt.notification_type_enabled = 1
 				ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
@@ -275,10 +275,9 @@ class manager
 		$sql = 'UPDATE ' . $this->notifications_table . "
 			SET notification_read = 1
 			WHERE notification_time <= " . (int) $time .
-				(($notification_type_name !== false) ? ' AND ' .
-					(is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') .
-				(($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '') .
-				(($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '');
+				(($notification_type_name !== false) ? ' AND ' . $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : '') .
+				(($user_id !== false) ? ' AND ' . $this->db->sql_in_set('user_id', $user_id) : '') .
+				(($item_id !== false) ? ' AND ' . $this->db->sql_in_set('item_id', $item_id) : '');
 		$this->db->sql_query($sql);
 	}
 
@@ -297,10 +296,9 @@ class manager
 		$sql = 'UPDATE ' . $this->notifications_table . "
 			SET notification_read = 1
 			WHERE notification_time <= " . (int) $time .
-				(($notification_type_name !== false) ? ' AND ' .
-					(is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') .
-				(($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
-				(($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
+				(($notification_type_name !== false) ? ' AND ' . $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : '') .
+				(($item_parent_id !== false) ? ' AND ' . $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : '') .
+				(($user_id !== false) ? ' AND ' . $this->db->sql_in_set('user_id', $user_id) : '');
 		$this->db->sql_query($sql);
 	}
 
@@ -317,7 +315,7 @@ class manager
 		$sql = 'UPDATE ' . $this->notifications_table . "
 			SET notification_read = 1
 			WHERE notification_time <= " . (int) $time . '
-				AND ' . ((is_array($notification_id)) ? $this->db->sql_in_set('notification_id', $notification_id) : 'notification_id = ' . (int) $notification_id);
+				AND ' . $this->db->sql_in_set('notification_id', $notification_id);
 		$this->db->sql_query($sql);
 	}
 
@@ -542,8 +540,8 @@ class manager
 
 		$sql = 'DELETE FROM ' . $this->notifications_table . '
 			WHERE notification_type_id = ' . (int) $notification_type_id . '
-				AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) .
-				(($parent_id !== false) ? ' AND ' . ((is_array($parent_id) ? $this->db->sql_in_set('item_parent_id', $parent_id) : 'item_parent_id = ' . (int) $parent_id)) : '');
+				AND ' . $this->db->sql_in_set('item_id', $item_id) .
+				(($parent_id !== false) ? ' AND ' . $this->db->sql_in_set('item_parent_id', $parent_id) : '');
 		$this->db->sql_query($sql);
 	}
 
@@ -947,6 +945,7 @@ class manager
 		{
 			if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
 			{
+				$this->db->sql_transaction('rollback');
 				throw new \phpbb\notification\exception($this->user->lang('NOTIFICATION_TYPE_NOT_EXIST', $notification_type_name));
 			}
 
@@ -969,11 +968,16 @@ class manager
 	/**
 	* Get notification type ids (as an array)
 	*
-	* @param array $notification_type_names Array of strings
+	* @param string|array $notification_type_names Notification type names
 	* @return array Array of integers
 	*/
-	public function get_notification_type_ids(array $notification_type_names)
+	public function get_notification_type_ids($notification_type_names)
 	{
+		if (!is_array($notification_type_names))
+		{
+			$notification_type_names = array($notification_type_names);
+		}
+
 		$notification_type_ids = array();
 
 		foreach ($notification_type_names as $name)
--- a/phpbb/notification/method/messenger_base.php
+++ b/phpbb/notification/method/messenger_base.php
@@ -81,7 +81,7 @@ abstract class messenger_base extends \phpbb\notification\method\base
 			$messenger->assign_vars(array_merge(array(
 				'USERNAME'						=> $user['username'],
 
-				'U_NOTIFICATION_SETTINGS'		=> generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&amp;mode=notification_options',
+				'U_NOTIFICATION_SETTINGS'		=> generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&mode=notification_options',
 			), $notification->get_email_template_variables()));
 
 			$messenger->send($notify_method);
--- a/phpbb/search/base.php
+++ b/phpbb/search/base.php
@@ -37,52 +37,6 @@ class base
 	}
 
 	/**
-	* Retrieves a language dependend list of words that should be ignored by the search
-	*/
-	function get_ignore_words()
-	{
-		if (!sizeof($this->ignore_words))
-		{
-			global $user, $phpEx;
-
-			$words = array();
-
-			if (file_exists("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx"))
-			{
-				// include the file containing ignore words
-				include("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx");
-			}
-
-			$this->ignore_words = $words;
-			unset($words);
-		}
-	}
-
-	/**
-	* Stores a list of synonyms that should be replaced in $this->match_synonym and $this->replace_synonym and caches them
-	*/
-	function get_synonyms()
-	{
-		if (!sizeof($this->match_synonym))
-		{
-			global $user, $phpEx;
-
-			$synonyms = array();
-
-			if (file_exists("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx"))
-			{
-				// include the file containing synonyms
-				include("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx");
-			}
-
-			$this->match_synonym = array_keys($synonyms);
-			$this->replace_synonym = array_values($synonyms);
-
-			unset($synonyms);
-		}
-	}
-
-	/**
 	* Retrieves cached search results
 	*
 	* @param string $search_key		an md5 string generated from all the passed search options to identify the results
--- a/phpbb/search/fulltext_mysql.php
+++ b/phpbb/search/fulltext_mysql.php
@@ -177,8 +177,10 @@ class fulltext_mysql extends \phpbb\search\base
 			$engine === 'MyISAM' ||
 			// FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to
 			// http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html
+			// We also require https://bugs.mysql.com/bug.php?id=67004 to be
+			// fixed for proper overall operation. Hence we require 5.6.8.
 			$engine === 'InnoDB' &&
-			phpbb_version_compare($this->db->sql_server_info(true), '5.6.4', '>=');
+			phpbb_version_compare($this->db->sql_server_info(true), '5.6.8', '>=');
 
 		if (!$fulltext_supported)
 		{
--- a/phpbb/search/fulltext_native.php
+++ b/phpbb/search/fulltext_native.php
@@ -1262,7 +1262,7 @@ class fulltext_native extends \phpbb\search\base
 		if (!$total_results && $is_mysql)
 		{
 			// Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it.
-			$sql_calc = str_replace('SELECT ' . $select, 'SELECT DISTINCT SQL_CALC_FOUND_ROWS p.post_id', $sql);
+			$sql_calc = str_replace('SELECT ' . $select, 'SELECT SQL_CALC_FOUND_ROWS ' . $select, $sql);
 
 			$result = $this->db->sql_query($sql_calc);
 			$this->db->sql_freeresult($result);
--- a/phpbb/session.php
+++ b/phpbb/session.php
@@ -219,7 +219,7 @@ class session
 	function session_begin($update_session_page = true)
 	{
 		global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
-		global $request, $phpbb_container;
+		global $request, $phpbb_container, $phpbb_dispatcher;
 
 		// Give us some basic information
 		$this->time_now				= time();
@@ -281,11 +281,21 @@ class session
 
 		// Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
 		// it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
-		$this->ip = htmlspecialchars_decode($request->server('REMOTE_ADDR'));
-		$this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));
+		$ip = htmlspecialchars_decode($request->server('REMOTE_ADDR'));
+		$ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $ip));
+
+		/**
+		* Event to alter user IP address
+		*
+		* @event core.session_ip_after
+		* @var	string	ip	REMOTE_ADDR
+		* @since 3.1.10-RC1
+		*/
+		$vars = array('ip');
+		extract($phpbb_dispatcher->trigger_event('core.session_ip_after', compact($vars)));
 
 		// split the list of IPs
-		$ips = explode(' ', trim($this->ip));
+		$ips = explode(' ', trim($ip));
 
 		// Default IP if REMOTE_ADDR is invalid
 		$this->ip = '127.0.0.1';
@@ -1585,7 +1595,7 @@ class session
 
 			$this->data = array_merge($this->data, $sql_ary);
 
-			if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
+			if ($this->data['user_id'] != ANONYMOUS && isset($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
 			{
 				$this->leave_newly_registered();
 			}
--- a/phpbb/template/twig/twig.php
+++ b/phpbb/template/twig/twig.php
@@ -350,7 +350,7 @@ class twig extends \phpbb\template\base
 			return $this->twig->render($this->get_filename_from_handle($handle), $this->get_template_vars());
 		}
 
-		$this->assign_var($template_var, $this->twig->render($this->get_filename_from_handle($handle, $this->get_template_vars())));
+		$this->assign_var($template_var, $this->twig->render($this->get_filename_from_handle($handle), $this->get_template_vars()));
 
 		return $this;
 	}
--- a/posting.php
+++ b/posting.php
@@ -371,7 +371,9 @@ switch ($mode)
 *							NOTE: Should be actual language strings, NOT
 *							language keys.
 * @var	bool	is_authed	Does the user have the required permissions?
+* @var	array	post_data	All post data from database
 * @since 3.1.3-RC1
+* @changed 3.1.10-RC1 Added post_data
 */
 $vars = array(
 	'post_id',
@@ -387,6 +389,7 @@ $vars = array(
 	'mode',
 	'error',
 	'is_authed',
+	'post_data',
 );
 extract($phpbb_dispatcher->trigger_event('core.modify_posting_auth', compact($vars)));
 
@@ -1741,6 +1744,7 @@ $page_data = array(
 	'L_POST_A'					=> $page_title,
 	'L_ICON'					=> ($mode == 'reply' || $mode == 'quote' || ($mode == 'edit' && $post_id != $post_data['topic_first_post_id'])) ? $user->lang['POST_ICON'] : $user->lang['TOPIC_ICON'],
 	'L_MESSAGE_BODY_EXPLAIN'	=> $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']),
+	'L_DELETE_POST_PERMANENTLY'	=> $user->lang('DELETE_POST_PERMANENTLY', 1),
 
 	'FORUM_NAME'			=> $post_data['forum_name'],
 	'FORUM_DESC'			=> ($post_data['forum_desc']) ? generate_text_for_display($post_data['forum_desc'], $post_data['forum_desc_uid'], $post_data['forum_desc_bitfield'], $post_data['forum_desc_options']) : '',
--- a/search.php
+++ b/search.php
@@ -126,6 +126,26 @@ gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $
 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
 $pagination = $phpbb_container->get('pagination');
 
+/**
+* This event allows you to alter the above parameters, such as keywords and submit
+*
+* @event core.search_modify_submit_parameters
+* @var	string	keywords	The search keywords
+* @var	string	author		Specifies the author match, when ANONYMOUS is also a search-match
+* @var	int		author_id	ID of the author to search by
+* @var	string	search_id	Predefined search type name
+* @var	bool	submit		Whether or not the form has been submitted
+* @since 3.1.10-RC1
+*/
+$vars = array(
+	'keywords',
+	'author',
+	'author_id',
+	'search_id',
+	'submit',
+);
+extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars)));
+
 if ($keywords || $author || $author_id || $search_id || $submit)
 {
 	// clear arrays
@@ -320,7 +340,10 @@ if ($keywords || $author || $author_id || $search_id || $submit)
 	* @var	array	ex_fid_ary		Array of excluded forum ids
 	* @var	array	author_id_ary	Array of exclusive author ids
 	* @var	string	search_id		The id of the search request
+	* @var	array	id_ary			Array of post or topic ids for search result
+	* @var	string	show_results	'posts' or 'topics' type of ids
 	* @since 3.1.3-RC1
+	* @changed 3.1.10-RC1 Added id_ary, show_results
 	*/
 	$vars = array(
 		'keywords',
@@ -328,6 +351,8 @@ if ($keywords || $author || $author_id || $search_id || $submit)
 		'ex_fid_ary',
 		'author_id_ary',
 		'search_id',
+		'id_ary',
+		'show_results',
 	);
 	extract($phpbb_dispatcher->trigger_event('core.search_modify_param_before', compact($vars)));
 
@@ -570,6 +595,48 @@ if ($keywords || $author || $author_id || $search_id || $submit)
 		$total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page);
 	}
 
+	/**
+	* Event to search otherwise than by keywords or author
+	*
+	* @event core.search_backend_search_after
+	* @var	string		show_results				'posts' or 'topics' type of ids
+	* @var	string		search_fields				The data fields to search in
+	* @var	string		search_terms				Is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words)
+	* @var	array		sort_by_sql					Array of SQL sorting instructions
+	* @var	string		sort_key					The sort key
+	* @var	string		sort_dir					The sort direction
+	* @var	int			sort_days					Limit the age of results
+	* @var	array		ex_fid_ary					Array of excluded forum ids
+	* @var	string		m_approve_posts_fid_sql		Specifies which types of posts the user can view in which forums
+	* @var	int			topic_id					is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched
+	* @var	array		author_id_ary				Array of exclusive author ids
+	* @var	string		sql_author_match			Specifies the author match, when ANONYMOUS is also a search-match
+	* @var	array		id_ary						Array of post or topic ids for search result
+	* @var	int			start						The starting id of the results
+	* @var	int			per_page					Number of ids each page is supposed to contain
+	* @var	int			total_match_count			The total number of search matches
+	* @since 3.1.10-RC1
+	*/
+	$vars = array(
+		'show_results',
+		'search_fields',
+		'search_terms',
+		'sort_by_sql',
+		'sort_key',
+		'sort_dir',
+		'sort_days',
+		'ex_fid_ary',
+		'm_approve_posts_fid_sql',
+		'topic_id',
+		'author_id_ary',
+		'sql_author_match',
+		'id_ary',
+		'start',
+		'per_page',
+		'total_match_count',
+	);
+	extract($phpbb_dispatcher->trigger_event('core.search_backend_search_after', compact($vars)));
+
 	$sql_where = '';
 
 	if (sizeof($id_ary))
@@ -620,11 +687,18 @@ if ($keywords || $author || $author_id || $search_id || $submit)
 	* @event core.search_modify_url_parameters
 	* @var	string	u_search		Search URL parameters string
 	* @var	string	search_id		Predefined search type name
+	* @var	string	show_results	String indicating the show results mode
+	* @var	string	sql_where		The SQL WHERE string used by search to get topic data
+	* @var	int		total_match_count	The total number of search matches
 	* @since 3.1.7-RC1
+	* @changed 3.1.10-RC1 Added show_results, sql_where, total_match_count
 	*/
 	$vars = array(
 		'u_search',
 		'search_id',
+		'show_results',
+		'sql_where',
+		'total_match_count',
 	);
 	extract($phpbb_dispatcher->trigger_event('core.search_modify_url_parameters', compact($vars)));
 
@@ -1249,6 +1323,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
 }
 
 // Search forum
+$rowset = array();
 $s_forums = '';
 $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id
 	FROM ' . FORUMS_TABLE . ' f
@@ -1257,11 +1332,27 @@ $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f
 	ORDER BY f.left_id ASC";
 $result = $db->sql_query($sql);
 
+while ($row = $db->sql_fetchrow($result))
+{
+	$rowset[(int) $row['forum_id']] = $row;
+}
+$db->sql_freeresult($result);
+
 $right = $cat_right = $padding_inc = 0;
 $padding = $forum_list = $holding = '';
 $pad_store = array('0' => '');
 
-while ($row = $db->sql_fetchrow($result))
+/**
+* Modify the forum select list for advanced search page
+*
+* @event core.search_modify_forum_select_list
+* @var	array	rowset	Array with the forums list data
+* @since 3.1.10-RC1
+*/
+$vars = array('rowset');
+extract($phpbb_dispatcher->trigger_event('core.search_modify_forum_select_list', compact($vars)));
+
+foreach ($rowset as $row)
 {
 	if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']))
 	{
@@ -1333,8 +1424,8 @@ if ($holding)
 	$s_forums .= $holding;
 }
 
-$db->sql_freeresult($result);
 unset($pad_store);
+unset($rowset);
 
 if (!$s_forums)
 {
--- a/styles/prosilver/style.cfg
+++ b/styles/prosilver/style.cfg
@@ -21,8 +21,8 @@
 # General Information about this style
 name = prosilver
 copyright = © phpBB Limited, 2007
-style_version = 3.1.9
-phpbb_version = 3.1.9
+style_version = 3.1.10
+phpbb_version = 3.1.10
 
 # Defining a different template bitfield
 # template_bitfield = lNg=
--- a/styles/prosilver/template/confirm_delete_body.html
+++ b/styles/prosilver/template/confirm_delete_body.html
@@ -7,7 +7,7 @@
 			<label>
 				<strong>{L_DELETE_PERMANENTLY}{L_COLON}</strong>
 				<input id="delete_permanent" name="delete_permanent" type="checkbox" value="1" {S_CHECKED_PERMANENT} />
-				<!-- IF S_TOPIC_MODE -->{L_DELETE_TOPIC_PERMANENTLY}<!-- ELSE -->{L_DELETE_POST_PERMANENTLY}<!-- ENDIF -->
+				<!-- IF S_TOPIC_MODE -->{DELETE_TOPIC_PERMANENTLY_EXPLAIN}<!-- ELSE -->{DELETE_POST_PERMANENTLY_EXPLAIN}<!-- ENDIF -->
 			</label>
 		<!-- ENDIF -->
 
@@ -43,7 +43,7 @@
 				<dd>
 					<label for="delete_permanent">
 						<input id="delete_permanent" name="delete_permanent" type="checkbox" value="1" {S_CHECKED_PERMANENT} />
-						<!-- IF S_TOPIC_MODE -->{L_DELETE_TOPIC_PERMANENTLY}<!-- ELSE -->{L_DELETE_POST_PERMANENTLY}<!-- ENDIF -->
+						<!-- IF S_TOPIC_MODE -->{DELETE_TOPIC_PERMANENTLY_EXPLAIN}<!-- ELSE -->{DELETE_POST_PERMANENTLY_EXPLAIN}<!-- ENDIF -->
 					</label>
 				</dd>
 			</dl>
--- a/styles/prosilver/template/mcp_forum.html
+++ b/styles/prosilver/template/mcp_forum.html
@@ -50,7 +50,7 @@
 					<!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF -->
 					<!-- IF topicrow.S_MOVED_TOPIC and S_CAN_DELETE -->&nbsp;<a href="{topicrow.U_DELETE_TOPIC}" class="topictitle">[ {L_DELETE_SHADOW_TOPIC} ]</a><!-- ENDIF -->
 					<br />
-
+					<!-- EVENT topiclist_row_topic_title_after -->
 					<div class="responsive-show" style="display: none;">
 						<!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
 						{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; {topicrow.LAST_POST_TIME}<br />
--- a/styles/prosilver/template/mcp_move.html
+++ b/styles/prosilver/template/mcp_move.html
@@ -31,6 +31,8 @@
 
 <!-- INCLUDE overall_header.html -->
 
+<!-- EVENT mcp_move_before -->
+
 <form id="confirm" action="{S_CONFIRM_ACTION}" method="post">
 
 <div class="panel">
@@ -54,7 +56,7 @@
 		</fieldset>
 
 		<fieldset class="submit-buttons">
-			{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp; 
+			{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp;
 			<input type="submit" name="cancel" value="{L_NO}" class="button2" />
 			{S_FORM_TOKEN}
 		</fieldset>
--- a/styles/prosilver/template/mcp_topic.html
+++ b/styles/prosilver/template/mcp_topic.html
@@ -73,7 +73,7 @@
 	<dl>
 		<dt><label for="to_topic_id">{L_MERGE_TOPIC_ID}{L_COLON}</label></dt>
 		<dd>
-			<input class="inputbox autowidth" type="number" min="0" max="999999" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
+			<input class="inputbox autowidth" type="number" min="0" max="9999999999" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
 			<a href="{U_SELECT_TOPIC}" >{L_SELECT_TOPIC}</a>
 		</dd>
 		<!-- IF TO_TOPIC_INFO --><dd>{TO_TOPIC_INFO}</dd><!-- ENDIF -->
@@ -112,7 +112,10 @@
 				</ul>
 
 				<h3><a href="{postrow.U_POST_DETAILS}">{postrow.POST_SUBJECT}</a></h3>
+
+				<!-- EVENT mcp_topic_postrow_post_details_before -->
 				<p class="author"><a href="#pr{postrow.POST_ID}">{postrow.MINI_POST_IMG}</a> {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong><!-- IF postrow.U_MCP_DETAILS --> [ <a href="{postrow.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF --></p>
+				<!-- EVENT mcp_topic_postrow_post_details_after -->
 
 				<!-- IF postrow.S_POST_UNAPPROVED -->
 				<p class="post-notice unapproved">
--- a/styles/prosilver/template/memberlist_email.html
+++ b/styles/prosilver/template/memberlist_email.html
@@ -1,5 +1,7 @@
 <!-- INCLUDE overall_header.html -->
 
+<!-- EVENT memberlist_email_before -->
+
 <!-- IF S_CONTACT_ADMIN-->
 <h2 class="titlespace">{L_CONTACT_ADMIN}</h2>
 <!-- ELSEIF S_SEND_USER -->
--- a/styles/prosilver/template/overall_header.html
+++ b/styles/prosilver/template/overall_header.html
@@ -76,6 +76,7 @@
 	<a id="top" class="anchor" accesskey="t"></a>
 	<div id="page-header">
 		<div class="headerbar" role="banner">
+		<!-- EVENT overall_header_headerbar_before -->
 			<div class="inner">
 
 			<div id="site-description">
@@ -100,6 +101,7 @@
 			<!-- ENDIF -->
 
 			</div>
+			<!-- EVENT overall_header_headerbar_after -->
 		</div>
 		<!-- EVENT overall_header_navbar_before -->
 		<!-- INCLUDE navbar_header.html -->
--- a/styles/prosilver/template/posting_editor.html
+++ b/styles/prosilver/template/posting_editor.html
@@ -23,7 +23,11 @@
 	<!-- IF S_POST_ACTION or S_PRIVMSGS or S_EDIT_DRAFT -->
 	<dl style="clear: left;">
 		<dt><label for="subject">{L_SUBJECT}{L_COLON}</label></dt>
-		<dd><input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" /></dd>
+		<dd>
+			<!-- EVENT posting_editor_subject_prepend -->
+			<input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" />
+			<!-- EVENT posting_editor_subject_append -->
+		</dd>
 	</dl>
 	<!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE -->
 		<!-- DEFINE $CAPTCHA_TAB_INDEX = 3 -->
--- a/styles/prosilver/template/posting_topic_review.html
+++ b/styles/prosilver/template/posting_topic_review.html
@@ -43,7 +43,10 @@
 			</ul>
 			<!-- ENDIF -->
 
+			<!-- EVENT posting_topic_review_row_post_details_before -->
 			<p class="author"><!-- IF S_IS_BOT -->{topic_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{topic_review_row.U_MINI_POST}">{topic_review_row.MINI_POST_IMG}</a><!-- ENDIF --> {L_POST_BY_AUTHOR} <strong>{topic_review_row.POST_AUTHOR_FULL}</strong> &raquo; {topic_review_row.POST_DATE}  </p>
+			<!-- EVENT posting_topic_review_row_post_details_after -->
+
 			<div class="content">{topic_review_row.MESSAGE}</div>
 
 			<!-- IF topic_review_row.S_HAS_ATTACHMENTS -->
--- a/styles/prosilver/template/search_results.html
+++ b/styles/prosilver/template/search_results.html
@@ -91,6 +91,7 @@
 							</div>
 							<!-- ENDIF -->
 							<!-- IF searchresults.S_HAS_POLL -->{POLL_IMG} <!-- ENDIF -->
+							<!-- EVENT topiclist_row_topic_title_after -->
 							{L_POST_BY_AUTHOR} {searchresults.TOPIC_AUTHOR_FULL} &raquo; {searchresults.FIRST_POST_TIME} &raquo; {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
 							<!-- EVENT topiclist_row_append -->
 
--- a/styles/prosilver/template/viewforum_body.html
+++ b/styles/prosilver/template/viewforum_body.html
@@ -121,6 +121,8 @@
 
 <!-- ENDIF -->
 
+<!-- EVENT viewforum_body_topic_row_before -->
+
 <!-- BEGIN topicrow -->
 
 	<!-- IF not topicrow.S_TOPIC_TYPE_SWITCH and not topicrow.S_FIRST_ROW -->
@@ -145,7 +147,7 @@
 		<ul class="topiclist topics">
 	<!-- ENDIF -->
 
-		<!-- EVENT viewforum_body_topic_row_before -->
+		<!-- EVENT viewforum_body_topicrow_row_before -->
 		<li class="row<!-- IF topicrow.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_POST_GLOBAL --> global-announce<!-- ENDIF --><!-- IF topicrow.S_POST_ANNOUNCE --> announce<!-- ENDIF --><!-- IF topicrow.S_POST_STICKY --> sticky<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
 			<!-- EVENT viewforum_body_topic_row_prepend -->
 			<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
@@ -157,7 +159,7 @@
 						<!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
 						<!-- IF topicrow.S_TOPIC_DELETED --><a href="{topicrow.U_MCP_QUEUE}">{DELETED_IMG}</a> <!-- ENDIF -->
 						<!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
-
+						<!-- EVENT topiclist_row_topic_title_after -->
 						<!-- IF not S_IS_BOT -->
 						<div class="responsive-show" style="display: none;">
 							{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{topicrow.LAST_POST_TIME}</a>
--- a/vendor/autoload.php
+++ b/vendor/autoload.php
@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer' . '/autoload_real.php';
 
-return ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25::getLoader();
+return ComposerAutoloaderInit302cb276591cf8e8fafc63fc4c8c0639::getLoader();
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -170,10 +170,10 @@ return array(
     'Symfony\\Component\\Config\\Tests\\Loader\\LoaderTest' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Loader/LoaderTest.php',
     'Symfony\\Component\\Config\\Tests\\Loader\\ProjectLoader1' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Loader/LoaderTest.php',
     'Symfony\\Component\\Config\\Tests\\Loader\\TestFileLoader' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php',
-    'Symfony\\Component\\Config\\Tests\\Loader\\Validator' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php',
-    'Symfony\\Component\\Config\\Tests\\Loader\\XmlUtilsTest' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php',
     'Symfony\\Component\\Config\\Tests\\Resource\\DirectoryResourceTest' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php',
     'Symfony\\Component\\Config\\Tests\\Resource\\FileResourceTest' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Resource/FileResourceTest.php',
+    'Symfony\\Component\\Config\\Tests\\Util\\Validator' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php',
+    'Symfony\\Component\\Config\\Tests\\Util\\XmlUtilsTest' => $vendorDir . '/symfony/config/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php',
     'Symfony\\Component\\Config\\Util\\XmlUtils' => $vendorDir . '/symfony/config/Symfony/Component/Config/Util/XmlUtils.php',
     'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Symfony/Component/Console/Application.php',
     'Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Symfony/Component/Console/Command/Command.php',
@@ -666,11 +666,13 @@ return array(
     'Symfony\\Component\\HttpKernel\\Tests\\Fragment\\InlineFragmentRendererTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\Fragment\\Renderer' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\Fragment\\RoutableFragmentRendererTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php',
+    'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\EsiResponseCacheStrategyTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/EsiResponseCacheStrategyTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\EsiTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\HttpCacheTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\HttpCacheTestCase' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\StoreTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\TestHttpKernel' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/TestHttpKernel.php',
+    'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\TestKernel' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpCache\\TestMultipleHttpKernel' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpCache/TestMultipleHttpKernel.php',
     'Symfony\\Component\\HttpKernel\\Tests\\HttpKernelTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\KernelTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/KernelTest.php',
@@ -689,6 +691,7 @@ return array(
     'Symfony\\Component\\HttpKernel\\Tests\\Profiler\\RedisProfilerStorageTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/Profiler/RedisProfilerStorageTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\Profiler\\SqliteProfilerStorageTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/Profiler/SqliteProfilerStorageTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\TestHttpKernel' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/TestHttpKernel.php',
+    'Symfony\\Component\\HttpKernel\\Tests\\TestKernel' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/KernelTest.php',
     'Symfony\\Component\\HttpKernel\\Tests\\UriSignerTest' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/Tests/UriSignerTest.php',
     'Symfony\\Component\\HttpKernel\\UriSigner' => $vendorDir . '/symfony/http-kernel/Symfony/Component/HttpKernel/UriSigner.php',
     'Symfony\\Component\\Routing\\Annotation\\Route' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Annotation/Route.php',
@@ -739,6 +742,7 @@ return array(
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\AnnotatedClasses\\AbstractClass' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php',
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\AnnotatedClasses\\BarClass' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php',
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\AnnotatedClasses\\FooClass' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php',
+    'Symfony\\Component\\Routing\\Tests\\Fixtures\\AnnotatedClasses\\FooTrait' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooTrait.php',
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\CustomXmlFileLoader' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php',
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\OtherAnnotatedClasses\\VariadicClass' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php',
     'Symfony\\Component\\Routing\\Tests\\Fixtures\\RedirectableUrlMatcher' => $vendorDir . '/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php',
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25
+class ComposerAutoloaderInit302cb276591cf8e8fafc63fc4c8c0639
 {
     private static $loader;
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInit302cb276591cf8e8fafc63fc4c8c0639', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInit302cb276591cf8e8fafc63fc4c8c0639', 'loadClassLoader'));
 
         $map = require __DIR__ . '/autoload_namespaces.php';
         foreach ($map as $namespace => $path) {
@@ -42,14 +42,14 @@ class ComposerAutoloaderInit98fc23e26098ada3cf8da314b4e5be25
 
         $includeFiles = require __DIR__ . '/autoload_files.php';
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire98fc23e26098ada3cf8da314b4e5be25($fileIdentifier, $file);
+            composerRequire302cb276591cf8e8fafc63fc4c8c0639($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
 
-function composerRequire98fc23e26098ada3cf8da314b4e5be25($fileIdentifier, $file)
+function composerRequire302cb276591cf8e8fafc63fc4c8c0639($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         require $file;
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -66,24 +66,24 @@
     },
     {
         "name": "symfony/filesystem",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Filesystem",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/filesystem.git",
-            "reference": "56f6725f520a357e19deaef6558c3d223046b843"
+            "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/filesystem/zipball/56f6725f520a357e19deaef6558c3d223046b843",
-            "reference": "56f6725f520a357e19deaef6558c3d223046b843",
+            "url": "https://api.github.com/repos/symfony/filesystem/zipball/8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
+            "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
             "shasum": ""
         },
         "require": {
             "php": ">=5.3.3"
         },
-        "time": "2016-03-10 16:50:02",
+        "time": "2016-04-12 15:20:10",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -118,25 +118,25 @@
     },
     {
         "name": "symfony/config",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Config",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/config.git",
-            "reference": "1324aed10a750ed5a0446a71d95e321bf5d3bd24"
+            "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/config/zipball/1324aed10a750ed5a0446a71d95e321bf5d3bd24",
-            "reference": "1324aed10a750ed5a0446a71d95e321bf5d3bd24",
+            "url": "https://api.github.com/repos/symfony/config/zipball/16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
+            "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
             "shasum": ""
         },
         "require": {
             "php": ">=5.3.3",
             "symfony/filesystem": "~2.3"
         },
-        "time": "2016-03-04 07:12:06",
+        "time": "2016-05-30 08:14:41",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -171,18 +171,18 @@
     },
     {
         "name": "symfony/console",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Console",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/console.git",
-            "reference": "cc386594e19024e53e81ee7b6d6c37c221864c4e"
+            "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/console/zipball/cc386594e19024e53e81ee7b6d6c37c221864c4e",
-            "reference": "cc386594e19024e53e81ee7b6d6c37c221864c4e",
+            "url": "https://api.github.com/repos/symfony/console/zipball/20c12c6d6c5a087a66d4e77999451713a92a3507",
+            "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507",
             "shasum": ""
         },
         "require": {
@@ -194,7 +194,7 @@
         "suggest": {
             "symfony/event-dispatcher": ""
         },
-        "time": "2016-03-04 09:20:54",
+        "time": "2016-05-26 08:04:58",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -229,18 +229,18 @@
     },
     {
         "name": "symfony/dependency-injection",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/DependencyInjection",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/dependency-injection.git",
-            "reference": "7cbda8ce5b5e4bd865401cf243070708e1f9a5e6"
+            "reference": "06265ee128644eb70356bd72ab28c9ded6618d19"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7cbda8ce5b5e4bd865401cf243070708e1f9a5e6",
-            "reference": "7cbda8ce5b5e4bd865401cf243070708e1f9a5e6",
+            "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/06265ee128644eb70356bd72ab28c9ded6618d19",
+            "reference": "06265ee128644eb70356bd72ab28c9ded6618d19",
             "shasum": ""
         },
         "require": {
@@ -255,7 +255,7 @@
             "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
             "symfony/yaml": ""
         },
-        "time": "2016-03-08 16:58:37",
+        "time": "2016-05-30 08:31:06",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -290,17 +290,17 @@
     },
     {
         "name": "symfony/polyfill-mbstring",
-        "version": "v1.1.1",
-        "version_normalized": "1.1.1.0",
+        "version": "v1.2.0",
+        "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/polyfill-mbstring.git",
-            "reference": "1289d16209491b584839022f29257ad859b8532d"
+            "reference": "dff51f72b0706335131b00a7f49606168c582594"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
-            "reference": "1289d16209491b584839022f29257ad859b8532d",
+            "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+            "reference": "dff51f72b0706335131b00a7f49606168c582594",
             "shasum": ""
         },
         "require": {
@@ -309,11 +309,11 @@
         "suggest": {
             "ext-mbstring": "For best performance"
         },
-        "time": "2016-01-20 09:13:37",
+        "time": "2016-05-18 14:26:46",
         "type": "library",
         "extra": {
             "branch-alias": {
-                "dev-master": "1.1-dev"
+                "dev-master": "1.2-dev"
             }
         },
         "installation-source": "dist",
@@ -351,25 +351,25 @@
     },
     {
         "name": "symfony/http-foundation",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/HttpFoundation",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/http-foundation.git",
-            "reference": "f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40"
+            "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40",
-            "reference": "f5cd42d4895d9ede5d26cb1b2883dd4f7e455a40",
+            "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
+            "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
             "shasum": ""
         },
         "require": {
             "php": ">=5.3.3",
             "symfony/polyfill-mbstring": "~1.1"
         },
-        "time": "2016-03-12 16:03:08",
+        "time": "2016-05-13 15:22:39",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -407,18 +407,18 @@
     },
     {
         "name": "symfony/event-dispatcher",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/EventDispatcher",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/event-dispatcher.git",
-            "reference": "b2d9d812e21d6e00983061d49ee61a82f54cace7"
+            "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b2d9d812e21d6e00983061d49ee61a82f54cace7",
-            "reference": "b2d9d812e21d6e00983061d49ee61a82f54cace7",
+            "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fd6d162d97bf3e6060622e5c015af39ca72e33bc",
+            "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc",
             "shasum": ""
         },
         "require": {
@@ -431,7 +431,7 @@
             "symfony/dependency-injection": "",
             "symfony/http-kernel": ""
         },
-        "time": "2016-03-04 07:12:06",
+        "time": "2016-04-04 09:22:54",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -466,18 +466,18 @@
     },
     {
         "name": "symfony/debug",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Debug",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/debug.git",
-            "reference": "a6f7b78e406658897f689fa8b00a06205446bebd"
+            "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/debug/zipball/a6f7b78e406658897f689fa8b00a06205446bebd",
-            "reference": "a6f7b78e406658897f689fa8b00a06205446bebd",
+            "url": "https://api.github.com/repos/symfony/debug/zipball/863d29c31a1ddfcf1faedf5f8362f392e3261632",
+            "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632",
             "shasum": ""
         },
         "require": {
@@ -495,7 +495,7 @@
             "symfony/http-foundation": "",
             "symfony/http-kernel": ""
         },
-        "time": "2016-03-04 13:04:09",
+        "time": "2016-03-30 09:02:35",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -570,18 +570,18 @@
     },
     {
         "name": "symfony/http-kernel",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/HttpKernel",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/http-kernel.git",
-            "reference": "a704146970a1ff261c05e865b636bcc5d95f1b5b"
+            "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a704146970a1ff261c05e865b636bcc5d95f1b5b",
-            "reference": "a704146970a1ff261c05e865b636bcc5d95f1b5b",
+            "url": "https://api.github.com/repos/symfony/http-kernel/zipball/57e0329236e8edf2b0e683043c604f7c9aba9398",
+            "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398",
             "shasum": ""
         },
         "require": {
@@ -613,7 +613,7 @@
             "symfony/dependency-injection": "",
             "symfony/finder": ""
         },
-        "time": "2016-03-13 16:38:02",
+        "time": "2016-05-30 08:41:10",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -648,18 +648,18 @@
     },
     {
         "name": "symfony/routing",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Routing",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/routing.git",
-            "reference": "9f464f27cb127232f5c32d5a736fe769e5249442"
+            "reference": "5b8a2bb7569df81401171829498809e90d6e446c"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/routing/zipball/9f464f27cb127232f5c32d5a736fe769e5249442",
-            "reference": "9f464f27cb127232f5c32d5a736fe769e5249442",
+            "url": "https://api.github.com/repos/symfony/routing/zipball/5b8a2bb7569df81401171829498809e90d6e446c",
+            "reference": "5b8a2bb7569df81401171829498809e90d6e446c",
             "shasum": ""
         },
         "require": {
@@ -677,7 +677,7 @@
             "symfony/config": "",
             "symfony/yaml": ""
         },
-        "time": "2016-03-04 07:12:06",
+        "time": "2016-05-29 10:13:06",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -712,24 +712,24 @@
     },
     {
         "name": "symfony/yaml",
-        "version": "v2.3.39",
-        "version_normalized": "2.3.39.0",
+        "version": "v2.3.42",
+        "version_normalized": "2.3.42.0",
         "target-dir": "Symfony/Component/Yaml",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/yaml.git",
-            "reference": "d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe"
+            "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/yaml/zipball/d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe",
-            "reference": "d5a6f4c771ae5d3faedda30eeb8db4cfb40a59fe",
+            "url": "https://api.github.com/repos/symfony/yaml/zipball/2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
+            "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
             "shasum": ""
         },
         "require": {
             "php": ">=5.3.3"
         },
-        "time": "2016-03-04 07:12:08",
+        "time": "2016-05-30 08:10:17",
         "type": "library",
         "extra": {
             "branch-alias": {
@@ -764,17 +764,17 @@
     },
     {
         "name": "twig/twig",
-        "version": "v1.24.0",
-        "version_normalized": "1.24.0.0",
+        "version": "v1.24.1",
+        "version_normalized": "1.24.1.0",
         "source": {
             "type": "git",
             "url": "https://github.com/twigphp/Twig.git",
-            "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
+            "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
-            "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
+            "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512",
+            "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512",
             "shasum": ""
         },
         "require": {
@@ -784,7 +784,7 @@
             "symfony/debug": "~2.7",
             "symfony/phpunit-bridge": "~2.7"
         },
-        "time": "2016-01-25 21:22:18",
+        "time": "2016-05-30 09:11:59",
         "type": "library",
         "extra": {
             "branch-alias": {
--- a/vendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.php
+++ b/vendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.php
@@ -108,6 +108,9 @@ abstract class FileLoader extends Loader
             } catch (\Exception $e) {
                 unset(self::$loading[$resource]);
                 throw $e;
+            } catch (\Throwable $e) {
+                unset(self::$loading[$resource]);
+                throw $e;
             }
 
             unset(self::$loading[$resource]);
--- a/vendor/symfony/console/Symfony/Component/Console/Command/Command.php
+++ b/vendor/symfony/console/Symfony/Component/Console/Command/Command.php
@@ -287,14 +287,14 @@ class Command
             return;
         }
 
+        $this->definition->addOptions($this->application->getDefinition()->getOptions());
+
         if ($mergeArgs) {
             $currentArguments = $this->definition->getArguments();
             $this->definition->setArguments($this->application->getDefinition()->getArguments());
             $this->definition->addArguments($currentArguments);
         }
 
-        $this->definition->addOptions($this->application->getDefinition()->getOptions());
-
         $this->applicationDefinitionMerged = true;
         if ($mergeArgs) {
             $this->applicationDefinitionMergedWithArgs = true;
@@ -537,10 +537,15 @@ class Command
      *
      * @return mixed The helper value
      *
+     * @throws \LogicException           if no HelperSet is defined
      * @throws \InvalidArgumentException if the helper is not defined
      */
     public function getHelper($name)
     {
+        if (null === $this->helperSet) {
+            throw new \LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
+        }
+
         return $this->helperSet->get($name);
     }
 
--- a/vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php
+++ b/vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php
@@ -85,7 +85,7 @@ class StreamOutput extends Output
      *
      * Colorization is disabled if not supported by the stream:
      *
-     *  -  Windows without Ansicon, ConEmu or Mintty
+     *  -  Windows before 10.0.10586 without Ansicon, ConEmu or Mintty
      *  -  non tty consoles
      *
      * @return bool true if the stream supports colorization, false otherwise
@@ -94,7 +94,11 @@ class StreamOutput extends Output
     {
         // @codeCoverageIgnoreStart
         if (DIRECTORY_SEPARATOR === '\\') {
-            return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
+            return
+                0 >= version_compare('10.0.10586', PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD)
+                || false !== getenv('ANSICON')
+                || 'ON' === getenv('ConEmuANSI')
+                || 'xterm' === getenv('TERM');
         }
 
         return function_exists('posix_isatty') && @posix_isatty($this->stream);
--- a/vendor/symfony/debug/Symfony/Component/Debug/Debug.php
+++ b/vendor/symfony/debug/Symfony/Component/Debug/Debug.php
@@ -46,6 +46,30 @@ class Debug
         ErrorHandler::register($errorReportingLevel, $displayErrors);
         if ('cli' !== PHP_SAPI) {
             ExceptionHandler::register();
+
+            if (PHP_VERSION_ID >= 70000) {
+                $exceptionHandler = set_exception_handler(function ($throwable) use (&$exceptionHandler) {
+                    if ($throwable instanceof \Exception) {
+                        $exception = $throwable;
+                    } else {
+                        static $refl = null;
+
+                        if (null === $refl) {
+                            $refl = array();
+                            foreach (array('file', 'line', 'trace') as $prop) {
+                                $prop = new \ReflectionProperty('Exception', $prop);
+                                $prop->setAccessible(true);
+                                $refl[] = $prop;
+                            }
+                        }
+                        $exception = new \Exception($throwable->getMessage(), $throwable->getCode());
+                        foreach ($refl as $prop) {
+                            $prop->setValue($exception, $throwable->{'get'.$prop->name}());
+                        }
+                    }
+                    $exceptionHandler($exception);
+                });
+            }
         // CLI - display errors only if they're not already logged to STDERR
         } elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) {
             ini_set('display_errors', 1);
--- a/vendor/symfony/debug/Symfony/Component/Debug/ErrorHandler.php
+++ b/vendor/symfony/debug/Symfony/Component/Debug/ErrorHandler.php
@@ -197,6 +197,12 @@ class ErrorHandler
         $exceptionHandler = set_exception_handler(function () {});
         restore_exception_handler();
 
+        if (PHP_VERSION_ID >= 70000 && $exceptionHandler instanceof \Closure) {
+            $reflector = new \ReflectionFunction($exceptionHandler);
+            foreach ($reflector->getStaticVariables() as $exceptionHandler) {
+                break;
+            }
+        }
         if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) {
             $level = isset($this->levels[$type]) ? $this->levels[$type] : $type;
             $message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']);
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.php
@@ -17,8 +17,6 @@ class Alias
     private $public;
 
     /**
-     * Constructor.
-     *
      * @param string $id     Alias identifier
      * @param bool   $public If this alias is public
      */
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php
@@ -34,8 +34,6 @@ class AnalyzeServiceReferencesPass implements RepeatablePassInterface
     private $onlyConstructorArguments;
 
     /**
-     * Constructor.
-     *
      * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
      */
     public function __construct($onlyConstructorArguments = false)
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.php
@@ -25,9 +25,6 @@ class Compiler
     private $loggingFormatter;
     private $serviceReferenceGraph;
 
-    /**
-     * Constructor.
-     */
     public function __construct()
     {
         $this->passConfig = new PassConfig();
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
@@ -35,9 +35,6 @@ class PassConfig
     private $optimizationPasses;
     private $removingPasses;
 
-    /**
-     * Constructor.
-     */
     public function __construct()
     {
         $this->mergePass = new MergeExtensionConfigurationPass();
@@ -59,8 +56,8 @@ class PassConfig
 
         $this->removingPasses = array(
             new RemovePrivateAliasesPass(),
-            new RemoveAbstractDefinitionsPass(),
             new ReplaceAliasByActualDefinitionPass(),
+            new RemoveAbstractDefinitionsPass(),
             new RepeatedPass(array(
                 new AnalyzeServiceReferencesPass(),
                 new InlineServiceDefinitionsPass(),
@@ -103,8 +100,7 @@ class PassConfig
             throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
         }
 
-        $passes = &$this->$property;
-        $passes[] = $pass;
+        $this->{$property}[] = $pass;
     }
 
     /**
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php
@@ -32,8 +32,6 @@ class RepeatedPass implements CompilerPassInterface
     private $passes;
 
     /**
-     * Constructor.
-     *
      * @param RepeatablePassInterface[] $passes An array of RepeatablePassInterface objects
      *
      * @throws InvalidArgumentException when the passes don't implement RepeatablePassInterface
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
@@ -25,7 +25,6 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
 {
     private $compiler;
     private $formatter;
-    private $sourceId;
 
     /**
      * Process the Container to replace aliases with service definitions.
@@ -36,101 +35,99 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
      */
     public function process(ContainerBuilder $container)
     {
+        // Setup
         $this->compiler = $container->getCompiler();
         $this->formatter = $this->compiler->getLoggingFormatter();
-
-        foreach ($container->getAliases() as $id => $alias) {
-            $aliasId = (string) $alias;
-
+        // First collect all alias targets that need to be replaced
+        $seenAliasTargets = array();
+        $replacements = array();
+        foreach ($container->getAliases() as $definitionId => $target) {
+            $targetId = (string) $target;
+            // Special case: leave this target alone
+            if ('service_container' === $targetId) {
+                continue;
+            }
+            // Check if target needs to be replaces
+            if (isset($replacements[$targetId])) {
+                $container->setAlias($definitionId, $replacements[$targetId]);
+            }
+            // No neeed to process the same target twice
+            if (isset($seenAliasTargets[$targetId])) {
+                continue;
+            }
+            // Process new target
+            $seenAliasTargets[$targetId] = true;
             try {
-                $definition = $container->getDefinition($aliasId);
+                $definition = $container->getDefinition($targetId);
             } catch (InvalidArgumentException $e) {
-                throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e);
+                throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e);
             }
-
             if ($definition->isPublic()) {
                 continue;
             }
-
+            // Remove private definition and schedule for replacement
             $definition->setPublic(true);
-            $container->setDefinition($id, $definition);
-            $container->removeDefinition($aliasId);
-
-            $this->updateReferences($container, $aliasId, $id);
-
-            // we have to restart the process due to concurrent modification of
-            // the container
-            $this->process($container);
-
-            break;
-        }
-    }
-
-    /**
-     * Updates references to remove aliases.
-     *
-     * @param ContainerBuilder $container The container
-     * @param string           $currentId The alias identifier being replaced
-     * @param string           $newId     The id of the service the alias points to
-     */
-    private function updateReferences($container, $currentId, $newId)
-    {
-        foreach ($container->getAliases() as $id => $alias) {
-            if ($currentId === (string) $alias) {
-                $container->setAlias($id, $newId);
-            }
+            $container->setDefinition($definitionId, $definition);
+            $container->removeDefinition($targetId);
+            $replacements[$targetId] = $definitionId;
         }
-
-        foreach ($container->getDefinitions() as $id => $definition) {
-            $this->sourceId = $id;
-
-            $definition->setArguments(
-                $this->updateArgumentReferences($definition->getArguments(), $currentId, $newId)
-            );
-
-            $definition->setMethodCalls(
-                $this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId)
-            );
-
-            $definition->setProperties(
-                $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
-            );
-
-            $definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(), $currentId, $newId));
+        // Now replace target instances in all definitions
+        foreach ($container->getDefinitions() as $definitionId => $definition) {
+            $definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments()));
+            $definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls()));
+            $definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties()));
+            $definition->setFactoryService($this->updateFactoryReferenceId($replacements, $definition->getFactoryService()));
         }
     }
 
     /**
-     * Updates argument references.
+     * Recursively updates references in an array.
      *
-     * @param array  $arguments An array of Arguments
-     * @param string $currentId The alias identifier
-     * @param string $newId     The identifier the alias points to
+     * @param array  $replacements Table of aliases to replace
+     * @param string $definitionId Identifier of this definition
+     * @param array  $arguments    Where to replace the aliases
      *
      * @return array
      */
-    private function updateArgumentReferences(array $arguments, $currentId, $newId)
+    private function updateArgumentReferences(array $replacements, $definitionId, array $arguments)
     {
         foreach ($arguments as $k => $argument) {
+            // Handle recursion step
             if (is_array($argument)) {
-                $arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId);
-            } elseif ($argument instanceof Reference) {
-                if ($currentId === (string) $argument) {
-                    $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
-                    $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId));
-                }
+                $arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument);
+                continue;
             }
+            // Skip arguments that don't need replacement
+            if (!$argument instanceof Reference) {
+                continue;
+            }
+            $referenceId = (string) $argument;
+            if (!isset($replacements[$referenceId])) {
+                continue;
+            }
+            // Perform the replacement
+            $newId = $replacements[$referenceId];
+            $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
+            $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $definitionId, $referenceId, $newId));
         }
 
         return $arguments;
     }
 
-    private function updateFactoryServiceReference($factoryService, $currentId, $newId)
+    /**
+     * Returns the updated reference for the factory service.
+     *
+     * @param array       $replacements Table of aliases to replace
+     * @param string|null $referenceId  Factory service reference identifier
+     *
+     * @return string|null
+     */
+    private function updateFactoryReferenceId(array $replacements, $referenceId)
     {
-        if (null === $factoryService) {
+        if (null === $referenceId) {
             return;
         }
 
-        return $currentId === $factoryService ? $newId : $factoryService;
+        return isset($replacements[$referenceId]) ? $replacements[$referenceId] : $referenceId;
     }
 }
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
@@ -28,9 +28,6 @@ class ServiceReferenceGraph
      */
     private $nodes;
 
-    /**
-     * Constructor.
-     */
     public function __construct()
     {
         $this->nodes = array();
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.php
@@ -25,8 +25,6 @@ class ServiceReferenceGraphEdge
     private $value;
 
     /**
-     * Constructor.
-     *
      * @param ServiceReferenceGraphNode $sourceNode
      * @param ServiceReferenceGraphNode $destNode
      * @param string                    $value
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php
@@ -29,8 +29,6 @@ class ServiceReferenceGraphNode
     private $value;
 
     /**
-     * Constructor.
-     *
      * @param string $id    The node identifier
      * @param mixed  $value The node value
      */
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php
@@ -77,8 +77,6 @@ class Container implements IntrospectableContainerInterface
     private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
 
     /**
-     * Constructor.
-     *
      * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
      */
     public function __construct(ParameterBagInterface $parameterBag = null)
@@ -323,6 +321,11 @@ class Container implements IntrospectableContainerInterface
                 }
 
                 throw $e;
+            } catch (\Throwable $e) {
+                unset($this->loading[$id]);
+                unset($this->services[$id]);
+
+                throw $e;
             }
 
             unset($this->loading[$id]);
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAware.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAware.php
@@ -24,9 +24,7 @@ abstract class ContainerAware implements ContainerAwareInterface
     protected $container;
 
     /**
-     * Sets the container.
-     *
-     * @param ContainerInterface|null $container A ContainerInterface instance or null
+     * {@inheritdoc}
      */
     public function setContainer(ContainerInterface $container = null)
     {
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php
@@ -462,6 +462,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
             }
 
             throw $e;
+        } catch (\Throwable $e) {
+            unset($this->loading[$id]);
+
+            throw $e;
         }
 
         unset($this->loading[$id]);
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.php
@@ -40,8 +40,6 @@ class Definition
     protected $arguments;
 
     /**
-     * Constructor.
-     *
      * @param string $class     The service class
      * @param array  $arguments An array of arguments to pass to the service constructor
      */
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/DefinitionDecorator.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/DefinitionDecorator.php
@@ -25,8 +25,6 @@ class DefinitionDecorator extends Definition
     private $changes;
 
     /**
-     * Constructor.
-     *
      * @param string $parent The id of Definition instance to decorate.
      */
     public function __construct($parent)
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php
@@ -23,8 +23,6 @@ abstract class Dumper implements DumperInterface
     protected $container;
 
     /**
-     * Constructor.
-     *
      * @param ContainerBuilder $container The service container to dump
      */
     public function __construct(ContainerBuilder $container)
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -1173,7 +1173,7 @@ EOF;
                     return true;
                 }
 
-                if ($deep && !isset($visited[(string) $argument])) {
+                if ($deep && !isset($visited[(string) $argument]) && 'service_container' !== (string) $argument) {
                     $visited[(string) $argument] = true;
 
                     $service = $this->container->getDefinition((string) $argument);
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php
@@ -24,8 +24,6 @@ class ParameterNotFoundException extends InvalidArgumentException
     private $alternatives;
 
     /**
-     * Constructor.
-     *
      * @param string     $key          The requested parameter key
      * @param string     $sourceId     The service id that references the non-existent parameter
      * @param string     $sourceKey    The parameter key that references the non-existent parameter
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/Extension.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/Extension.php
@@ -27,9 +27,7 @@ use Symfony\Component\Config\Definition\ConfigurationInterface;
 abstract class Extension implements ExtensionInterface, ConfigurationExtensionInterface
 {
     /**
-     * Returns the base path for the XSD files.
-     *
-     * @return string The XSD base path
+     * {@inheritdoc}
      */
     public function getXsdValidationBasePath()
     {
@@ -37,9 +35,7 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
     }
 
     /**
-     * Returns the namespace to be used for this extension (XML namespace).
-     *
-     * @return string The XML namespace
+     * {@inheritdoc}
      */
     public function getNamespace()
     {
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php
@@ -26,8 +26,6 @@ class ClosureLoader extends Loader
     private $container;
 
     /**
-     * Constructor.
-     *
      * @param ContainerBuilder $container A ContainerBuilder instance
      */
     public function __construct(ContainerBuilder $container)
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/FileLoader.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/FileLoader.php
@@ -25,8 +25,6 @@ abstract class FileLoader extends BaseFileLoader
     protected $container;
 
     /**
-     * Constructor.
-     *
      * @param ContainerBuilder     $container A ContainerBuilder instance
      * @param FileLocatorInterface $locator   A FileLocator instance
      */
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -237,6 +237,9 @@ class XmlFileLoader extends FileLoader
 
                 $definitions[(string) $node['id']] = array($node->service, $file, false);
                 $node->service['id'] = (string) $node['id'];
+
+                // anonymous services are always private
+                $node->service['public'] = false;
             }
         }
 
@@ -254,9 +257,6 @@ class XmlFileLoader extends FileLoader
         // resolve definitions
         krsort($definitions);
         foreach ($definitions as $id => $def) {
-            // anonymous services are always private
-            $def[0]['public'] = false;
-
             $this->parseDefinition($id, $def[0], $def[1]);
 
             $oNode = dom_import_simplexml($def[0]);
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
@@ -24,14 +24,28 @@
       ]]></xsd:documentation>
     </xsd:annotation>
     <xsd:sequence>
-      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
-      <xsd:element name="imports" type="imports" minOccurs="0" maxOccurs="1" />
-      <xsd:element name="parameters" type="parameters" minOccurs="0" maxOccurs="1" />
-      <xsd:element name="services" type="services" minOccurs="0" maxOccurs="1" />
-      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:group ref="foreign" />
+      <xsd:sequence minOccurs="0">
+        <xsd:element name="imports" type="imports" />
+        <xsd:group ref="foreign" />
+      </xsd:sequence>
+      <xsd:sequence minOccurs="0">
+        <xsd:element name="parameters" type="parameters" />
+        <xsd:group ref="foreign" />
+      </xsd:sequence>
+      <xsd:sequence minOccurs="0">
+        <xsd:element name="services" type="services" />
+        <xsd:group ref="foreign" />
+      </xsd:sequence>
     </xsd:sequence>
   </xsd:complexType>
 
+  <xsd:group name="foreign">
+    <xsd:sequence>
+      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:group>
+
   <xsd:complexType name="services">
     <xsd:annotation>
       <xsd:documentation><![CDATA[
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.php
@@ -21,8 +21,6 @@ class Parameter
     private $id;
 
     /**
-     * Constructor.
-     *
      * @param string $id The parameter key
      */
     public function __construct($id)
@@ -31,8 +29,6 @@ class Parameter
     }
 
     /**
-     * __toString.
-     *
      * @return string The parameter key
      */
     public function __toString()
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/FrozenParameterBag.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/FrozenParameterBag.php
@@ -21,8 +21,6 @@ use Symfony\Component\DependencyInjection\Exception\LogicException;
 class FrozenParameterBag extends ParameterBag
 {
     /**
-     * Constructor.
-     *
      * For performance reasons, the constructor assumes that
      * all keys are already lowercased.
      *
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php
@@ -26,8 +26,6 @@ class ParameterBag implements ParameterBagInterface
     protected $resolved;
 
     /**
-     * Constructor.
-     *
      * @param array $parameters An array of parameters
      */
     public function __construct(array $parameters = array())
@@ -58,9 +56,7 @@ class ParameterBag implements ParameterBagInterface
     }
 
     /**
-     * Gets the service container parameters.
-     *
-     * @return array An array of parameters
+     * {@inheritdoc}
      */
     public function all()
     {
@@ -68,13 +64,7 @@ class ParameterBag implements ParameterBagInterface
     }
 
     /**
-     * Gets a service container parameter.
-     *
-     * @param string $name The parameter name
-     *
-     * @return mixed The parameter value
-     *
-     * @throws ParameterNotFoundException if the parameter is not defined
+     * {@inheritdoc}
      */
     public function get($name)
     {
@@ -111,11 +101,7 @@ class ParameterBag implements ParameterBagInterface
     }
 
     /**
-     * Returns true if a parameter name is defined.
-     *
-     * @param string $name The parameter name
-     *
-     * @return bool true if the parameter name is defined, false otherwise
+     * {@inheritdoc}
      */
     public function has($name)
     {
@@ -133,7 +119,7 @@ class ParameterBag implements ParameterBagInterface
     }
 
     /**
-     * Replaces parameter placeholders (%name%) by their values for all parameters.
+     * {@inheritdoc}
      */
     public function resolve()
     {
@@ -268,6 +254,9 @@ class ParameterBag implements ParameterBagInterface
         return $value;
     }
 
+    /**
+     * {@inheritdoc}
+     */
     public function unescapeValue($value)
     {
         if (is_string($value)) {
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php
@@ -23,8 +23,6 @@ class Reference
     private $strict;
 
     /**
-     * Constructor.
-     *
      * @param string $id              The service identifier
      * @param int    $invalidBehavior The behavior when the service does not exist
      * @param bool   $strict          Sets how this reference is validated
@@ -39,8 +37,6 @@ class Reference
     }
 
     /**
-     * __toString.
-     *
      * @return string The service identifier
      */
     public function __toString()
--- a/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Variable.php
+++ b/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Variable.php
@@ -29,8 +29,6 @@ class Variable
     private $name;
 
     /**
-     * Constructor.
-     *
      * @param string $name
      */
     public function __construct($name)
--- a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php
@@ -155,10 +155,10 @@ class EventDispatcher implements EventDispatcherInterface
     protected function doDispatch($listeners, $eventName, Event $event)
     {
         foreach ($listeners as $listener) {
-            call_user_func($listener, $event);
             if ($event->isPropagationStopped()) {
                 break;
             }
+            call_user_func($listener, $event);
         }
     }
 
--- a/vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php
@@ -23,17 +23,17 @@ class Filesystem
     /**
      * Copies a file.
      *
-     * This method only copies the file if the origin file is newer than the target file.
+     * If the target file is older than the origin file, it's always overwritten.
+     * If the target file is newer, it is overwritten only when the
+     * $overwriteNewerFiles option is set to true.
      *
-     * By default, if the target already exists, it is not overridden.
-     *
-     * @param string $originFile The original filename
-     * @param string $targetFile The target filename
-     * @param bool   $override   Whether to override an existing file or not
+     * @param string $originFile          The original filename
+     * @param string $targetFile          The target filename
+     * @param bool   $overwriteNewerFiles If true, target files newer than origin files are overwritten
      *
      * @throws IOException When copy fails
      */
-    public function copy($originFile, $targetFile, $override = false)
+    public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
     {
         if (stream_is_local($originFile) && !is_file($originFile)) {
             throw new IOException(sprintf('Failed to copy %s because file not exists', $originFile));
@@ -42,7 +42,7 @@ class Filesystem
         $this->mkdir(dirname($targetFile));
 
         $doCopy = true;
-        if (!$override && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
+        if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
             $doCopy = filemtime($originFile) > filemtime($targetFile);
         }
 
@@ -140,24 +140,27 @@ class Filesystem
      */
     public function remove($files)
     {
-        $files = iterator_to_array($this->toIterator($files));
+        if ($files instanceof \Traversable) {
+            $files = iterator_to_array($files, false);
+        } elseif (!is_array($files)) {
+            $files = array($files);
+        }
         $files = array_reverse($files);
         foreach ($files as $file) {
-            if (@(unlink($file) || rmdir($file))) {
-                continue;
-            }
             if (is_link($file)) {
                 // See https://bugs.php.net/52176
-                $error = error_get_last();
-                throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
+                if (!@(unlink($file) || '\\' !== DIRECTORY_SEPARATOR || rmdir($file)) && file_exists($file)) {
+                    $error = error_get_last();
+                    throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
+                }
             } elseif (is_dir($file)) {
-                $this->remove(new \FilesystemIterator($file));
+                $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
 
-                if (!@rmdir($file)) {
+                if (!@rmdir($file) && file_exists($file)) {
                     $error = error_get_last();
                     throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, $error['message']));
                 }
-            } elseif (file_exists($file)) {
+            } elseif (!@unlink($file) && file_exists($file)) {
                 $error = error_get_last();
                 throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
             }
--- a/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/UploadedFile.php
+++ b/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/UploadedFile.php
@@ -50,7 +50,7 @@ class UploadedFile extends File
     /**
      * The file size provided by the uploader.
      *
-     * @var string
+     * @var int|null
      */
     private $size;
 
@@ -75,12 +75,12 @@ class UploadedFile extends File
      *
      * Calling any other method on an non-valid instance will cause an unpredictable result.
      *
-     * @param string $path         The full temporary path to the file
-     * @param string $originalName The original file name
-     * @param string $mimeType     The type of the file as provided by PHP
-     * @param int    $size         The file size
-     * @param int    $error        The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants)
-     * @param bool   $test         Whether the test mode is active
+     * @param string      $path         The full temporary path to the file
+     * @param string      $originalName The original file name
+     * @param string|null $mimeType     The type of the file as provided by PHP; null defaults to application/octet-stream
+     * @param int|null    $size         The file size
+     * @param int|null    $error        The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
+     * @param bool        $test         Whether the test mode is active
      *
      * @throws FileException         If file_uploads is disabled
      * @throws FileNotFoundException If the file does not exist
--- a/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Request.php
+++ b/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Request.php
@@ -674,7 +674,7 @@ class Request
      * public property instead (query, attributes, request).
      *
      * @param string $key     the key
-     * @param mixed  $default the default value
+     * @param mixed  $default the default value if the parameter key does not exist
      * @param bool   $deep    is parameter deep in multidimensional array
      *
      * @return mixed
@@ -1238,8 +1238,9 @@ class Request
      */
     public function getFormat($mimeType)
     {
+        $canonicalMimeType = null;
         if (false !== $pos = strpos($mimeType, ';')) {
-            $mimeType = substr($mimeType, 0, $pos);
+            $canonicalMimeType = substr($mimeType, 0, $pos);
         }
 
         if (null === static::$formats) {
@@ -1250,6 +1251,9 @@ class Request
             if (in_array($mimeType, (array) $mimeTypes)) {
                 return $format;
             }
+            if (null !== $canonicalMimeType && in_array($canonicalMimeType, (array) $mimeTypes)) {
+                return $format;
+            }
         }
     }
 
--- a/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Response.php
+++ b/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Response.php
@@ -53,7 +53,7 @@ class Response
      *
      * The list of codes is complete according to the
      * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}
-     * (last updated 2012-02-13).
+     * (last updated 2016-03-01).
      *
      * Unless otherwise noted, the status code is defined in RFC2616.
      *
@@ -101,6 +101,7 @@ class Response
         416 => 'Requested Range Not Satisfiable',
         417 => 'Expectation Failed',
         418 => 'I\'m a teapot',                                               // RFC2324
+        421 => 'Misdirected Request',                                         // RFC7540
         422 => 'Unprocessable Entity',                                        // RFC4918
         423 => 'Locked',                                                      // RFC4918
         424 => 'Failed Dependency',                                           // RFC4918
--- a/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php
+++ b/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php
@@ -136,6 +136,10 @@ class TraceableEventDispatcher implements EventDispatcherInterface, TraceableEve
             $event = new Event();
         }
 
+        if (null !== $this->logger && $event->isPropagationStopped()) {
+            $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
+        }
+
         $eventId = ++$this->lastEventId;
 
         $this->preDispatch($eventName, $eventId, $event);
--- a/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php
+++ b/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php
@@ -65,6 +65,11 @@ class ContainerAwareHttpKernel extends HttpKernel
             $this->container->leaveScope('request');
 
             throw $e;
+        } catch (\Throwable $e) {
+            $this->container->set('request', null, 'request');
+            $this->container->leaveScope('request');
+
+            throw $e;
         }
 
         $this->container->set('request', null, 'request');
--- a/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategy.php
+++ b/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategy.php
@@ -32,6 +32,7 @@ class EsiResponseCacheStrategy implements EsiResponseCacheStrategyInterface
     private $embeddedResponses = 0;
     private $ttls = array();
     private $maxAges = array();
+    private $isNotCacheableResponseEmbedded = false;
 
     /**
      * {@inheritdoc}
@@ -41,8 +42,13 @@ class EsiResponseCacheStrategy implements EsiResponseCacheStrategyInterface
         if ($response->isValidateable()) {
             $this->cacheable = false;
         } else {
+            $maxAge = $response->getMaxAge();
             $this->ttls[] = $response->getTtl();
-            $this->maxAges[] = $response->getMaxAge();
+            $this->maxAges[] = $maxAge;
+
+            if (null === $maxAge) {
+                $this->isNotCacheableResponseEmbedded = true;
+            }
         }
 
         ++$this->embeddedResponses;
@@ -76,7 +82,9 @@ class EsiResponseCacheStrategy implements EsiResponseCacheStrategyInterface
         $this->ttls[] = $response->getTtl();
         $this->maxAges[] = $response->getMaxAge();
 
-        if (null !== $maxAge = min($this->maxAges)) {
+        if ($this->isNotCacheableResponseEmbedded) {
+            $response->headers->removeCacheControlDirective('s-maxage');
+        } elseif (null !== $maxAge = min($this->maxAges)) {
             $response->setSharedMaxAge($maxAge);
             $response->headers->set('Age', $maxAge - min($this->ttls));
         }
--- a/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Kernel.php
+++ b/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Kernel.php
@@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
     protected $startTime;
     protected $loadClassCache;
 
-    const VERSION = '2.3.39';
-    const VERSION_ID = 20339;
+    const VERSION = '2.3.42';
+    const VERSION_ID = 20342;
     const MAJOR_VERSION = 2;
     const MINOR_VERSION = 3;
-    const RELEASE_VERSION = 39;
+    const RELEASE_VERSION = 42;
     const EXTRA_VERSION = '';
 
     /**
--- a/vendor/symfony/polyfill-mbstring/Mbstring.php
+++ b/vendor/symfony/polyfill-mbstring/Mbstring.php
@@ -577,8 +577,8 @@ final class Mbstring
 
     private static function getData($file)
     {
-        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.ser')) {
-            return unserialize(file_get_contents($file));
+        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
+            return require $file;
         }
 
         return false;
--- /dev/null
+++ b/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php
@@ -0,0 +1,1101 @@
+<?php
+
+static $data = array (
+  'A' => 'a',
+  'B' => 'b',
+  'C' => 'c',
+  'D' => 'd',
+  'E' => 'e',
+  'F' => 'f',
+  'G' => 'g',
+  'H' => 'h',
+  'I' => 'i',
+  'J' => 'j',
+  'K' => 'k',
+  'L' => 'l',
+  'M' => 'm',
+  'N' => 'n',
+  'O' => 'o',
+  'P' => 'p',
+  'Q' => 'q',
+  'R' => 'r',
+  'S' => 's',
+  'T' => 't',
+  'U' => 'u',
+  'V' => 'v',
+  'W' => 'w',
+  'X' => 'x',
+  'Y' => 'y',
+  'Z' => 'z',
+  'À' => 'à',
+  'Á' => 'á',
+  'Â' => 'â',
+  'Ã' => 'ã',
+  'Ä' => 'ä',
+  'Å' => 'å',
+  'Æ' => 'æ',
+  'Ç' => 'ç',
+  'È' => 'è',
+  'É' => 'é',
+  'Ê' => 'ê',
+  'Ë' => 'ë',
+  'Ì' => 'ì',
+  'Í' => 'í',
+  'Î' => 'î',
+  'Ï' => 'ï',
+  'Ð' => 'ð',
+  'Ñ' => 'ñ',
+  'Ò' => 'ò',
+  'Ó' => 'ó',
+  'Ô' => 'ô',
+  'Õ' => 'õ',
+  'Ö' => 'ö',
+  'Ø' => 'ø',
+  'Ù' => 'ù',
+  'Ú' => 'ú',
+  'Û' => 'û',
+  'Ü' => 'ü',
+  'Ý' => 'ý',
+  'Þ' => 'þ',
+  'Ā' => 'ā',
+  'Ă' => 'ă',
+  'Ą' => 'ą',
+  'Ć' => 'ć',
+  'Ĉ' => 'ĉ',
+  'Ċ' => 'ċ',
+  'Č' => 'č',
+  'Ď' => 'ď',
+  'Đ' => 'đ',
+  'Ē' => 'ē',
+  'Ĕ' => 'ĕ',
+  'Ė' => 'ė',
+  'Ę' => 'ę',
+  'Ě' => 'ě',
+  'Ĝ' => 'ĝ',
+  'Ğ' => 'ğ',
+  'Ġ' => 'ġ',
+  'Ģ' => 'ģ',
+  'Ĥ' => 'ĥ',
+  'Ħ' => 'ħ',
+  'Ĩ' => 'ĩ',
+  'Ī' => 'ī',
+  'Ĭ' => 'ĭ',
+  'Į' => 'į',
+  'İ' => 'i',
+  'Ĳ' => 'ĳ',
+  'Ĵ' => 'ĵ',
+  'Ķ' => 'ķ',
+  'Ĺ' => 'ĺ',
+  'Ļ' => 'ļ',
+  'Ľ' => 'ľ',
+  'Ŀ' => 'ŀ',
+  'Ł' => 'ł',
+  'Ń' => 'ń',
+  'Ņ' => 'ņ',
+  'Ň' => 'ň',
+  'Ŋ' => 'ŋ',
+  'Ō' => 'ō',
+  'Ŏ' => 'ŏ',
+  'Ő' => 'ő',
+  'Œ' => 'œ',
+  'Ŕ' => 'ŕ',
+  'Ŗ' => 'ŗ',
+  'Ř' => 'ř',
+  'Ś' => 'ś',
+  'Ŝ' => 'ŝ',
+  'Ş' => 'ş',
+  'Š' => 'š',
+  'Ţ' => 'ţ',
+  'Ť' => 'ť',
+  'Ŧ' => 'ŧ',
+  'Ũ' => 'ũ',
+  'Ū' => 'ū',
+  'Ŭ' => 'ŭ',
+  'Ů' => 'ů',
+  'Ű' => 'ű',
+  'Ų' => 'ų',
+  'Ŵ' => 'ŵ',
+  'Ŷ' => 'ŷ',
+  'Ÿ' => 'ÿ',
+  'Ź' => 'ź',
+  'Ż' => 'ż',
+  'Ž' => 'ž',
+  'Ɓ' => 'ɓ',
+  'Ƃ' => 'ƃ',
+  'Ƅ' => 'ƅ',
+  'Ɔ' => 'ɔ',
+  'Ƈ' => 'ƈ',
+  'Ɖ' => 'ɖ',
+  'Ɗ' => 'ɗ',
+  'Ƌ' => 'ƌ',
+  'Ǝ' => 'ǝ',
+  'Ə' => 'ə',
+  'Ɛ' => 'ɛ',
+  'Ƒ' => 'ƒ',
+  'Ɠ' => 'ɠ',
+  'Ɣ' => 'ɣ',
+  'Ɩ' => 'ɩ',
+  'Ɨ' => 'ɨ',
+  'Ƙ' => 'ƙ',
+  'Ɯ' => 'ɯ',
+  'Ɲ' => 'ɲ',
+  'Ɵ' => 'ɵ',
+  'Ơ' => 'ơ',
+  'Ƣ' => 'ƣ',
+  'Ƥ' => 'ƥ',
+  'Ʀ' => 'ʀ',
+  'Ƨ' => 'ƨ',
+  'Ʃ' => 'ʃ',
+  'Ƭ' => 'ƭ',
+  'Ʈ' => 'ʈ',
+  'Ư' => 'ư',
+  'Ʊ' => 'ʊ',
+  'Ʋ' => 'ʋ',
+  'Ƴ' => 'ƴ',
+  'Ƶ' => 'ƶ',
+  'Ʒ' => 'ʒ',
+  'Ƹ' => 'ƹ',
+  'Ƽ' => 'ƽ',
+  'Ǆ' => 'ǆ',
+  'ǅ' => 'ǆ',
+  'Ǉ' => 'ǉ',
+  'ǈ' => 'ǉ',
+  'Ǌ' => 'ǌ',
+  'ǋ' => 'ǌ',
+  'Ǎ' => 'ǎ',
+  'Ǐ' => 'ǐ',
+  'Ǒ' => 'ǒ',
+  'Ǔ' => 'ǔ',
+  'Ǖ' => 'ǖ',
+  'Ǘ' => 'ǘ',
+  'Ǚ' => 'ǚ',
+  'Ǜ' => 'ǜ',
+  'Ǟ' => 'ǟ',
+  'Ǡ' => 'ǡ',
+  'Ǣ' => 'ǣ',
+  'Ǥ' => 'ǥ',
+  'Ǧ' => 'ǧ',
+  'Ǩ' => 'ǩ',
+  'Ǫ' => 'ǫ',
+  'Ǭ' => 'ǭ',
+  'Ǯ' => 'ǯ',
+  'Ǳ' => 'ǳ',
+  'ǲ' => 'ǳ',
+  'Ǵ' => 'ǵ',
+  'Ƕ' => 'ƕ',
+  'Ƿ' => 'ƿ',
+  'Ǹ' => 'ǹ',
+  'Ǻ' => 'ǻ',
+  'Ǽ' => 'ǽ',
+  'Ǿ' => 'ǿ',
+  'Ȁ' => 'ȁ',
+  'Ȃ' => 'ȃ',
+  'Ȅ' => 'ȅ',
+  'Ȇ' => 'ȇ',
+  'Ȉ' => 'ȉ',
+  'Ȋ' => 'ȋ',
+  'Ȍ' => 'ȍ',
+  'Ȏ' => 'ȏ',
+  'Ȑ' => 'ȑ',
+  'Ȓ' => 'ȓ',
+  'Ȕ' => 'ȕ',
+  'Ȗ' => 'ȗ',
+  'Ș' => 'ș',
+  'Ț' => 'ț',
+  'Ȝ' => 'ȝ',
+  'Ȟ' => 'ȟ',
+  'Ƞ' => 'ƞ',
+  'Ȣ' => 'ȣ',
+  'Ȥ' => 'ȥ',
+  'Ȧ' => 'ȧ',
+  'Ȩ' => 'ȩ',
+  'Ȫ' => 'ȫ',
+  'Ȭ' => 'ȭ',
+  'Ȯ' => 'ȯ',
+  'Ȱ' => 'ȱ',
+  'Ȳ' => 'ȳ',
+  'Ⱥ' => 'ⱥ',
+  'Ȼ' => 'ȼ',
+  'Ƚ' => 'ƚ',
+  'Ⱦ' => 'ⱦ',
+  'Ɂ' => 'ɂ',
+  'Ƀ' => 'ƀ',
+  'Ʉ' => 'ʉ',
+  'Ʌ' => 'ʌ',
+  'Ɇ' => 'ɇ',
+  'Ɉ' => 'ɉ',
+  'Ɋ' => 'ɋ',
+  'Ɍ' => 'ɍ',
+  'Ɏ' => 'ɏ',
+  'Ͱ' => 'ͱ',
+  'Ͳ' => 'ͳ',
+  'Ͷ' => 'ͷ',
+  'Ϳ' => 'ϳ',
+  'Ά' => 'ά',
+  'Έ' => 'έ',
+  'Ή' => 'ή',
+  'Ί' => 'ί',
+  'Ό' => 'ό',
+  'Ύ' => 'ύ',
+  'Ώ' => 'ώ',
+  'Α' => 'α',
+  'Β' => 'β',
+  'Γ' => 'γ',
+  'Δ' => 'δ',
+  'Ε' => 'ε',
+  'Ζ' => 'ζ',
+  'Η' => 'η',
+  'Θ' => 'θ',
+  'Ι' => 'ι',
+  'Κ' => 'κ',
+  'Λ' => 'λ',
+  'Μ' => 'μ',
+  'Ν' => 'ν',
+  'Ξ' => 'ξ',
+  'Ο' => 'ο',
+  'Π' => 'π',
+  'Ρ' => 'ρ',
+  'Σ' => 'σ',
+  'Τ' => 'τ',
+  'Υ' => 'υ',
+  'Φ' => 'φ',
+  'Χ' => 'χ',
+  'Ψ' => 'ψ',
+  'Ω' => 'ω',
+  'Ϊ' => 'ϊ',
+  'Ϋ' => 'ϋ',
+  'Ϗ' => 'ϗ',
+  'Ϙ' => 'ϙ',
+  'Ϛ' => 'ϛ',
+  'Ϝ' => 'ϝ',
+  'Ϟ' => 'ϟ',
+  'Ϡ' => 'ϡ',
+  'Ϣ' => 'ϣ',
+  'Ϥ' => 'ϥ',
+  'Ϧ' => 'ϧ',
+  'Ϩ' => 'ϩ',
+  'Ϫ' => 'ϫ',
+  'Ϭ' => 'ϭ',
+  'Ϯ' => 'ϯ',
+  'ϴ' => 'θ',
+  'Ϸ' => 'ϸ',
+  'Ϲ' => 'ϲ',
+  'Ϻ' => 'ϻ',
+  'Ͻ' => 'ͻ',
+  'Ͼ' => 'ͼ',
+  'Ͽ' => 'ͽ',
+  'Ѐ' => 'ѐ',
+  'Ё' => 'ё',
+  'Ђ' => 'ђ',
+  'Ѓ' => 'ѓ',
+  'Є' => 'є',
+  'Ѕ' => 'ѕ',
+  'І' => 'і',
+  'Ї' => 'ї',
+  'Ј' => 'ј',
+  'Љ' => 'љ',
+  'Њ' => 'њ',
+  'Ћ' => 'ћ',
+  'Ќ' => 'ќ',
+  'Ѝ' => 'ѝ',
+  'Ў' => 'ў',
+  'Џ' => 'џ',
+  'А' => 'а',
+  'Б' => 'б',
+  'В' => 'в',
+  'Г' => 'г',
+  'Д' => 'д',
+  'Е' => 'е',
+  'Ж' => 'ж',
+  'З' => 'з',
+  'И' => 'и',
+  'Й' => 'й',
+  'К' => 'к',
+  'Л' => 'л',
+  'М' => 'м',
+  'Н' => 'н',
+  'О' => 'о',
+  'П' => 'п',
+  'Р' => 'р',
+  'С' => 'с',
+  'Т' => 'т',
+  'У' => 'у',
+  'Ф' => 'ф',
+  'Х' => 'х',
+  'Ц' => 'ц',
+  'Ч' => 'ч',
+  'Ш' => 'ш',
+  'Щ' => 'щ',
+  'Ъ' => 'ъ',
+  'Ы' => 'ы',
+  'Ь' => 'ь',
+  'Э' => 'э',
+  'Ю' => 'ю',
+  'Я' => 'я',
+  'Ѡ' => 'ѡ',
+  'Ѣ' => 'ѣ',
+  'Ѥ' => 'ѥ',
+  'Ѧ' => 'ѧ',
+  'Ѩ' => 'ѩ',
+  'Ѫ' => 'ѫ',
+  'Ѭ' => 'ѭ',
+  'Ѯ' => 'ѯ',
+  'Ѱ' => 'ѱ',
+  'Ѳ' => 'ѳ',
+  'Ѵ' => 'ѵ',
+  'Ѷ' => 'ѷ',
+  'Ѹ' => 'ѹ',
+  'Ѻ' => 'ѻ',
+  'Ѽ' => 'ѽ',
+  'Ѿ' => 'ѿ',
+  'Ҁ' => 'ҁ',
+  'Ҋ' => 'ҋ',
+  'Ҍ' => 'ҍ',
+  'Ҏ' => 'ҏ',
+  'Ґ' => 'ґ',
+  'Ғ' => 'ғ',
+  'Ҕ' => 'ҕ',
+  'Җ' => 'җ',
+  'Ҙ' => 'ҙ',
+  'Қ' => 'қ',
+  'Ҝ' => 'ҝ',
+  'Ҟ' => 'ҟ',
+  'Ҡ' => 'ҡ',
+  'Ң' => 'ң',
+  'Ҥ' => 'ҥ',
+  'Ҧ' => 'ҧ',
+  'Ҩ' => 'ҩ',
+  'Ҫ' => 'ҫ',
+  'Ҭ' => 'ҭ',
+  'Ү' => 'ү',
+  'Ұ' => 'ұ',
+  'Ҳ' => 'ҳ',
+  'Ҵ' => 'ҵ',
+  'Ҷ' => 'ҷ',
+  'Ҹ' => 'ҹ',
+  'Һ' => 'һ',
+  'Ҽ' => 'ҽ',
+  'Ҿ' => 'ҿ',
+  'Ӏ' => 'ӏ',
+  'Ӂ' => 'ӂ',
+  'Ӄ' => 'ӄ',
+  'Ӆ' => 'ӆ',
+  'Ӈ' => 'ӈ',
+  'Ӊ' => 'ӊ',
+  'Ӌ' => 'ӌ',
+  'Ӎ' => 'ӎ',
+  'Ӑ' => 'ӑ',
+  'Ӓ' => 'ӓ',
+  'Ӕ' => 'ӕ',
+  'Ӗ' => 'ӗ',
+  'Ә' => 'ә',
+  'Ӛ' => 'ӛ',
+  'Ӝ' => 'ӝ',
+  'Ӟ' => 'ӟ',
+  'Ӡ' => 'ӡ',
+  'Ӣ' => 'ӣ',
+  'Ӥ' => 'ӥ',
+  'Ӧ' => 'ӧ',
+  'Ө' => 'ө',
+  'Ӫ' => 'ӫ',
+  'Ӭ' => 'ӭ',
+  'Ӯ' => 'ӯ',
+  'Ӱ' => 'ӱ',
+  'Ӳ' => 'ӳ',
+  'Ӵ' => 'ӵ',
+  'Ӷ' => 'ӷ',
+  'Ӹ' => 'ӹ',
+  'Ӻ' => 'ӻ',
+  'Ӽ' => 'ӽ',
+  'Ӿ' => 'ӿ',
+  'Ԁ' => 'ԁ',
+  'Ԃ' => 'ԃ',
+  'Ԅ' => 'ԅ',
+  'Ԇ' => 'ԇ',
+  'Ԉ' => 'ԉ',
+  'Ԋ' => 'ԋ',
+  'Ԍ' => 'ԍ',
+  'Ԏ' => 'ԏ',
+  'Ԑ' => 'ԑ',
+  'Ԓ' => 'ԓ',
+  'Ԕ' => 'ԕ',
+  'Ԗ' => 'ԗ',
+  'Ԙ' => 'ԙ',
+  'Ԛ' => 'ԛ',
+  'Ԝ' => 'ԝ',
+  'Ԟ' => 'ԟ',
+  'Ԡ' => 'ԡ',
+  'Ԣ' => 'ԣ',
+  'Ԥ' => 'ԥ',
+  'Ԧ' => 'ԧ',
+  'Ԩ' => 'ԩ',
+  'Ԫ' => 'ԫ',
+  'Ԭ' => 'ԭ',
+  'Ԯ' => 'ԯ',
+  'Ա' => 'ա',
+  'Բ' => 'բ',
+  'Գ' => 'գ',
+  'Դ' => 'դ',
+  'Ե' => 'ե',
+  'Զ' => 'զ',
+  'Է' => 'է',
+  'Ը' => 'ը',
+  'Թ' => 'թ',
+  'Ժ' => 'ժ',
+  'Ի' => 'ի',
+  'Լ' => 'լ',
+  'Խ' => 'խ',
+  'Ծ' => 'ծ',
+  'Կ' => 'կ',
+  'Հ' => 'հ',
+  'Ձ' => 'ձ',
+  'Ղ' => 'ղ',
+  'Ճ' => 'ճ',
+  'Մ' => 'մ',
+  'Յ' => 'յ',
+  'Ն' => 'ն',
+  'Շ' => 'շ',
+  'Ո' => 'ո',
+  'Չ' => 'չ',
+  'Պ' => 'պ',
+  'Ջ' => 'ջ',
+  'Ռ' => 'ռ',
+  'Ս' => 'ս',
+  'Վ' => 'վ',
+  'Տ' => 'տ',
+  'Ր' => 'ր',
+  'Ց' => 'ց',
+  'Ւ' => 'ւ',
+  'Փ' => 'փ',
+  'Ք' => 'ք',
+  'Օ' => 'օ',
+  'Ֆ' => 'ֆ',
+  'Ⴀ' => 'ⴀ',
+  'Ⴁ' => 'ⴁ',
+  'Ⴂ' => 'ⴂ',
+  'Ⴃ' => 'ⴃ',
+  'Ⴄ' => 'ⴄ',
+  'Ⴅ' => 'ⴅ',
+  'Ⴆ' => 'ⴆ',
+  'Ⴇ' => 'ⴇ',
+  'Ⴈ' => 'ⴈ',
+  'Ⴉ' => 'ⴉ',
+  'Ⴊ' => 'ⴊ',
+  'Ⴋ' => 'ⴋ',
+  'Ⴌ' => 'ⴌ',
+  'Ⴍ' => 'ⴍ',
+  'Ⴎ' => 'ⴎ',
+  'Ⴏ' => 'ⴏ',
+  'Ⴐ' => 'ⴐ',
+  'Ⴑ' => 'ⴑ',
+  'Ⴒ' => 'ⴒ',
+  'Ⴓ' => 'ⴓ',
+  'Ⴔ' => 'ⴔ',
+  'Ⴕ' => 'ⴕ',
+  'Ⴖ' => 'ⴖ',
+  'Ⴗ' => 'ⴗ',
+  'Ⴘ' => 'ⴘ',
+  'Ⴙ' => 'ⴙ',
+  'Ⴚ' => 'ⴚ',
+  'Ⴛ' => 'ⴛ',
+  'Ⴜ' => 'ⴜ',
+  'Ⴝ' => 'ⴝ',
+  'Ⴞ' => 'ⴞ',
+  'Ⴟ' => 'ⴟ',
+  'Ⴠ' => 'ⴠ',
+  'Ⴡ' => 'ⴡ',
+  'Ⴢ' => 'ⴢ',
+  'Ⴣ' => 'ⴣ',
+  'Ⴤ' => 'ⴤ',
+  'Ⴥ' => 'ⴥ',
+  'Ⴧ' => 'ⴧ',
+  'Ⴭ' => 'ⴭ',
+  'Ḁ' => 'ḁ',
+  'Ḃ' => 'ḃ',
+  'Ḅ' => 'ḅ',
+  'Ḇ' => 'ḇ',
+  'Ḉ' => 'ḉ',
+  'Ḋ' => 'ḋ',
+  'Ḍ' => 'ḍ',
+  'Ḏ' => 'ḏ',
+  'Ḑ' => 'ḑ',
+  'Ḓ' => 'ḓ',
+  'Ḕ' => 'ḕ',
+  'Ḗ' => 'ḗ',
+  'Ḙ' => 'ḙ',
+  'Ḛ' => 'ḛ',
+  'Ḝ' => 'ḝ',
+  'Ḟ' => 'ḟ',
+  'Ḡ' => 'ḡ',
+  'Ḣ' => 'ḣ',
+  'Ḥ' => 'ḥ',
+  'Ḧ' => 'ḧ',
+  'Ḩ' => 'ḩ',
+  'Ḫ' => 'ḫ',
+  'Ḭ' => 'ḭ',
+  'Ḯ' => 'ḯ',
+  'Ḱ' => 'ḱ',
+  'Ḳ' => 'ḳ',
+  'Ḵ' => 'ḵ',
+  'Ḷ' => 'ḷ',
+  'Ḹ' => 'ḹ',
+  'Ḻ' => 'ḻ',
+  'Ḽ' => 'ḽ',
+  'Ḿ' => 'ḿ',
+  'Ṁ' => 'ṁ',
+  'Ṃ' => 'ṃ',
+  'Ṅ' => 'ṅ',
+  'Ṇ' => 'ṇ',
+  'Ṉ' => 'ṉ',
+  'Ṋ' => 'ṋ',
+  'Ṍ' => 'ṍ',
+  'Ṏ' => 'ṏ',
+  'Ṑ' => 'ṑ',
+  'Ṓ' => 'ṓ',
+  'Ṕ' => 'ṕ',
+  'Ṗ' => 'ṗ',
+  'Ṙ' => 'ṙ',
+  'Ṛ' => 'ṛ',
+  'Ṝ' => 'ṝ',
+  'Ṟ' => 'ṟ',
+  'Ṡ' => 'ṡ',
+  'Ṣ' => 'ṣ',
+  'Ṥ' => 'ṥ',
+  'Ṧ' => 'ṧ',
+  'Ṩ' => 'ṩ',
+  'Ṫ' => 'ṫ',
+  'Ṭ' => 'ṭ',
+  'Ṯ' => 'ṯ',
+  'Ṱ' => 'ṱ',
+  'Ṳ' => 'ṳ',
+  'Ṵ' => 'ṵ',
+  'Ṷ' => 'ṷ',
+  'Ṹ' => 'ṹ',
+  'Ṻ' => 'ṻ',
+  'Ṽ' => 'ṽ',
+  'Ṿ' => 'ṿ',
+  'Ẁ' => 'ẁ',
+  'Ẃ' => 'ẃ',
+  'Ẅ' => 'ẅ',
+  'Ẇ' => 'ẇ',
+  'Ẉ' => 'ẉ',
+  'Ẋ' => 'ẋ',
+  'Ẍ' => 'ẍ',
+  'Ẏ' => 'ẏ',
+  'Ẑ' => 'ẑ',
+  'Ẓ' => 'ẓ',
+  'Ẕ' => 'ẕ',
+  'ẞ' => 'ß',
+  'Ạ' => 'ạ',
+  'Ả' => 'ả',
+  'Ấ' => 'ấ',
+  'Ầ' => 'ầ',
+  'Ẩ' => 'ẩ',
+  'Ẫ' => 'ẫ',
+  'Ậ' => 'ậ',
+  'Ắ' => 'ắ',
+  'Ằ' => 'ằ',
+  'Ẳ' => 'ẳ',
+  'Ẵ' => 'ẵ',
+  'Ặ' => 'ặ',
+  'Ẹ' => 'ẹ',
+  'Ẻ' => 'ẻ',
+  'Ẽ' => 'ẽ',
+  'Ế' => 'ế',
+  'Ề' => 'ề',
+  'Ể' => 'ể',
+  'Ễ' => 'ễ',
+  'Ệ' => 'ệ',
+  'Ỉ' => 'ỉ',
+  'Ị' => 'ị',
+  'Ọ' => 'ọ',
+  'Ỏ' => 'ỏ',
+  'Ố' => 'ố',
+  'Ồ' => 'ồ',
+  'Ổ' => 'ổ',
+  'Ỗ' => 'ỗ',
+  'Ộ' => 'ộ',
+  'Ớ' => 'ớ',
+  'Ờ' => 'ờ',
+  'Ở' => 'ở',
+  'Ỡ' => 'ỡ',
+  'Ợ' => 'ợ',
+  'Ụ' => 'ụ',
+  'Ủ' => 'ủ',
+  'Ứ' => 'ứ',
+  'Ừ' => 'ừ',
+  'Ử' => 'ử',
+  'Ữ' => 'ữ',
+  'Ự' => 'ự',
+  'Ỳ' => 'ỳ',
+  'Ỵ' => 'ỵ',
+  'Ỷ' => 'ỷ',
+  'Ỹ' => 'ỹ',
+  'Ỻ' => 'ỻ',
+  'Ỽ' => 'ỽ',
+  'Ỿ' => 'ỿ',
+  'Ἀ' => 'ἀ',
+  'Ἁ' => 'ἁ',
+  'Ἂ' => 'ἂ',
+  'Ἃ' => 'ἃ',
+  'Ἄ' => 'ἄ',
+  'Ἅ' => 'ἅ',
+  'Ἆ' => 'ἆ',
+  'Ἇ' => 'ἇ',
+  'Ἐ' => 'ἐ',
+  'Ἑ' => 'ἑ',
+  'Ἒ' => 'ἒ',
+  'Ἓ' => 'ἓ',
+  'Ἔ' => 'ἔ',
+  'Ἕ' => 'ἕ',
+  'Ἠ' => 'ἠ',
+  'Ἡ' => 'ἡ',
+  'Ἢ' => 'ἢ',
+  'Ἣ' => 'ἣ',
+  'Ἤ' => 'ἤ',
+  'Ἥ' => 'ἥ',
+  'Ἦ' => 'ἦ',
+  'Ἧ' => 'ἧ',
+  'Ἰ' => 'ἰ',
+  'Ἱ' => 'ἱ',
+  'Ἲ' => 'ἲ',
+  'Ἳ' => 'ἳ',
+  'Ἴ' => 'ἴ',
+  'Ἵ' => 'ἵ',
+  'Ἶ' => 'ἶ',
+  'Ἷ' => 'ἷ',
+  'Ὀ' => 'ὀ',
+  'Ὁ' => 'ὁ',
+  'Ὂ' => 'ὂ',
+  'Ὃ' => 'ὃ',
+  'Ὄ' => 'ὄ',
+  'Ὅ' => 'ὅ',
+  'Ὑ' => 'ὑ',
+  'Ὓ' => 'ὓ',
+  'Ὕ' => 'ὕ',
+  'Ὗ' => 'ὗ',
+  'Ὠ' => 'ὠ',
+  'Ὡ' => 'ὡ',
+  'Ὢ' => 'ὢ',
+  'Ὣ' => 'ὣ',
+  'Ὤ' => 'ὤ',
+  'Ὥ' => 'ὥ',
+  'Ὦ' => 'ὦ',
+  'Ὧ' => 'ὧ',
+  'ᾈ' => 'ᾀ',
+  'ᾉ' => 'ᾁ',
+  'ᾊ' => 'ᾂ',
+  'ᾋ' => 'ᾃ',
+  'ᾌ' => 'ᾄ',
+  'ᾍ' => 'ᾅ',
+  'ᾎ' => 'ᾆ',
+  'ᾏ' => 'ᾇ',
+  'ᾘ' => 'ᾐ',
+  'ᾙ' => 'ᾑ',
+  'ᾚ' => 'ᾒ',
+  'ᾛ' => 'ᾓ',
+  'ᾜ' => 'ᾔ',
+  'ᾝ' => 'ᾕ',
+  'ᾞ' => 'ᾖ',
+  'ᾟ' => 'ᾗ',
+  'ᾨ' => 'ᾠ',
+  'ᾩ' => 'ᾡ',
+  'ᾪ' => 'ᾢ',
+  'ᾫ' => 'ᾣ',
+  'ᾬ' => 'ᾤ',
+  'ᾭ' => 'ᾥ',
+  'ᾮ' => 'ᾦ',
+  'ᾯ' => 'ᾧ',
+  'Ᾰ' => 'ᾰ',
+  'Ᾱ' => 'ᾱ',
+  'Ὰ' => 'ὰ',
+  'Ά' => 'ά',
+  'ᾼ' => 'ᾳ',
+  'Ὲ' => 'ὲ',
+  'Έ' => 'έ',
+  'Ὴ' => 'ὴ',
+  'Ή' => 'ή',
+  'ῌ' => 'ῃ',
+  'Ῐ' => 'ῐ',
+  'Ῑ' => 'ῑ',
+  'Ὶ' => 'ὶ',
+  'Ί' => 'ί',
+  'Ῠ' => 'ῠ',
+  'Ῡ' => 'ῡ',
+  'Ὺ' => 'ὺ',
+  'Ύ' => 'ύ',
+  'Ῥ' => 'ῥ',
+  'Ὸ' => 'ὸ',
+  'Ό' => 'ό',
+  'Ὼ' => 'ὼ',
+  'Ώ' => 'ώ',
+  'ῼ' => 'ῳ',
+  'Ω' => 'ω',
+  'K' => 'k',
+  'Å' => 'å',
+  'Ⅎ' => 'ⅎ',
+  'Ⅰ' => 'ⅰ',
+  'Ⅱ' => 'ⅱ',
+  'Ⅲ' => 'ⅲ',
+  'Ⅳ' => 'ⅳ',
+  'Ⅴ' => 'ⅴ',
+  'Ⅵ' => 'ⅵ',
+  'Ⅶ' => 'ⅶ',
+  'Ⅷ' => 'ⅷ',
+  'Ⅸ' => 'ⅸ',
+  'Ⅹ' => 'ⅹ',
+  'Ⅺ' => 'ⅺ',
+  'Ⅻ' => 'ⅻ',
+  'Ⅼ' => 'ⅼ',
+  'Ⅽ' => 'ⅽ',
+  'Ⅾ' => 'ⅾ',
+  'Ⅿ' => 'ⅿ',
+  'Ↄ' => 'ↄ',
+  'Ⓐ' => 'ⓐ',
+  'Ⓑ' => 'ⓑ',
+  'Ⓒ' => 'ⓒ',
+  'Ⓓ' => 'ⓓ',
+  'Ⓔ' => 'ⓔ',
+  'Ⓕ' => 'ⓕ',
+  'Ⓖ' => 'ⓖ',
+  'Ⓗ' => 'ⓗ',
+  'Ⓘ' => 'ⓘ',
+  'Ⓙ' => 'ⓙ',
+  'Ⓚ' => 'ⓚ',
+  'Ⓛ' => 'ⓛ',
+  'Ⓜ' => 'ⓜ',
+  'Ⓝ' => 'ⓝ',
+  'Ⓞ' => 'ⓞ',
+  'Ⓟ' => 'ⓟ',
+  'Ⓠ' => 'ⓠ',
+  'Ⓡ' => 'ⓡ',
+  'Ⓢ' => 'ⓢ',
+  'Ⓣ' => 'ⓣ',
+  'Ⓤ' => 'ⓤ',
+  'Ⓥ' => 'ⓥ',
+  'Ⓦ' => 'ⓦ',
+  'Ⓧ' => 'ⓧ',
+  'Ⓨ' => 'ⓨ',
+  'Ⓩ' => 'ⓩ',
+  'Ⰰ' => 'ⰰ',
+  'Ⰱ' => 'ⰱ',
+  'Ⰲ' => 'ⰲ',
+  'Ⰳ' => 'ⰳ',
+  'Ⰴ' => 'ⰴ',
+  'Ⰵ' => 'ⰵ',
+  'Ⰶ' => 'ⰶ',
+  'Ⰷ' => 'ⰷ',
+  'Ⰸ' => 'ⰸ',
+  'Ⰹ' => 'ⰹ',
+  'Ⰺ' => 'ⰺ',
+  'Ⰻ' => 'ⰻ',
+  'Ⰼ' => 'ⰼ',
+  'Ⰽ' => 'ⰽ',
+  'Ⰾ' => 'ⰾ',
+  'Ⰿ' => 'ⰿ',
+  'Ⱀ' => 'ⱀ',
+  'Ⱁ' => 'ⱁ',
+  'Ⱂ' => 'ⱂ',
+  'Ⱃ' => 'ⱃ',
+  'Ⱄ' => 'ⱄ',
+  'Ⱅ' => 'ⱅ',
+  'Ⱆ' => 'ⱆ',
+  'Ⱇ' => 'ⱇ',
+  'Ⱈ' => 'ⱈ',
+  'Ⱉ' => 'ⱉ',
+  'Ⱊ' => 'ⱊ',
+  'Ⱋ' => 'ⱋ',
+  'Ⱌ' => 'ⱌ',
+  'Ⱍ' => 'ⱍ',
+  'Ⱎ' => 'ⱎ',
+  'Ⱏ' => 'ⱏ',
+  'Ⱐ' => 'ⱐ',
+  'Ⱑ' => 'ⱑ',
+  'Ⱒ' => 'ⱒ',
+  'Ⱓ' => 'ⱓ',
+  'Ⱔ' => 'ⱔ',
+  'Ⱕ' => 'ⱕ',
+  'Ⱖ' => 'ⱖ',
+  'Ⱗ' => 'ⱗ',
+  'Ⱘ' => 'ⱘ',
+  'Ⱙ' => 'ⱙ',
+  'Ⱚ' => 'ⱚ',
+  'Ⱛ' => 'ⱛ',
+  'Ⱜ' => 'ⱜ',
+  'Ⱝ' => 'ⱝ',
+  'Ⱞ' => 'ⱞ',
+  'Ⱡ' => 'ⱡ',
+  'Ɫ' => 'ɫ',
+  'Ᵽ' => 'ᵽ',
+  'Ɽ' => 'ɽ',
+  'Ⱨ' => 'ⱨ',
+  'Ⱪ' => 'ⱪ',
+  'Ⱬ' => 'ⱬ',
+  'Ɑ' => 'ɑ',
+  'Ɱ' => 'ɱ',
+  'Ɐ' => 'ɐ',
+  'Ɒ' => 'ɒ',
+  'Ⱳ' => 'ⱳ',
+  'Ⱶ' => 'ⱶ',
+  'Ȿ' => 'ȿ',
+  'Ɀ' => 'ɀ',
+  'Ⲁ' => 'ⲁ',
+  'Ⲃ' => 'ⲃ',
+  'Ⲅ' => 'ⲅ',
+  'Ⲇ' => 'ⲇ',
+  'Ⲉ' => 'ⲉ',
+  'Ⲋ' => 'ⲋ',
+  'Ⲍ' => 'ⲍ',
+  'Ⲏ' => 'ⲏ',
+  'Ⲑ' => 'ⲑ',
+  'Ⲓ' => 'ⲓ',
+  'Ⲕ' => 'ⲕ',
+  'Ⲗ' => 'ⲗ',
+  'Ⲙ' => 'ⲙ',
+  'Ⲛ' => 'ⲛ',
+  'Ⲝ' => 'ⲝ',
+  'Ⲟ' => 'ⲟ',
+  'Ⲡ' => 'ⲡ',
+  'Ⲣ' => 'ⲣ',
+  'Ⲥ' => 'ⲥ',
+  'Ⲧ' => 'ⲧ',
+  'Ⲩ' => 'ⲩ',
+  'Ⲫ' => 'ⲫ',
+  'Ⲭ' => 'ⲭ',
+  'Ⲯ' => 'ⲯ',
+  'Ⲱ' => 'ⲱ',
+  'Ⲳ' => 'ⲳ',
+  'Ⲵ' => 'ⲵ',
+  'Ⲷ' => 'ⲷ',
+  'Ⲹ' => 'ⲹ',
+  'Ⲻ' => 'ⲻ',
+  'Ⲽ' => 'ⲽ',
+  'Ⲿ' => 'ⲿ',
+  'Ⳁ' => 'ⳁ',
+  'Ⳃ' => 'ⳃ',
+  'Ⳅ' => 'ⳅ',
+  'Ⳇ' => 'ⳇ',
+  'Ⳉ' => 'ⳉ',
+  'Ⳋ' => 'ⳋ',
+  'Ⳍ' => 'ⳍ',
+  'Ⳏ' => 'ⳏ',
+  'Ⳑ' => 'ⳑ',
+  'Ⳓ' => 'ⳓ',
+  'Ⳕ' => 'ⳕ',
+  'Ⳗ' => 'ⳗ',
+  'Ⳙ' => 'ⳙ',
+  'Ⳛ' => 'ⳛ',
+  'Ⳝ' => 'ⳝ',
+  'Ⳟ' => 'ⳟ',
+  'Ⳡ' => 'ⳡ',
+  'Ⳣ' => 'ⳣ',
+  'Ⳬ' => 'ⳬ',
+  'Ⳮ' => 'ⳮ',
+  'Ⳳ' => 'ⳳ',
+  'Ꙁ' => 'ꙁ',
+  'Ꙃ' => 'ꙃ',
+  'Ꙅ' => 'ꙅ',
+  'Ꙇ' => 'ꙇ',
+  'Ꙉ' => 'ꙉ',
+  'Ꙋ' => 'ꙋ',
+  'Ꙍ' => 'ꙍ',
+  'Ꙏ' => 'ꙏ',
+  'Ꙑ' => 'ꙑ',
+  'Ꙓ' => 'ꙓ',
+  'Ꙕ' => 'ꙕ',
+  'Ꙗ' => 'ꙗ',
+  'Ꙙ' => 'ꙙ',
+  'Ꙛ' => 'ꙛ',
+  'Ꙝ' => 'ꙝ',
+  'Ꙟ' => 'ꙟ',
+  'Ꙡ' => 'ꙡ',
+  'Ꙣ' => 'ꙣ',
+  'Ꙥ' => 'ꙥ',
+  'Ꙧ' => 'ꙧ',
+  'Ꙩ' => 'ꙩ',
+  'Ꙫ' => 'ꙫ',
+  'Ꙭ' => 'ꙭ',
+  'Ꚁ' => 'ꚁ',
+  'Ꚃ' => 'ꚃ',
+  'Ꚅ' => 'ꚅ',
+  'Ꚇ' => 'ꚇ',
+  'Ꚉ' => 'ꚉ',
+  'Ꚋ' => 'ꚋ',
+  'Ꚍ' => 'ꚍ',
+  'Ꚏ' => 'ꚏ',
+  'Ꚑ' => 'ꚑ',
+  'Ꚓ' => 'ꚓ',
+  'Ꚕ' => 'ꚕ',
+  'Ꚗ' => 'ꚗ',
+  'Ꚙ' => 'ꚙ',
+  'Ꚛ' => 'ꚛ',
+  'Ꜣ' => 'ꜣ',
+  'Ꜥ' => 'ꜥ',
+  'Ꜧ' => 'ꜧ',
+  'Ꜩ' => 'ꜩ',
+  'Ꜫ' => 'ꜫ',
+  'Ꜭ' => 'ꜭ',
+  'Ꜯ' => 'ꜯ',
+  'Ꜳ' => 'ꜳ',
+  'Ꜵ' => 'ꜵ',
+  'Ꜷ' => 'ꜷ',
+  'Ꜹ' => 'ꜹ',
+  'Ꜻ' => 'ꜻ',
+  'Ꜽ' => 'ꜽ',
+  'Ꜿ' => 'ꜿ',
+  'Ꝁ' => 'ꝁ',
+  'Ꝃ' => 'ꝃ',
+  'Ꝅ' => 'ꝅ',
+  'Ꝇ' => 'ꝇ',
+  'Ꝉ' => 'ꝉ',
+  'Ꝋ' => 'ꝋ',
+  'Ꝍ' => 'ꝍ',
+  'Ꝏ' => 'ꝏ',
+  'Ꝑ' => 'ꝑ',
+  'Ꝓ' => 'ꝓ',
+  'Ꝕ' => 'ꝕ',
+  'Ꝗ' => 'ꝗ',
+  'Ꝙ' => 'ꝙ',
+  'Ꝛ' => 'ꝛ',
+  'Ꝝ' => 'ꝝ',
+  'Ꝟ' => 'ꝟ',
+  'Ꝡ' => 'ꝡ',
+  'Ꝣ' => 'ꝣ',
+  'Ꝥ' => 'ꝥ',
+  'Ꝧ' => 'ꝧ',
+  'Ꝩ' => 'ꝩ',
+  'Ꝫ' => 'ꝫ',
+  'Ꝭ' => 'ꝭ',
+  'Ꝯ' => 'ꝯ',
+  'Ꝺ' => 'ꝺ',
+  'Ꝼ' => 'ꝼ',
+  'Ᵹ' => 'ᵹ',
+  'Ꝿ' => 'ꝿ',
+  'Ꞁ' => 'ꞁ',
+  'Ꞃ' => 'ꞃ',
+  'Ꞅ' => 'ꞅ',
+  'Ꞇ' => 'ꞇ',
+  'Ꞌ' => 'ꞌ',
+  'Ɥ' => 'ɥ',
+  'Ꞑ' => 'ꞑ',
+  'Ꞓ' => 'ꞓ',
+  'Ꞗ' => 'ꞗ',
+  'Ꞙ' => 'ꞙ',
+  'Ꞛ' => 'ꞛ',
+  'Ꞝ' => 'ꞝ',
+  'Ꞟ' => 'ꞟ',
+  'Ꞡ' => 'ꞡ',
+  'Ꞣ' => 'ꞣ',
+  'Ꞥ' => 'ꞥ',
+  'Ꞧ' => 'ꞧ',
+  'Ꞩ' => 'ꞩ',
+  'Ɦ' => 'ɦ',
+  'Ɜ' => 'ɜ',
+  'Ɡ' => 'ɡ',
+  'Ɬ' => 'ɬ',
+  'Ʞ' => 'ʞ',
+  'Ʇ' => 'ʇ',
+  'Ａ' => 'ａ',
+  'Ｂ' => 'ｂ',
+  'Ｃ' => 'ｃ',
+  'Ｄ' => 'ｄ',
+  'Ｅ' => 'ｅ',
+  'Ｆ' => 'ｆ',
+  'Ｇ' => 'ｇ',
+  'Ｈ' => 'ｈ',
+  'Ｉ' => 'ｉ',
+  'Ｊ' => 'ｊ',
+  'Ｋ' => 'ｋ',
+  'Ｌ' => 'ｌ',
+  'Ｍ' => 'ｍ',
+  'Ｎ' => 'ｎ',
+  'Ｏ' => 'ｏ',
+  'Ｐ' => 'ｐ',
+  'Ｑ' => 'ｑ',
+  'Ｒ' => 'ｒ',
+  'Ｓ' => 'ｓ',
+  'Ｔ' => 'ｔ',
+  'Ｕ' => 'ｕ',
+  'Ｖ' => 'ｖ',
+  'Ｗ' => 'ｗ',
+  'Ｘ' => 'ｘ',
+  'Ｙ' => 'ｙ',
+  'Ｚ' => 'ｚ',
+  '𐐀' => '𐐨',
+  '𐐁' => '𐐩',
+  '𐐂' => '𐐪',
+  '𐐃' => '𐐫',
+  '𐐄' => '𐐬',
+  '𐐅' => '𐐭',
+  '𐐆' => '𐐮',
+  '𐐇' => '𐐯',
+  '𐐈' => '𐐰',
+  '𐐉' => '𐐱',
+  '𐐊' => '𐐲',
+  '𐐋' => '𐐳',
+  '𐐌' => '𐐴',
+  '𐐍' => '𐐵',
+  '𐐎' => '𐐶',
+  '𐐏' => '𐐷',
+  '𐐐' => '𐐸',
+  '𐐑' => '𐐹',
+  '𐐒' => '𐐺',
+  '𐐓' => '𐐻',
+  '𐐔' => '𐐼',
+  '𐐕' => '𐐽',
+  '𐐖' => '𐐾',
+  '𐐗' => '𐐿',
+  '𐐘' => '𐑀',
+  '𐐙' => '𐑁',
+  '𐐚' => '𐑂',
+  '𐐛' => '𐑃',
+  '𐐜' => '𐑄',
+  '𐐝' => '𐑅',
+  '𐐞' => '𐑆',
+  '𐐟' => '𐑇',
+  '𐐠' => '𐑈',
+  '𐐡' => '𐑉',
+  '𐐢' => '𐑊',
+  '𐐣' => '𐑋',
+  '𐐤' => '𐑌',
+  '𐐥' => '𐑍',
+  '𐐦' => '𐑎',
+  '𐐧' => '𐑏',
+  '𑢠' => '𑣀',
+  '𑢡' => '𑣁',
+  '𑢢' => '𑣂',
+  '𑢣' => '𑣃',
+  '𑢤' => '𑣄',
+  '𑢥' => '𑣅',
+  '𑢦' => '𑣆',
+  '𑢧' => '𑣇',
+  '𑢨' => '𑣈',
+  '𑢩' => '𑣉',
+  '𑢪' => '𑣊',
+  '𑢫' => '𑣋',
+  '𑢬' => '𑣌',
+  '𑢭' => '𑣍',
+  '𑢮' => '𑣎',
+  '𑢯' => '𑣏',
+  '𑢰' => '𑣐',
+  '𑢱' => '𑣑',
+  '𑢲' => '𑣒',
+  '𑢳' => '𑣓',
+  '𑢴' => '𑣔',
+  '𑢵' => '𑣕',
+  '𑢶' => '𑣖',
+  '𑢷' => '𑣗',
+  '𑢸' => '𑣘',
+  '𑢹' => '𑣙',
+  '𑢺' => '𑣚',
+  '𑢻' => '𑣛',
+  '𑢼' => '𑣜',
+  '𑢽' => '𑣝',
+  '𑢾' => '𑣞',
+  '𑢿' => '𑣟',
+);
+
+$result =& $data;
+unset($data);
+
+return $result;
--- /dev/null
+++ b/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php
@@ -0,0 +1,1109 @@
+<?php
+
+static $data = array (
+  'a' => 'A',
+  'b' => 'B',
+  'c' => 'C',
+  'd' => 'D',
+  'e' => 'E',
+  'f' => 'F',
+  'g' => 'G',
+  'h' => 'H',
+  'i' => 'I',
+  'j' => 'J',
+  'k' => 'K',
+  'l' => 'L',
+  'm' => 'M',
+  'n' => 'N',
+  'o' => 'O',
+  'p' => 'P',
+  'q' => 'Q',
+  'r' => 'R',
+  's' => 'S',
+  't' => 'T',
+  'u' => 'U',
+  'v' => 'V',
+  'w' => 'W',
+  'x' => 'X',
+  'y' => 'Y',
+  'z' => 'Z',
+  'µ' => 'Μ',
+  'à' => 'À',
+  'á' => 'Á',
+  'â' => 'Â',
+  'ã' => 'Ã',
+  'ä' => 'Ä',
+  'å' => 'Å',
+  'æ' => 'Æ',
+  'ç' => 'Ç',
+  'è' => 'È',
+  'é' => 'É',
+  'ê' => 'Ê',
+  'ë' => 'Ë',
+  'ì' => 'Ì',
+  'í' => 'Í',
+  'î' => 'Î',
+  'ï' => 'Ï',
+  'ð' => 'Ð',
+  'ñ' => 'Ñ',
+  'ò' => 'Ò',
+  'ó' => 'Ó',
+  'ô' => 'Ô',
+  'õ' => 'Õ',
+  'ö' => 'Ö',
+  'ø' => 'Ø',
+  'ù' => 'Ù',
+  'ú' => 'Ú',
+  'û' => 'Û',
+  'ü' => 'Ü',
+  'ý' => 'Ý',
+  'þ' => 'Þ',
+  'ÿ' => 'Ÿ',
+  'ā' => 'Ā',
+  'ă' => 'Ă',
+  'ą' => 'Ą',
+  'ć' => 'Ć',
+  'ĉ' => 'Ĉ',
+  'ċ' => 'Ċ',
+  'č' => 'Č',
+  'ď' => 'Ď',
+  'đ' => 'Đ',
+  'ē' => 'Ē',
+  'ĕ' => 'Ĕ',
+  'ė' => 'Ė',
+  'ę' => 'Ę',
+  'ě' => 'Ě',
+  'ĝ' => 'Ĝ',
+  'ğ' => 'Ğ',
+  'ġ' => 'Ġ',
+  'ģ' => 'Ģ',
+  'ĥ' => 'Ĥ',
+  'ħ' => 'Ħ',
+  'ĩ' => 'Ĩ',
+  'ī' => 'Ī',
+  'ĭ' => 'Ĭ',
+  'į' => 'Į',
+  'ı' => 'I',
+  'ĳ' => 'Ĳ',
+  'ĵ' => 'Ĵ',
+  'ķ' => 'Ķ',
+  'ĺ' => 'Ĺ',
+  'ļ' => 'Ļ',
+  'ľ' => 'Ľ',
+  'ŀ' => 'Ŀ',
+  'ł' => 'Ł',
+  'ń' => 'Ń',
+  'ņ' => 'Ņ',
+  'ň' => 'Ň',
+  'ŋ' => 'Ŋ',
+  'ō' => 'Ō',
+  'ŏ' => 'Ŏ',
+  'ő' => 'Ő',
+  'œ' => 'Œ',
+  'ŕ' => 'Ŕ',
+  'ŗ' => 'Ŗ',
+  'ř' => 'Ř',
+  'ś' => 'Ś',
+  'ŝ' => 'Ŝ',
+  'ş' => 'Ş',
+  'š' => 'Š',
+  'ţ' => 'Ţ',
+  'ť' => 'Ť',
+  'ŧ' => 'Ŧ',
+  'ũ' => 'Ũ',
+  'ū' => 'Ū',
+  'ŭ' => 'Ŭ',
+  'ů' => 'Ů',
+  'ű' => 'Ű',
+  'ų' => 'Ų',
+  'ŵ' => 'Ŵ',
+  'ŷ' => 'Ŷ',
+  'ź' => 'Ź',
+  'ż' => 'Ż',
+  'ž' => 'Ž',
+  'ſ' => 'S',
+  'ƀ' => 'Ƀ',
+  'ƃ' => 'Ƃ',
+  'ƅ' => 'Ƅ',
+  'ƈ' => 'Ƈ',
+  'ƌ' => 'Ƌ',
+  'ƒ' => 'Ƒ',
+  'ƕ' => 'Ƕ',
+  'ƙ' => 'Ƙ',
+  'ƚ' => 'Ƚ',
+  'ƞ' => 'Ƞ',
+  'ơ' => 'Ơ',
+  'ƣ' => 'Ƣ',
+  'ƥ' => 'Ƥ',
+  'ƨ' => 'Ƨ',
+  'ƭ' => 'Ƭ',
+  'ư' => 'Ư',
+  'ƴ' => 'Ƴ',
+  'ƶ' => 'Ƶ',
+  'ƹ' => 'Ƹ',
+  'ƽ' => 'Ƽ',
+  'ƿ' => 'Ƿ',
+  'ǅ' => 'Ǆ',
+  'ǆ' => 'Ǆ',
+  'ǈ' => 'Ǉ',
+  'ǉ' => 'Ǉ',
+  'ǋ' => 'Ǌ',
+  'ǌ' => 'Ǌ',
+  'ǎ' => 'Ǎ',
+  'ǐ' => 'Ǐ',
+  'ǒ' => 'Ǒ',
+  'ǔ' => 'Ǔ',
+  'ǖ' => 'Ǖ',
+  'ǘ' => 'Ǘ',
+  'ǚ' => 'Ǚ',
+  'ǜ' => 'Ǜ',
+  'ǝ' => 'Ǝ',
+  'ǟ' => 'Ǟ',
+  'ǡ' => 'Ǡ',
+  'ǣ' => 'Ǣ',
+  'ǥ' => 'Ǥ',
+  'ǧ' => 'Ǧ',
+  'ǩ' => 'Ǩ',
+  'ǫ' => 'Ǫ',
+  'ǭ' => 'Ǭ',
+  'ǯ' => 'Ǯ',
+  'ǲ' => 'Ǳ',
+  'ǳ' => 'Ǳ',
+  'ǵ' => 'Ǵ',
+  'ǹ' => 'Ǹ',
+  'ǻ' => 'Ǻ',
+  'ǽ' => 'Ǽ',
+  'ǿ' => 'Ǿ',
+  'ȁ' => 'Ȁ',
+  'ȃ' => 'Ȃ',
+  'ȅ' => 'Ȅ',
+  'ȇ' => 'Ȇ',
+  'ȉ' => 'Ȉ',
+  'ȋ' => 'Ȋ',
+  'ȍ' => 'Ȍ',
+  'ȏ' => 'Ȏ',
+  'ȑ' => 'Ȑ',
+  'ȓ' => 'Ȓ',
+  'ȕ' => 'Ȕ',
+  'ȗ' => 'Ȗ',
+  'ș' => 'Ș',
+  'ț' => 'Ț',
+  'ȝ' => 'Ȝ',
+  'ȟ' => 'Ȟ',
+  'ȣ' => 'Ȣ',
+  'ȥ' => 'Ȥ',
+  'ȧ' => 'Ȧ',
+  'ȩ' => 'Ȩ',
+  'ȫ' => 'Ȫ',
+  'ȭ' => 'Ȭ',
+  'ȯ' => 'Ȯ',
+  'ȱ' => 'Ȱ',
+  'ȳ' => 'Ȳ',
+  'ȼ' => 'Ȼ',
+  'ȿ' => 'Ȿ',
+  'ɀ' => 'Ɀ',
+  'ɂ' => 'Ɂ',
+  'ɇ' => 'Ɇ',
+  'ɉ' => 'Ɉ',
+  'ɋ' => 'Ɋ',
+  'ɍ' => 'Ɍ',
+  'ɏ' => 'Ɏ',
+  'ɐ' => 'Ɐ',
+  'ɑ' => 'Ɑ',
+  'ɒ' => 'Ɒ',
+  'ɓ' => 'Ɓ',
+  'ɔ' => 'Ɔ',
+  'ɖ' => 'Ɖ',
+  'ɗ' => 'Ɗ',
+  'ə' => 'Ə',
+  'ɛ' => 'Ɛ',
+  'ɜ' => 'Ɜ',
+  'ɠ' => 'Ɠ',
+  'ɡ' => 'Ɡ',
+  'ɣ' => 'Ɣ',
+  'ɥ' => 'Ɥ',
+  'ɦ' => 'Ɦ',
+  'ɨ' => 'Ɨ',
+  'ɩ' => 'Ɩ',
+  'ɫ' => 'Ɫ',
+  'ɬ' => 'Ɬ',
+  'ɯ' => 'Ɯ',
+  'ɱ' => 'Ɱ',
+  'ɲ' => 'Ɲ',
+  'ɵ' => 'Ɵ',
+  'ɽ' => 'Ɽ',
+  'ʀ' => 'Ʀ',
+  'ʃ' => 'Ʃ',
+  'ʇ' => 'Ʇ',
+  'ʈ' => 'Ʈ',
+  'ʉ' => 'Ʉ',
+  'ʊ' => 'Ʊ',
+  'ʋ' => 'Ʋ',
+  'ʌ' => 'Ʌ',
+  'ʒ' => 'Ʒ',
+  'ʞ' => 'Ʞ',
+  'ͅ' => 'Ι',
+  'ͱ' => 'Ͱ',
+  'ͳ' => 'Ͳ',
+  'ͷ' => 'Ͷ',
+  'ͻ' => 'Ͻ',
+  'ͼ' => 'Ͼ',
+  'ͽ' => 'Ͽ',
+  'ά' => 'Ά',
+  'έ' => 'Έ',
+  'ή' => 'Ή',
+  'ί' => 'Ί',
+  'α' => 'Α',
+  'β' => 'Β',
+  'γ' => 'Γ',
+  'δ' => 'Δ',
+  'ε' => 'Ε',
+  'ζ' => 'Ζ',
+  'η' => 'Η',
+  'θ' => 'Θ',
+  'ι' => 'Ι',
+  'κ' => 'Κ',
+  'λ' => 'Λ',
+  'μ' => 'Μ',
+  'ν' => 'Ν',
+  'ξ' => 'Ξ',
+  'ο' => 'Ο',
+  'π' => 'Π',
+  'ρ' => 'Ρ',
+  'ς' => 'Σ',
+  'σ' => 'Σ',
+  'τ' => 'Τ',
+  'υ' => 'Υ',
+  'φ' => 'Φ',
+  'χ' => 'Χ',
+  'ψ' => 'Ψ',
+  'ω' => 'Ω',
+  'ϊ' => 'Ϊ',
+  'ϋ' => 'Ϋ',
+  'ό' => 'Ό',
+  'ύ' => 'Ύ',
+  'ώ' => 'Ώ',
+  'ϐ' => 'Β',
+  'ϑ' => 'Θ',
+  'ϕ' => 'Φ',
+  'ϖ' => 'Π',
+  'ϗ' => 'Ϗ',
+  'ϙ' => 'Ϙ',
+  'ϛ' => 'Ϛ',
+  'ϝ' => 'Ϝ',
+  'ϟ' => 'Ϟ',
+  'ϡ' => 'Ϡ',
+  'ϣ' => 'Ϣ',
+  'ϥ' => 'Ϥ',
+  'ϧ' => 'Ϧ',
+  'ϩ' => 'Ϩ',
+  'ϫ' => 'Ϫ',
+  'ϭ' => 'Ϭ',
+  'ϯ' => 'Ϯ',
+  'ϰ' => 'Κ',
+  'ϱ' => 'Ρ',
+  'ϲ' => 'Ϲ',
+  'ϳ' => 'Ϳ',
+  'ϵ' => 'Ε',
+  'ϸ' => 'Ϸ',
+  'ϻ' => 'Ϻ',
+  'а' => 'А',
+  'б' => 'Б',
+  'в' => 'В',
+  'г' => 'Г',
+  'д' => 'Д',
+  'е' => 'Е',
+  'ж' => 'Ж',
+  'з' => 'З',
+  'и' => 'И',
+  'й' => 'Й',
+  'к' => 'К',
+  'л' => 'Л',
+  'м' => 'М',
+  'н' => 'Н',
+  'о' => 'О',
+  'п' => 'П',
+  'р' => 'Р',
+  'с' => 'С',
+  'т' => 'Т',
+  'у' => 'У',
+  'ф' => 'Ф',
+  'х' => 'Х',
+  'ц' => 'Ц',
+  'ч' => 'Ч',
+  'ш' => 'Ш',
+  'щ' => 'Щ',
+  'ъ' => 'Ъ',
+  'ы' => 'Ы',
+  'ь' => 'Ь',
+  'э' => 'Э',
+  'ю' => 'Ю',
+  'я' => 'Я',
+  'ѐ' => 'Ѐ',
+  'ё' => 'Ё',
+  'ђ' => 'Ђ',
+  'ѓ' => 'Ѓ',
+  'є' => 'Є',
+  'ѕ' => 'Ѕ',
+  'і' => 'І',
+  'ї' => 'Ї',
+  'ј' => 'Ј',
+  'љ' => 'Љ',
+  'њ' => 'Њ',
+  'ћ' => 'Ћ',
+  'ќ' => 'Ќ',
+  'ѝ' => 'Ѝ',
+  'ў' => 'Ў',
+  'џ' => 'Џ',
+  'ѡ' => 'Ѡ',
+  'ѣ' => 'Ѣ',
+  'ѥ' => 'Ѥ',
+  'ѧ' => 'Ѧ',
+  'ѩ' => 'Ѩ',
+  'ѫ' => 'Ѫ',
+  'ѭ' => 'Ѭ',
+  'ѯ' => 'Ѯ',
+  'ѱ' => 'Ѱ',
+  'ѳ' => 'Ѳ',
+  'ѵ' => 'Ѵ',
+  'ѷ' => 'Ѷ',
+  'ѹ' => 'Ѹ',
+  'ѻ' => 'Ѻ',
+  'ѽ' => 'Ѽ',
+  'ѿ' => 'Ѿ',
+  'ҁ' => 'Ҁ',
+  'ҋ' => 'Ҋ',
+  'ҍ' => 'Ҍ',
+  'ҏ' => 'Ҏ',
+  'ґ' => 'Ґ',
+  'ғ' => 'Ғ',
+  'ҕ' => 'Ҕ',
+  'җ' => 'Җ',
+  'ҙ' => 'Ҙ',
+  'қ' => 'Қ',
+  'ҝ' => 'Ҝ',
+  'ҟ' => 'Ҟ',
+  'ҡ' => 'Ҡ',
+  'ң' => 'Ң',
+  'ҥ' => 'Ҥ',
+  'ҧ' => 'Ҧ',
+  'ҩ' => 'Ҩ',
+  'ҫ' => 'Ҫ',
+  'ҭ' => 'Ҭ',
+  'ү' => 'Ү',
+  'ұ' => 'Ұ',
+  'ҳ' => 'Ҳ',
+  'ҵ' => 'Ҵ',
+  'ҷ' => 'Ҷ',
+  'ҹ' => 'Ҹ',
+  'һ' => 'Һ',
+  'ҽ' => 'Ҽ',
+  'ҿ' => 'Ҿ',
+  'ӂ' => 'Ӂ',
+  'ӄ' => 'Ӄ',
+  'ӆ' => 'Ӆ',
+  'ӈ' => 'Ӈ',
+  'ӊ' => 'Ӊ',
+  'ӌ' => 'Ӌ',
+  'ӎ' => 'Ӎ',
+  'ӏ' => 'Ӏ',
+  'ӑ' => 'Ӑ',
+  'ӓ' => 'Ӓ',
+  'ӕ' => 'Ӕ',
+  'ӗ' => 'Ӗ',
+  'ә' => 'Ә',
+  'ӛ' => 'Ӛ',
+  'ӝ' => 'Ӝ',
+  'ӟ' => 'Ӟ',
+  'ӡ' => 'Ӡ',
+  'ӣ' => 'Ӣ',
+  'ӥ' => 'Ӥ',
+  'ӧ' => 'Ӧ',
+  'ө' => 'Ө',
+  'ӫ' => 'Ӫ',
+  'ӭ' => 'Ӭ',
+  'ӯ' => 'Ӯ',
+  'ӱ' => 'Ӱ',
+  'ӳ' => 'Ӳ',
+  'ӵ' => 'Ӵ',
+  'ӷ' => 'Ӷ',
+  'ӹ' => 'Ӹ',
+  'ӻ' => 'Ӻ',
+  'ӽ' => 'Ӽ',
+  'ӿ' => 'Ӿ',
+  'ԁ' => 'Ԁ',
+  'ԃ' => 'Ԃ',
+  'ԅ' => 'Ԅ',
+  'ԇ' => 'Ԇ',
+  'ԉ' => 'Ԉ',
+  'ԋ' => 'Ԋ',
+  'ԍ' => 'Ԍ',
+  'ԏ' => 'Ԏ',
+  'ԑ' => 'Ԑ',
+  'ԓ' => 'Ԓ',
+  'ԕ' => 'Ԕ',
+  'ԗ' => 'Ԗ',
+  'ԙ' => 'Ԙ',
+  'ԛ' => 'Ԛ',
+  'ԝ' => 'Ԝ',
+  'ԟ' => 'Ԟ',
+  'ԡ' => 'Ԡ',
+  'ԣ' => 'Ԣ',
+  'ԥ' => 'Ԥ',
+  'ԧ' => 'Ԧ',
+  'ԩ' => 'Ԩ',
+  'ԫ' => 'Ԫ',
+  'ԭ' => 'Ԭ',
+  'ԯ' => 'Ԯ',
+  'ա' => 'Ա',
+  'բ' => 'Բ',
+  'գ' => 'Գ',
+  'դ' => 'Դ',
+  'ե' => 'Ե',
+  'զ' => 'Զ',
+  'է' => 'Է',
+  'ը' => 'Ը',
+  'թ' => 'Թ',
+  'ժ' => 'Ժ',
+  'ի' => 'Ի',
+  'լ' => 'Լ',
+  'խ' => 'Խ',
+  'ծ' => 'Ծ',
+  'կ' => 'Կ',
+  'հ' => 'Հ',
+  'ձ' => 'Ձ',
+  'ղ' => 'Ղ',
+  'ճ' => 'Ճ',
+  'մ' => 'Մ',
+  'յ' => 'Յ',
+  'ն' => 'Ն',
+  'շ' => 'Շ',
+  'ո' => 'Ո',
+  'չ' => 'Չ',
+  'պ' => 'Պ',
+  'ջ' => 'Ջ',
+  'ռ' => 'Ռ',
+  'ս' => 'Ս',
+  'վ' => 'Վ',
+  'տ' => 'Տ',
+  'ր' => 'Ր',
+  'ց' => 'Ց',
+  'ւ' => 'Ւ',
+  'փ' => 'Փ',
+  'ք' => 'Ք',
+  'օ' => 'Օ',
+  'ֆ' => 'Ֆ',
+  'ᵹ' => 'Ᵹ',
+  'ᵽ' => 'Ᵽ',
+  'ḁ' => 'Ḁ',
+  'ḃ' => 'Ḃ',
+  'ḅ' => 'Ḅ',
+  'ḇ' => 'Ḇ',
+  'ḉ' => 'Ḉ',
+  'ḋ' => 'Ḋ',
+  'ḍ' => 'Ḍ',
+  'ḏ' => 'Ḏ',
+  'ḑ' => 'Ḑ',
+  'ḓ' => 'Ḓ',
+  'ḕ' => 'Ḕ',
+  'ḗ' => 'Ḗ',
+  'ḙ' => 'Ḙ',
+  'ḛ' => 'Ḛ',
+  'ḝ' => 'Ḝ',
+  'ḟ' => 'Ḟ',
+  'ḡ' => 'Ḡ',
+  'ḣ' => 'Ḣ',
+  'ḥ' => 'Ḥ',
+  'ḧ' => 'Ḧ',
+  'ḩ' => 'Ḩ',
+  'ḫ' => 'Ḫ',
+  'ḭ' => 'Ḭ',
+  'ḯ' => 'Ḯ',
+  'ḱ' => 'Ḱ',
+  'ḳ' => 'Ḳ',
+  'ḵ' => 'Ḵ',
+  'ḷ' => 'Ḷ',
+  'ḹ' => 'Ḹ',
+  'ḻ' => 'Ḻ',
+  'ḽ' => 'Ḽ',
+  'ḿ' => 'Ḿ',
+  'ṁ' => 'Ṁ',
+  'ṃ' => 'Ṃ',
+  'ṅ' => 'Ṅ',
+  'ṇ' => 'Ṇ',
+  'ṉ' => 'Ṉ',
+  'ṋ' => 'Ṋ',
+  'ṍ' => 'Ṍ',
+  'ṏ' => 'Ṏ',
+  'ṑ' => 'Ṑ',
+  'ṓ' => 'Ṓ',
+  'ṕ' => 'Ṕ',
+  'ṗ' => 'Ṗ',
+  'ṙ' => 'Ṙ',
+  'ṛ' => 'Ṛ',
+  'ṝ' => 'Ṝ',
+  'ṟ' => 'Ṟ',
+  'ṡ' => 'Ṡ',
+  'ṣ' => 'Ṣ',
+  'ṥ' => 'Ṥ',
+  'ṧ' => 'Ṧ',
+  'ṩ' => 'Ṩ',
+  'ṫ' => 'Ṫ',
+  'ṭ' => 'Ṭ',
+  'ṯ' => 'Ṯ',
+  'ṱ' => 'Ṱ',
+  'ṳ' => 'Ṳ',
+  'ṵ' => 'Ṵ',
+  'ṷ' => 'Ṷ',
+  'ṹ' => 'Ṹ',
+  'ṻ' => 'Ṻ',
+  'ṽ' => 'Ṽ',
+  'ṿ' => 'Ṿ',
+  'ẁ' => 'Ẁ',
+  'ẃ' => 'Ẃ',
+  'ẅ' => 'Ẅ',
+  'ẇ' => 'Ẇ',
+  'ẉ' => 'Ẉ',
+  'ẋ' => 'Ẋ',
+  'ẍ' => 'Ẍ',
+  'ẏ' => 'Ẏ',
+  'ẑ' => 'Ẑ',
+  'ẓ' => 'Ẓ',
+  'ẕ' => 'Ẕ',
+  'ẛ' => 'Ṡ',
+  'ạ' => 'Ạ',
+  'ả' => 'Ả',
+  'ấ' => 'Ấ',
+  'ầ' => 'Ầ',
+  'ẩ' => 'Ẩ',
+  'ẫ' => 'Ẫ',
+  'ậ' => 'Ậ',
+  'ắ' => 'Ắ',
+  'ằ' => 'Ằ',
+  'ẳ' => 'Ẳ',
+  'ẵ' => 'Ẵ',
+  'ặ' => 'Ặ',
+  'ẹ' => 'Ẹ',
+  'ẻ' => 'Ẻ',
+  'ẽ' => 'Ẽ',
+  'ế' => 'Ế',
+  'ề' => 'Ề',
+  'ể' => 'Ể',
+  'ễ' => 'Ễ',
+  'ệ' => 'Ệ',
+  'ỉ' => 'Ỉ',
+  'ị' => 'Ị',
+  'ọ' => 'Ọ',
+  'ỏ' => 'Ỏ',
+  'ố' => 'Ố',
+  'ồ' => 'Ồ',
+  'ổ' => 'Ổ',
+  'ỗ' => 'Ỗ',
+  'ộ' => 'Ộ',
+  'ớ' => 'Ớ',
+  'ờ' => 'Ờ',
+  'ở' => 'Ở',
+  'ỡ' => 'Ỡ',
+  'ợ' => 'Ợ',
+  'ụ' => 'Ụ',
+  'ủ' => 'Ủ',
+  'ứ' => 'Ứ',
+  'ừ' => 'Ừ',
+  'ử' => 'Ử',
+  'ữ' => 'Ữ',
+  'ự' => 'Ự',
+  'ỳ' => 'Ỳ',
+  'ỵ' => 'Ỵ',
+  'ỷ' => 'Ỷ',
+  'ỹ' => 'Ỹ',
+  'ỻ' => 'Ỻ',
+  'ỽ' => 'Ỽ',
+  'ỿ' => 'Ỿ',
+  'ἀ' => 'Ἀ',
+  'ἁ' => 'Ἁ',
+  'ἂ' => 'Ἂ',
+  'ἃ' => 'Ἃ',
+  'ἄ' => 'Ἄ',
+  'ἅ' => 'Ἅ',
+  'ἆ' => 'Ἆ',
+  'ἇ' => 'Ἇ',
+  'ἐ' => 'Ἐ',
+  'ἑ' => 'Ἑ',
+  'ἒ' => 'Ἒ',
+  'ἓ' => 'Ἓ',
+  'ἔ' => 'Ἔ',
+  'ἕ' => 'Ἕ',
+  'ἠ' => 'Ἠ',
+  'ἡ' => 'Ἡ',
+  'ἢ' => 'Ἢ',
+  'ἣ' => 'Ἣ',
+  'ἤ' => 'Ἤ',
+  'ἥ' => 'Ἥ',
+  'ἦ' => 'Ἦ',
+  'ἧ' => 'Ἧ',
+  'ἰ' => 'Ἰ',
+  'ἱ' => 'Ἱ',
+  'ἲ' => 'Ἲ',
+  'ἳ' => 'Ἳ',
+  'ἴ' => 'Ἴ',
+  'ἵ' => 'Ἵ',
+  'ἶ' => 'Ἶ',
+  'ἷ' => 'Ἷ',
+  'ὀ' => 'Ὀ',
+  'ὁ' => 'Ὁ',
+  'ὂ' => 'Ὂ',
+  'ὃ' => 'Ὃ',
+  'ὄ' => 'Ὄ',
+  'ὅ' => 'Ὅ',
+  'ὑ' => 'Ὑ',
+  'ὓ' => 'Ὓ',
+  'ὕ' => 'Ὕ',
+  'ὗ' => 'Ὗ',
+  'ὠ' => 'Ὠ',
+  'ὡ' => 'Ὡ',
+  'ὢ' => 'Ὢ',
+  'ὣ' => 'Ὣ',
+  'ὤ' => 'Ὤ',
+  'ὥ' => 'Ὥ',
+  'ὦ' => 'Ὦ',
+  'ὧ' => 'Ὧ',
+  'ὰ' => 'Ὰ',
+  'ά' => 'Ά',
+  'ὲ' => 'Ὲ',
+  'έ' => 'Έ',
+  'ὴ' => 'Ὴ',
+  'ή' => 'Ή',
+  'ὶ' => 'Ὶ',
+  'ί' => 'Ί',
+  'ὸ' => 'Ὸ',
+  'ό' => 'Ό',
+  'ὺ' => 'Ὺ',
+  'ύ' => 'Ύ',
+  'ὼ' => 'Ὼ',
+  'ώ' => 'Ώ',
+  'ᾀ' => 'ᾈ',
+  'ᾁ' => 'ᾉ',
+  'ᾂ' => 'ᾊ',
+  'ᾃ' => 'ᾋ',
+  'ᾄ' => 'ᾌ',
+  'ᾅ' => 'ᾍ',
+  'ᾆ' => 'ᾎ',
+  'ᾇ' => 'ᾏ',
+  'ᾐ' => 'ᾘ',
+  'ᾑ' => 'ᾙ',
+  'ᾒ' => 'ᾚ',
+  'ᾓ' => 'ᾛ',
+  'ᾔ' => 'ᾜ',
+  'ᾕ' => 'ᾝ',
+  'ᾖ' => 'ᾞ',
+  'ᾗ' => 'ᾟ',
+  'ᾠ' => 'ᾨ',
+  'ᾡ' => 'ᾩ',
+  'ᾢ' => 'ᾪ',
+  'ᾣ' => 'ᾫ',
+  'ᾤ' => 'ᾬ',
+  'ᾥ' => 'ᾭ',
+  'ᾦ' => 'ᾮ',
+  'ᾧ' => 'ᾯ',
+  'ᾰ' => 'Ᾰ',
+  'ᾱ' => 'Ᾱ',
+  'ᾳ' => 'ᾼ',
+  'ι' => 'Ι',
+  'ῃ' => 'ῌ',
+  'ῐ' => 'Ῐ',
+  'ῑ' => 'Ῑ',
+  'ῠ' => 'Ῠ',
+  'ῡ' => 'Ῡ',
+  'ῥ' => 'Ῥ',
+  'ῳ' => 'ῼ',
+  'ⅎ' => 'Ⅎ',
+  'ⅰ' => 'Ⅰ',
+  'ⅱ' => 'Ⅱ',
+  'ⅲ' => 'Ⅲ',
+  'ⅳ' => 'Ⅳ',
+  'ⅴ' => 'Ⅴ',
+  'ⅵ' => 'Ⅵ',
+  'ⅶ' => 'Ⅶ',
+  'ⅷ' => 'Ⅷ',
+  'ⅸ' => 'Ⅸ',
+  'ⅹ' => 'Ⅹ',
+  'ⅺ' => 'Ⅺ',
+  'ⅻ' => 'Ⅻ',
+  'ⅼ' => 'Ⅼ',
+  'ⅽ' => 'Ⅽ',
+  'ⅾ' => 'Ⅾ',
+  'ⅿ' => 'Ⅿ',
+  'ↄ' => 'Ↄ',
+  'ⓐ' => 'Ⓐ',
+  'ⓑ' => 'Ⓑ',
+  'ⓒ' => 'Ⓒ',
+  'ⓓ' => 'Ⓓ',
+  'ⓔ' => 'Ⓔ',
+  'ⓕ' => 'Ⓕ',
+  'ⓖ' => 'Ⓖ',
+  'ⓗ' => 'Ⓗ',
+  'ⓘ' => 'Ⓘ',
+  'ⓙ' => 'Ⓙ',
+  'ⓚ' => 'Ⓚ',
+  'ⓛ' => 'Ⓛ',
+  'ⓜ' => 'Ⓜ',
+  'ⓝ' => 'Ⓝ',
+  'ⓞ' => 'Ⓞ',
+  'ⓟ' => 'Ⓟ',
+  'ⓠ' => 'Ⓠ',
+  'ⓡ' => 'Ⓡ',
+  'ⓢ' => 'Ⓢ',
+  'ⓣ' => 'Ⓣ',
+  'ⓤ' => 'Ⓤ',
+  'ⓥ' => 'Ⓥ',
+  'ⓦ' => 'Ⓦ',
+  'ⓧ' => 'Ⓧ',
+  'ⓨ' => 'Ⓨ',
+  'ⓩ' => 'Ⓩ',
+  'ⰰ' => 'Ⰰ',
+  'ⰱ' => 'Ⰱ',
+  'ⰲ' => 'Ⰲ',
+  'ⰳ' => 'Ⰳ',
+  'ⰴ' => 'Ⰴ',
+  'ⰵ' => 'Ⰵ',
+  'ⰶ' => 'Ⰶ',
+  'ⰷ' => 'Ⰷ',
+  'ⰸ' => 'Ⰸ',
+  'ⰹ' => 'Ⰹ',
+  'ⰺ' => 'Ⰺ',
+  'ⰻ' => 'Ⰻ',
+  'ⰼ' => 'Ⰼ',
+  'ⰽ' => 'Ⰽ',
+  'ⰾ' => 'Ⰾ',
+  'ⰿ' => 'Ⰿ',
+  'ⱀ' => 'Ⱀ',
+  'ⱁ' => 'Ⱁ',
+  'ⱂ' => 'Ⱂ',
+  'ⱃ' => 'Ⱃ',
+  'ⱄ' => 'Ⱄ',
+  'ⱅ' => 'Ⱅ',
+  'ⱆ' => 'Ⱆ',
+  'ⱇ' => 'Ⱇ',
+  'ⱈ' => 'Ⱈ',
+  'ⱉ' => 'Ⱉ',
+  'ⱊ' => 'Ⱊ',
+  'ⱋ' => 'Ⱋ',
+  'ⱌ' => 'Ⱌ',
+  'ⱍ' => 'Ⱍ',
+  'ⱎ' => 'Ⱎ',
+  'ⱏ' => 'Ⱏ',
+  'ⱐ' => 'Ⱐ',
+  'ⱑ' => 'Ⱑ',
+  'ⱒ' => 'Ⱒ',
+  'ⱓ' => 'Ⱓ',
+  'ⱔ' => 'Ⱔ',
+  'ⱕ' => 'Ⱕ',
+  'ⱖ' => 'Ⱖ',
+  'ⱗ' => 'Ⱗ',
+  'ⱘ' => 'Ⱘ',
+  'ⱙ' => 'Ⱙ',
+  'ⱚ' => 'Ⱚ',
+  'ⱛ' => 'Ⱛ',
+  'ⱜ' => 'Ⱜ',
+  'ⱝ' => 'Ⱝ',
+  'ⱞ' => 'Ⱞ',
+  'ⱡ' => 'Ⱡ',
+  'ⱥ' => 'Ⱥ',
+  'ⱦ' => 'Ⱦ',
+  'ⱨ' => 'Ⱨ',
+  'ⱪ' => 'Ⱪ',
+  'ⱬ' => 'Ⱬ',
+  'ⱳ' => 'Ⱳ',
+  'ⱶ' => 'Ⱶ',
+  'ⲁ' => 'Ⲁ',
+  'ⲃ' => 'Ⲃ',
+  'ⲅ' => 'Ⲅ',
+  'ⲇ' => 'Ⲇ',
+  'ⲉ' => 'Ⲉ',
+  'ⲋ' => 'Ⲋ',
+  'ⲍ' => 'Ⲍ',
+  'ⲏ' => 'Ⲏ',
+  'ⲑ' => 'Ⲑ',
+  'ⲓ' => 'Ⲓ',
+  'ⲕ' => 'Ⲕ',
+  'ⲗ' => 'Ⲗ',
+  'ⲙ' => 'Ⲙ',
+  'ⲛ' => 'Ⲛ',
+  'ⲝ' => 'Ⲝ',
+  'ⲟ' => 'Ⲟ',
+  'ⲡ' => 'Ⲡ',
+  'ⲣ' => 'Ⲣ',
+  'ⲥ' => 'Ⲥ',
+  'ⲧ' => 'Ⲧ',
+  'ⲩ' => 'Ⲩ',
+  'ⲫ' => 'Ⲫ',
+  'ⲭ' => 'Ⲭ',
+  'ⲯ' => 'Ⲯ',
+  'ⲱ' => 'Ⲱ',
+  'ⲳ' => 'Ⲳ',
+  'ⲵ' => 'Ⲵ',
+  'ⲷ' => 'Ⲷ',
+  'ⲹ' => 'Ⲹ',
+  'ⲻ' => 'Ⲻ',
+  'ⲽ' => 'Ⲽ',
+  'ⲿ' => 'Ⲿ',
+  'ⳁ' => 'Ⳁ',
+  'ⳃ' => 'Ⳃ',
+  'ⳅ' => 'Ⳅ',
+  'ⳇ' => 'Ⳇ',
+  'ⳉ' => 'Ⳉ',
+  'ⳋ' => 'Ⳋ',
+  'ⳍ' => 'Ⳍ',
+  'ⳏ' => 'Ⳏ',
+  'ⳑ' => 'Ⳑ',
+  'ⳓ' => 'Ⳓ',
+  'ⳕ' => 'Ⳕ',
+  'ⳗ' => 'Ⳗ',
+  'ⳙ' => 'Ⳙ',
+  'ⳛ' => 'Ⳛ',
+  'ⳝ' => 'Ⳝ',
+  'ⳟ' => 'Ⳟ',
+  'ⳡ' => 'Ⳡ',
+  'ⳣ' => 'Ⳣ',
+  'ⳬ' => 'Ⳬ',
+  'ⳮ' => 'Ⳮ',
+  'ⳳ' => 'Ⳳ',
+  'ⴀ' => 'Ⴀ',
+  'ⴁ' => 'Ⴁ',
+  'ⴂ' => 'Ⴂ',
+  'ⴃ' => 'Ⴃ',
+  'ⴄ' => 'Ⴄ',
+  'ⴅ' => 'Ⴅ',
+  'ⴆ' => 'Ⴆ',
+  'ⴇ' => 'Ⴇ',
+  'ⴈ' => 'Ⴈ',
+  'ⴉ' => 'Ⴉ',
+  'ⴊ' => 'Ⴊ',
+  'ⴋ' => 'Ⴋ',
+  'ⴌ' => 'Ⴌ',
+  'ⴍ' => 'Ⴍ',
+  'ⴎ' => 'Ⴎ',
+  'ⴏ' => 'Ⴏ',
+  'ⴐ' => 'Ⴐ',
+  'ⴑ' => 'Ⴑ',
+  'ⴒ' => 'Ⴒ',
+  'ⴓ' => 'Ⴓ',
+  'ⴔ' => 'Ⴔ',
+  'ⴕ' => 'Ⴕ',
+  'ⴖ' => 'Ⴖ',
+  'ⴗ' => 'Ⴗ',
+  'ⴘ' => 'Ⴘ',
+  'ⴙ' => 'Ⴙ',
+  'ⴚ' => 'Ⴚ',
+  'ⴛ' => 'Ⴛ',
+  'ⴜ' => 'Ⴜ',
+  'ⴝ' => 'Ⴝ',
+  'ⴞ' => 'Ⴞ',
+  'ⴟ' => 'Ⴟ',
+  'ⴠ' => 'Ⴠ',
+  'ⴡ' => 'Ⴡ',
+  'ⴢ' => 'Ⴢ',
+  'ⴣ' => 'Ⴣ',
+  'ⴤ' => 'Ⴤ',
+  'ⴥ' => 'Ⴥ',
+  'ⴧ' => 'Ⴧ',
+  'ⴭ' => 'Ⴭ',
+  'ꙁ' => 'Ꙁ',
+  'ꙃ' => 'Ꙃ',
+  'ꙅ' => 'Ꙅ',
+  'ꙇ' => 'Ꙇ',
+  'ꙉ' => 'Ꙉ',
+  'ꙋ' => 'Ꙋ',
+  'ꙍ' => 'Ꙍ',
+  'ꙏ' => 'Ꙏ',
+  'ꙑ' => 'Ꙑ',
+  'ꙓ' => 'Ꙓ',
+  'ꙕ' => 'Ꙕ',
+  'ꙗ' => 'Ꙗ',
+  'ꙙ' => 'Ꙙ',
+  'ꙛ' => 'Ꙛ',
+  'ꙝ' => 'Ꙝ',
+  'ꙟ' => 'Ꙟ',
+  'ꙡ' => 'Ꙡ',
+  'ꙣ' => 'Ꙣ',
+  'ꙥ' => 'Ꙥ',
+  'ꙧ' => 'Ꙧ',
+  'ꙩ' => 'Ꙩ',
+  'ꙫ' => 'Ꙫ',
+  'ꙭ' => 'Ꙭ',
+  'ꚁ' => 'Ꚁ',
+  'ꚃ' => 'Ꚃ',
+  'ꚅ' => 'Ꚅ',
+  'ꚇ' => 'Ꚇ',
+  'ꚉ' => 'Ꚉ',
+  'ꚋ' => 'Ꚋ',
+  'ꚍ' => 'Ꚍ',
+  'ꚏ' => 'Ꚏ',
+  'ꚑ' => 'Ꚑ',
+  'ꚓ' => 'Ꚓ',
+  'ꚕ' => 'Ꚕ',
+  'ꚗ' => 'Ꚗ',
+  'ꚙ' => 'Ꚙ',
+  'ꚛ' => 'Ꚛ',
+  'ꜣ' => 'Ꜣ',
+  'ꜥ' => 'Ꜥ',
+  'ꜧ' => 'Ꜧ',
+  'ꜩ' => 'Ꜩ',
+  'ꜫ' => 'Ꜫ',
+  'ꜭ' => 'Ꜭ',
+  'ꜯ' => 'Ꜯ',
+  'ꜳ' => 'Ꜳ',
+  'ꜵ' => 'Ꜵ',
+  'ꜷ' => 'Ꜷ',
+  'ꜹ' => 'Ꜹ',
+  'ꜻ' => 'Ꜻ',
+  'ꜽ' => 'Ꜽ',
+  'ꜿ' => 'Ꜿ',
+  'ꝁ' => 'Ꝁ',
+  'ꝃ' => 'Ꝃ',
+  'ꝅ' => 'Ꝅ',
+  'ꝇ' => 'Ꝇ',
+  'ꝉ' => 'Ꝉ',
+  'ꝋ' => 'Ꝋ',
+  'ꝍ' => 'Ꝍ',
+  'ꝏ' => 'Ꝏ',
+  'ꝑ' => 'Ꝑ',
+  'ꝓ' => 'Ꝓ',
+  'ꝕ' => 'Ꝕ',
+  'ꝗ' => 'Ꝗ',
+  'ꝙ' => 'Ꝙ',
+  'ꝛ' => 'Ꝛ',
+  'ꝝ' => 'Ꝝ',
+  'ꝟ' => 'Ꝟ',
+  'ꝡ' => 'Ꝡ',
+  'ꝣ' => 'Ꝣ',
+  'ꝥ' => 'Ꝥ',
+  'ꝧ' => 'Ꝧ',
+  'ꝩ' => 'Ꝩ',
+  'ꝫ' => 'Ꝫ',
+  'ꝭ' => 'Ꝭ',
+  'ꝯ' => 'Ꝯ',
+  'ꝺ' => 'Ꝺ',
+  'ꝼ' => 'Ꝼ',
+  'ꝿ' => 'Ꝿ',
+  'ꞁ' => 'Ꞁ',
+  'ꞃ' => 'Ꞃ',
+  'ꞅ' => 'Ꞅ',
+  'ꞇ' => 'Ꞇ',
+  'ꞌ' => 'Ꞌ',
+  'ꞑ' => 'Ꞑ',
+  'ꞓ' => 'Ꞓ',
+  'ꞗ' => 'Ꞗ',
+  'ꞙ' => 'Ꞙ',
+  'ꞛ' => 'Ꞛ',
+  'ꞝ' => 'Ꞝ',
+  'ꞟ' => 'Ꞟ',
+  'ꞡ' => 'Ꞡ',
+  'ꞣ' => 'Ꞣ',
+  'ꞥ' => 'Ꞥ',
+  'ꞧ' => 'Ꞧ',
+  'ꞩ' => 'Ꞩ',
+  'ａ' => 'Ａ',
+  'ｂ' => 'Ｂ',
+  'ｃ' => 'Ｃ',
+  'ｄ' => 'Ｄ',
+  'ｅ' => 'Ｅ',
+  'ｆ' => 'Ｆ',
+  'ｇ' => 'Ｇ',
+  'ｈ' => 'Ｈ',
+  'ｉ' => 'Ｉ',
+  'ｊ' => 'Ｊ',
+  'ｋ' => 'Ｋ',
+  'ｌ' => 'Ｌ',
+  'ｍ' => 'Ｍ',
+  'ｎ' => 'Ｎ',
+  'ｏ' => 'Ｏ',
+  'ｐ' => 'Ｐ',
+  'ｑ' => 'Ｑ',
+  'ｒ' => 'Ｒ',
+  'ｓ' => 'Ｓ',
+  'ｔ' => 'Ｔ',
+  'ｕ' => 'Ｕ',
+  'ｖ' => 'Ｖ',
+  'ｗ' => 'Ｗ',
+  'ｘ' => 'Ｘ',
+  'ｙ' => 'Ｙ',
+  'ｚ' => 'Ｚ',
+  '𐐨' => '𐐀',
+  '𐐩' => '𐐁',
+  '𐐪' => '𐐂',
+  '𐐫' => '𐐃',
+  '𐐬' => '𐐄',
+  '𐐭' => '𐐅',
+  '𐐮' => '𐐆',
+  '𐐯' => '𐐇',
+  '𐐰' => '𐐈',
+  '𐐱' => '𐐉',
+  '𐐲' => '𐐊',
+  '𐐳' => '𐐋',
+  '𐐴' => '𐐌',
+  '𐐵' => '𐐍',
+  '𐐶' => '𐐎',
+  '𐐷' => '𐐏',
+  '𐐸' => '𐐐',
+  '𐐹' => '𐐑',
+  '𐐺' => '𐐒',
+  '𐐻' => '𐐓',
+  '𐐼' => '𐐔',
+  '𐐽' => '𐐕',
+  '𐐾' => '𐐖',
+  '𐐿' => '𐐗',
+  '𐑀' => '𐐘',
+  '𐑁' => '𐐙',
+  '𐑂' => '𐐚',
+  '𐑃' => '𐐛',
+  '𐑄' => '𐐜',
+  '𐑅' => '𐐝',
+  '𐑆' => '𐐞',
+  '𐑇' => '𐐟',
+  '𐑈' => '𐐠',
+  '𐑉' => '𐐡',
+  '𐑊' => '𐐢',
+  '𐑋' => '𐐣',
+  '𐑌' => '𐐤',
+  '𐑍' => '𐐥',
+  '𐑎' => '𐐦',
+  '𐑏' => '𐐧',
+  '𑣀' => '𑢠',
+  '𑣁' => '𑢡',
+  '𑣂' => '𑢢',
+  '𑣃' => '𑢣',
+  '𑣄' => '𑢤',
+  '𑣅' => '𑢥',
+  '𑣆' => '𑢦',
+  '𑣇' => '𑢧',
+  '𑣈' => '𑢨',
+  '𑣉' => '𑢩',
+  '𑣊' => '𑢪',
+  '𑣋' => '𑢫',
+  '𑣌' => '𑢬',
+  '𑣍' => '𑢭',
+  '𑣎' => '𑢮',
+  '𑣏' => '𑢯',
+  '𑣐' => '𑢰',
+  '𑣑' => '𑢱',
+  '𑣒' => '𑢲',
+  '𑣓' => '𑢳',
+  '𑣔' => '𑢴',
+  '𑣕' => '𑢵',
+  '𑣖' => '𑢶',
+  '𑣗' => '𑢷',
+  '𑣘' => '𑢸',
+  '𑣙' => '𑢹',
+  '𑣚' => '𑢺',
+  '𑣛' => '𑢻',
+  '𑣜' => '𑢼',
+  '𑣝' => '𑢽',
+  '𑣞' => '𑢾',
+  '𑣟' => '𑢿',
+);
+
+$result =& $data;
+unset($data);
+
+return $result;
--- a/vendor/symfony/polyfill-mbstring/composer.json
+++ b/vendor/symfony/polyfill-mbstring/composer.json
@@ -28,7 +28,7 @@
     "minimum-stability": "dev",
     "extra": {
         "branch-alias": {
-            "dev-master": "1.1-dev"
+            "dev-master": "1.2-dev"
         }
     }
 }
--- a/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
@@ -257,7 +257,10 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
         }
 
         // add a query string if needed
-        $extra = array_diff_key($parameters, $variables, $defaults);
+        $extra = array_udiff_assoc(array_diff_key($parameters, $variables), $defaults, function ($a, $b) {
+            return $a == $b ? 0 : 1;
+        });
+
         if ($extra && $query = http_build_query($extra, '', '&')) {
             $url .= '?'.$query;
         }
--- a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
@@ -112,7 +112,24 @@ class AnnotationFileLoader extends FileLoader
             }
 
             if (T_CLASS === $token[0]) {
-                $class = true;
+                // Skip usage of ::class constant
+                $isClassConstant = false;
+                for ($j = $i - 1; $j > 0; --$j) {
+                    if (!isset($tokens[$j][1])) {
+                        break;
+                    }
+
+                    if (T_DOUBLE_COLON === $tokens[$j][0]) {
+                        $isClassConstant = true;
+                        break;
+                    } elseif (!in_array($tokens[$j][0], array(T_WHITESPACE, T_DOC_COMMENT, T_COMMENT))) {
+                        break;
+                    }
+                }
+
+                if (!$isClassConstant) {
+                    $class = true;
+                }
             }
 
             if (T_NAMESPACE === $token[0]) {
--- a/vendor/symfony/yaml/Symfony/Component/Yaml/Dumper.php
+++ b/vendor/symfony/yaml/Symfony/Component/Yaml/Dumper.php
@@ -58,7 +58,7 @@ class Dumper
         if ($inline <= 0 || !is_array($input) || empty($input)) {
             $output .= $prefix.Inline::dump($input, $exceptionOnInvalidType, $objectSupport);
         } else {
-            $isAHash = array_keys($input) !== range(0, count($input) - 1);
+            $isAHash = Inline::isHash($input);
 
             foreach ($input as $key => $value) {
                 $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
--- a/vendor/symfony/yaml/Symfony/Component/Yaml/Inline.php
+++ b/vendor/symfony/yaml/Symfony/Component/Yaml/Inline.php
@@ -146,6 +146,28 @@ class Inline
     }
 
     /**
+     * Check if given array is hash or just normal indexed array.
+     *
+     * @internal
+     *
+     * @param array $value The PHP array to check
+     *
+     * @return bool true if value is hash array, false otherwise
+     */
+    public static function isHash(array $value)
+    {
+        $expectedKey = 0;
+
+        foreach ($value as $key => $val) {
+            if ($key !== $expectedKey++) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Dumps a PHP array to a YAML string.
      *
      * @param array $value                  The PHP array to dump
@@ -157,11 +179,7 @@ class Inline
     private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
     {
         // array
-        $keys = array_keys($value);
-        $keysCount = count($keys);
-        if ((1 === $keysCount && '0' == $keys[0])
-            || ($keysCount > 1 && array_reduce($keys, function ($v, $w) { return (int) $v + $w; }, 0) === $keysCount * ($keysCount - 1) / 2)
-        ) {
+        if ($value && !self::isHash($value)) {
             $output = array();
             foreach ($value as $val) {
                 $output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
@@ -170,7 +188,7 @@ class Inline
             return sprintf('[%s]', implode(', ', $output));
         }
 
-        // mapping
+        // hash
         $output = array();
         foreach ($value as $key => $val) {
             $output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
--- a/vendor/symfony/yaml/Symfony/Component/Yaml/Parser.php
+++ b/vendor/symfony/yaml/Symfony/Component/Yaml/Parser.php
@@ -25,6 +25,7 @@ class Parser
     const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;
 
     private $offset = 0;
+    private $totalNumberOfLines;
     private $lines = array();
     private $currentLineNb = -1;
     private $currentLine = '';
@@ -33,11 +34,13 @@ class Parser
     /**
      * Constructor.
      *
-     * @param int $offset The offset of YAML document (used for line numbers in error messages)
+     * @param int      $offset             The offset of YAML document (used for line numbers in error messages)
+     * @param int|null $totalNumberOfLines The overall number of lines being parsed
      */
-    public function __construct($offset = 0)
+    public function __construct($offset = 0, $totalNumberOfLines = null)
     {
         $this->offset = $offset;
+        $this->totalNumberOfLines = $totalNumberOfLines;
     }
 
     /**
@@ -61,6 +64,10 @@ class Parser
         $value = $this->cleanup($value);
         $this->lines = explode("\n", $value);
 
+        if (null === $this->totalNumberOfLines) {
+            $this->totalNumberOfLines = count($this->lines);
+        }
+
         if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
             $mbEncoding = mb_internal_encoding();
             mb_internal_encoding('UTF-8');
@@ -81,7 +88,7 @@ class Parser
             $isRef = $isInPlace = $isProcessed = false;
             if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
                 if ($context && 'mapping' == $context) {
-                    throw new ParseException('You cannot define a sequence item when in a mapping');
+                    throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine);
                 }
                 $context = 'sequence';
 
@@ -93,7 +100,7 @@ class Parser
                 // array
                 if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
                     $c = $this->getRealCurrentLineNb() + 1;
-                    $parser = new self($c);
+                    $parser = new self($c, $this->totalNumberOfLines);
                     $parser->refs = &$this->refs;
                     $data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport);
                 } else {
@@ -102,7 +109,7 @@ class Parser
                     ) {
                         // this is a compact notation element, add to next block and parse
                         $c = $this->getRealCurrentLineNb();
-                        $parser = new self($c);
+                        $parser = new self($c, $this->totalNumberOfLines);
                         $parser->refs = &$this->refs;
 
                         $block = $values['value'];
@@ -120,7 +127,7 @@ class Parser
                 }
             } elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) {
                 if ($context && 'sequence' == $context) {
-                    throw new ParseException('You cannot define a mapping item when in a sequence');
+                    throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine);
                 }
                 $context = 'mapping';
 
@@ -153,7 +160,7 @@ class Parser
                             $value = $this->getNextEmbedBlock();
                         }
                         $c = $this->getRealCurrentLineNb() + 1;
-                        $parser = new self($c);
+                        $parser = new self($c, $this->totalNumberOfLines);
                         $parser->refs = &$this->refs;
                         $parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport);
 
@@ -190,7 +197,7 @@ class Parser
                         $data[$key] = null;
                     } else {
                         $c = $this->getRealCurrentLineNb() + 1;
-                        $parser = new self($c);
+                        $parser = new self($c, $this->totalNumberOfLines);
                         $parser->refs = &$this->refs;
                         $data[$key] = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport);
                     }
@@ -207,7 +214,7 @@ class Parser
             } else {
                 // multiple documents are not supported
                 if ('---' === $this->currentLine) {
-                    throw new ParseException('Multiple documents are not supported.');
+                    throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine);
                 }
 
                 // 1-liner optionally followed by newline(s)
@@ -442,7 +449,7 @@ class Parser
             }
 
             if (!array_key_exists($value, $this->refs)) {
-                throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
+                throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine);
             }
 
             return $this->refs[$value];
@@ -528,6 +535,8 @@ class Parser
         if ($notEOF) {
             $blockLines[] = '';
             $this->moveToPreviousLine();
+        } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) {
+            $blockLines[] = '';
         }
 
         // folded style
@@ -634,6 +643,11 @@ class Parser
         return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#';
     }
 
+    private function isCurrentLineLastLineInDocument()
+    {
+        return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
+    }
+
     /**
      * Cleanups a YAML string to be parsed.
      *
@@ -711,7 +725,7 @@ class Parser
      */
     private function isStringUnIndentedCollectionItem()
     {
-        return 0 === strpos($this->currentLine, '- ');
+        return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- ');
     }
 
     /**
--- a/vendor/twig/twig/lib/Twig/Environment.php
+++ b/vendor/twig/twig/lib/Twig/Environment.php
@@ -16,7 +16,7 @@
  */
 class Twig_Environment
 {
-    const VERSION = '1.24.0';
+    const VERSION = '1.24.1';
 
     protected $charset;
     protected $loader;
@@ -439,6 +439,10 @@ class Twig_Environment
             $this->setLoader($current);
 
             throw $e;
+        } catch (Throwable $e) {
+            $this->setLoader($current);
+
+            throw $e;
         }
         $this->setLoader($current);
 
@@ -855,6 +859,8 @@ class Twig_Environment
      * Gets the registered Token Parsers.
      *
      * @return Twig_TokenParserBrokerInterface A broker containing token parsers
+     *
+     * @internal
      */
     public function getTokenParsers()
     {
@@ -871,6 +877,8 @@ class Twig_Environment
      * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
      *
      * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
+     *
+     * @internal
      */
     public function getTags()
     {
@@ -902,6 +910,8 @@ class Twig_Environment
      * Gets the registered Node Visitors.
      *
      * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
+     *
+     * @internal
      */
     public function getNodeVisitors()
     {
@@ -947,6 +957,8 @@ class Twig_Environment
      * @param string $name The filter name
      *
      * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
+     *
+     * @internal
      */
     public function getFilter($name)
     {
@@ -993,6 +1005,8 @@ class Twig_Environment
      * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
      *
      * @see registerUndefinedFilterCallback
+     *
+     * @internal
      */
     public function getFilters()
     {
@@ -1033,6 +1047,8 @@ class Twig_Environment
      * Gets the registered Tests.
      *
      * @return Twig_TestInterface[] An array of Twig_TestInterface instances
+     *
+     * @internal
      */
     public function getTests()
     {
@@ -1049,6 +1065,8 @@ class Twig_Environment
      * @param string $name The test name
      *
      * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
+     *
+     * @internal
      */
     public function getTest($name)
     {
@@ -1098,6 +1116,8 @@ class Twig_Environment
      * @param string $name function name
      *
      * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
+     *
+     * @internal
      */
     public function getFunction($name)
     {
@@ -1144,6 +1164,8 @@ class Twig_Environment
      * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
      *
      * @see registerUndefinedFunctionCallback
+     *
+     * @internal
      */
     public function getFunctions()
     {
@@ -1189,6 +1211,8 @@ class Twig_Environment
      * Gets the registered Globals.
      *
      * @return array An array of globals
+     *
+     * @internal
      */
     public function getGlobals()
     {
@@ -1227,6 +1251,8 @@ class Twig_Environment
      * Gets the registered unary Operators.
      *
      * @return array An array of unary operators
+     *
+     * @internal
      */
     public function getUnaryOperators()
     {
@@ -1241,6 +1267,8 @@ class Twig_Environment
      * Gets the registered binary Operators.
      *
      * @return array An array of binary operators
+     *
+     * @internal
      */
     public function getBinaryOperators()
     {
@@ -1261,6 +1289,9 @@ class Twig_Environment
         return Twig_Error_Syntax::computeAlternatives($name, $items);
     }
 
+    /**
+     * @internal
+     */
     protected function initGlobals()
     {
         $globals = array();
@@ -1286,6 +1317,9 @@ class Twig_Environment
         return call_user_func_array('array_merge', $globals);
     }
 
+    /**
+     * @internal
+     */
     protected function initExtensions()
     {
         if ($this->extensionInitialized) {
@@ -1307,6 +1341,9 @@ class Twig_Environment
         $this->initExtension($this->staging);
     }
 
+    /**
+     * @internal
+     */
     protected function initExtension(Twig_ExtensionInterface $extension)
     {
         // filters
--- a/vendor/twig/twig/lib/Twig/ExpressionParser.php
+++ b/vendor/twig/twig/lib/Twig/ExpressionParser.php
@@ -539,10 +539,11 @@ class Twig_ExpressionParser
         $targets = array();
         while (true) {
             $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
-            if (in_array($token->getValue(), array('true', 'false', 'none'))) {
-                throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $token->getValue()), $token->getLine(), $this->parser->getFilename());
+            $value = $token->getValue();
+            if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
+                throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $value), $token->getLine(), $this->parser->getFilename());
             }
-            $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
+            $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
 
             if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
                 break;
--- a/vendor/twig/twig/lib/Twig/Node/Macro.php
+++ b/vendor/twig/twig/lib/Twig/Node/Macro.php
@@ -109,6 +109,11 @@ class Twig_Node_Macro extends Twig_Node
             ->write("ob_end_clean();\n\n")
             ->write("throw \$e;\n")
             ->outdent()
+            ->write("} catch (Throwable \$e) {\n")
+            ->indent()
+            ->write("ob_end_clean();\n\n")
+            ->write("throw \$e;\n")
+            ->outdent()
             ->write("}\n\n")
             ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
             ->outdent()
--- a/vendor/twig/twig/lib/Twig/Template.php
+++ b/vendor/twig/twig/lib/Twig/Template.php
@@ -370,6 +370,12 @@ abstract class Twig_Template implements Twig_TemplateInterface
             }
 
             throw $e;
+        } catch (Throwable $e) {
+            while (ob_get_level() > $level) {
+                ob_end_clean();
+            }
+
+            throw $e;
         }
 
         return ob_get_clean();
@@ -581,7 +587,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
                 return;
             }
 
-            throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
+            throw new Twig_Error_Runtime(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s"', $item, get_class($object)), -1, $this->getTemplateName());
         }
 
         if ($isDefinedTest) {
--- a/viewforum.php
+++ b/viewforum.php
@@ -492,6 +492,28 @@ if ($forum_data['forum_type'] == FORUM_POST)
 
 		'ORDER_BY'	=> 't.topic_time DESC',
 	);
+
+	/**
+	* Event to modify the SQL query before the announcement topic ids data is retrieved
+	*
+	* @event core.viewforum_get_announcement_topic_ids_data
+	* @var	array	forum_data			Data about the forum
+	* @var	array	g_forum_ary			Global announcement forums array
+	* @var	array	sql_anounce_array	SQL announcement array
+	* @var	array	sql_ary				SQL query array to get the announcement topic ids data
+	* @var	int		forum_id			The forum ID
+	*
+	* @since 3.1.10-RC1
+	*/
+	$vars = array(
+		'forum_data',
+		'g_forum_ary',
+		'sql_anounce_array',
+		'sql_ary',
+		'forum_id',
+	);
+	extract($phpbb_dispatcher->trigger_event('core.viewforum_get_announcement_topic_ids_data', compact($vars)));
+
 	$sql = $db->sql_build_query('SELECT', $sql_ary);
 	$result = $db->sql_query($sql);
 
@@ -917,11 +939,15 @@ if (sizeof($topic_list))
 		* Modify the topic data before it is assigned to the template
 		*
 		* @event core.viewforum_modify_topicrow
-		* @var	array	row			Array with topic data
-		* @var	array	topic_row	Template array with topic data
+		* @var	array	row					Array with topic data
+		* @var	array	topic_row			Template array with topic data
+		* @var	bool	s_type_switch		Flag indicating if the topic type is [global] announcement
+		* @var	bool	s_type_switch_test	Flag indicating if the test topic type is [global] announcement
 		* @since 3.1.0-a1
+		*
+		* @changed 3.1.10-RC1 Added s_type_switch, s_type_switch_test
 		*/
-		$vars = array('row', 'topic_row');
+		$vars = array('row', 'topic_row', 's_type_switch', 's_type_switch_test');
 		extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_topicrow', compact($vars)));
 
 		$template->assign_block_vars('topicrow', $topic_row);
