diff --git a/.gitattributes b/.gitattributes
index 6beb1fb7a7b4a9e58415a5d82f6ab073654e51a3..40fb1f5520b7b8e79ab99bbc77ef8333f93ef4b1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -9,6 +9,7 @@
 .gitignore export-ignore
 .editorconfig export-ignore
 .travis.yml export-ignore
+appveyor.yml export-ignore
 composer.json export-ignore
 composer.lock export-ignore
 _test export-ignore
diff --git a/.gitignore b/.gitignore
index 758d216359984bea13b41ab6ea5232fc1a95da72..a2e2107b1576992c41348d14f18f80844c011a8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,3 +81,12 @@ vendor/paragonie/random_compat/build-phar.sh
 vendor/paragonie/random_compat/dist/*
 vendor/paragonie/random_compat/other/*
 vendor/simplepie/simplepie/db.sql
+vendor/marcusschwarz/lesserphp/package.sh
+vendor/marcusschwarz/lesserphp/lessify*
+vendor/marcusschwarz/lesserphp/Makefile
+vendor/marcusschwarz/lesserphp/plessc
+vendor/splitbrain/php-cli/examples/*
+vendor/splitbrain/php-cli/screenshot*
+vendor/splitbrain/php-cli/generate-api.sh
+vendor/splitbrain/php-cli/apigen.neon
+
diff --git a/.htaccess.dist b/.htaccess.dist
index 1d2bd418e61468fc3bf1c07186f5af5379d6ea87..d8845e781bb58b004d38ac174088a87fc267a14e 100644
--- a/.htaccess.dist
+++ b/.htaccess.dist
@@ -1,5 +1,3 @@
-## Enable this to restrict editing to logged in users only
-
 ## You should disable Indexes and MultiViews either here or in the
 ## global config. Symlinks maybe needed for URL rewriting.
 #Options -Indexes -MultiViews +FollowSymLinks
diff --git a/.travis.yml b/.travis.yml
index 32b8bb49ad539373684ec70a5b8331f422be2093..44affc5eee4eb6489913620785991b0ea141438c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ language: php
 sudo: false
 php:
   - "nightly"
+  - "7.2"
   - "7.1"
   - "7.0"
   - "5.6"
diff --git a/README b/README
index 4254de082f7d2841a0f099200136f5e482afe627..3e7cb62ad274d67ef4ca369ffb9e897c90f08904 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ at http://www.dokuwiki.org/
 For Installation Instructions see
 http://www.dokuwiki.org/install
 
-DokuWiki - 2004-2016 (c) Andreas Gohr <andi@splitbrain.org>
+DokuWiki - 2004-2018 (c) Andreas Gohr <andi@splitbrain.org>
                          and the DokuWiki Community
 See COPYING and file headers for license info
 
diff --git a/_test/core/DokuWikiTest.php b/_test/core/DokuWikiTest.php
index 2e4caefdbba79bd516197a7d560bf531813b4229..dbaf29eda6e466e7bae6e785e0496294e6f92893 100644
--- a/_test/core/DokuWikiTest.php
+++ b/_test/core/DokuWikiTest.php
@@ -1,12 +1,12 @@
 <?php
-
-
 if(!class_exists('PHPUnit_Framework_TestCase')) {
     /**
      * phpunit 5/6 compatibility
      */
     class PHPUnit_Framework_TestCase extends PHPUnit\Framework\TestCase {
         /**
+         * setExpectedException is deprecated in PHPUnit 6
+         *
          * @param string $class
          * @param null|string $message
          */
@@ -19,10 +19,10 @@ if(!class_exists('PHPUnit_Framework_TestCase')) {
     }
 }
 
-
-
 /**
  * Helper class to provide basic functionality for tests
+ *
+ * @uses PHPUnit_Framework_TestCase and thus PHPUnit 5.7+ is required
  */
 abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
 
@@ -150,35 +150,6 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
         $INPUT = new Input();
     }
 
-    /**
-     * Compatibility for older PHPUnit versions
-     *
-     * @param string $originalClassName
-     * @return PHPUnit_Framework_MockObject_MockObject
-     */
-    protected function createMock($originalClassName) {
-        if(is_callable(array('parent', 'createMock'))) {
-            return parent::createMock($originalClassName);
-        } else {
-            return $this->getMock($originalClassName);
-        }
-    }
-
-    /**
-     * Compatibility for older PHPUnit versions
-     *
-     * @param string $originalClassName
-     * @param array $methods
-     * @return PHPUnit_Framework_MockObject_MockObject
-     */
-    protected function createPartialMock($originalClassName, array $methods) {
-        if(is_callable(array('parent', 'createPartialMock'))) {
-            return parent::createPartialMock($originalClassName, $methods);
-        } else {
-            return $this->getMock($originalClassName, $methods);
-        }
-    }
-
     /**
      * Waits until a new second has passed
      *
@@ -200,4 +171,24 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
         $last = $now;
         return $now;
     }
+
+    /**
+     * Allow for testing inaccessible methods (private or protected)
+     *
+     * This makes it easier to test protected methods without needing to create intermediate
+     * classes inheriting and changing the access.
+     *
+     * @link https://stackoverflow.com/a/8702347/172068
+     * @param object $obj Object in which to call the method
+     * @param string $func The method to call
+     * @param array $args The arguments to call the method with
+     * @return mixed
+     * @throws ReflectionException when the given obj/func does not exist
+     */
+    protected static function callInaccessibleMethod($obj, $func, array $args) {
+        $class = new \ReflectionClass($obj);
+        $method = $class->getMethod($func);
+        $method->setAccessible(true);
+        return $method->invokeArgs($obj, $args);
+    }
 }
diff --git a/_test/core/TestRequest.php b/_test/core/TestRequest.php
index dad2060e5cafb7f05e4db672774462a1030fd862..fcc80328c1006910eab0ad9124b180f070be1eba 100644
--- a/_test/core/TestRequest.php
+++ b/_test/core/TestRequest.php
@@ -4,46 +4,122 @@
  * runtime inspection.
  */
 
-// output buffering
-$output_buffer = '';
-
-function ob_start_callback($buffer) {
-    global $output_buffer;
-    $output_buffer .= $buffer;
-}
-
-
 /**
  * Helper class to execute a fake request
  */
 class TestRequest {
 
-    private $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php');
-    private $script;
+    protected $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php');
+    protected $script;
+
+    protected $server = array();
+    protected $session = array();
+    protected $get = array();
+    protected $post = array();
+    protected $data = array();
+
+    /** @var string stores the output buffer, even when it's flushed */
+    protected $output_buffer = '';
+
+    /** @var null|TestRequest the currently running request */
+    static protected $running = null;
+
+    /**
+     * Get a $_SERVER var
+     *
+     * @param string $key
+     * @return mixed
+     */
+    public function getServer($key) {
+        return $this->server[$key];
+    }
+
+    /**
+     * Get a $_SESSION var
+     *
+     * @param string $key
+     * @return mixed
+     */
+    public function getSession($key) {
+        return $this->session[$key];
+    }
+
+    /**
+     * Get a $_GET var
+     *
+     * @param string $key
+     * @return mixed
+     */
+    public function getGet($key) {
+        return $this->get[$key];
+    }
+
+    /**
+     * Get a $_POST var
+     *
+     * @param string $key
+     * @return mixed
+     */
+    public function getPost($key) {
+        return $this->post[$key];
+    }
+
+    /**
+     * Get the script that will execute the request
+     *
+     * @return string
+     */
+    public function getScript() {
+        return $this->script;
+    }
+
+    /**
+     * Set a $_SERVER var
+     *
+     * @param string $key
+     * @param mixed $value
+     */
+    public function setServer($key, $value) {
+        $this->server[$key] = $value;
+    }
 
-    private $server = array();
-    private $session = array();
-    private $get = array();
-    private $post = array();
+    /**
+     * Set a $_SESSION var
+     *
+     * @param string $key
+     * @param mixed $value
+     */
+    public function setSession($key, $value) {
+        $this->session[$key] = $value;
+    }
 
-    public function getServer($key) { return $this->server[$key]; }
-    public function getSession($key) { return $this->session[$key]; }
-    public function getGet($key) { return $this->get[$key]; }
-    public function getPost($key) { return $this->post[$key]; }
-    public function getScript() { return $this->script; }
+    /**
+     * Set a $_GET var
+     *
+     * @param string $key
+     * @param mixed $value
+     */
+    public function setGet($key, $value) {
+        $this->get[$key] = $value;
+    }
 
-    public function setServer($key, $value) { $this->server[$key] = $value; }
-    public function setSession($key, $value) { $this->session[$key] = $value; }
-    public function setGet($key, $value) { $this->get[$key] = $value; }
-    public function setPost($key, $value) { $this->post[$key] = $value; }
+    /**
+     * Set a $_POST var
+     *
+     * @param string $key
+     * @param mixed $value
+     */
+    public function setPost($key, $value) {
+        $this->post[$key] = $value;
+    }
 
     /**
      * Executes the request
      *
-     * @param string $url  end URL to simulate, needs to start with /doku.php currently
+     * @param string $uri end URL to simulate, needs to be one of the testable scripts
      * @return TestResponse the resulting output of the request
      */
-    public function execute($uri='/doku.php') {
+    public function execute($uri = '/doku.php') {
         global $INPUT;
 
         // save old environment
@@ -53,12 +129,12 @@ class TestRequest {
         $post = $_POST;
         $request = $_REQUEST;
         $input = $INPUT;
-        
+
         // prepare the right URI
         $this->setUri($uri);
 
         // import all defined globals into the function scope
-        foreach(array_keys($GLOBALS) as $glb){
+        foreach(array_keys($GLOBALS) as $glb) {
             global $$glb;
         }
 
@@ -71,20 +147,23 @@ class TestRequest {
         $_REQUEST = array_merge($_GET, $_POST);
 
         // reset output buffer
-        global $output_buffer;
-        $output_buffer = '';
+        $this->output_buffer = '';
 
         // now execute dokuwiki and grep the output
+        self::$running = $this;
         header_remove();
-        ob_start('ob_start_callback');
+        ob_start(array($this, 'ob_start_callback'));
         $INPUT = new Input();
-        include(DOKU_INC.$this->script);
+        include(DOKU_INC . $this->script);
         ob_end_flush();
+        self::$running = null;
 
         // create the response object
         $response = new TestResponse(
-            $output_buffer,
-            (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list())   // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli
+            $this->output_buffer,
+            // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli
+            (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()),
+            $this->data
         );
 
         // reset environment
@@ -107,28 +186,28 @@ class TestRequest {
      * It initializes the $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING']
      * with all set GET variables.
      *
-     * @param string $url  end URL to simulate, needs to start with /doku.php currently
-     * @todo make this work with other end points
+     * @param string $uri end URL to simulate
+     * @throws Exception when an invalid script is passed
      */
-    protected function setUri($uri){
-        if(!preg_match('#^('.join('|',$this->valid_scripts).')#',$uri)){
-            throw new Exception("$uri \n--- only ".join(', ',$this->valid_scripts)." are supported currently");
+    protected function setUri($uri) {
+        if(!preg_match('#^(' . join('|', $this->valid_scripts) . ')#', $uri)) {
+            throw new Exception("$uri \n--- only " . join(', ', $this->valid_scripts) . " are supported currently");
         }
 
         $params = array();
-        list($uri, $query) = explode('?',$uri,2);
+        list($uri, $query) = explode('?', $uri, 2);
         if($query) parse_str($query, $params);
 
-        $this->script = substr($uri,1);
-        $this->get  = array_merge($params, $this->get);
-        if(count($this->get)){
-            $query = '?'.http_build_query($this->get, '', '&');
+        $this->script = substr($uri, 1);
+        $this->get = array_merge($params, $this->get);
+        if(count($this->get)) {
+            $query = '?' . http_build_query($this->get, '', '&');
             $query = str_replace(
                 array('%3A', '%5B', '%5D'),
                 array(':', '[', ']'),
                 $query
             );
-            $uri = $uri.$query;
+            $uri = $uri . $query;
         }
 
         $this->setServer('QUERY_STRING', $query);
@@ -138,11 +217,11 @@ class TestRequest {
     /**
      * Simulate a POST request with the given variables
      *
-     * @param array $post  all the POST parameters to use
-     * @param string $url  end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently
-     * @param return TestResponse
+     * @param array $post all the POST parameters to use
+     * @param string $uri end URL to simulate
+     * @return TestResponse
      */
-    public function post($post=array(), $uri='/doku.php') {
+    public function post($post = array(), $uri = '/doku.php') {
         $this->post = array_merge($this->post, $post);
         $this->setServer('REQUEST_METHOD', 'POST');
         return $this->execute($uri);
@@ -151,15 +230,51 @@ class TestRequest {
     /**
      * Simulate a GET request with the given variables
      *
-     * @param array $GET   all the GET parameters to use
-     * @param string $url  end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently
-     * @param return TestResponse
+     * @param array $get all the GET parameters to use
+     * @param string $uri end URL to simulate
+     * @return TestResponse
      */
-    public function get($get=array(), $uri='/doku.php') {
-        $this->get  = array_merge($this->get, $get);
+    public function get($get = array(), $uri = '/doku.php') {
+        $this->get = array_merge($this->get, $get);
         $this->setServer('REQUEST_METHOD', 'GET');
         return $this->execute($uri);
     }
 
+    /**
+     * Callback for ob_start
+     *
+     * This continues to fill our own buffer, even when some part
+     * of the code askes for flushing the buffers
+     *
+     * @param string $buffer
+     */
+    public function ob_start_callback($buffer) {
+        $this->output_buffer .= $buffer;
+    }
+
+    /**
+     * Access the TestRequest from the executed code
+     *
+     * This allows certain functions to access the TestRequest that is accessing them
+     * to add additional info.
+     *
+     * @return null|TestRequest the currently executed request if any
+     */
+    public static function getRunning() {
+        return self::$running;
+    }
 
+    /**
+     * Store data to be read in the response later
+     *
+     * When called multiple times with the same key, the data is appended to this
+     * key's array
+     *
+     * @param string $key the identifier for this information
+     * @param mixed $value arbitrary data to store
+     */
+    public function addData($key, $value) {
+        if(!isset($this->data[$key])) $this->data[$key] = array();
+        $this->data[$key][] = $value;
+    }
 }
diff --git a/_test/core/TestResponse.php b/_test/core/TestResponse.php
index 7cc50ee4fcea61f05be97de1235d2b34e0ef68ae..55225a54ee6b557fcbb163b9f7fa05b3fb9bbe9a 100644
--- a/_test/core/TestResponse.php
+++ b/_test/core/TestResponse.php
@@ -1,33 +1,37 @@
 <?php
+
 /**
  * holds a copy of all produced outputs of a TestRequest
  */
 class TestResponse {
-    /**
-     * @var string
-     */
-    private $content;
+    /** @var string */
+    protected $content;
 
-    /**
-     * @var array
-     */
-    private $headers;
+    /** @var array */
+    protected $headers;
 
-    /**
-     * @var phpQueryObject
-     */
-    private $pq = null;
+    /** @var phpQueryObject */
+    protected $pq = null;
+
+    /** @var array */
+    protected $data = array();
 
     /**
-     * @param $content string
-     * @param $headers array
+     * Constructor
+     *
+     * @param $content string the response body
+     * @param $headers array the headers sent in the response
+     * @param array $data any optional data passed back to the test system
      */
-    function __construct($content, $headers) {
+    function __construct($content, $headers, $data = array()) {
         $this->content = $content;
         $this->headers = $headers;
+        $this->data = $data;
     }
 
     /**
+     * Returns the response body
+     *
      * @return string
      */
     public function getContent() {
@@ -35,6 +39,8 @@ class TestResponse {
     }
 
     /**
+     * Returns the headers set in the response
+     *
      * @return array
      */
     public function getHeaders() {
@@ -42,13 +48,15 @@ class TestResponse {
     }
 
     /**
+     * Return a single header
+     *
      * @param  $name   string, the name of the header without the ':', e.g. 'Content-Type', 'Pragma'
      * @return mixed   if exactly one header, the header (string); otherwise an array of headers, empty when no headers
      */
     public function getHeader($name) {
         $result = array();
-        foreach ($this->headers as $header) {
-            if (substr($header,0,strlen($name)+1) == $name.':') {
+        foreach($this->headers as $header) {
+            if(substr($header, 0, strlen($name) + 1) == $name . ':') {
                 $result[] = $header;
             }
         }
@@ -57,26 +65,28 @@ class TestResponse {
     }
 
     /**
-     * @return  int  http status code
+     * Access the http status code
      *
      * in the test environment, only status codes explicitly set by dokuwiki are likely to be returned
      * this means succcessful status codes (e.g. 200 OK) will not be present, but error codes will be
+     *
+     * @return  int  http status code
      */
     public function getStatusCode() {
         $headers = $this->getHeader('Status');
         $code = null;
 
-        if ($headers) {
+        if($headers) {
             // if there is more than one status header, use the last one
             $status = is_array($headers) ? array_pop($headers) : $headers;
             $matches = array();
-            preg_match('/^Status: ?(\d+)/',$status,$matches);
-            if ($matches){
+            preg_match('/^Status: ?(\d+)/', $status, $matches);
+            if($matches) {
                 $code = $matches[1];
             }
-         }
+        }
 
-         return $code;
+        return $code;
     }
 
     /**
@@ -86,8 +96,19 @@ class TestResponse {
      * @param $selector string
      * @return phpQueryObject
      */
-    public function queryHTML($selector){
+    public function queryHTML($selector) {
         if(is_null($this->pq)) $this->pq = phpQuery::newDocument($this->content);
         return $this->pq->find($selector);
     }
+
+    /**
+     * Returns all collected data for the given key
+     *
+     * @param string $key
+     * @return array
+     */
+    public function getData($key) {
+        if(!isset($this->data[$key])) return array();
+        return $this->data[$key];
+    }
 }
diff --git a/_test/core/TestUtils.php b/_test/core/TestUtils.php
index 2750a3edf1972690913e31f75eb23ae6a802ffc7..e855cb00798bbded6a94b1cf123979d3b3a6c38b 100644
--- a/_test/core/TestUtils.php
+++ b/_test/core/TestUtils.php
@@ -5,6 +5,15 @@
  */
 class TestUtils {
 
+    /**
+     * converts path to unix-like on windows OS
+     * @param string $path UNIX-like path to be converted
+     * @return string
+     */
+    public static function w2u($path) {
+        return isWindows() ? str_replace('\\', '/', $path) : $path;
+    }
+
     /**
      * helper for recursive copy()
      *
diff --git a/_test/data/pages/int/editandsavetest.txt b/_test/data/pages/int/editandsavetest.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f1e0655df1f26749d205ea3cec45f3c265c535ed
--- /dev/null
+++ b/_test/data/pages/int/editandsavetest.txt
@@ -0,0 +1,16 @@
+This is a test page for testing the redirect happening on the ''edit and save'' workflow.
+This page is required for the tests in **_tests/test/test/edit_and_save.test.php**. Do not edit this file.
+
+====== Headline1 ======
+Headline 1 content.
+
+====== Headline2 ======
+Headline 2a content.
+
+====== Headline2 ======
+Headline 2b content.
+
+====== Headline3 ======
+Headline 3 content.
+
+It is essential for the tests that there are two headlines with the title **Headline2**!
diff --git a/_test/tests/inc/Action/general.test.php b/_test/tests/inc/Action/general.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..9aacfbf96bb15416ca4186c6298134fd7bc380c7
--- /dev/null
+++ b/_test/tests/inc/Action/general.test.php
@@ -0,0 +1,182 @@
+<?php
+
+use dokuwiki\Action\AbstractAclAction;
+use dokuwiki\Action\AbstractUserAction;
+use dokuwiki\Action\Exception\ActionAclRequiredException;
+use dokuwiki\Action\Exception\ActionDisabledException;
+use dokuwiki\Action\Exception\ActionUserRequiredException;
+
+class action_general extends DokuWikiTest {
+
+    public function dataProvider() {
+        return array(
+            array('Login', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Logout', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Search', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Recent', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Profile', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('ProfileDelete', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Index', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Sitemap', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Denied', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Register', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Resendpwd', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Backlink', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+
+            array('Revert', AUTH_ADMIN, array('exists' => true, 'ismanager' => false)),
+            array('Revert', AUTH_EDIT, array('exists' => true, 'ismanager' => true)),
+
+            array('Admin', AUTH_ADMIN, array('exists' => true, 'ismanager' => false)),
+            array('Admin', AUTH_READ, array('exists' => true, 'ismanager' => true)), // let in, check later again
+
+            array('Check', AUTH_READ, array('exists' => true, 'ismanager' => false)), // sensible?
+            array('Diff', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Show', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Subscribe', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Locked', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Source', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Export', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Media', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Revisions', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+
+            array('Draftdel', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
+
+            // aliases
+            array('Cancel', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+            array('Recover', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
+
+            // EDITING existing page
+            array('Save', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
+            array('Conflict', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
+            array('Draft', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
+            //the edit function will check again and do a source show
+            //when no AUTH_EDIT available:
+            array('Edit', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+            array('Preview', AUTH_READ, array('exists' => true, 'ismanager' => false)),
+
+            // EDITING new page
+            array('Save', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
+            array('Conflict', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
+            array('Draft', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
+            array('Edit', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
+            array('Preview', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
+        );
+    }
+
+    /**
+     * @dataProvider dataProvider
+     * @param $name
+     * @param $expected
+     * @param $info
+     */
+    public function testMinimumPermissions($name, $expected, $info) {
+        global $INFO;
+        $INFO = $info;
+
+        $classname = 'dokuwiki\\Action\\' . $name;
+        /** @var \dokuwiki\Action\AbstractAction $class */
+        $class = new $classname();
+
+        $this->assertSame($expected, $class->minimumPermission());
+    }
+
+    /**
+     * All actions should handle the disableactions setting
+     *
+     * @dataProvider dataProvider
+     * @param $name
+     */
+    public function testBaseClassActionOkPermission($name) {
+        $this->assertTrue(true); // mark as not risky
+        if($name == 'Show') return; // disabling show does not work
+
+        $classname = 'dokuwiki\\Action\\' . $name;
+        /** @var \dokuwiki\Action\AbstractAction $class */
+        $class = new $classname();
+
+        global $conf;
+        $conf['useacl'] = 1;
+        $conf['subscribers'] = 1;
+        $conf['disableactions'] = '';
+        $_SERVER['REMOTE_USER'] = 'someone';
+
+        try {
+            \dokuwiki\ActionRouter::getInstance(true)->checkAction($class);
+        } catch(\Exception $e) {
+            $this->assertNotSame(ActionDisabledException::class, get_class($e));
+        }
+
+        $conf['disableactions'] = $class->getActionName();
+
+        try {
+            \dokuwiki\ActionRouter::getInstance(true)->checkAction($class);
+        } catch(\Exception $e) {
+            $this->assertSame(ActionDisabledException::class, get_class($e), $e);
+        }
+    }
+
+    /**
+     * Actions inheriting from AbstractAclAction should have an ACL enabled check
+     *
+     * @dataProvider dataProvider
+     * @param $name
+     */
+    public function testBaseClassAclPermission($name) {
+        $classname = 'dokuwiki\\Action\\' . $name;
+        /** @var \dokuwiki\Action\AbstractAction $class */
+        $class = new $classname();
+        $this->assertTrue(true); // mark as not risky
+        if(!is_a($class, AbstractAclAction::class)) return;
+
+        global $conf;
+        $conf['useacl'] = 1;
+        $conf['subscribers'] = 1;
+
+        try {
+            $class->checkPreconditions();
+        } catch(\Exception $e) {
+            $this->assertNotSame(ActionAclRequiredException::class, get_class($e));
+        }
+
+        $conf['useacl'] = 0;
+
+        try {
+            $class->checkPreconditions();
+        } catch(\Exception $e) {
+            $this->assertSame(ActionAclRequiredException::class, get_class($e));
+        }
+    }
+
+    /**
+     * Actions inheriting from AbstractUserAction should have user check
+     *
+     * @dataProvider dataProvider
+     * @param $name
+     */
+    public function testBaseClassUserPermission($name) {
+        $classname = 'dokuwiki\\Action\\' . $name;
+        /** @var \dokuwiki\Action\AbstractAction $class */
+        $class = new $classname();
+        $this->assertTrue(true); // mark as not risky
+        if(!is_a($class, AbstractUserAction::class)) return;
+
+        global $conf;
+        $conf['useacl'] = 1;
+        $conf['subscribers'] = 1;
+        $_SERVER['REMOTE_USER'] = 'test';
+
+        try {
+            $class->checkPreconditions();
+        } catch(\Exception $e) {
+            $this->assertNotSame(ActionUserRequiredException::class, get_class($e));
+        }
+
+        unset($_SERVER['REMOTE_USER']);
+
+        try {
+            $class->checkPreconditions();
+        } catch(\Exception $e) {
+            $this->assertSame(ActionUserRequiredException::class, get_class($e));
+        }
+    }
+}
diff --git a/_test/tests/inc/difference_engine.test.php b/_test/tests/inc/difference_engine.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd0c9c0317a4e03fe2bc80d8a1ae8494544d52e2
--- /dev/null
+++ b/_test/tests/inc/difference_engine.test.php
@@ -0,0 +1,85 @@
+<?php
+
+require_once DOKU_INC.'inc/DifferenceEngine.php';
+
+/**
+ * Class difference_engine_test
+ */
+class difference_engine_test extends DokuWikiTest {
+    public $x = "zzz\n\naaa\n\nbbb\n\nccc\n\nddd\n\nddd\n\nddd\n\neee\n\nfff";
+    public $y = "ddd\n\naaa\n\nbbb\n\nbbb\n\nccc\n\nccc\n\neee";
+
+    function test_render_table(){
+        $diff = new Diff(explode("\n", $this->x), explode("\n", $this->y));
+        $diffformatter = new TableDiffFormatter();
+        $actual = $diffformatter->format($diff);
+        $expected = '<tr><td class="diff-blockheader" colspan="2">Line 1:</td>
+<td class="diff-blockheader" colspan="2">Line 1:</td>
+</tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark">zzz</strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"><strong class="diff-mark">ddd</strong></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">aaa</td><td class="diff-lineheader">&#160;</td><td class="diff-context">aaa</td></tr>
+<tr><td colspan="2">&#160;</td><td class="diff-lineheader">+</td><td class="diff-addedline"></td></tr>
+<tr><td colspan="2">&#160;</td><td class="diff-lineheader">+</td><td class="diff-addedline">bbb</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">bbb</td><td class="diff-lineheader">&#160;</td><td class="diff-context">bbb</td></tr>
+<tr><td class="diff-blockheader" colspan="2">Line 7:</td>
+<td class="diff-blockheader" colspan="2">Line 9:</td>
+</tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">ccc</td><td class="diff-lineheader">&#160;</td><td class="diff-context">ccc</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark">ddd </strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"><strong class="diff-mark">ccc</strong></td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark"> </strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"></td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark">ddd </strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"></td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark"> </strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"></td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"><strong class="diff-mark">ddd</strong></td><td class="diff-lineheader">+</td><td class="diff-addedline"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">eee</td><td class="diff-lineheader">&#160;</td><td class="diff-context">eee</td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline"></td><td colspan="2">&#160;</td></tr>
+<tr><td class="diff-lineheader">-</td><td class="diff-deletedline">fff</td><td colspan="2">&#160;</td></tr>
+';
+        $this->assertEquals($expected, $actual);
+    }
+
+    function test_render_inline(){
+        $diff = new Diff(explode("\n", $this->x), explode("\n", $this->y));
+        $diffformatter = new InlineDiffFormatter();
+        $actual = $diffformatter->format($diff);
+        $expected = '<tr><td colspan="2" class="diff-blockheader">@@ Line -1,5 +1,7 @@&#160;<span class="diff-deletedline"><del>removed</del></span>&#160;<span class="diff-addedline">created</span></td></tr>
+
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del>zzz</del></span><span class="diff-addedline">ddd</span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">aaa</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-addedline"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-addedline">bbb</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">bbb</td></tr>
+<tr><td colspan="2" class="diff-blockheader">@@ Line -7,11 +9,5 @@&#160;<span class="diff-deletedline"><del>removed</del></span>&#160;<span class="diff-addedline">created</span></td></tr>
+
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">ccc</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del>ddd </del></span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del> </del></span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del>ddd </del></span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del> </del></span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td><span class="diff-deletedline"><del>ddd</del></span><span class="diff-addedline">ccc</span></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context"></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-context">eee</td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-deletedline"><del></del></td></tr>
+<tr><td class="diff-lineheader">&#160;</td><td class="diff-deletedline"><del>fff</del></td></tr>
+';
+        $this->assertEquals($expected, $actual);
+    }
+
+    function test_engine_diag(){
+        // initialize
+        $eng = new _DiffEngine;
+        $eng->diff(explode("\n", $this->x), explode("\n", $this->y));
+        // check
+        $this->assertEquals(
+            array(9, array(array(0,0),array(1,2),array(3,4),array(4,5),array(5,7),array(6,9),array(7,10),array(9,12),array(15,13))),
+            $eng->_diag(0, 15, 0, 13, 8)
+        );
+    }
+}
+//Setup VIM: ex: et ts=4 :
diff --git a/_test/tests/inc/form/dropdownelement.test.php b/_test/tests/inc/form/dropdownelement.test.php
index 3aa0f16e4be1d10dfae4e1e7c6e223dd4e570c64..5f6b35e7521d450f3c8f9caab1e2f7c719aab670 100644
--- a/_test/tests/inc/form/dropdownelement.test.php
+++ b/_test/tests/inc/form/dropdownelement.test.php
@@ -129,6 +129,21 @@ class form_dropdownelement_test extends DokuWikiTest {
         $this->assertEquals('label of third option', $selected->text());
     }
 
+    /**
+     * Prevent double select that might occur because `'Auto' == 0` is true
+     */
+    public function test_doubleselect() {
+        $form = new Form\Form();
+        $form->addDropdown('foo', ['Auto', 0, 1]);
+
+        $html = $form->toHTML();
+
+        $pq = phpQuery::newDocumentXHTML($html);
+        $selected = $pq->find('option[selected=selected]');
+        $this->assertEquals(1, $selected->length);
+        $this->assertEquals('Auto', $selected->text());
+    }
+
     /**
      * Ensure that there is always only a single one selected option
      */
diff --git a/_test/tests/inc/fulltext_query.test.php b/_test/tests/inc/fulltext_query.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f95a95108524f8c0ff9b8ef98cd9558333b7a38
--- /dev/null
+++ b/_test/tests/inc/fulltext_query.test.php
@@ -0,0 +1,104 @@
+<?php
+
+// must be run within Dokuwiki
+if (!defined('DOKU_INC')) {
+    die();
+}
+
+/**
+ * Test cases for the link index
+ *
+ * @author Michael Große <grosse@cosmocode.de>
+ *
+ * @group  fulltext
+ */
+class fulltext_query_test extends DokuWikiTest
+{
+    public function test_parse_query()
+    {
+        $Indexer = idx_get_indexer();
+        $inputQuery = 'test -baz "foo bar" @abc ^def';
+
+        $actualParsedQuery = ft_queryParser($Indexer, $inputQuery);
+
+        $expectedParsedQuery = [
+            'query' => 'test -baz "foo bar" @abc ^def',
+            'parsed_str' => '(W+:test)ANDNOT((W-:baz))AND((W_:foo)AND(W_:bar)AND(P+:foo bar))AND(N+:abc)ANDNOT(N-:def)',
+            'parsed_ary' => [
+                'W+:test',
+                'W-:baz',
+                'NOT',
+                'AND',
+                'W_:foo',
+                'W_:bar',
+                'AND',
+                'P+:foo bar',
+                'AND',
+                'AND',
+                'N+:abc',
+                'AND',
+                'N-:def',
+                'NOT',
+                'AND',
+            ],
+            'words' => [
+                'test',
+                'baz',
+                'foo',
+                'bar',
+            ],
+            'highlight' => [
+                'test',
+                'foo bar',
+            ],
+            'and' => [
+                'test',
+            ],
+            'phrases' => [
+                'foo bar',
+            ],
+            'ns' => [
+                'abc',
+            ],
+            'notns' => [
+                'def',
+            ],
+            'not' => [
+                'baz',
+            ],
+        ];
+        $this->assertEquals($expectedParsedQuery, $actualParsedQuery);
+    }
+
+    public function test_unparse_query()
+    {
+        $input = [
+            'and' => [
+                'test',
+            ],
+            'not' => [
+                'baz'
+            ],
+            'phrases' => [
+                'foo bar',
+            ],
+            'ns' => [
+                'abc',
+            ],
+            'notns' => [
+                'def'
+            ],
+        ];
+
+        $actualQuery = ft_queryUnparser_simple(
+            $input['and'],
+            $input['not'],
+            $input['phrases'],
+            $input['ns'],
+            $input['notns']
+        );
+
+        $expectedQuery = 'test -baz "foo bar" @abc ^def';
+        $this->assertEquals($expectedQuery, $actualQuery);
+    }
+}
diff --git a/_test/tests/inc/html_secedit_pattern.test.php b/_test/tests/inc/html_secedit_pattern.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca161588577056b2a64098b5d0cd49bbb4d2a9db
--- /dev/null
+++ b/_test/tests/inc/html_secedit_pattern.test.php
@@ -0,0 +1,59 @@
+<?php
+
+class html_scedit_pattern_test extends DokuWikiTest {
+
+
+    public function dataProviderForTestSecEditPattern() {
+        return [
+            [
+                '<!-- EDIT{"target":"SECTION","name":"Plugins","hid":"plugins","codeblockOffset":0,"secid":5,"range":"1406-"} -->',
+                [
+                    'secid' => 5,
+                    'target' => 'SECTION',
+                    'name' => 'Plugins',
+                    'hid' => 'plugins',
+                    'range' => '1406-',
+                ],
+                'basic section edit',
+            ],
+            [
+                '<!-- EDIT{"target":"TABLE","name":"","hid":"table4","codeblockOffset":0,"secid":10,"range":"11908-14014"} -->',
+                [
+                    'secid' => 10,
+                    'target' => 'TABLE',
+                    'name' => '',
+                    'hid' => 'table4',
+                    'range' => '11908-14014',
+                ],
+                'table edit'
+            ],
+            [
+                '<!-- EDIT{"target":"PLUGIN_DATA","name":"","hid":"","codeblockOffset":0,"secid":2,"range":"27-432"} -->',
+                [
+                    'secid' => 2,
+                    'target' => 'PLUGIN_DATA',
+                    'name' => '',
+                    'hid' => '',
+                    'range' => '27-432',
+                ],
+                'data plugin'
+            ],
+        ];
+    }
+
+    /**
+     * @dataProvider dataProviderForTestSecEditPattern
+     *
+     * @param $text
+     * @param $expectedMatches
+     * @param $msg
+     */
+    public function testSecEditPattern($text, $expectedMatches, $msg) {
+        preg_match(SEC_EDIT_PATTERN, $text, $matches);
+        $data = json_decode($matches[1], true);
+        foreach ($expectedMatches as $key => $expected_value) {
+            $this->assertSame($expected_value, $data[$key], $msg);
+        }
+    }
+
+}
diff --git a/_test/tests/inc/httpclient_http.test.php b/_test/tests/inc/httpclient_http.test.php
index f496507d0deca08e9a225b8ded458883e58f77a2..6cc783b2ba319e684f11fd1cf6a36163c36d82f9 100644
--- a/_test/tests/inc/httpclient_http.test.php
+++ b/_test/tests/inc/httpclient_http.test.php
@@ -16,7 +16,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('args',$resp);
@@ -33,7 +33,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('args',$resp);
@@ -50,7 +50,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('gzipped',$resp);
@@ -67,7 +67,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('form',$resp);
@@ -84,7 +84,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('url',$resp);
@@ -101,7 +101,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('url',$resp);
@@ -118,7 +118,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data === false, 'HTTP response '.$http->error);
+        $this->assertTrue($data === false, $http->errorInfo());
         $this->assertEquals('Maximum number of redirects exceeded',$http->error);
     }
 
@@ -138,7 +138,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('cookies',$resp);
@@ -155,7 +155,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data === false, 'HTTP response '.$http->error);
+        $this->assertTrue($data === false, $http->errorInfo());
         $this->assertEquals(418,$http->status);
     }
 
@@ -172,7 +172,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data === false, 'HTTP response '.$http->error);
+        $this->assertTrue($data === false, $http->errorInfo());
 
         // this should read just the needed bytes
         $http->max_bodysize_abort = false;
@@ -182,7 +182,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         /* should read no more than max_bodysize+1 */
         $this->assertLessThanOrEqual(251,strlen($data));
     }
@@ -198,14 +198,14 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data !== false, 'HTTP response '.$http->error);
+        $this->assertTrue($data !== false, $http->errorInfo());
         $http->max_bodysize_abort = false;
         $data = $http->get($this->server.'/stream/5');
         if($http->noconnection()) {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data !== false, 'HTTP response '.$http->error);
+        $this->assertTrue($data !== false, $http->errorInfo());
     }
 
     /**
@@ -220,7 +220,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertEquals(array('authenticated'=>true,'user'=>'user'), $resp);
@@ -238,7 +238,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data === false, 'HTTP response '.$http->error);
+        $this->assertTrue($data === false, $http->errorInfo());
         $this->assertEquals(401,$http->status);
     }
 
@@ -249,7 +249,7 @@ class httpclient_http_test extends DokuWikiTest {
         $http = new HTTPMockClient();
         $http->timeout = 5;
         $data = $http->get($this->server.'/delay/10');
-        $this->assertTrue($data === false, 'HTTP response '.$http->error);
+        $this->assertTrue($data === false, $http->errorInfo());
         $this->assertEquals(-100,$http->status);
     }
 
@@ -263,7 +263,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $resp = json_decode($data, true);
         $this->assertTrue(is_array($resp), 'JSON response');
         $this->assertArrayHasKey('baz',$http->resp_headers);
@@ -281,7 +281,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertFalse($data === false, 'HTTP response '.$http->error);
+        $this->assertFalse($data === false, $http->errorInfo());
         $this->assertEquals(2550,strlen($data));
     }
 
@@ -298,7 +298,7 @@ class httpclient_http_test extends DokuWikiTest {
             $this->markTestSkipped('connection timed out');
             return;
         }
-        $this->assertTrue($data !== false, 'HTTP response '.$http->error);
+        $this->assertTrue($data !== false, $http->errorInfo());
     }
 
     function test_postencode(){
diff --git a/_test/tests/inc/httpclient_http_proxy.test.php b/_test/tests/inc/httpclient_http_proxy.test.php
index 4b95b5d6e3c9e79e90901c7d7691257aa4905587..615eebb4f05cbb5db150e840bf698daaec8596ab 100644
--- a/_test/tests/inc/httpclient_http_proxy.test.php
+++ b/_test/tests/inc/httpclient_http_proxy.test.php
@@ -15,7 +15,7 @@ class httpclient_http_proxy_test extends DokuWikiTest {
         $http->proxy_port = 8080;
 
         $data = $http->get($this->url);
-        $this->assertFalse($data === false, 'HTTP response: '.$http->error.' ['.$this->url.']');
+        $this->assertFalse($data === false, $http->errorInfo($this->url));
         $this->assertTrue(strpos($data,'DokuWiki') !== false, 'response content');
     }
 }
diff --git a/_test/tests/inc/httpclient_mock.php b/_test/tests/inc/httpclient_mock.php
index 038045c8bb1cc91319a90c6ba0e3de6587d5183d..b66b907755f73c75a16df5ec34edcbc089b15538 100644
--- a/_test/tests/inc/httpclient_mock.php
+++ b/_test/tests/inc/httpclient_mock.php
@@ -7,11 +7,12 @@
  */
 class HTTPMockClient extends HTTPClient {
     protected $tries;
+    protected $lasturl;
 
     /**
      * Sets shorter timeout
      */
-    function __construct() {
+    public function __construct() {
         parent::__construct();
         $this->timeout = 8; // slightly faster timeouts
     }
@@ -21,7 +22,7 @@ class HTTPMockClient extends HTTPClient {
      *
      * @return bool
      */
-    function noconnection() {
+    public function noconnection() {
         return ($this->tries === 0);
     }
 
@@ -33,14 +34,34 @@ class HTTPMockClient extends HTTPClient {
      * @param string $method
      * @return bool
      */
-    function sendRequest($url, $data = '', $method = 'GET') {
+    public function sendRequest($url, $data = '', $method = 'GET') {
+        $this->lasturl = $url;
         $this->tries = 2; // configures the number of retries
         $return      = false;
         while($this->tries) {
             $return = parent::sendRequest($url, $data, $method);
-            if($this->status != -100) break;
+            if($this->status != -100 && $this->status != 408) break;
+            usleep((3 - $this->tries) * 250000);
             $this->tries--;
         }
         return $return;
     }
-}
\ No newline at end of file
+
+    /**
+     * Return detailed error data
+     *
+     * @param string $info optional additional info
+     * @return string
+     */
+    public function errorInfo($info = '') {
+        return json_encode(
+            array(
+                'URL' => $this->lasturl,
+                'Error' => $this->error,
+                'Status' => $this->status,
+                'Body' => $this->resp_body,
+                'Info' => $info
+            ), JSON_PRETTY_PRINT
+        );
+    }
+}
diff --git a/_test/tests/inc/io_replaceinfile.test.php b/_test/tests/inc/io_replaceinfile.test.php
index 3fb81b256b8b7d54767d7ed3d6b42337831ece19..61b0e12e0d4e9b453e9d1c2b151ebc8f8570c2b4 100644
--- a/_test/tests/inc/io_replaceinfile.test.php
+++ b/_test/tests/inc/io_replaceinfile.test.php
@@ -109,7 +109,7 @@ class io_replaceinfile_test extends DokuWikiTest {
         } else {
             $expect = 'PHPUnit_Framework_Error_Warning'; // PHPUnit 5
         }
-        $this->setExpectedException($expect);
+        $this->expectException($expect);
 
         /* The empty $oldline parameter should be caught before the file doesn't exist test. */
         $this->assertFalse(io_replaceInFile(TMP_DIR.'/not_existing_file.txt', '', '', false, 0));
diff --git a/_test/tests/inc/mailer.test.php b/_test/tests/inc/mailer.test.php
index 6100ef1bf9c048868027f4a348c0ba2181536bac..6f35863c2afd8b9d84c0a74948bf6a7c5ff61e7a 100644
--- a/_test/tests/inc/mailer.test.php
+++ b/_test/tests/inc/mailer.test.php
@@ -73,6 +73,10 @@ class mailer_test extends DokuWikiTest {
     }
 
     function test_addresses(){
+        if (isWindows()) {
+            $this->markTestSkipped();
+        }
+
         $mail = new TestMailer();
 
         $mail->to('andi@splitbrain.org');
diff --git a/_test/tests/inc/media_searchlist.test.php b/_test/tests/inc/media_searchlist.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..c038d3a20996d6222a09f06dab71185194eb7f03
--- /dev/null
+++ b/_test/tests/inc/media_searchlist.test.php
@@ -0,0 +1,258 @@
+<?php
+
+class media_searchlist_test extends DokuWikiTest {
+
+    /**
+     * @var string namespace used for testing
+     */
+    protected $upload_ns = 'media_searchlist_test';
+
+    /**
+     * Save the file
+     *
+     * @param $name name of saving file
+     * @param $copy file used as a content of uploaded file
+     */
+    protected function save($name, $copy) {
+        $media_id = $this->upload_ns.':'.$name;
+        media_save(array('name' => $copy), $media_id, true, AUTH_UPLOAD, 'copy');
+    }
+
+    /**
+     * Called for each test
+     *
+     * @throws Exception
+     */
+    function setUp() {
+        //create some files to search
+        $png = mediaFN('wiki:kind_zu_katze.png');
+        $ogv = mediaFN('wiki:kind_zu_katze.ogv');
+        $webm = mediaFN('wiki:kind_zu_katze.webm');
+
+        $this->save('a.png', $png);
+        $this->save('aa.png', $png);
+        $this->save('ab.png', $png);
+
+        $this->save('a.ogv', $ogv);
+        $this->save('aa.ogv', $ogv);
+        $this->save('ab.ogv', $ogv);
+
+        $this->save('a:a.png', $png);
+        $this->save('b:a.png', $png);
+
+        $this->save('0.webm', $webm);
+
+    }
+
+    /*
+     * Reset media_printfile static variable $twibble to stat state
+     */
+    protected function reset_media_printfile() {
+        $reflect = new ReflectionFunction('media_printfile');
+        $static = $reflect->getStaticVariables();
+        if ($static['twibble'] == -1) {
+            ob_start();
+            @media_printfile(array(), 0, '');
+            ob_end_clean();
+        }
+    }
+
+    /**
+     * Build search result header as in media_searchlist() with $fullscreen = false
+     *
+     * @param $query search query
+     * @param $ns namespece where we search
+     *
+     * @return string
+     */
+    protected function media_searchlist_header($query, $ns) {
+        global $lang;
+
+        $header = '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
+        ob_start();
+        media_searchform($ns,$query);
+        $header .= ob_get_contents();
+        ob_end_clean();
+
+        return $header;
+    }
+
+    /**
+     * Wrap around media_printfile: return the result.
+     *
+     * @param $item
+     * @return string
+     */
+    protected function media_printfile($item) {
+        ob_start();
+        media_printfile($item,$item['perm'],'',true);
+        $out = ob_get_contents();
+        ob_end_clean();
+
+        return $out;
+    }
+
+    /**
+     * Wrap around media_searchlist: return the result
+     * Reset media_printfile static variables afterwards
+     *
+     * @param $query
+     * @param $ns
+     * @return string
+     */
+    protected function media_searchlist($query, $ns) {
+        ob_start();
+        media_searchlist($query, $ns);
+        $out = ob_get_contents();
+        ob_end_clean();
+
+        //reset media_printfile static variables
+        $this->reset_media_printfile();
+
+        return $out;
+    }
+
+    /**
+     *
+     * @param array[string] $rel_ids media ids relative to $this->upload_ns
+     * @return array $items as required by media_printfile
+     */
+    protected function create_media_items($rel_ids) {
+        $items = array();
+        foreach ($rel_ids as $rel_id){
+            $file = mediaFN($this->upload_ns . ':' . $rel_id);
+            $info             = array();
+            $info['id']       = $this->upload_ns . ':' . $rel_id;
+            $info['perm']     = auth_quickaclcheck(getNS($info['id']).':*');
+            $info['file']     = utf8_basename($file);
+            $info['size']     = filesize($file);
+            $info['mtime']    = filemtime($file);
+            $info['writable'] = is_writable($file);
+            if(preg_match("/\.(jpe?g|gif|png)$/",$file)){
+                $info['isimg'] = true;
+                $info['meta']  = new JpegMeta($file);
+            }else{
+                $info['isimg'] = false;
+            }
+            $info['hash']     = md5(io_readFile(mediaFN($info['id']),false));
+
+            $items[] = $info;
+        }
+        return $items;
+    }
+
+    /**
+     * Output result as in 'media_searchlist' but use an arbitrary media IDs list instead of actual searching
+     * Reset media_printfile static variables afterwards
+     *
+     * @param array[string] $rel_ids media ids relative to $this->upload_ns
+     * @param string $query actual seqrch query (used for filling search filed input)
+     * @param string $ns
+     * @return string
+     */
+    protected function media_searchlist_except($rel_ids, $query, $ns) {
+        //build a search result header
+        $expect = $this->media_searchlist_header($query, $ns);
+
+        //get the items list
+        $items = $this->create_media_items($rel_ids);
+        foreach ($items as $item) {
+            $expect .= $this->media_printfile($item);
+        }
+
+        //reset media_printfile static variables
+        $this->reset_media_printfile();
+
+        return $expect;
+    }
+
+    public function test_noglobbing(){
+        $query = 'a.png';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('a:a.png', 'b:a.png', 'a.png', 'aa.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_asterisk(){
+        $query = 'a*.png';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('a:a.png', 'b:a.png', 'a.png', 'aa.png', 'ab.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_find_by_ext(){
+        $query = '*.ogv';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('a.ogv', 'aa.ogv', 'ab.ogv'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_question_mark(){
+        $query = 'a?.png';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('aa.png', 'ab.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_question_mark_and_asterisk(){
+        $query = 'a?.*';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('aa.ogv', 'aa.png', 'ab.ogv', 'ab.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_question_mark_on_the_begining(){
+        $query = '?.png';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('a:a.png', 'b:a.png', 'a.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_two_question_marks_on_the_begining(){
+        $query = '??.png';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('aa.png', 'ab.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_globbing_two_letter_file_names(){
+        $query = '??.*';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('aa.ogv', 'aa.png', 'ab.ogv', 'ab.png'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+
+    public function test_zero_search(){
+        $query = '0';
+        $ns = $this->upload_ns;
+
+        $result = $this->media_searchlist($query, $ns);
+        $expect = $this->media_searchlist_except(array('0.webm'), $query, $ns);
+
+        $this->assertEquals($expect, $result);
+    }
+}
diff --git a/_test/tests/inc/pageutils_wikiFN.test.php b/_test/tests/inc/pageutils_wikiFN.test.php
index 6d9b73e2263b1e38ccf4cf7650abb54240f0e580..664aa64272cfb07bd5683ba0d1c923d05f9b7edb 100644
--- a/_test/tests/inc/pageutils_wikiFN.test.php
+++ b/_test/tests/inc/pageutils_wikiFN.test.php
@@ -4,13 +4,13 @@ class wikifn_test extends DokuWikiTest {
 
 
     function test_cache_cleaning_cleanToUnclean(){
-        $this->assertEquals(wikiFN('wiki:',null,false),DOKU_TMP_DATA.'pages/wiki/.txt');
-        $this->assertEquals(wikiFN('wiki:',null,true),DOKU_TMP_DATA.'pages/wiki.txt');
+        $this->assertEquals(wikiFN('wiki:',null,false), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki/.txt'));
+        $this->assertEquals(wikiFN('wiki:',null,true), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki.txt'));
     }
 
     function test_cache_cleaning_uncleanToClean(){
-        $this->assertEquals(wikiFN('wiki:',null,true),DOKU_TMP_DATA.'pages/wiki.txt');
-        $this->assertEquals(wikiFN('wiki:',null,false),DOKU_TMP_DATA.'pages/wiki/.txt');
+        $this->assertEquals(wikiFN('wiki:',null,true), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki.txt'));
+        $this->assertEquals(wikiFN('wiki:',null,false), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki/.txt'));
     }
 
 }
diff --git a/_test/tests/inc/parser/parser.inc.php b/_test/tests/inc/parser/parser.inc.php
index f1207b11970484a327ec40f10c3517c15bad7c75..c73f8d13750b75eca9ffcfc74075a3287d69083a 100644
--- a/_test/tests/inc/parser/parser.inc.php
+++ b/_test/tests/inc/parser/parser.inc.php
@@ -5,14 +5,16 @@ require_once DOKU_INC . 'inc/parser/handler.php';
 
 abstract class TestOfDoku_Parser extends DokuWikiTest {
 
-    var $P;
-    var $H;
+    /** @var  Doku_Parser */
+    protected $P;
+    /** @var  Doku_Handler */
+    protected $H;
 
     function setUp() {
         parent::setUp();
         $this->P = new Doku_Parser();
         $this->H = new Doku_Handler();
-        $this->P->Handler = & $this->H;
+        $this->P->Handler = $this->H;
     }
 
     function tearDown() {
diff --git a/_test/tests/inc/parser/parser_links.test.php b/_test/tests/inc/parser/parser_links.test.php
index 529efac6e6141936db37cfc6fc3900681a7bcf3f..ee001e73af04cd69432cecf4b9be580d7d48398e 100644
--- a/_test/tests/inc/parser/parser_links.test.php
+++ b/_test/tests/inc/parser/parser_links.test.php
@@ -1,6 +1,11 @@
 <?php
 require_once 'parser.inc.php';
 
+/**
+ * Tests for the implementation of link syntax
+ *
+ * @group parser_links
+*/
 class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
 
     function testExternalLinkSimple() {
@@ -139,6 +144,35 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
         $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
     }
 
+    function testExternalWWWLinkInPath() {
+        $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+        // See issue #936. Should NOT generate a link!
+        $this->P->parse("Foo /home/subdir/www/www.something.de/somedir/ Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo /home/subdir/www/www.something.de/somedir/ Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+    function testExternalWWWLinkFollowingPath() {
+        $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+        $this->P->parse("Foo /home/subdir/www/ www.something.de/somedir/ Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo /home/subdir/www/ ')),
+            array('externallink',array('http://www.something.de/somedir/', 'www.something.de/somedir/')),
+            array('cdata',array(' Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
     function testExternalFTPLink() {
         $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
         $this->P->parse("Foo ftp.sunsite.com Bar");
@@ -153,6 +187,36 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
         );
         $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
     }
+
+    function testExternalFTPLinkInPath() {
+        $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+        // See issue #936. Should NOT generate a link!
+        $this->P->parse("Foo /home/subdir/www/ftp.something.de/somedir/ Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo /home/subdir/www/ftp.something.de/somedir/ Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+    function testExternalFTPLinkFollowingPath() {
+        $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+        $this->P->parse("Foo /home/subdir/www/ ftp.something.de/somedir/ Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo /home/subdir/www/ ')),
+            array('externallink',array('ftp://ftp.something.de/somedir/', 'ftp.something.de/somedir/')),
+            array('cdata',array(' Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
     function testEmail() {
         $this->P->addMode('emaillink',new Doku_Parser_Mode_Emaillink());
         $this->P->parse("Foo <bugs@php.net> Bar");
@@ -274,6 +338,36 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
         $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
     }
 
+    function testInternalLinkCodeFollows() {
+        $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+        $this->P->parse("Foo [[wiki:internal:link|Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo ')),
+            array('internallink',array('wiki:internal:link','Test')),
+            array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+    function testInternalLinkCodeFollows2() {
+        $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+        $this->P->parse("Foo [[wiki:internal:link|[Square brackets in title] Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo ')),
+            array('internallink',array('wiki:internal:link','[Square brackets in title] Test')),
+            array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
     function testExternalInInternalLink() {
         $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
         $this->P->parse("Foo [[http://www.google.com|Google]] Bar");
@@ -289,6 +383,54 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
         $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
     }
 
+    function testExternalInInternalLink2() {
+        $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+        $this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo ')),
+            array('externallink',array('http://www.google.com?test[]=squarebracketsinurl','Google')),
+            array('cdata',array(' Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+    function testExternalInInternalLink2CodeFollows() {
+        $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+        $this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo ')),
+            array('externallink',array('http://www.google.com?test[]=squarebracketsinurl','Google')),
+            array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+    function testTwoInternalLinks() {
+        $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+        $this->P->parse("Foo [[foo:bar|one]] and [[bar:foo|two]] Bar");
+        $calls = array (
+            array('document_start',array()),
+            array('p_open',array()),
+            array('cdata',array("\n".'Foo ')),
+            array('internallink',array('foo:bar','one')),
+            array('cdata',array(' and ')),
+            array('internallink',array('bar:foo','two')),
+            array('cdata',array(' Bar')),
+            array('p_close',array()),
+            array('document_end',array()),
+        );
+        $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
+    }
+
+
     function testInterwikiLink() {
         $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
         $this->P->parse("Foo [[iw>somepage|Some Page]] Bar");
@@ -393,7 +535,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
         );
         $this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
     }
-    
+
     function testWindowsShareLinkHyphen() {
         $this->P->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
         $this->P->parse('Foo \\\server\share-hyphen Bar');
diff --git a/_test/tests/inc/parserutils_set_metadata.test.php b/_test/tests/inc/parserutils_set_metadata.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..c31010ce880e98834354133089627a6240b9802b
--- /dev/null
+++ b/_test/tests/inc/parserutils_set_metadata.test.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Class parserutils_set_metadata_test
+ */
+class parserutils_set_metadata_test extends DokuWikiTest {
+    // the id used for this test case
+    private $id;
+
+    /**
+     * Set up fake user environment with for the gieven user
+     *
+     * @param string $user
+     */
+    function helper_prepare_user($user = '1') {
+        global $INFO, $USERINFO;
+
+        // prepare fake users
+        static $users = [
+            '1' => [
+                'pass' => '179ad45c6ce2cb97cf1029e212046e81',
+                'name' => 'Tester1',
+                'mail' => 'tester1@example.com',
+                'grps' => array('admin', 'user'),
+            ]
+            ,
+            'tester2' => [
+                'pass' => '179ad45c6ce2cb97cf1029e212046e81',
+                'name' => 'Tester2',
+                'mail' => 'tester2@example.com',
+                'grps' => array('user'),
+            ]
+        ];
+        if(!isset($users[$user])) throw new RuntimeException('requested non-existing user');
+
+        // set up globals
+        $_SERVER['REMOTE_ADDR'] = '1.2.3.4';
+        $USERINFO = $users[$user];
+        $INFO['userinfo'] = $USERINFO;
+        $_SERVER['REMOTE_USER'] = $user;
+    }
+
+    /**
+     *  test array merge, including contributors with numeric keys and array data overwritting
+     */
+    function test_array_replace(){
+        // prepare user
+        $this->helper_prepare_user('1');
+
+        // prepare page
+        $this->id = 'test:set_metadata_array_replace';
+        saveWikiText($this->id, 'Test', 'Test data setup');
+        $meta = p_get_metadata($this->id);
+
+        $this->assertEquals('1', $meta['user'], 'Initial page has wrong user ID');
+        // $this->assertEquals(empty($meta['contributor']), true, 'Initial page should have no contributors');
+
+        // first revision with numeric user
+        $this->waitForTick();
+        saveWikiText($this->id, 'Test1', 'Test first edit');
+        $meta = p_get_metadata($this->id);
+
+        $last_edit_date = $meta['date']['modified'];
+        $this->assertEquals(array('1'=>'Tester1'), $meta['contributor'], 'First edit contributors error');
+
+        // second revision with alphabetic user
+        $this->waitForTick();
+        $this->helper_prepare_user('tester2');
+        saveWikiText($this->id, 'Test2', 'Test second edit');
+        $meta = p_get_metadata($this->id);
+
+        $this->assertNotEquals($last_edit_date, $meta['date']['modified'], 'First edit date merge error');
+        $this->assertEquals(array('tester2'=>'Tester2', '1'=>'Tester1'), $meta['contributor'], 'Second edit contributors error');
+
+        // third revision with the first user
+        $this->waitForTick();
+        $this->helper_prepare_user('1');
+        saveWikiText($this->id, 'Test3', 'Test third edit');
+        $meta = p_get_metadata($this->id);
+
+        $this->assertEquals(array('tester2'=>'Tester2', '1'=>'Tester1'), $meta['contributor'], 'Third edit contributors error');
+    }
+}
diff --git a/_test/tests/inc/template_tpl_get_action.php b/_test/tests/inc/template_tpl_get_action.php
new file mode 100644
index 0000000000000000000000000000000000000000..b18fe552d25893d06cf6764060d92616ebccc539
--- /dev/null
+++ b/_test/tests/inc/template_tpl_get_action.php
@@ -0,0 +1,483 @@
+<?php
+
+class template_tpl_get_action_test extends DokuWikiTest {
+
+    public function setUp() {
+        parent::setUp();
+        global $ID;
+        $ID = 'start'; // run all tests on the start page
+
+    }
+
+    public function test_edit_edit() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        $ACT = 'show';
+        $REV = '';
+        $INFO['writable'] = true;
+        $INFO['exists'] = true;
+        $INFO['draft'] = '';
+
+        $expect = array(
+            'accesskey' => 'e',
+            'type' => 'edit',
+            'id' => 'start',
+            'method' => 'post',
+            'params' => array(
+                'do' => 'edit',
+                'rev' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('edit'));
+    }
+
+    public function test_edit_edit_rev() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        $ACT = 'show';
+        $REV = '1234';
+        $INFO['writable'] = true;
+        $INFO['exists'] = true;
+        $INFO['draft'] = '';
+
+        $expect = array(
+            'accesskey' => 'e',
+            'type' => 'edit',
+            'id' => 'start',
+            'method' => 'post',
+            'params' => array(
+                'do' => 'edit',
+                'rev' => '1234',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('edit'));
+    }
+
+    public function test_edit_create() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        $ACT = 'show';
+        $REV = '';
+        $INFO['writable'] = true;
+        $INFO['exists'] = false;
+        $INFO['draft'] = '';
+
+        $expect = array(
+            'accesskey' => 'e',
+            'type' => 'create',
+            'id' => 'start',
+            'method' => 'post',
+            'params' => array(
+                'do' => 'edit',
+                'rev' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('edit'));
+    }
+
+    public function test_edit_draft() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        $ACT = 'show';
+        $REV = '';
+        $INFO['writable'] = true;
+        $INFO['exists'] = true;
+        $INFO['draft'] = 'foobar';
+
+        $expect = array(
+            'accesskey' => 'e',
+            'type' => 'draft',
+            'id' => 'start',
+            'method' => 'post',
+            'params' => array(
+                'do' => 'draft',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('edit'));
+    }
+
+    public function test_edit_show() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        $ACT = 'edit';
+        $REV = '';
+        $INFO['writable'] = true;
+        $INFO['exists'] = true;
+        $INFO['draft'] = '';
+
+        $expect = array(
+            'accesskey' => 'v',
+            'type' => 'show',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('edit'));
+    }
+
+    public function test_revisions() {
+        $expect = array(
+            'accesskey' => 'o',
+            'type' => 'revs',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'revisions',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+
+        $this->assertEquals($expect, tpl_get_action('history'));
+        $this->assertEquals($expect, tpl_get_action('revisions'));
+    }
+
+    public function test_recent() {
+        $expect = array(
+            'accesskey' => 'r',
+            'type' => 'recent',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'recent',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+
+        );
+        $this->assertEquals($expect, tpl_get_action('recent'));
+    }
+
+    public function test_login() {
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'login',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'login',
+                'sectok' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('login'));
+
+        $_SERVER['REMOTE_USER'] = 'someone'; // logged in user
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'logout',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'logout',
+                'sectok' => getSecurityToken(),
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('login'));
+    }
+
+    public function test_profile() {
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('profile'));
+
+        $_SERVER['REMOTE_USER'] = 'someone'; // logged in user
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'profile',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'profile',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('profile'));
+    }
+
+    public function test_index() {
+        $expect = array(
+            'accesskey' => 'x',
+            'type' => 'index',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'index',
+            ),
+            'nofollow' => false,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('index'));
+
+        global $ID;
+        $ID = 'wiki:syntax';  // change to different page
+
+        $expect = array(
+            'accesskey' => 'x',
+            'type' => 'index',
+            'id' => 'wiki:syntax',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'index',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('index'));
+    }
+
+    public function test_admin() {
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('admin'));
+
+        // logged in super user
+        global $INFO;
+        $_SERVER['REMOTE_USER'] = 'testuser';
+        $INFO['ismanager'] = true;
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'admin',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'admin',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('admin'));
+    }
+
+    public function test_top() {
+        $expect = array(
+            'accesskey' => 't',
+            'type' => 'top',
+            'id' => '#dokuwiki__top',
+            'method' => 'get',
+            'params' => array(
+                'do' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('top'));
+    }
+
+    public function test_back() {
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('back'));
+
+        global $ID;
+        $ID = 'wiki:syntax';
+
+        $expect = array(
+            'accesskey' => 'b',
+            'type' => 'back',
+            'id' => 'wiki:start',
+            'method' => 'get',
+            'params' => array(
+                'do' => '',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('back'));
+    }
+
+    public function test_backlink() {
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'backlink',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'backlink',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('backlink'));
+    }
+
+    public function test_subscribe() {
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('subscribe'));
+        $this->assertEquals($expect, tpl_get_action('subscription'));
+
+        $_SERVER['REMOTE_USER'] = 'someone'; // logged in user
+
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('subscribe'));
+        $this->assertEquals($expect, tpl_get_action('subscription'));
+
+        // enable subscriptions
+        global $conf;
+        $conf['subscribers'] = true;
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'subscribe',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'subscribe',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('subscribe'));
+        $this->assertEquals($expect, tpl_get_action('subscription'));
+    }
+
+    public function test_register() {
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'register',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'register',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('register'));
+
+        $_SERVER['REMOTE_USER'] = 'somebody'; // logged in user
+
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('register'));
+    }
+
+    public function test_resendpwd() {
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'resendpwd',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'resendpwd',
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('resendpwd'));
+
+        $_SERVER['REMOTE_USER'] = 'somebody'; // logged in user
+
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('resendpwd'));
+    }
+
+    public function test_revert() {
+        $expect = false;
+        $this->assertEquals($expect, tpl_get_action('revert'));
+
+        global $REV;
+        global $INFO;
+        $REV = '1234';
+        $INFO['writable'] = true;
+        $INFO['ismanager'] = true;
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'revert',
+            'id' => 'start',
+            'method' => 'get', // FIXME should this be post?
+            'params' => array(
+                'do' => 'revert',
+                'rev' => '1234',
+                'sectok' => '' // FIXME is this correct?
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('revert'));
+    }
+
+    public function test_media() {
+        global $ID;
+        $ID = 'wiki:syntax';
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'media',
+            'id' => 'wiki:syntax',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'media',
+                'ns' => 'wiki'
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('media'));
+    }
+
+    public function test_mediaManager() {
+        global $IMG;
+        $IMG = 'wiki:dokuwiki.png';
+
+        $expect = array(
+            'accesskey' => null,
+            'type' => 'mediaManager',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(
+                'do' => 'media',
+                'ns' => 'wiki',
+                'image' => 'wiki:dokuwiki.png'
+            ),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $this->assertEquals($expect, tpl_get_action('mediaManager'));
+    }
+
+    public function test_img_backto() {
+        $expect = array(
+            'accesskey' => 'b',
+            'type' => 'img_backto',
+            'id' => 'start',
+            'method' => 'get',
+            'params' => array(),
+            'nofollow' => true,
+            'replacement' => 'start',
+        );
+        $this->assertEquals($expect, tpl_get_action('img_backto'));
+    }
+
+    public function test_unknown() {
+        $expect = '[unknown %s type]';
+        $this->assertEquals($expect, tpl_get_action('unknown'));
+    }
+
+}
diff --git a/_test/tests/lib/exe/ajax_requests.test.php b/_test/tests/lib/exe/ajax_requests.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..e65a7eab5fe76a2081da333a219c5b0bb3b8a338
--- /dev/null
+++ b/_test/tests/lib/exe/ajax_requests.test.php
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @group ajax
+ */
+class ajax_requests_test extends DokuWikiTest {
+
+    /**
+     * DataProvider for the builtin Ajax calls
+     *
+     * @return array
+     */
+    public function defaultCalls() {
+        return [
+            // TODO: better logic and DOM walks
+            // Call           | POST     |   regexp pattern to match
+            [ 'linkwiz',      ['q' => ''], '/^<div class="odd type_d/' ],
+            [ 'suggestions',  ['q' => ''], null ],
+            [ 'lock',         ['id' => ''], null ],
+            [ 'draftdel',     ['id' => ''], null ],
+            [ 'medians',      ['ns' => 'some:ns'], null ],
+            [ 'medialist',    ['ns' => '', 'recent' => '', 'do' => ''], null ],
+            [ 'mediadetails', ['image' => ''], null ],
+            [ 'mediadiff',    ['image' => ''], null ],
+            [ 'mediaupload',  ['mediaid' => '', 'qqfile' => '' ], null ], // $_FILES
+            [ 'index',        ['idx' => ''], null ],
+            [ 'linkwiz',      ['q' => ''], null ],
+        ];
+    }
+
+    /**
+     * @dataProvider defaultCalls
+     * @param string $call
+     * @param array $post
+     * @param string $regexp
+     */
+    public function test_defaultCallsExist($call, $post, $regexp) {
+
+        $request = new TestRequest();
+        $response = $request->post(['call'=> $call]+$post, '/lib/exe/ajax.php');
+        $this->assertNotEquals("AJAX call '$call' unknown!\n", $response->getContent());
+
+        if (!empty($regexp)) {
+            $this->assertRegExp($regexp, $response->getContent());
+        }
+    }
+
+    public function test_CallNotProvided() {
+        $request = new TestRequest();
+        $response = $request->post([], '/lib/exe/ajax.php');
+        $this->assertEquals('', $response->getContent());
+    }
+
+    public function test_UnknownCall() {
+        $call = 'unknownCALL';
+        $request = new TestRequest();
+        $response = $request->post(['call'=> $call], '/lib/exe/ajax.php');
+        $this->assertEquals("AJAX call '$call' unknown!\n", $response->getContent());
+    }
+
+
+    public function test_EventOnUnknownCall() {
+        global $EVENT_HANDLER;
+        $call = 'unknownCALL';
+        $request = new TestRequest();
+
+        // referenced data from event hook
+        $hookTriggered = false;
+        $eventDataTriggered = '';
+        $dataTriggered = '';
+        $postTriggered = '';
+
+        $hookTriggered_AFTER = false;
+        $eventDataTriggered_AFTER  = '';
+        $dataTriggered_AFTER  = '';
+        $postTriggered_AFTER  = '';
+
+        $EVENT_HANDLER->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', null,
+            function($event, $data) use (&$hookTriggered, &$dataTriggered, &$eventDataTriggered, &$postTriggered) {
+                /** @var Doku_Event $event */
+                $hookTriggered = true;
+                $dataTriggered = $data;
+                $eventDataTriggered = $event->data;
+                $postTriggered = $GLOBALS['INPUT']->post->str('q');
+                $event->preventDefault();
+                $event->stopPropagation();
+                echo "captured event BEFORE\n";
+            }, 'some passed data'
+        );
+
+        $EVENT_HANDLER->register_hook('AJAX_CALL_UNKNOWN', 'AFTER', null,
+            function($event, $data) use (&$hookTriggered_AFTER , &$dataTriggered_AFTER , &$eventDataTriggered_AFTER , &$postTriggered_AFTER ) {
+                /** @var Doku_Event $event */
+                $hookTriggered_AFTER  = true;
+                $dataTriggered_AFTER  = $data;
+                $eventDataTriggered_AFTER  = $event->data;
+                $postTriggered_AFTER  = $GLOBALS['INPUT']->post->str('q');
+                $event->preventDefault();
+                $event->stopPropagation();
+                echo "captured event AFTER";
+            }, 'some passed data AFTER'
+        );
+
+
+        $response = $request->post(['call'=> $call, 'q' => 'some-post-param'], '/lib/exe/ajax.php');
+
+        // BEFORE
+        $this->assertEquals(true, $hookTriggered, 'Testing plugin did not trigger!');
+        $this->assertEquals('some passed data', $dataTriggered);
+        $this->assertEquals($call, $eventDataTriggered, 'Must pass call name as event data');
+        $this->assertEquals('some-post-param', $postTriggered);
+
+        // AFTER
+        $this->assertEquals(true, $hookTriggered_AFTER, 'Testing plugin did not trigger!');
+        $this->assertEquals('some passed data AFTER', $dataTriggered_AFTER);
+        $this->assertEquals($call, $eventDataTriggered_AFTER, 'Must pass call name as event data');
+        $this->assertEquals('some-post-param', $postTriggered_AFTER);
+
+        //output
+        $this->assertEquals("captured event BEFORE\ncaptured event AFTER", $response->getContent());
+
+    }
+}
diff --git a/_test/tests/lib/exe/css_at_import_less.test.php b/_test/tests/lib/exe/css_at_import_less.test.php
index 4a6efcf44d3e9c5b48211d53f9cad2401aec97f5..759272ebfa12b4f4ee7458f810efa8b2c506d87d 100644
--- a/_test/tests/lib/exe/css_at_import_less.test.php
+++ b/_test/tests/lib/exe/css_at_import_less.test.php
@@ -38,10 +38,22 @@ class css_at_import_less_test extends DokuWikiTest {
         $this->assertEquals($expected_less, $less);
     }
 
+    /**
+     * makes proper relative path to be used in CSS @import
+     * @param string $path
+     * @return string
+     */
+    private function importPath($path) {
+        if (isWindows()) {
+            return preg_replace('#(^.*[\\\\])#','', $path);
+        }
+        return preg_replace('#(^.*[/])#','', $path);
+    }
+
     public function test_basic() {
         $this->setUpFiles();
 
-        $import = preg_replace('#(^.*[/])#','',$this->import);
+        $import = $this->importPath($this->import);
         $in_css = '@import "'.$import.'";';
         $in_less = '@foo: "bar";
 content: @foo;';
@@ -56,12 +68,12 @@ content: @foo;';
     public function test_subdirectory() {
         $this->setUpFiles('/foo/bar');
 
-        $import = preg_replace('#(^.*[/])#','',$this->import);
+        $import = $this->importPath($this->import);
         $in_css = '@import "'.$import.'";';
         $in_less = '@foo: "bar";
 content: @foo;';
 
-        $expected_css = '@import "/foo/bar/'.$import.'";';
+        $expected_css = isWindows() ? '@import "\\foo\\bar/'.$import.'";' : '@import "/foo/bar/'.$import.'";';
         $expected_less = 'content: "bar";';
 
         io_saveFile($this->import, $in_less);
diff --git a/_test/tests/lib/exe/css_css_loadfile.test.php b/_test/tests/lib/exe/css_css_loadfile.test.php
index 624becd2927997acd03c31e50d0fb281ade11f43..2b9d1fd2abd5d75f4e6538e8dd28c39f11ef7c61 100644
--- a/_test/tests/lib/exe/css_css_loadfile.test.php
+++ b/_test/tests/lib/exe/css_css_loadfile.test.php
@@ -77,11 +77,17 @@ class css_css_loadfile_test extends DokuWikiTest {
 
         $this->file = tempnam($dir, 'css');
 
-        $this->csstest('@import "test.less"', '@import "/foo/bar/test.less"');
-        $this->csstest('@import \'test.less\'', '@import \'/foo/bar/test.less\'');
-        $this->csstest('@import url(test.less)', '@import url(/foo/bar/test.less)');
-
-        $this->csstest('@import "abc/test.less"', '@import "/foo/bar/abc/test.less"');
+        if (isWindows()) {
+            $this->csstest('@import "test.less"', '@import "\foo\bar/test.less"');
+            $this->csstest('@import \'test.less\'', '@import \'\foo\bar/test.less\'');
+            $this->csstest('@import url(test.less)', '@import url(\foo\bar/test.less)');
+            $this->csstest('@import "abc/test.less"', '@import "\foo\bar/abc/test.less"');
+        } else {
+            $this->csstest('@import "test.less"', '@import "/foo/bar/test.less"');
+            $this->csstest('@import \'test.less\'', '@import \'/foo/bar/test.less\'');
+            $this->csstest('@import url(test.less)', '@import url(/foo/bar/test.less)');
+            $this->csstest('@import "abc/test.less"', '@import "/foo/bar/abc/test.less"');
+        }
     }
 
     public function tearDown() {
diff --git a/_test/tests/test/edit_and_save.test.php b/_test/tests/test/edit_and_save.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..fdf86a541439b61b2dc2e5c66cf8d912026f5e29
--- /dev/null
+++ b/_test/tests/test/edit_and_save.test.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @group integration
+ */
+class EditAndSaveTest extends DokuWikiTest {
+
+    /**
+     * Execute the following requests:
+     * - Section edit a page (headline 2, first occurrence)
+     * - Save a page
+     * - Redirect
+     * Check if the header id is transmitted and if the final redirect
+     * points to the correct header.
+     */
+    function testEditSaveRedirect_Headline2_A() {
+        $request = new TestRequest();
+
+        $input = array(
+            'id'     => 'int:editandsavetest'
+        );
+
+        // Show page
+        $response = $request->post($input);
+        $content = $response->getContent();
+        $this->assertTrue(!empty($content));
+
+        // If the test page has got the right content for our test it should have
+        // two headlines with the title "Headline2"
+        preg_match_all('#<h1[^>]*>Headline2</h1[^>]*>#', $content, $matches, PREG_SET_ORDER);
+        $this->assertEquals(2, count($matches));
+
+        // Get the header ids
+        $result = preg_match('/id="(.*)"/', $matches [0][0], $idA);
+        $this->assertEquals(1, $result);
+        $result = preg_match('/id="(.*)"/', $matches [1][0], $idB);
+        $this->assertEquals(1, $result);
+        $this->assertTrue($idA != $idB);
+
+        // Search the section edit form/button for the second id
+        $pattern  = '/<form class="button btn_secedit".*>.*';
+        $pattern .= '<input type="hidden" name="hid" value="';
+        $pattern .= $idA[1];
+        $pattern .= '" \/>.*<\/form>/';
+        $result = preg_match($pattern, $content, $formA);
+        $this->assertEquals(1, $result);
+
+        // Extract all inputs from the form
+        $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $formA[0], $matches, PREG_SET_ORDER);
+        $input = array();
+        foreach ($matches as $match) {
+            $input[$match[1]] = $match[2];
+        }
+        $this->assertEquals($input['hid'], $idA[1]);
+
+        // Post the input fields (= do a section edit)
+        $response = $request->post($input, '/doku.php');
+        $content = $response->getContent();
+
+        // Our header id should have been sent back to us in the edit
+        // form as an hidden input field
+        $content = str_replace("\n", " ", $content);
+        $pattern  = '/<form id="dw__editform"[^>]*>.*';
+        $pattern .= '<input type="hidden" name="hid" value="';
+        $pattern .= $idA[1];
+        $pattern .= '" \/>.*<\/form>/';
+        $result = preg_match($pattern, $content, $editForm);
+        $this->assertEquals(1, $result);
+
+        // Extract all inputs from the edit form
+        $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $editForm[0], $matches, PREG_SET_ORDER);
+        $input = array();
+        foreach ($matches as $match) {
+            $input[$match[1]] = $match[2];
+        }
+        $this->assertEquals($input['hid'], $idA[1]);
+        $input['do'] = 'save';
+
+        // Post the input fields (= save page)
+        $response = $request->post($input, '/doku.php');
+
+        // The response should carry a notification that a redirect
+        // was executed to our header ID
+        $found = $response->getData('send_redirect');
+        $this->assertCount(1, $found);
+        $hash = strpos($found[0], '#');
+        $headerID = substr($found[0], $hash);
+        $this->assertEquals($headerID, '#'.$idA[1]);
+    }
+
+    /**
+     * Execute the following requests:
+     * - Section edit a page (headline 2, second occurrence)
+     * - Save a page
+     * - Redirect
+     * Check if the header id is transmitted and if the final redirect
+     * points to the correct header.
+     */
+    function testEditSaveRedirect_Headline2_B() {
+        $request = new TestRequest();
+
+        $input = array(
+            'id'     => 'int:editandsavetest'
+        );
+
+        // Show page
+        $response = $request->post($input);
+        $content = $response->getContent();
+        $this->assertTrue(!empty($content));
+
+        // If the test page has got the right content for our test it should have
+        // two headlines with the title "Headline2"
+        preg_match_all('#<h1[^>]*>Headline2</h1[^>]*>#', $content, $matches, PREG_SET_ORDER);
+        $this->assertEquals(2, count($matches));
+
+        // Get the header ids
+        $result = preg_match('/id="(.*)"/', $matches [0][0], $idA);
+        $this->assertEquals(1, $result);
+        $result = preg_match('/id="(.*)"/', $matches [1][0], $idB);
+        $this->assertEquals(1, $result);
+        $this->assertTrue($idA != $idB);
+
+        // Search the section edit form/button for the second id
+        $pattern  = '/<form class="button btn_secedit".*>.*';
+        $pattern .= '<input type="hidden" name="hid" value="';
+        $pattern .= $idB[1];
+        $pattern .= '" \/>.*<\/form>/';
+        $result = preg_match($pattern, $content, $formB);
+        $this->assertEquals(1, $result);
+
+        // Extract all inputs from the form
+        $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $formB[0], $matches, PREG_SET_ORDER);
+        $input = array();
+        foreach ($matches as $match) {
+            $input[$match[1]] = $match[2];
+        }
+        $this->assertEquals($input['hid'], $idB[1]);
+
+        // Post the input fields (= do a section edit)
+        $response = $request->post($input, '/doku.php');
+        $content = $response->getContent();
+
+        // Our header id should have been sent back to us in the edit
+        // form as an hidden input field
+        $content = str_replace("\n", " ", $content);
+        $pattern  = '/<form id="dw__editform"[^>]*>.*';
+        $pattern .= '<input type="hidden" name="hid" value="';
+        $pattern .= $idB[1];
+        $pattern .= '" \/>.*<\/form>/';
+        $result = preg_match($pattern, $content, $editForm);
+        $this->assertEquals(1, $result);
+
+        // Extract all inputs from the edit form
+        $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $editForm[0], $matches, PREG_SET_ORDER);
+        $input = array();
+        foreach ($matches as $match) {
+            $input[$match[1]] = $match[2];
+        }
+        $this->assertEquals($input['hid'], $idB[1]);
+        $input['do'] = 'save';
+
+        // Post the input fields (= save page)
+        $response = $request->post($input, '/doku.php');
+
+        // The response should carry a notification that a redirect
+        // was executed to our header ID
+        $found = $response->getData('send_redirect');
+        $this->assertCount(1, $found);
+        $hash = strpos($found[0], '#');
+        $headerID = substr($found[0], $hash);
+        $this->assertEquals($headerID, '#'.$idB[1]);
+    }
+}
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dd1140a559a1c94fccc1979bbe0f131ffdf52579
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,47 @@
+build: false
+clone_folder: c:\dokuwiki
+max_jobs: 3
+platform: x86
+pull_requests:
+  do_not_increment_build_number: true
+version: '{build}.{branch}'
+
+environment:
+  matrix:
+    - PHP_VERSION: '7.0.21'
+      VC: 'VC14'
+      PHPUNIT: '6.3'
+    - PHP_VERSION: '5.6.30'
+      VC: 'VC11'
+      PHPUNIT: '5.7'
+
+cache:
+  - c:\php -> appveyor.yml
+
+init:
+  - SET PATH=c:\php\%PHP_VERSION%;%PATH%
+
+install:
+  - echo %PHP_VERSION%
+  - IF NOT EXIST c:\php mkdir c:\php
+  - IF NOT EXIST c:\php\%PHP_VERSION% mkdir c:\php\%PHP_VERSION%
+  - cd c:\php\%PHP_VERSION%
+  - IF NOT EXIST php-installed.txt appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-%PHP_VERSION%-Win32-%VC%-x86.zip
+  - IF NOT EXIST php-installed.txt 7z x php-%PHP_VERSION%-Win32-%VC%-x86.zip -y >nul
+  - IF NOT EXIST php-installed.txt del /Q *.zip
+  - IF NOT EXIST php-installed.txt copy /Y php.ini-development php.ini
+  - IF NOT EXIST php-installed.txt echo max_execution_time=1200 >> php.ini
+  - IF NOT EXIST php-installed.txt echo date.timezone="UTC" >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension_dir=ext >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension=php_openssl.dll >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension=php_mbstring.dll >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension=php_gd2.dll >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension=php_bz2.dll >> php.ini
+  - IF NOT EXIST php-installed.txt echo extension=php_pdo_sqlite.dll >> php.ini
+  - IF NOT EXIST php-installed.txt appveyor DownloadFile https://phar.phpunit.de/phpunit-%PHPUNIT%.phar -FileName phpunit.phar
+  - IF NOT EXIST php-installed.txt type nul >> php-installed.txt
+
+test_script:
+  - php -v
+  - cd c:\dokuwiki\_test
+  - php c:\php\%PHP_VERSION%\phpunit.phar
diff --git a/bin/dwpage.php b/bin/dwpage.php
index 1c1a1c10ee6f38cb5e41e75e51a31829600c97ec..3124563fcec8ca331b5e8238f69db9937279fa1d 100755
--- a/bin/dwpage.php
+++ b/bin/dwpage.php
@@ -1,13 +1,17 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
 define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * Checkout and commit pages from the command line while maintaining the history
  */
-class PageCLI extends DokuCLI {
+class PageCLI extends CLI {
 
     protected $force = false;
     protected $username = '';
@@ -15,10 +19,10 @@ class PageCLI extends DokuCLI {
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
         /* global */
         $options->registerOption(
             'force',
@@ -32,17 +36,17 @@ class PageCLI extends DokuCLI {
             'username'
         );
         $options->setHelp(
-            'Utility to help command line Dokuwiki page editing, allow '.
+            'Utility to help command line Dokuwiki page editing, allow ' .
             'pages to be checked out for editing then committed after changes'
         );
 
         /* checkout command */
         $options->registerCommand(
             'checkout',
-            'Checks out a file from the repository, using the wiki id and obtaining '.
-            'a lock for the page. '."\n".
-            'If a working_file is specified, this is where the page is copied to. '.
-            'Otherwise defaults to the same as the wiki page in the current '.
+            'Checks out a file from the repository, using the wiki id and obtaining ' .
+            'a lock for the page. ' . "\n" .
+            'If a working_file is specified, this is where the page is copied to. ' .
+            'Otherwise defaults to the same as the wiki page in the current ' .
             'working directory.'
         );
         $options->registerArgument(
@@ -61,7 +65,7 @@ class PageCLI extends DokuCLI {
         /* commit command */
         $options->registerCommand(
             'commit',
-            'Checks in the working_file into the repository using the specified '.
+            'Checks in the working_file into the repository using the specified ' .
             'wiki id, archiving the previous version.'
         );
         $options->registerArgument(
@@ -121,23 +125,24 @@ class PageCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
-        $this->force    = $options->getOpt('force', false);
+    protected function main(Options $options) {
+        $this->force = $options->getOpt('force', false);
         $this->username = $options->getOpt('user', $this->getUser());
 
         $command = $options->getCmd();
+        $args = $options->getArgs();
         switch($command) {
             case 'checkout':
-                $wiki_id   = array_shift($options->args);
-                $localfile = array_shift($options->args);
+                $wiki_id = array_shift($args);
+                $localfile = array_shift($args);
                 $this->commandCheckout($wiki_id, $localfile);
                 break;
             case 'commit':
-                $localfile = array_shift($options->args);
-                $wiki_id   = array_shift($options->args);
+                $localfile = array_shift($args);
+                $wiki_id = array_shift($args);
                 $this->commandCommit(
                     $localfile,
                     $wiki_id,
@@ -146,12 +151,12 @@ class PageCLI extends DokuCLI {
                 );
                 break;
             case 'lock':
-                $wiki_id = array_shift($options->args);
+                $wiki_id = array_shift($args);
                 $this->obtainLock($wiki_id);
                 $this->success("$wiki_id locked");
                 break;
             case 'unlock':
-                $wiki_id = array_shift($options->args);
+                $wiki_id = array_shift($args);
                 $this->clearLock($wiki_id);
                 $this->success("$wiki_id unlocked");
                 break;
@@ -177,11 +182,11 @@ class PageCLI extends DokuCLI {
         }
 
         if(empty($localfile)) {
-            $localfile = getcwd().'/'.utf8_basename($wiki_fn);
+            $localfile = getcwd() . '/' . utf8_basename($wiki_fn);
         }
 
         if(!file_exists(dirname($localfile))) {
-            $this->fatal("Directory ".dirname($localfile)." does not exist");
+            $this->fatal("Directory " . dirname($localfile) . " does not exist");
         }
 
         if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
@@ -204,7 +209,7 @@ class PageCLI extends DokuCLI {
      * @param string $localfile
      * @param string $wiki_id
      * @param string $message
-     * @param bool   $minor
+     * @param bool $minor
      */
     protected function commandCommit($localfile, $wiki_id, $message, $minor) {
         $wiki_id = cleanID($wiki_id);
@@ -312,7 +317,6 @@ class PageCLI extends DokuCLI {
     }
 }
 
-
 // Main
 $cli = new PageCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/bin/gittool.php b/bin/gittool.php
index cbadb5bfa27ba3f5cf8ccd29030f704c5dad6f66..63d5b4426a3a70b33e8692158625c7cb685a4a5e 100755
--- a/bin/gittool.php
+++ b/bin/gittool.php
@@ -1,27 +1,31 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
 define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * Easily manage DokuWiki git repositories
  *
  * @author Andreas Gohr <andi@splitbrain.org>
  */
-class GitToolCLI extends DokuCLI {
+class GitToolCLI extends CLI {
 
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
         $options->setHelp(
-            "Manage git repositories for DokuWiki and its plugins and templates.\n\n".
-            "$> ./bin/gittool.php clone gallery template:ach\n".
-            "$> ./bin/gittool.php repos\n".
+            "Manage git repositories for DokuWiki and its plugins and templates.\n\n" .
+            "$> ./bin/gittool.php clone gallery template:ach\n" .
+            "$> ./bin/gittool.php repos\n" .
             "$> ./bin/gittool.php origin -v"
         );
 
@@ -33,7 +37,7 @@ class GitToolCLI extends DokuCLI {
 
         $options->registerCommand(
             'clone',
-            'Tries to install a known plugin or template (prefix with template:) via git. Uses the DokuWiki.org '.
+            'Tries to install a known plugin or template (prefix with template:) via git. Uses the DokuWiki.org ' .
             'plugin repository to find the proper git repository. Multiple extensions can be given as parameters'
         );
         $options->registerArgument(
@@ -45,7 +49,7 @@ class GitToolCLI extends DokuCLI {
 
         $options->registerCommand(
             'install',
-            'The same as clone, but when no git source repository can be found, the extension is installed via '.
+            'The same as clone, but when no git source repository can be found, the extension is installed via ' .
             'download'
         );
         $options->registerArgument(
@@ -62,7 +66,7 @@ class GitToolCLI extends DokuCLI {
 
         $options->registerCommand(
             '*',
-            'Any unknown commands are assumed to be arguments to git and will be executed in all repositories '.
+            'Any unknown commands are assumed to be arguments to git and will be executed in all repositories ' .
             'found within this DokuWiki installation'
         );
     }
@@ -72,39 +76,40 @@ class GitToolCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
+    protected function main(Options $options) {
         $command = $options->getCmd();
-        if(!$command) $command = array_shift($options->args);
+        $args = $options->getArgs();
+        if(!$command) $command = array_shift($args);
 
         switch($command) {
             case '':
                 echo $options->help();
                 break;
             case 'clone':
-                $this->cmd_clone($options->args);
+                $this->cmd_clone($args);
                 break;
             case 'install':
-                $this->cmd_install($options->args);
+                $this->cmd_install($args);
                 break;
             case 'repo':
             case 'repos':
                 $this->cmd_repos();
                 break;
             default:
-                $this->cmd_git($command, $options->args);
+                $this->cmd_git($command, $args);
         }
     }
 
     /**
      * Tries to install the given extensions using git clone
      *
-     * @param array      $extensions
+     * @param array $extensions
      */
     public function cmd_clone($extensions) {
-        $errors    = array();
+        $errors = array();
         $succeeded = array();
 
         foreach($extensions as $ext) {
@@ -123,17 +128,17 @@ class GitToolCLI extends DokuCLI {
         }
 
         echo "\n";
-        if($succeeded) $this->success('successfully cloned the following extensions: '.join(', ', $succeeded));
-        if($errors) $this->error('failed to clone the following extensions: '.join(', ', $errors));
+        if($succeeded) $this->success('successfully cloned the following extensions: ' . join(', ', $succeeded));
+        if($errors) $this->error('failed to clone the following extensions: ' . join(', ', $errors));
     }
 
     /**
      * Tries to install the given extensions using git clone with fallback to install
      *
-     * @param array      $extensions
+     * @param array $extensions
      */
     public function cmd_install($extensions) {
-        $errors    = array();
+        $errors = array();
         $succeeded = array();
 
         foreach($extensions as $ext) {
@@ -156,8 +161,8 @@ class GitToolCLI extends DokuCLI {
         }
 
         echo "\n";
-        if($succeeded) $this->success('successfully installed the following extensions: '.join(', ', $succeeded));
-        if($errors) $this->error('failed to install the following extensions: '.join(', ', $errors));
+        if($succeeded) $this->success('successfully installed the following extensions: ' . join(', ', $succeeded));
+        if($errors) $this->error('failed to install the following extensions: ' . join(', ', $errors));
     }
 
     /**
@@ -179,7 +184,6 @@ class GitToolCLI extends DokuCLI {
                 continue;
             }
 
-            echo "\n";
             $this->info("executing $shell in $repo");
             $ret = 0;
             system($shell, $ret);
@@ -247,9 +251,9 @@ class GitToolCLI extends DokuCLI {
      */
     private function cloneExtension($ext, $repo) {
         if(substr($ext, 0, 9) == 'template:') {
-            $target = fullpath(tpl_incdir().'../'.substr($ext, 9));
+            $target = fullpath(tpl_incdir() . '../' . substr($ext, 9));
         } else {
-            $target = DOKU_PLUGIN.$ext;
+            $target = DOKU_PLUGIN . $ext;
         }
 
         $this->info("cloning $ext from $repo to $target");
@@ -274,15 +278,15 @@ class GitToolCLI extends DokuCLI {
     private function findRepos() {
         $this->info('Looking for .git directories');
         $data = array_merge(
-            glob(DOKU_INC.'.git', GLOB_ONLYDIR),
-            glob(DOKU_PLUGIN.'*/.git', GLOB_ONLYDIR),
-            glob(fullpath(tpl_incdir().'../').'/*/.git', GLOB_ONLYDIR)
+            glob(DOKU_INC . '.git', GLOB_ONLYDIR),
+            glob(DOKU_PLUGIN . '*/.git', GLOB_ONLYDIR),
+            glob(fullpath(tpl_incdir() . '../') . '/*/.git', GLOB_ONLYDIR)
         );
 
         if(!$data) {
             $this->error('Found no .git directories');
         } else {
-            $this->success('Found '.count($data).' .git directories');
+            $this->success('Found ' . count($data) . ' .git directories');
         }
         $data = array_map('fullpath', array_map('dirname', $data));
         return $data;
@@ -308,7 +312,7 @@ class GitToolCLI extends DokuCLI {
         if(preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
             $user = $m[1];
             $repo = $m[2];
-            return 'https://github.com/'.$user.'/'.$repo.'.git';
+            return 'https://github.com/' . $user . '/' . $repo . '.git';
         }
 
         // match gitorious repos
@@ -317,14 +321,14 @@ class GitToolCLI extends DokuCLI {
             $repo = $m[2];
             if(!$repo) $repo = $user;
 
-            return 'https://git.gitorious.org/'.$user.'/'.$repo.'.git';
+            return 'https://git.gitorious.org/' . $user . '/' . $repo . '.git';
         }
 
         // match bitbucket repos - most people seem to use mercurial there though
         if(preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
             $user = $m[1];
             $repo = $m[2];
-            return 'https://bitbucket.org/'.$user.'/'.$repo.'.git';
+            return 'https://bitbucket.org/' . $user . '/' . $repo . '.git';
         }
 
         return false;
@@ -333,4 +337,4 @@ class GitToolCLI extends DokuCLI {
 
 // Main
 $cli = new GitToolCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/bin/indexer.php b/bin/indexer.php
index 13895c36a507e9b73930f1e2f023b186d3abd668..4d19a9515c57651c8f6a7e005364880ad8720ce7 100755
--- a/bin/indexer.php
+++ b/bin/indexer.php
@@ -1,13 +1,17 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
 define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * Update the Search Index from command line
  */
-class IndexerCLI extends DokuCLI {
+class IndexerCLI extends CLI {
 
     private $quiet = false;
     private $clear = false;
@@ -15,12 +19,12 @@ class IndexerCLI extends DokuCLI {
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
         $options->setHelp(
-            'Updates the searchindex by indexing all new or changed pages. When the -c option is '.
+            'Updates the searchindex by indexing all new or changed pages. When the -c option is ' .
             'given the index is cleared first.'
         );
 
@@ -41,10 +45,10 @@ class IndexerCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
+    protected function main(Options $options) {
         $this->clear = $options->getOpt('clear');
         $this->quiet = $options->getOpt('quiet');
 
@@ -61,7 +65,7 @@ class IndexerCLI extends DokuCLI {
         $data = array();
         $this->quietecho("Searching pages... ");
         search($data, $conf['datadir'], 'search_allpages', array('skipacl' => true));
-        $this->quietecho(count($data)." pages found.\n");
+        $this->quietecho(count($data) . " pages found.\n");
 
         foreach($data as $val) {
             $this->index($val['id']);
@@ -100,4 +104,4 @@ class IndexerCLI extends DokuCLI {
 
 // Main
 $cli = new IndexerCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/bin/plugin.php b/bin/plugin.php
new file mode 100755
index 0000000000000000000000000000000000000000..cbe0b1fe73bacac14acaf9975d19a1f63db2b3aa
--- /dev/null
+++ b/bin/plugin.php
@@ -0,0 +1,103 @@
+#!/usr/bin/php
+<?php
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Colors;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
+define('NOSESSION', 1);
+require_once(DOKU_INC . 'inc/init.php');
+
+class PluginCLI extends CLI {
+
+    /**
+     * Register options and arguments on the given $options object
+     *
+     * @param Options $options
+     * @return void
+     */
+    protected function setup(Options $options) {
+        $options->setHelp('Excecutes Plugin command line tools');
+        $options->registerArgument('plugin', 'The plugin CLI you want to run. Leave off to see list', false);
+    }
+
+    /**
+     * Your main program
+     *
+     * Arguments and options have been parsed when this is run
+     *
+     * @param Options $options
+     * @return void
+     */
+    protected function main(Options $options) {
+        global $argv;
+        $argv = $options->getArgs();
+
+        if($argv) {
+            $plugin = $this->loadPlugin($argv[0]);
+            if($plugin !== null) {
+                $plugin->run();
+            } else {
+                $this->fatal('Command {cmd} not found.', ['cmd' => $argv[0]]);
+            }
+        } else {
+            echo $options->help();
+            $this->listPlugins();
+        }
+    }
+
+    /**
+     * List available plugins
+     */
+    protected function listPlugins() {
+        /** @var Doku_Plugin_Controller $plugin_controller */
+        global $plugin_controller;
+
+        echo "\n";
+        echo "\n";
+        echo $this->colors->wrap('AVAILABLE PLUGINS:', Colors::C_BROWN);
+        echo "\n";
+
+        $list = $plugin_controller->getList('cli');
+        sort($list);
+        if(!count($list)) {
+            echo $this->colors->wrap("  No plugins providing CLI components available\n", Colors::C_RED);
+        } else {
+            $tf = new \splitbrain\phpcli\TableFormatter($this->colors);
+
+            foreach($list as $name) {
+                $plugin = $this->loadPlugin($name);
+                if($plugin === null) continue;
+                $info = $plugin->getInfo();
+
+                echo $tf->format(
+                    [2, '30%', '*'],
+                    ['', $name, $info['desc']],
+                    ['', Colors::C_CYAN, '']
+
+                );
+            }
+        }
+    }
+
+    /**
+     * Instantiate a CLI plugin
+     *
+     * @param string $name
+     * @return DokuWiki_CLI_Plugin|null
+     */
+    protected
+    function loadPlugin($name) {
+        // execute the plugin CLI
+        $class = "cli_plugin_$name";
+        if(class_exists($class)) {
+            return new $class();
+        }
+        return null;
+    }
+}
+
+// Main
+$cli = new PluginCLI();
+$cli->run();
diff --git a/bin/render.php b/bin/render.php
index 672993223466ba266dd8965761849b2c9163a21a..cc4a00314bd1626e4c9479414da3e5340dc2ee25 100755
--- a/bin/render.php
+++ b/bin/render.php
@@ -1,9 +1,12 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
-define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
 
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
+define('NOSESSION', 1);
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * A simple commandline tool to render some DokuWiki syntax with a given
@@ -16,20 +19,20 @@ require_once(DOKU_INC.'inc/init.php');
  * @license GPL2
  * @author  Andreas Gohr <andi@splitbrain.org>
  */
-class RenderCLI extends DokuCLI {
+class RenderCLI extends CLI {
 
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
         $options->setHelp(
-            'A simple commandline tool to render some DokuWiki syntax with a given renderer.'.
-            "\n\n".
-            'This may not work for plugins that expect a certain environment to be '.
-            'set up before rendering, but should work for most or even all standard '.
+            'A simple commandline tool to render some DokuWiki syntax with a given renderer.' .
+            "\n\n" .
+            'This may not work for plugins that expect a certain environment to be ' .
+            'set up before rendering, but should work for most or even all standard ' .
             'DokuWiki markup'
         );
         $options->registerOption('renderer', 'The renderer mode to use. Defaults to xhtml', 'r', 'mode');
@@ -40,16 +43,16 @@ class RenderCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @throws DokuCLI_Exception
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
+    protected function main(Options $options) {
         $renderer = $options->getOpt('renderer', 'xhtml');
 
         // do the action
         $source = stream_get_contents(STDIN);
-        $info   = array();
+        $info = array();
         $result = p_render($renderer, p_get_instructions($source), $info);
         if(is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer");
         echo $result;
@@ -58,4 +61,4 @@ class RenderCLI extends DokuCLI {
 
 // Main
 $cli = new RenderCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/bin/striplangs.php b/bin/striplangs.php
index 82d27d4627a9e80a26c64d04241ba41c1a3b0ec1..1800971e547f6583467e8bdb895051a7314e428a 100755
--- a/bin/striplangs.php
+++ b/bin/striplangs.php
@@ -1,25 +1,28 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
-define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
 
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
+define('NOSESSION', 1);
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * Remove unwanted languages from a DokuWiki install
  */
-class StripLangsCLI extends DokuCLI {
+class StripLangsCLI extends CLI {
 
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
 
         $options->setHelp(
-            'Remove all languages from the installation, besides the ones specified. English language '.
+            'Remove all languages from the installation, besides the ones specified. English language ' .
             'is never removed!'
         );
 
@@ -41,10 +44,10 @@ class StripLangsCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
+    protected function main(Options $options) {
         if($options->getOpt('keep')) {
             $keep = explode(',', $options->getOpt('keep'));
             if(!in_array('en', $keep)) $keep[] = 'en';
@@ -56,16 +59,16 @@ class StripLangsCLI extends DokuCLI {
         }
 
         // Kill all language directories in /inc/lang and /lib/plugins besides those in $langs array
-        $this->stripDirLangs(realpath(dirname(__FILE__).'/../inc/lang'), $keep);
-        $this->processExtensions(realpath(dirname(__FILE__).'/../lib/plugins'), $keep);
-        $this->processExtensions(realpath(dirname(__FILE__).'/../lib/tpl'), $keep);
+        $this->stripDirLangs(realpath(dirname(__FILE__) . '/../inc/lang'), $keep);
+        $this->processExtensions(realpath(dirname(__FILE__) . '/../lib/plugins'), $keep);
+        $this->processExtensions(realpath(dirname(__FILE__) . '/../lib/tpl'), $keep);
     }
 
     /**
      * Strip languages from extensions
      *
-     * @param string $path       path to plugin or template dir
-     * @param array  $keep_langs languages to keep
+     * @param string $path path to plugin or template dir
+     * @param array $keep_langs languages to keep
      */
     protected function processExtensions($path, $keep_langs) {
         if(is_dir($path)) {
@@ -73,9 +76,9 @@ class StripLangsCLI extends DokuCLI {
 
             foreach($entries as $entry) {
                 if($entry != "." && $entry != "..") {
-                    if(is_dir($path.'/'.$entry)) {
+                    if(is_dir($path . '/' . $entry)) {
 
-                        $plugin_langs = $path.'/'.$entry.'/lang';
+                        $plugin_langs = $path . '/' . $entry . '/lang';
 
                         if(is_dir($plugin_langs)) {
                             $this->stripDirLangs($plugin_langs, $keep_langs);
@@ -89,17 +92,17 @@ class StripLangsCLI extends DokuCLI {
     /**
      * Strip languages from path
      *
-     * @param string $path       path to lang dir
-     * @param array  $keep_langs languages to keep
+     * @param string $path path to lang dir
+     * @param array $keep_langs languages to keep
      */
     protected function stripDirLangs($path, $keep_langs) {
         $dir = dir($path);
 
         while(($cur_dir = $dir->read()) !== false) {
-            if($cur_dir != '.' and $cur_dir != '..' and is_dir($path.'/'.$cur_dir)) {
+            if($cur_dir != '.' and $cur_dir != '..' and is_dir($path . '/' . $cur_dir)) {
 
                 if(!in_array($cur_dir, $keep_langs, true)) {
-                    io_rmdir($path.'/'.$cur_dir, true);
+                    io_rmdir($path . '/' . $cur_dir, true);
                 }
             }
         }
@@ -108,4 +111,4 @@ class StripLangsCLI extends DokuCLI {
 }
 
 $cli = new StripLangsCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/bin/wantedpages.php b/bin/wantedpages.php
index 54bfd47558a76452464a8fb5d86f707cc9c1ec09..0240eb958e0fe2e1b73b97c22d123cf8fedd6575 100755
--- a/bin/wantedpages.php
+++ b/bin/wantedpages.php
@@ -1,33 +1,56 @@
 #!/usr/bin/php
 <?php
-if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
 define('NOSESSION', 1);
-require_once(DOKU_INC.'inc/init.php');
+require_once(DOKU_INC . 'inc/init.php');
 
 /**
  * Find wanted pages
  */
-class WantedPagesCLI extends DokuCLI {
+class WantedPagesCLI extends CLI {
 
     const DIR_CONTINUE = 1;
-    const DIR_NS       = 2;
-    const DIR_PAGE     = 3;
+    const DIR_NS = 2;
+    const DIR_PAGE = 3;
+
+    private $skip = false;
+    private $sort = 'wanted';
+
+    private $result = array();
 
     /**
      * Register options and arguments on the given $options object
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function setup(DokuCLI_Options $options) {
+    protected function setup(Options $options) {
         $options->setHelp(
-            'Outputs a list of wanted pages (pages which have internal links but do not yet exist).'
+            'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
+            ' (the pages that are linkin to these missing pages).'
         );
         $options->registerArgument(
             'namespace',
             'The namespace to lookup. Defaults to root namespace',
             false
         );
+
+        $options->registerOption(
+            'sort',
+            'Sort by wanted or origin page',
+            's',
+            '(wanted|origin)'
+        );
+
+        $options->registerOption(
+            'skip',
+            'Do not show the second dimension',
+            'k'
+        );
     }
 
     /**
@@ -35,29 +58,36 @@ class WantedPagesCLI extends DokuCLI {
      *
      * Arguments and options have been parsed when this is run
      *
-     * @param DokuCLI_Options $options
+     * @param Options $options
      * @return void
      */
-    protected function main(DokuCLI_Options $options) {
-
-        if($options->args) {
-            $startdir = dirname(wikiFN($options->args[0].':xxx'));
+    protected function main(Options $options) {
+        $args = $options->getArgs();
+        if($args) {
+            $startdir = dirname(wikiFN($args[0] . ':xxx'));
         } else {
             $startdir = dirname(wikiFN('xxx'));
         }
 
-        $this->info("searching $startdir");
+        $this->skip = $options->getOpt('skip');
+        $this->sort = $options->getOpt('sort');
 
-        $wanted_pages = array();
+        $this->info("searching $startdir");
 
         foreach($this->get_pages($startdir) as $page) {
-            $wanted_pages = array_merge($wanted_pages, $this->internal_links($page));
+            $this->internal_links($page);
         }
-        $wanted_pages = array_unique($wanted_pages);
-        sort($wanted_pages);
-
-        foreach($wanted_pages as $page) {
-            print $page."\n";
+        ksort($this->result);
+        foreach($this->result as $main => $subs) {
+            if($this->skip) {
+                print "$main\n";
+            } else {
+                $subs = array_unique($subs);
+                sort($subs);
+                foreach($subs as $sub) {
+                    printf("%-40s %s\n", $main, $sub);
+                }
+            }
         }
     }
 
@@ -72,7 +102,7 @@ class WantedPagesCLI extends DokuCLI {
         if($entry == '.' || $entry == '..') {
             return WantedPagesCLI::DIR_CONTINUE;
         }
-        if(is_dir($basepath.'/'.$entry)) {
+        if(is_dir($basepath . '/' . $entry)) {
             if(strpos($entry, '_') === 0) {
                 return WantedPagesCLI::DIR_CONTINUE;
             }
@@ -95,7 +125,7 @@ class WantedPagesCLI extends DokuCLI {
         static $trunclen = null;
         if(!$trunclen) {
             global $conf;
-            $trunclen = strlen($conf['datadir'].':');
+            $trunclen = strlen($conf['datadir'] . ':');
         }
 
         if(!is_dir($dir)) {
@@ -103,17 +133,17 @@ class WantedPagesCLI extends DokuCLI {
         }
 
         $pages = array();
-        $dh    = opendir($dir);
+        $dh = opendir($dir);
         while(false !== ($entry = readdir($dh))) {
             $status = $this->dir_filter($entry, $dir);
             if($status == WantedPagesCLI::DIR_CONTINUE) {
                 continue;
             } else if($status == WantedPagesCLI::DIR_NS) {
-                $pages = array_merge($pages, $this->get_pages($dir.'/'.$entry));
+                $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
             } else {
-                $page    = array(
-                    'id'   => pathID(substr($dir.'/'.$entry, $trunclen)),
-                    'file' => $dir.'/'.$entry,
+                $page = array(
+                    'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
+                    'file' => $dir . '/' . $entry,
                 );
                 $pages[] = $page;
             }
@@ -123,31 +153,34 @@ class WantedPagesCLI extends DokuCLI {
     }
 
     /**
-     * Parse instructions and returns the non-existing links
+     * Parse instructions and add the non-existing links to the result array
      *
      * @param array $page array with page id and file path
-     * @return array
      */
     function internal_links($page) {
         global $conf;
         $instructions = p_get_instructions(file_get_contents($page['file']));
-        $links        = array();
-        $cns          = getNS($page['id']);
-        $exists       = false;
+        $cns = getNS($page['id']);
+        $exists = false;
+        $pid = $page['id'];
         foreach($instructions as $ins) {
             if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
                 $mid = $ins[1][0];
                 resolve_pageid($cns, $mid, $exists);
                 if(!$exists) {
-                    list($mid) = explode('#', $mid); //record pages without hashs
-                    $links[] = $mid;
+                    list($mid) = explode('#', $mid); //record pages without hashes
+
+                    if($this->sort == 'origin') {
+                        $this->result[$pid][] = $mid;
+                    } else {
+                        $this->result[$mid][] = $pid;
+                    }
                 }
             }
         }
-        return $links;
     }
 }
 
 // Main
 $cli = new WantedPagesCLI();
-$cli->run();
\ No newline at end of file
+$cli->run();
diff --git a/composer.json b/composer.json
index 715f97dbf0041016b22e4c42df350191fcf42f87..948b97a62c878735baa178e31b3a3c736e5810ee 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,15 @@
         "paragonie/random_compat": "^2.0",
         "simplepie/simplepie": "^1.4",
         "geshi/geshi": "^1.0",
-        "openpsa/universalfeedcreator": "^1.8"
+        "openpsa/universalfeedcreator": "^1.8",
+        "aziraphale/email-address-validator": "^2",
+        "marcusschwarz/lesserphp": "^0.5.1",
+        "splitbrain/php-cli": "^1.1"
+    },
+    "config": {
+        "platform": {
+            "php": "5.6"
+        }
     },
     "suggest": {
         "squizlabs/php_codesniffer": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
diff --git a/composer.lock b/composer.lock
index e830d3882c76e867501381e7080f76ac606bf1a7..9f6f6849c5eb31f7bc2b256c666805b9c2593ced 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,49 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "915e6fb408fdf5780e4f49b03325adcd",
+    "content-hash": "d5c15248668d2dd749de47b106049b77",
     "packages": [
+        {
+            "name": "aziraphale/email-address-validator",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/aziraphale/email-address-validator.git",
+                "reference": "fa25bc22c1c0b6491657c91473fae3e40719a650"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/aziraphale/email-address-validator/zipball/fa25bc22c1c0b6491657c91473fae3e40719a650",
+                "reference": "fa25bc22c1c0b6491657c91473fae3e40719a650",
+                "shasum": ""
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "EmailAddressValidator": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Dave Child",
+                    "email": "dave@addedbytes.com"
+                },
+                {
+                    "name": "Andrew Gillard",
+                    "email": "andrew@lorddeath.net"
+                }
+            ],
+            "description": "Fork of AddedBytes' PHP EmailAddressValidator script, now with Composer support!",
+            "homepage": "https://github.com/aziraphale/email-address-validator",
+            "time": "2017-05-22T14:05:57+00:00"
+        },
         {
             "name": "geshi/geshi",
             "version": "v1.0.9.0",
@@ -46,6 +87,58 @@
             "homepage": "http://qbnz.com/highlighter/",
             "time": "2017-05-05T05:51:25+00:00"
         },
+        {
+            "name": "marcusschwarz/lesserphp",
+            "version": "v0.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/MarcusSchwarz/lesserphp.git",
+                "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/MarcusSchwarz/lesserphp/zipball/e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
+                "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
+                "shasum": ""
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.3"
+            },
+            "bin": [
+                "plessc"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.5.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "lessc.inc.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT",
+                "GPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Leaf Corcoran",
+                    "email": "leafot@gmail.com",
+                    "homepage": "http://leafo.net"
+                },
+                {
+                    "name": "Marcus Schwarz",
+                    "email": "github@maswaba.de",
+                    "homepage": "https://www.maswaba.de"
+                }
+            ],
+            "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.",
+            "homepage": "http://leafo.net/lessphp/",
+            "time": "2016-09-30T11:13:18+00:00"
+        },
         {
             "name": "openpsa/universalfeedcreator",
             "version": "v1.8.3",
@@ -96,16 +189,16 @@
         },
         {
             "name": "paragonie/random_compat",
-            "version": "v2.0.10",
+            "version": "v2.0.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
+                "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
-                "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
+                "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
                 "shasum": ""
             },
             "require": {
@@ -140,20 +233,20 @@
                 "pseudorandom",
                 "random"
             ],
-            "time": "2017-03-13T16:27:32+00:00"
+            "time": "2018-04-04T21:24:14+00:00"
         },
         {
             "name": "phpseclib/phpseclib",
-            "version": "2.0.4",
+            "version": "2.0.10",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpseclib/phpseclib.git",
-                "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf"
+                "reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
-                "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d305b780829ea4252ed9400b3f5937c2c99b51d4",
+                "reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4",
                 "shasum": ""
             },
             "require": {
@@ -161,7 +254,7 @@
             },
             "require-dev": {
                 "phing/phing": "~2.7",
-                "phpunit/phpunit": "~4.0",
+                "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
                 "sami/sami": "~2.0",
                 "squizlabs/php_codesniffer": "~2.0"
             },
@@ -232,20 +325,20 @@
                 "x.509",
                 "x509"
             ],
-            "time": "2016-10-04T00:57:04+00:00"
+            "time": "2018-02-19T04:29:13+00:00"
         },
         {
             "name": "simplepie/simplepie",
-            "version": "1.4.3",
+            "version": "1.5.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplepie/simplepie.git",
-                "reference": "2a24b6e74aa9bf33243020f52895fe77efe94ccf"
+                "reference": "db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplepie/simplepie/zipball/2a24b6e74aa9bf33243020f52895fe77efe94ccf",
-                "reference": "2a24b6e74aa9bf33243020f52895fe77efe94ccf",
+                "url": "https://api.github.com/repos/simplepie/simplepie/zipball/db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e",
+                "reference": "db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e",
                 "shasum": ""
             },
             "require": {
@@ -292,20 +385,20 @@
                 "feeds",
                 "rss"
             ],
-            "time": "2016-11-27T01:39:18+00:00"
+            "time": "2017-11-12T02:03:34+00:00"
         },
         {
             "name": "splitbrain/php-archive",
-            "version": "1.0.8",
+            "version": "1.0.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/splitbrain/php-archive.git",
-                "reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c"
+                "reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/splitbrain/php-archive/zipball/6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
-                "reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
+                "url": "https://api.github.com/repos/splitbrain/php-archive/zipball/2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
+                "reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
                 "shasum": ""
             },
             "require": {
@@ -343,7 +436,58 @@
                 "unzip",
                 "zip"
             ],
-            "time": "2017-03-19T09:10:53+00:00"
+            "time": "2017-06-11T06:11:38+00:00"
+        },
+        {
+            "name": "splitbrain/php-cli",
+            "version": "1.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/splitbrain/php-cli.git",
+                "reference": "1d6f0bf9eccbfd79d1f4d185ef27573601185c23"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/splitbrain/php-cli/zipball/1d6f0bf9eccbfd79d1f4d185ef27573601185c23",
+                "reference": "1d6f0bf9eccbfd79d1f4d185ef27573601185c23",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.5.*"
+            },
+            "suggest": {
+                "psr/log": "Allows you to make the CLI available as PSR-3 logger"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "splitbrain\\phpcli\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Andreas Gohr",
+                    "email": "andi@splitbrain.org"
+                }
+            ],
+            "description": "Easy command line scripts for PHP with opt parsing and color output. No dependencies",
+            "keywords": [
+                "argparse",
+                "cli",
+                "command line",
+                "console",
+                "getopt",
+                "optparse",
+                "terminal"
+            ],
+            "time": "2018-02-02T08:46:12+00:00"
         }
     ],
     "packages-dev": [],
@@ -355,5 +499,8 @@
     "platform": {
         "php": ">=5.6"
     },
-    "platform-dev": []
+    "platform-dev": [],
+    "platform-overrides": {
+        "php": "5.6"
+    }
 }
diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php
index 5b725063de3c6862208d2163d0b5b0fb7e8c8264..d57cf1c57d0b19888671cdc9a929bc5628aaa5f6 100644
--- a/conf/dokuwiki.php
+++ b/conf/dokuwiki.php
@@ -108,6 +108,7 @@ $conf['subscribe_time'] = 24*60*60;      //Time after which digests / lists are
 $conf['notify']      = '';               //send change info to this email (leave blank for nobody)
 $conf['registernotify'] = '';            //send info about newly registered users to this email (leave blank for nobody)
 $conf['mailfrom']    = '';               //use this email when sending mails
+$conf['mailreturnpath']    = '';         //use this email as returnpath for bounce mails
 $conf['mailprefix']  = '';               //use this as prefix of outgoing mails
 $conf['htmlmail']    = 1;                //send HTML multipart mails
 
@@ -155,6 +156,8 @@ $conf['broken_iua']  = 0;                //Platform with broken ignore_user_abor
 $conf['xsendfile']   = 0;                //Use X-Sendfile (1 = lighttpd, 2 = standard)
 $conf['renderer_xhtml'] = 'xhtml';       //renderer to use for main page generation
 $conf['readdircache'] = 0;               //time cache in second for the readdir operation, 0 to deactivate.
+$conf['search_nslimit'] = 0;             //limit the search to the current X namespaces
+$conf['search_fragment'] = 'exact';      //specify the default fragment search behavior
 
 /* Network Settings */
 $conf['dnslookups'] = 1;                 //disable to disallow IP to hostname lookups
diff --git a/conf/manifest.json b/conf/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..891bd79fbfe119c185a3dc5606063eeda60ccc47
--- /dev/null
+++ b/conf/manifest.json
@@ -0,0 +1,3 @@
+{
+    "display": "standalone"
+}
diff --git a/conf/mime.conf b/conf/mime.conf
index c2e03b775de1a2f2b93dce41f9eaa7d3414fe93f..56b72a42cfe140323c726bc89e30a6a46a51a3a3 100644
--- a/conf/mime.conf
+++ b/conf/mime.conf
@@ -15,6 +15,7 @@ wav     audio/wav
 webm    video/webm
 ogv     video/ogg
 mp4     video/mp4
+vtt     text/vtt
 
 tgz     !application/octet-stream
 tar     !application/x-gtar
diff --git a/conf/users.auth.php.dist b/conf/users.auth.php.dist
index df3c7848278b83255ce80df3b209dd1696e768f5..8231aa5c133c090d8445c6735cb507b3cef9dad2 100644
--- a/conf/users.auth.php.dist
+++ b/conf/users.auth.php.dist
@@ -6,5 +6,5 @@
 #
 # Format:
 #
-# login:passwordhash:Real Name:email:groups,comma,seperated
+# login:passwordhash:Real Name:email:groups,comma,separated
 
diff --git a/data/deleted.files b/data/deleted.files
index 0188e1c9ee7ec42104deebaad1a309749f92c3a2..9c0b125527ef8f7dc085c4f9a87bc091b147ef9e 100644
--- a/data/deleted.files
+++ b/data/deleted.files
@@ -2,6 +2,9 @@
 # but were removed later. An up to date DokuWiki should not have any of
 # the files installed
 
+# removed in 2018-01-06
+inc/plugin.php
+
 # remove in 2017-02-19
 inc/SimplePie.php
 inc/Tar.class.php
diff --git a/data/security.png b/data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png
similarity index 100%
rename from data/security.png
rename to data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png
diff --git a/data/security.xcf b/data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.xcf
similarity index 100%
rename from data/security.xcf
rename to data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.xcf
diff --git a/data/media/wiki/dokuwiki.svg b/data/media/wiki/dokuwiki.svg
new file mode 100644
index 0000000000000000000000000000000000000000..6e522c8b2735690091e42ee6d869446c5a922ae1
--- /dev/null
+++ b/data/media/wiki/dokuwiki.svg
@@ -0,0 +1,586 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="128.17094"
+   height="128.03864"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.48.1 "
+   sodipodi:docname="dokuwiki-logo.svg"
+   version="1.1">
+  <title
+     id="title3181">DokuWiki Logo</title>
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient2624">
+      <stop
+         style="stop-color:#3a9030;stop-opacity:0.83673471;"
+         offset="0"
+         id="stop2626" />
+      <stop
+         style="stop-color:#3d9c32;stop-opacity:0.79591835;"
+         offset="1"
+         id="stop2628" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2612">
+      <stop
+         style="stop-color:#25901b;stop-opacity:0.83673471;"
+         offset="0"
+         id="stop2614" />
+      <stop
+         style="stop-color:#25901b;stop-opacity:0.37755102;"
+         offset="1"
+         id="stop2616" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2600">
+      <stop
+         style="stop-color:#e32525;stop-opacity:0.81632656;"
+         offset="0"
+         id="stop2602" />
+      <stop
+         style="stop-color:#e32525;stop-opacity:0.5714286;"
+         offset="1"
+         id="stop2604" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible">
+      <path
+         id="path2488"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.8,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path2571"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,-5.5,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       id="linearGradient2408">
+      <stop
+         id="stop2410"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:0.17346939;" />
+      <stop
+         id="stop2412"
+         offset="1"
+         style="stop-color:#c7cec2;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2389">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.17346939;"
+         offset="0"
+         id="stop2391" />
+      <stop
+         style="stop-color:#c7cec2;stop-opacity:0;"
+         offset="1"
+         id="stop2393" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2370">
+      <stop
+         style="stop-color:#fbfaf9;stop-opacity:1;"
+         offset="0"
+         id="stop2372" />
+      <stop
+         style="stop-color:#e9dac7;stop-opacity:1;"
+         offset="1"
+         id="stop2374" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2364">
+      <stop
+         id="stop2366"
+         offset="0"
+         style="stop-color:#fbf6f0;stop-opacity:1;" />
+      <stop
+         id="stop2368"
+         offset="1"
+         style="stop-color:#e9dac7;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2348">
+      <stop
+         style="stop-color:#fbf6f0;stop-opacity:1;"
+         offset="0"
+         id="stop2350" />
+      <stop
+         style="stop-color:#e9dac7;stop-opacity:1;"
+         offset="1"
+         id="stop2352" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2332">
+      <stop
+         style="stop-color:#ede1ae;stop-opacity:1;"
+         offset="0"
+         id="stop2334" />
+      <stop
+         style="stop-color:#fefdfa;stop-opacity:1;"
+         offset="1"
+         id="stop2336" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2249">
+      <stop
+         style="stop-color:#00a423;stop-opacity:1;"
+         offset="0"
+         id="stop2251" />
+      <stop
+         style="stop-color:#00b427;stop-opacity:1;"
+         offset="1"
+         id="stop2253" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2229">
+      <stop
+         id="stop2231"
+         offset="0"
+         style="stop-color:#00b62b;stop-opacity:1;" />
+      <stop
+         id="stop2233"
+         offset="1"
+         style="stop-color:#a1d784;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2213">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop2215" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop2217" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2360">
+      <stop
+         style="stop-color:#d69c00;stop-opacity:1;"
+         offset="0"
+         id="stop2362" />
+      <stop
+         style="stop-color:#ffe658;stop-opacity:1;"
+         offset="1"
+         id="stop2364" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2352">
+      <stop
+         id="stop2354"
+         offset="0"
+         style="stop-color:#ce411e;stop-opacity:1;" />
+      <stop
+         id="stop2356"
+         offset="1"
+         style="stop-color:#ecad8d;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2336">
+      <stop
+         style="stop-color:#8f2a15;stop-opacity:1;"
+         offset="0"
+         id="stop2338" />
+      <stop
+         style="stop-color:#c8381b;stop-opacity:1;"
+         offset="1"
+         id="stop2340" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2336"
+       id="linearGradient2342"
+       x1="219.21262"
+       y1="189.01556"
+       x2="286.22665"
+       y2="189.01556"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2352"
+       id="linearGradient2350"
+       x1="219.66267"
+       y1="192.73286"
+       x2="277.8761"
+       y2="192.73286"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2360"
+       id="radialGradient2366"
+       cx="224.41418"
+       cy="212.80016"
+       fx="224.41418"
+       fy="212.80016"
+       r="8.6813803"
+       gradientTransform="matrix(1,0,0,0.984179,0,3.366635)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2249"
+       id="linearGradient2227"
+       x1="192.03938"
+       y1="262.25757"
+       x2="263.67093"
+       y2="262.25757"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2229"
+       id="linearGradient2247"
+       x1="191.75092"
+       y1="258.91571"
+       x2="255.6561"
+       y2="258.91571"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2360"
+       id="radialGradient2317"
+       cx="257.41144"
+       cy="274.64203"
+       fx="257.41144"
+       fy="274.64203"
+       r="7.1440549"
+       gradientTransform="matrix(1,0,0,1.631384,0,-173.4045)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2360"
+       id="linearGradient2325"
+       x1="184.07063"
+       y1="246.35907"
+       x2="201.40646"
+       y2="246.35907"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2332"
+       id="linearGradient2346"
+       x1="162.76369"
+       y1="184.99277"
+       x2="240.84924"
+       y2="289.50323"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2348"
+       id="linearGradient2354"
+       x1="140.15784"
+       y1="303.78967"
+       x2="136.14151"
+       y2="195.87151"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2370"
+       id="linearGradient2362"
+       x1="286.15598"
+       y1="262.28729"
+       x2="185.81258"
+       y2="172.32423"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2389"
+       id="linearGradient2395"
+       x1="213.96568"
+       y1="220.07191"
+       x2="244.79126"
+       y2="265.40363"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2408"
+       id="linearGradient2406"
+       x1="184.30582"
+       y1="241.52789"
+       x2="224.67441"
+       y2="307.52844"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2600"
+       id="linearGradient2606"
+       x1="202.41772"
+       y1="222.05145"
+       x2="206.06017"
+       y2="210.3558"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2612"
+       id="linearGradient2618"
+       x1="248.62152"
+       y1="234.52202"
+       x2="251.64362"
+       y2="213.12164"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2624"
+       id="linearGradient2630"
+       x1="275.71765"
+       y1="251.56442"
+       x2="255.68353"
+       y2="217.94008"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2352"
+       id="linearGradient2640"
+       gradientUnits="userSpaceOnUse"
+       x1="219.66267"
+       y1="192.73286"
+       x2="277.8761"
+       y2="192.73286" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2336"
+       id="linearGradient2643"
+       gradientUnits="userSpaceOnUse"
+       x1="219.21262"
+       y1="189.01556"
+       x2="286.22665"
+       y2="189.01556" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2360"
+       id="radialGradient2647"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.984179,0,3.366635)"
+       cx="224.41418"
+       cy="212.80016"
+       fx="224.41418"
+       fy="212.80016"
+       r="8.6813803" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.03"
+     inkscape:cx="35.144424"
+     inkscape:cy="83.160427"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer3"
+     inkscape:window-width="1366"
+     inkscape:window-height="716"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-maximized="1"
+     inkscape:showpageshadow="false"
+     showborder="true"
+     borderlayer="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>DokuWiki Logo</dc:title>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Esther Brunner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <cc:license
+           rdf:resource="http://www.gnu.org/licenses/gpl-2.0.html" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="paper"
+     style="display:inline"
+     transform="translate(-158.10602,-158.67323)">
+    <g
+       id="g1419"
+       transform="matrix(0.99993322,0,0,0.9959778,0.01483419,0.8957919)">
+      <g
+         id="g2376">
+        <path
+           transform="matrix(0.989976,-0.141236,0.201069,0.979577,0,0)"
+           style="fill:url(#linearGradient2354);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.7216621px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+           d="m 120.21543,196.43769 70.90655,-0.79226 -2.40261,109.05308 -71.71761,0.37344 3.21367,-108.63426 z"
+           id="rect1422"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2362);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+           d="m 179.20033,182.08731 79.84173,-19.51687 26.61391,101.72428 -82.50312,21.58684 -23.95252,-103.79425 z"
+           id="rect1425"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="matrix(0.995676,-0.09289891,0.08102261,0.996712,0,0)"
+           style="fill:url(#linearGradient2346);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00418305px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+           d="m 159.01353,181.74387 85.58587,0.53396 0,110.47429 -84.53387,-2.5127 -1.052,-108.49555 z"
+           id="rect1419"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+      </g>
+      <path
+         id="text2382"
+         d="m 167.55116,214.00773 0,-20.1846 5.34962,0 0,2.37403 -2.48145,0 0,15.43654 2.48145,0 0,2.37403 -5.34962,0 m 7.34767,0 0,-20.1846 5.34961,0 0,2.37403 -2.48144,0 0,15.43654 2.48144,0 0,2.37403 -5.34961,0 m 7.36915,-20.1846 5.81153,0 c 1.31054,2e-5 2.30956,0.10028 2.99707,0.30078 0.92382,0.27216 1.71516,0.75555 2.37403,1.4502 0.65884,0.69468 1.16014,1.54689 1.50391,2.55664 0.34373,1.00262 0.51561,2.24155 0.51562,3.71681 -10e-6,1.29623 -0.16115,2.41342 -0.4834,3.35156 -0.39389,1.14584 -0.95607,2.07325 -1.68652,2.78223 -0.55145,0.53711 -1.29624,0.95606 -2.23438,1.25684 -0.70183,0.222 -1.63999,0.33301 -2.81446,0.33301 l -5.9834,0 0,-15.74807 m 3.17969,2.66407 0,10.43067 2.37402,0 c 0.88802,1e-5 1.52897,-0.0501 1.92286,-0.15039 0.51561,-0.1289 0.94172,-0.34732 1.27832,-0.65527 0.34374,-0.30794 0.62304,-0.81282 0.83789,-1.51465 0.21483,-0.70898 0.32226,-1.6722 0.32227,-2.88965 -1e-5,-1.21744 -0.10744,-2.15201 -0.32227,-2.80372 -0.21485,-0.65168 -0.51563,-1.16014 -0.90234,-1.52539 -0.38673,-0.36522 -0.87729,-0.61229 -1.47168,-0.74121 -0.44402,-0.10025 -1.31414,-0.15038 -2.61036,-0.15039 l -1.42871,0 m 14.96388,13.084 -3.75977,-15.74807 3.25489,0 2.37403,10.8174 2.87891,-10.8174 3.78125,0 2.76074,11.00002 2.417,-11.00002 3.20118,0 -3.82423,15.74807 -3.37305,0 -3.13672,-11.77345 -3.12598,11.77345 -3.44825,0 m 22.76272,-15.74807 0,20.1846 -5.34961,0 0,-2.37403 2.48145,0 0,-15.45803 -2.48145,0 0,-2.35254 5.34961,0 m 7.34767,0 0,20.1846 -5.34962,0 0,-2.37403 2.48145,0 0,-15.45803 -2.48145,0 0,-2.35254 5.34962,0"
+         style="font-size:12.0000124px;font-style:normal;font-weight:normal;line-height:125%;fill:#6184a3;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans"
+         transform="matrix(0.995433,-0.09546066,0.09546066,0.995433,0,0)"
+         inkscape:connector-curvature="0" />
+      <g
+         id="g2632"
+         style="display:inline">
+        <path
+           style="fill:url(#linearGradient2606);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker-end:none"
+           d="m 174.75585,201.60224 c -6.04576,2.46667 -10.16789,4.4194 -12.88454,6.35064 -2.71665,1.93124 -3.19257,4.60007 -3.24631,6.26587 -0.0269,0.8329 0.0809,1.77774 0.63189,2.44014 0.55103,0.6624 1.80769,1.87421 2.75794,2.38558 1.90049,1.02274 7.5417,2.42901 10.51899,3.07308 11.90917,2.57627 26.80568,1.68117 26.80568,1.68117 1.69307,1.2452 2.83283,2.82434 3.269,4.26902 4.5766,-1.88674 11.81084,-6.58439 13.15657,-8.57706 -5.45142,-4.19955 -10.79692,-6.33346 -16.51317,-8.30847 -1.59867,-0.71918 -2.87956,-1.22649 -0.71773,2.55635 0.98506,2.47275 0.85786,5.05143 0.57176,7.41825 0,0 -16.52749,0.40678 -28.23838,-2.1266 -2.92772,-0.63334 -5.46627,-0.95523 -7.21875,-1.89832 -0.87624,-0.47154 -1.48296,-0.8208 -1.91578,-1.3411 -0.43282,-0.5203 -0.2196,-1.29055 -0.20128,-1.85858 0.0366,-1.13607 0.25336,-1.67063 2.86177,-3.52492 2.60841,-1.85429 5.65407,-3.36195 11.65936,-5.81211 -0.0877,-1.29125 -0.29025,-2.5059 -1.29702,-2.99294 z"
+           id="path2414"
+           sodipodi:nodetypes="csssssccccccssssscc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2618);fill-opacity:1;fill-rule:evenodd;stroke:none"
+           d="m 269.62539,220.7482 c -1.43576,-0.13963 -2.58044,0.30288 -2.56084,1.50218 0.94391,0.85652 1.34942,2.43518 1.48562,3.14008 0.1362,0.7049 0.0359,1.21914 -0.48562,1.89004 -1.043,1.3418 -3.12498,1.56875 -6.5006,2.72063 -6.75124,2.30377 -16.89306,2.52561 -27.90689,3.84639 -22.02767,2.64157 -39.03164,3.76107 -39.03164,3.76107 1.98346,-4.64758 6.32828,-4.41197 6.34903,-8.20969 0.27376,-0.89755 -3.14597,-1.31638 -5.09943,-0.10731 -4.26694,3.70137 -7.59152,6.75353 -10.69418,10.51311 l 1.88795,3.08438 c 0,0 26.13006,-2.88973 48.19776,-5.5361 11.03385,-1.32318 20.95601,-1.99856 27.80968,-4.33728 3.42683,-1.16936 5.95975,-1.49022 7.6409,-3.51958 0.63172,-0.76256 1.35238,-3.04699 1.06804,-4.73369 -0.21951,-1.30213 -1.14979,-3.09774 -2.15978,-4.01423 z"
+           id="path2608"
+           sodipodi:nodetypes="ccsssscccccssssc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2630);fill-opacity:1;fill-rule:evenodd;stroke:none"
+           d="m 254.36185,220.33948 c -6.84997,3.24198 -7.15311,8.60912 -5.95953,12.79884 1.19358,4.18972 5.26293,8.75677 9.32121,12.40608 8.11656,7.29861 12.06046,9.33163 12.06046,9.33163 -3.71515,-0.10342 -7.89887,-1.41174 -8.13315,0.49304 -0.9483,2.97582 11.49137,3.47486 17.43787,2.70205 -1.39456,-7.57836 -3.79323,-13.21546 -7.73151,-14.90312 -1.68464,-0.14804 0.31242,4.72441 0.76985,9.39604 0,0 -3.62454,-1.73122 -11.60519,-8.90762 -3.99032,-3.5882 -7.37386,-7.3421 -8.47319,-11.20099 -1.09933,-3.85889 0.0776,-6.1205 4.95082,-9.53176 0.92816,-0.99528 -1.28985,-2.45913 -2.63764,-2.58419 z"
+           id="path2620"
+           sodipodi:nodetypes="csscccccsscc"
+           inkscape:connector-curvature="0" />
+      </g>
+      <path
+         sodipodi:nodetypes="cccccc"
+         id="rect2386"
+         d="m 213.96569,234.57806 2.18756,-14.42897 15.21982,6.08793 21.49387,29.94828 -20.40591,9.21832 -18.49534,-30.82556 z"
+         style="fill:url(#linearGradient2395);fill-opacity:1;stroke:none;display:inline"
+         inkscape:connector-curvature="0" />
+      <g
+         id="g2649"
+         style="display:inline">
+        <path
+           style="fill:url(#radialGradient2647);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+           d="m 232.55816,219.5295 -15.92827,0.32199 3.08809,-15.15716 12.84018,14.83517 z"
+           id="path1443"
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#812310;fill-opacity:1;fill-rule:evenodd;stroke:none"
+           d="m 221.60041,219.29315 -4.41205,0.0782 0.85429,-3.98263 3.55776,3.90445 z"
+           id="path1452"
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2643);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+           d="m 269.44172,159.27421 0.098,8.91471 8.0581,8.72344 7.75906,0.7992 -52.80669,41.84092 -6.66532,-3.30696 -5.08243,-5.618 -1.08987,-5.91194 49.72911,-45.44137 z"
+           id="rect1437"
+           sodipodi:nodetypes="ccccccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2640);fill-opacity:1;fill-rule:evenodd;stroke:none"
+           d="m 268.94766,168.32844 8.3426,8.82719 -51.1007,38.68262 -4.9197,-5.4436 47.6778,-42.06621 z"
+           id="rect1446"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffe965;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+           d="m 285.33776,177.73216 -8.16219,-0.86619 -7.7518,-8.67862 0.0132,-9.14293 8.36213,0.75209 7.18862,9.57682 0.35007,8.35883 z"
+           id="path1440"
+           sodipodi:nodetypes="ccccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#cb391c;fill-opacity:1;fill-rule:evenodd;stroke:none"
+           d="m 280.72049,168.46367 0.1644,4.05654 -3.81335,-0.71676 -2.87504,-3.18901 -0.28089,-3.53393 3.85447,-0.16637 2.95041,3.54953 z"
+           id="path1449"
+           sodipodi:nodetypes="ccccccc"
+           inkscape:connector-curvature="0" />
+      </g>
+      <g
+         id="g2657"
+         style="display:inline">
+        <path
+           style="fill:url(#linearGradient2406);fill-opacity:1;stroke:none"
+           d="m 183.88617,256.82796 0.99991,-16.30721 17.2878,8.44012 26.05488,38.00946 -29.28095,-1.13363 -15.06164,-29.00874 z"
+           id="rect2397"
+           sodipodi:nodetypes="cccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2325);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
+           d="m 200.90647,238.44836 -8.04601,15.77386 -7.05577,-13.57337 15.10178,-2.20049 z"
+           id="rect2207"
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2227);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
+           d="m 201.05389,238.55401 62.11704,24.91912 -7.88689,3.21429 -4.35152,9.30976 1.1716,9.96396 -59.31453,-31.72759 -0.49402,-7.36382 3.09592,-5.82826 5.6624,-2.48746 z"
+           id="rect1328"
+           sodipodi:nodetypes="ccccccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#radialGradient2317);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
+           d="m 255.27801,266.53504 7.9241,-3.04772 0.85337,10.24037 -3.9011,8.28983 -8.04601,3.77919 -1.341,-9.63083 4.51064,-9.63084 z"
+           id="rect2204"
+           sodipodi:nodetypes="ccccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:url(#linearGradient2247);fill-opacity:1;stroke:none;display:inline"
+           d="m 195.7549,241.421 59.13059,24.7962 -4.5917,9.76614 -57.48995,-29.00967 2.95106,-5.55267 z"
+           id="rect2210"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#00b527;fill-opacity:1;stroke:none"
+           d="m 255.02263,275.21029 2.08411,-4.1069 2.96459,-1.06995 0.69433,3.37197 -1.76759,3.85723 -3.15516,1.38315 -0.82028,-3.4355 z"
+           id="rect2308"
+           sodipodi:nodetypes="ccccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#258209;fill-opacity:1;stroke:none;display:inline"
+           d="m 186.56849,241.00362 3.54963,-0.47312 -2.02297,3.53926 -1.52666,-3.06614 z"
+           id="rect2327"
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/doku.php b/doku.php
index 42624fd2e8d908ec1fdec72b87e603a8c0c9e24f..e6d58fc7609e1a3ecd3b6387334aa2354953b19b 100644
--- a/doku.php
+++ b/doku.php
@@ -9,7 +9,7 @@
  */
 
 // update message version - always use a string to avoid localized floats!
-$updateVersion = "49.2";
+$updateVersion = "50";
 
 //  xdebug_start_profiling();
 
@@ -35,7 +35,7 @@ require_once(DOKU_INC.'inc/init.php');
 
 //import variables
 $INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen
-$QUERY          = trim($INPUT->str('id'));
+$QUERY          = trim($INPUT->str('q'));
 $ID             = getID();
 
 $REV   = $INPUT->int('rev');
@@ -62,7 +62,7 @@ if($DATE_AT) {
     } else { // check for UNIX Timestamp
         $date_parse = @date('Ymd',$DATE_AT);
         if(!$date_parse || $date_parse === '19700101') {
-            msg(sprintf($lang['unable_to_parse_date'], $DATE_AT));
+            msg(sprintf($lang['unable_to_parse_date'], hsc($DATE_AT)));
             $DATE_AT = null;
         }
     }
@@ -90,10 +90,6 @@ if($DATE_AT) {
 //make infos about the selected page available
 $INFO = pageinfo();
 
-//export minimal info to JS, plugins can add more
-$JSINFO['id']        = $ID;
-$JSINFO['namespace'] = (string) $INFO['namespace'];
-
 // handle debugging
 if($conf['allowdebug'] && $ACT == 'debug') {
     html_debug();
diff --git a/feed.php b/feed.php
index ea4ed7c600a92c81e53af071fb6277db763cc75d..65d751b3ebab22375e853e1ec0a292469a522822 100644
--- a/feed.php
+++ b/feed.php
@@ -402,34 +402,30 @@ function rss_buildItems(&$rss, &$data, $opt) {
             // add user
             # FIXME should the user be pulled from metadata as well?
             $user         = @$ditem['user']; // the @ spares time repeating lookup
-            $item->author = '';
-            if($user && $conf['useacl'] && $auth) {
-                $userInfo = $auth->getUserData($user);
-                if($userInfo) {
-                    switch($conf['showuseras']) {
-                        case 'username':
-                        case 'username_link':
-                            $item->author = $userInfo['name'];
-                            break;
-                        default:
-                            $item->author = $user;
-                            break;
+            if(blank($user)) {
+                $item->author = 'Anonymous';
+                $item->authorEmail = 'anonymous@undisclosed.example.com';
+            } else {
+                $item->author = $user;
+                $item->authorEmail = $user . '@undisclosed.example.com';
+
+                // get real user name if configured
+                if($conf['useacl'] && $auth) {
+                    $userInfo = $auth->getUserData($user);
+                    if($userInfo) {
+                        switch($conf['showuseras']) {
+                            case 'username':
+                            case 'username_link':
+                                $item->author = $userInfo['name'];
+                                break;
+                            default:
+                                $item->author = $user;
+                                break;
+                        }
+                    } else {
+                        $item->author = $user;
                     }
-                } else {
-                    $item->author = $user;
                 }
-                if($userInfo && !$opt['guardmail']) {
-                    $item->authorEmail = $userInfo['mail'];
-                } else {
-                    //cannot obfuscate because some RSS readers may check validity
-                    $item->authorEmail = $user.'@'.$ditem['ip'];
-                }
-            } elseif($user) {
-                // this happens when no ACL but some Apache auth is used
-                $item->author      = $user;
-                $item->authorEmail = $user.'@'.$ditem['ip'];
-            } else {
-                $item->authorEmail = 'anonymous@'.$ditem['ip'];
             }
 
             // add category
diff --git a/inc/Action/AbstractAclAction.php b/inc/Action/AbstractAclAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..871edb0ae5dd750c76b747b5cba0294b30aeb648
--- /dev/null
+++ b/inc/Action/AbstractAclAction.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAclRequiredException;
+
+/**
+ * Class AbstractAclAction
+ *
+ * An action that requires the ACL subsystem to be enabled (eg. useacl=1)
+ *
+ * @package dokuwiki\Action
+ */
+abstract class AbstractAclAction extends AbstractAction {
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+        global $conf;
+        global $auth;
+        if(!$conf['useacl']) throw new ActionAclRequiredException();
+        if(!$auth) throw new ActionAclRequiredException();
+    }
+
+}
diff --git a/inc/Action/AbstractAction.php b/inc/Action/AbstractAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea862386eb6066c48f013f024443c7e6981a0b42
--- /dev/null
+++ b/inc/Action/AbstractAction.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionDisabledException;
+use dokuwiki\Action\Exception\ActionException;
+use dokuwiki\Action\Exception\FatalException;
+
+/**
+ * Class AbstractAction
+ *
+ * Base class for all actions
+ *
+ * @package dokuwiki\Action
+ */
+abstract class AbstractAction {
+
+    /** @var string holds the name of the action (lowercase class name, no namespace) */
+    protected $actionname;
+
+    /**
+     * AbstractAction constructor.
+     *
+     * @param string $actionname the name of this action (see getActionName() for caveats)
+     */
+    public function __construct($actionname = '') {
+        if($actionname !== '') {
+            $this->actionname = $actionname;
+        } else {
+            // http://stackoverflow.com/a/27457689/172068
+            $this->actionname = strtolower(substr(strrchr(get_class($this), '\\'), 1));
+        }
+    }
+
+    /**
+     * Return the minimum permission needed
+     *
+     * This needs to return one of the AUTH_* constants. It will be checked against
+     * the current user and page after checkPermissions() ran through. If it fails,
+     * the user will be shown the Denied action.
+     *
+     * @return int
+     */
+    abstract public function minimumPermission();
+
+    /**
+     * Check conditions are met to run this action
+     *
+     * @throws ActionException
+     * @return void
+     */
+    public function checkPreconditions() {
+    }
+
+    /**
+     * Process data
+     *
+     * This runs before any output is sent to the browser.
+     *
+     * Throw an Exception if a different action should be run after this step.
+     *
+     * @throws ActionException
+     * @return void
+     */
+    public function preProcess() {
+    }
+
+    /**
+     * Output whatever content is wanted within tpl_content();
+     *
+     * @fixme we may want to return a Ui class here
+     */
+    public function tplContent() {
+        throw new FatalException('No content for Action ' . $this->actionname);
+    }
+
+    /**
+     * Returns the name of this action
+     *
+     * This is usually the lowercased class name, but may differ for some actions.
+     * eg. the export_ modes or for the Plugin action.
+     *
+     * @return string
+     */
+    public function getActionName() {
+        return $this->actionname;
+    }
+}
diff --git a/inc/Action/AbstractAliasAction.php b/inc/Action/AbstractAliasAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..7240f5edf0f11ba6d89d48db162dde9bf54f1506
--- /dev/null
+++ b/inc/Action/AbstractAliasAction.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\FatalException;
+
+/**
+ * Class AbstractAliasAction
+ *
+ * An action that is an alias for another action. Skips the minimumPermission check
+ *
+ * Be sure to implement preProcess() and throw an ActionAbort exception
+ * with the proper action.
+ *
+ * @package dokuwiki\Action
+ */
+abstract class AbstractAliasAction extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    public function preProcess() {
+        throw new FatalException('Alias Actions need to implement preProcess to load the aliased action');
+    }
+
+}
diff --git a/inc/Action/AbstractUserAction.php b/inc/Action/AbstractUserAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4e3f1a4d995e0fc6ba0196a230b8f642d3bbfc8
--- /dev/null
+++ b/inc/Action/AbstractUserAction.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionUserRequiredException;
+
+/**
+ * Class AbstractUserAction
+ *
+ * An action that requires a logged in user
+ *
+ * @package dokuwiki\Action
+ */
+abstract class AbstractUserAction extends AbstractAclAction {
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+        global $INPUT;
+        if(!$INPUT->server->str('REMOTE_USER')) {
+            throw new ActionUserRequiredException();
+        }
+    }
+
+}
diff --git a/inc/Action/Admin.php b/inc/Action/Admin.php
new file mode 100644
index 0000000000000000000000000000000000000000..8d43057888fdd26c00e55f5cdc40bedcee954796
--- /dev/null
+++ b/inc/Action/Admin.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Admin
+ *
+ * Action to show the admin interface or admin plugins
+ *
+ * @package dokuwiki\Action
+ */
+class Admin extends AbstractUserAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+
+        if($INFO['ismanager']) {
+            return AUTH_READ; // let in check later
+        } else {
+            return AUTH_ADMIN;
+        }
+    }
+
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        global $INFO;
+        if(!$INFO['ismanager']) {
+            throw new ActionException('denied');
+        }
+    }
+
+    public function preProcess() {
+        global $INPUT;
+        global $INFO;
+
+        // retrieve admin plugin name from $_REQUEST['page']
+        if(($page = $INPUT->str('page', '', true)) != '') {
+            /** @var $plugin \DokuWiki_Admin_Plugin */
+            if($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
+                if($plugin->forAdminOnly() && !$INFO['isadmin']) {
+                    throw new ActionException('denied');
+                }
+                $plugin->handle();
+            }
+        }
+    }
+
+    public function tplContent() {
+        tpl_admin();
+    }
+
+}
diff --git a/inc/Action/Backlink.php b/inc/Action/Backlink.php
new file mode 100644
index 0000000000000000000000000000000000000000..0337917b35b363ab7145cf54d5dfa1cff389072f
--- /dev/null
+++ b/inc/Action/Backlink.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Backlink
+ *
+ * Shows which pages link to the current page
+ *
+ * @package dokuwiki\Action
+ */
+class Backlink extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_backlinks();
+    }
+
+}
diff --git a/inc/Action/Cancel.php b/inc/Action/Cancel.php
new file mode 100644
index 0000000000000000000000000000000000000000..c3e185534d94f97ad7e75e9138b135a7f75cacfe
--- /dev/null
+++ b/inc/Action/Cancel.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Cancel
+ *
+ * Alias for show. Aborts editing
+ *
+ * @package dokuwiki\Action
+ */
+class Cancel extends AbstractAliasAction {
+
+    public function preProcess() {
+        // continue with draftdel -> redirect -> show
+        throw new ActionAbort('draftdel');
+    }
+
+}
diff --git a/inc/Action/Check.php b/inc/Action/Check.php
new file mode 100644
index 0000000000000000000000000000000000000000..36ae8e8bd279da7f4581ca3f0b385b32e1097a03
--- /dev/null
+++ b/inc/Action/Check.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Check
+ *
+ * Adds some debugging info before aborting to show
+ *
+ * @package dokuwiki\Action
+ */
+class Check extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    public function preProcess() {
+        check();
+        throw new ActionAbort();
+    }
+
+}
diff --git a/inc/Action/Conflict.php b/inc/Action/Conflict.php
new file mode 100644
index 0000000000000000000000000000000000000000..d880b5b28f48d2ad7180eef33e0a7a8eb0e16b3c
--- /dev/null
+++ b/inc/Action/Conflict.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Conflict
+ *
+ * Show the conflict resolution screen
+ *
+ * @package dokuwiki\Action
+ */
+class Conflict extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+        if($INFO['exists']) {
+            return AUTH_EDIT;
+        } else {
+            return AUTH_CREATE;
+        }
+    }
+
+    public function tplContent() {
+        global $PRE;
+        global $TEXT;
+        global $SUF;
+        global $SUM;
+
+        html_conflict(con($PRE, $TEXT, $SUF), $SUM);
+        html_diff(con($PRE, $TEXT, $SUF), false);
+    }
+
+}
diff --git a/inc/Action/Denied.php b/inc/Action/Denied.php
new file mode 100644
index 0000000000000000000000000000000000000000..c8e01926265cb86dd3b373cb2c69c4830b966dca
--- /dev/null
+++ b/inc/Action/Denied.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Denied
+ *
+ * Show the access denied screen
+ *
+ * @package dokuwiki\Action
+ */
+class Denied extends AbstractAclAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    public function tplContent() {
+        html_denied();
+    }
+
+}
diff --git a/inc/Action/Diff.php b/inc/Action/Diff.php
new file mode 100644
index 0000000000000000000000000000000000000000..b14b1d04ed91c4bb47fc739b4c339080a9d4143c
--- /dev/null
+++ b/inc/Action/Diff.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Diff
+ *
+ * Show the differences between two revisions
+ *
+ * @package dokuwiki\Action
+ */
+class Diff extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $INPUT;
+
+        // store the selected diff type in cookie
+        $difftype = $INPUT->str('difftype');
+        if(!empty($difftype)) {
+            set_doku_pref('difftype', $difftype);
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_diff();
+    }
+
+}
diff --git a/inc/Action/Draft.php b/inc/Action/Draft.php
new file mode 100644
index 0000000000000000000000000000000000000000..caf08701170cf3ce2d8a948d7427a1e27a6746f6
--- /dev/null
+++ b/inc/Action/Draft.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Draft
+ *
+ * Screen to see and recover a draft
+ *
+ * @package dokuwiki\Action
+ * @fixme combine with Recover?
+ */
+class Draft extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+        if($INFO['exists']) {
+            return AUTH_EDIT;
+        } else {
+            return AUTH_CREATE;
+        }
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+        global $INFO;
+        if(!file_exists($INFO['draft'])) throw new ActionException('edit');
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_draft();
+    }
+
+}
diff --git a/inc/Action/Draftdel.php b/inc/Action/Draftdel.php
new file mode 100644
index 0000000000000000000000000000000000000000..77378f7cb8086ee0e5c65508585bc70326e2f698
--- /dev/null
+++ b/inc/Action/Draftdel.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Draftdel
+ *
+ * Delete a draft
+ *
+ * @package dokuwiki\Action
+ */
+class Draftdel extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_EDIT;
+    }
+
+    /**
+     * Delete an existing draft if any
+     *
+     * Reads draft information from $INFO. Redirects to show, afterwards.
+     *
+     * @throws ActionAbort
+     */
+    public function preProcess() {
+        global $INFO;
+        @unlink($INFO['draft']);
+        $INFO['draft'] = null;
+
+        throw new ActionAbort('redirect');
+    }
+
+}
diff --git a/inc/Action/Edit.php b/inc/Action/Edit.php
new file mode 100644
index 0000000000000000000000000000000000000000..061c9e2ca3b0e1d6886ce848b3a8e314f23f8a05
--- /dev/null
+++ b/inc/Action/Edit.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Edit
+ *
+ * Handle editing
+ *
+ * @package dokuwiki\Action
+ */
+class Edit extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+        if($INFO['exists']) {
+            return AUTH_READ; // we check again below
+        } else {
+            return AUTH_CREATE;
+        }
+    }
+
+    /**
+     * @inheritdoc falls back to 'source' if page not writable
+     */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+        global $INFO;
+
+        // no edit permission? view source
+        if($INFO['exists'] && !$INFO['writable']) {
+            throw new ActionAbort('source');
+        }
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $ID;
+        global $INFO;
+
+        global $TEXT;
+        global $RANGE;
+        global $PRE;
+        global $SUF;
+        global $REV;
+        global $SUM;
+        global $lang;
+        global $DATE;
+
+        if(!isset($TEXT)) {
+            if($INFO['exists']) {
+                if($RANGE) {
+                    list($PRE, $TEXT, $SUF) = rawWikiSlices($RANGE, $ID, $REV);
+                } else {
+                    $TEXT = rawWiki($ID, $REV);
+                }
+            } else {
+                $TEXT = pageTemplate($ID);
+            }
+        }
+
+        //set summary default
+        if(!$SUM) {
+            if($REV) {
+                $SUM = sprintf($lang['restored'], dformat($REV));
+            } elseif(!$INFO['exists']) {
+                $SUM = $lang['created'];
+            }
+        }
+
+        // Use the date of the newest revision, not of the revision we edit
+        // This is used for conflict detection
+        if(!$DATE) $DATE = @filemtime(wikiFN($ID));
+
+        //check if locked by anyone - if not lock for my self
+        $lockedby = checklock($ID);
+        if($lockedby) {
+            throw new ActionAbort('locked');
+        };
+        lock($ID);
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_edit();
+    }
+
+}
diff --git a/inc/Action/Exception/ActionAbort.php b/inc/Action/Exception/ActionAbort.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c188bb4b30ea0ac7ffddd3956fe5efd4cb74eac
--- /dev/null
+++ b/inc/Action/Exception/ActionAbort.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class ActionAbort
+ *
+ * Strictly speaking not an Exception but an expected execution path. Used to
+ * signal when one action is done and another should take over.
+ *
+ * If you want to signal the same but under some error condition use ActionException
+ * or one of it's decendants.
+ *
+ * The message will NOT be shown to the enduser
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class ActionAbort extends ActionException {
+
+}
diff --git a/inc/Action/Exception/ActionAclRequiredException.php b/inc/Action/Exception/ActionAclRequiredException.php
new file mode 100644
index 0000000000000000000000000000000000000000..64a2c61e3e156da01873eed41bfaefe891240067
--- /dev/null
+++ b/inc/Action/Exception/ActionAclRequiredException.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class ActionAclRequiredException
+ *
+ * Thrown by AbstractACLAction when an action requires that the ACL subsystem is
+ * enabled but it isn't. You should not use it
+ *
+ * The message will NOT be shown to the enduser
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class ActionAclRequiredException extends ActionException {
+
+}
diff --git a/inc/Action/Exception/ActionDisabledException.php b/inc/Action/Exception/ActionDisabledException.php
new file mode 100644
index 0000000000000000000000000000000000000000..40a0c7dd70fdc1f3c8a6c2066ec6ce3e83e15ae9
--- /dev/null
+++ b/inc/Action/Exception/ActionDisabledException.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class ActionDisabledException
+ *
+ * Thrown when the requested action has been disabled. Eg. through the 'disableactions'
+ * config setting. You should probably not use it.
+ *
+ * The message will NOT be shown to the enduser, but a generic information will be shown.
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class ActionDisabledException extends ActionException {
+
+}
diff --git a/inc/Action/Exception/ActionException.php b/inc/Action/Exception/ActionException.php
new file mode 100644
index 0000000000000000000000000000000000000000..381584c15b483c7901ba2efd07d156c7e5d74eaf
--- /dev/null
+++ b/inc/Action/Exception/ActionException.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class ActionException
+ *
+ * This exception and its subclasses signal that the current action should be
+ * aborted and a different action should be used instead. The new action can
+ * be given as parameter in the constructor. Defaults to 'show'
+ *
+ * The message will NOT be shown to the enduser
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class ActionException extends \Exception {
+
+    /** @var string the new action */
+    protected $newaction;
+
+    /** @var bool should the exception's message be shown to the user? */
+    protected $displayToUser = false;
+
+    /**
+     * ActionException constructor.
+     *
+     * When no new action is given 'show' is assumed. For requests that originated in a POST,
+     * a 'redirect' is used which will cause a redirect to the 'show' action.
+     *
+     * @param string|null $newaction the action that should be used next
+     * @param string $message optional message, will not be shown except for some dub classes
+     */
+    public function __construct($newaction = null, $message = '') {
+        global $INPUT;
+        parent::__construct($message);
+        if(is_null($newaction)) {
+            if(strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') {
+                $newaction = 'redirect';
+            } else {
+                $newaction = 'show';
+            }
+        }
+
+        $this->newaction = $newaction;
+    }
+
+    /**
+     * Returns the action to use next
+     *
+     * @return string
+     */
+    public function getNewAction() {
+        return $this->newaction;
+    }
+
+    /**
+     * Should this Exception's message be shown to the user?
+     *
+     * @param null|bool $set when null is given, the current setting is not changed
+     * @return bool
+     */
+    public function displayToUser($set = null) {
+        if(!is_null($set)) $this->displayToUser = $set;
+        return $set;
+    }
+}
diff --git a/inc/Action/Exception/ActionUserRequiredException.php b/inc/Action/Exception/ActionUserRequiredException.php
new file mode 100644
index 0000000000000000000000000000000000000000..aab06cca11fd4f6be10bc59cdd4ae2ac407df329
--- /dev/null
+++ b/inc/Action/Exception/ActionUserRequiredException.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class ActionUserRequiredException
+ *
+ * Thrown by AbstractUserAction when an action requires that a user is logged
+ * in but it isn't. You should not use it.
+ *
+ * The message will NOT be shown to the enduser
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class ActionUserRequiredException extends ActionException {
+
+}
diff --git a/inc/Action/Exception/FatalException.php b/inc/Action/Exception/FatalException.php
new file mode 100644
index 0000000000000000000000000000000000000000..5f2516fa2edd0304a98b41dd1a3dbe7d6dbc3bbe
--- /dev/null
+++ b/inc/Action/Exception/FatalException.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class FatalException
+ *
+ * A fatal exception during handling the action
+ *
+ * Will abort all handling and display some info to the user. The HTTP status code
+ * can be defined.
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class FatalException extends \Exception {
+
+    protected $status;
+
+    /**
+     * FatalException constructor.
+     *
+     * @param string $message the message to send
+     * @param int $status the HTTP status to send
+     * @param null|\Exception $previous previous exception
+     */
+    public function __construct($message = 'A fatal error occured', $status = 500, $previous = null) {
+        parent::__construct($message, $status, $previous);
+    }
+}
diff --git a/inc/Action/Exception/NoActionException.php b/inc/Action/Exception/NoActionException.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c4e4d0944ebe6402b573ae5198dd5d75f8e59c0
--- /dev/null
+++ b/inc/Action/Exception/NoActionException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace dokuwiki\Action\Exception;
+
+/**
+ * Class NoActionException
+ *
+ * Thrown in the ActionRouter when a wanted action can not be found. Triggers
+ * the unknown action event
+ *
+ * @package dokuwiki\Action\Exception
+ */
+class NoActionException extends \Exception {
+
+}
diff --git a/inc/Action/Export.php b/inc/Action/Export.php
new file mode 100644
index 0000000000000000000000000000000000000000..1eec27ec3a260e5677cfe684cce59b7f80d79526
--- /dev/null
+++ b/inc/Action/Export.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Export
+ *
+ * Handle exporting by calling the appropriate renderer
+ *
+ * @package dokuwiki\Action
+ */
+class Export extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /**
+     * Export a wiki page for various formats
+     *
+     * Triggers ACTION_EXPORT_POSTPROCESS
+     *
+     *  Event data:
+     *    data['id']      -- page id
+     *    data['mode']    -- requested export mode
+     *    data['headers'] -- export headers
+     *    data['output']  -- export output
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     * @author Michael Klier <chi@chimeric.de>
+     * @inheritdoc
+     */
+    public function preProcess() {
+        global $ID;
+        global $REV;
+        global $conf;
+        global $lang;
+
+        $pre = '';
+        $post = '';
+        $headers = array();
+
+        // search engines: never cache exported docs! (Google only currently)
+        $headers['X-Robots-Tag'] = 'noindex';
+
+        $mode = substr($this->actionname, 7);
+        switch($mode) {
+            case 'raw':
+                $headers['Content-Type'] = 'text/plain; charset=utf-8';
+                $headers['Content-Disposition'] = 'attachment; filename=' . noNS($ID) . '.txt';
+                $output = rawWiki($ID, $REV);
+                break;
+            case 'xhtml':
+                $pre .= '<!DOCTYPE html>' . DOKU_LF;
+                $pre .= '<html lang="' . $conf['lang'] . '" dir="' . $lang['direction'] . '">' . DOKU_LF;
+                $pre .= '<head>' . DOKU_LF;
+                $pre .= '  <meta charset="utf-8" />' . DOKU_LF; // FIXME improve wrapper
+                $pre .= '  <title>' . $ID . '</title>' . DOKU_LF;
+
+                // get metaheaders
+                ob_start();
+                tpl_metaheaders();
+                $pre .= ob_get_clean();
+
+                $pre .= '</head>' . DOKU_LF;
+                $pre .= '<body>' . DOKU_LF;
+                $pre .= '<div class="dokuwiki export">' . DOKU_LF;
+
+                // get toc
+                $pre .= tpl_toc(true);
+
+                $headers['Content-Type'] = 'text/html; charset=utf-8';
+                $output = p_wiki_xhtml($ID, $REV, false);
+
+                $post .= '</div>' . DOKU_LF;
+                $post .= '</body>' . DOKU_LF;
+                $post .= '</html>' . DOKU_LF;
+                break;
+            case 'xhtmlbody':
+                $headers['Content-Type'] = 'text/html; charset=utf-8';
+                $output = p_wiki_xhtml($ID, $REV, false);
+                break;
+            default:
+                $output = p_cached_output(wikiFN($ID, $REV), $mode, $ID);
+                $headers = p_get_metadata($ID, "format $mode");
+                break;
+        }
+
+        // prepare event data
+        $data = array();
+        $data['id'] = $ID;
+        $data['mode'] = $mode;
+        $data['headers'] = $headers;
+        $data['output'] =& $output;
+
+        trigger_event('ACTION_EXPORT_POSTPROCESS', $data);
+
+        if(!empty($data['output'])) {
+            if(is_array($data['headers'])) foreach($data['headers'] as $key => $val) {
+                header("$key: $val");
+            }
+            print $pre . $data['output'] . $post;
+            exit;
+        }
+
+        throw new ActionAbort();
+    }
+
+}
diff --git a/inc/Action/Index.php b/inc/Action/Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..c87a3f89cd97ace23baffae2d5d83346084b25d6
--- /dev/null
+++ b/inc/Action/Index.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Index
+ *
+ * Show the human readable sitemap. Do not confuse with Sitemap
+ *
+ * @package dokuwiki\Action
+ */
+class Index extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        global $IDX;
+        html_index($IDX);
+    }
+
+}
diff --git a/inc/Action/Locked.php b/inc/Action/Locked.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ff2c5b8016be2977978d8dcdefd6f94a2ffe73d
--- /dev/null
+++ b/inc/Action/Locked.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Locked
+ *
+ * Show a locked screen when a page is locked
+ *
+ * @package dokuwiki\Action
+ */
+class Locked extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_locked();
+    }
+
+}
diff --git a/inc/Action/Login.php b/inc/Action/Login.php
new file mode 100644
index 0000000000000000000000000000000000000000..7f903ff2de3875be3e755e385657e4d3977a66a5
--- /dev/null
+++ b/inc/Action/Login.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Login
+ *
+ * The login form. Actual logins are handled in inc/auth.php
+ *
+ * @package dokuwiki\Action
+ */
+class Login extends AbstractAclAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        global $INPUT;
+        parent::checkPreconditions();
+        if($INPUT->server->has('REMOTE_USER')) {
+            // nothing to do
+            throw new ActionException();
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_login();
+    }
+
+}
diff --git a/inc/Action/Logout.php b/inc/Action/Logout.php
new file mode 100644
index 0000000000000000000000000000000000000000..159090423eb43e9816ddcd0888891642bf067a1d
--- /dev/null
+++ b/inc/Action/Logout.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionDisabledException;
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Logout
+ *
+ * Log out a user
+ *
+ * @package dokuwiki\Action
+ */
+class Logout extends AbstractUserAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        /** @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        if(!$auth->canDo('logout')) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $ID;
+        global $INPUT;
+
+        // when logging out during an edit session, unlock the page
+        $lockedby = checklock($ID);
+        if($lockedby == $INPUT->server->str('REMOTE_USER')) {
+            unlock($ID);
+        }
+
+        // do the logout stuff and redirect to login
+        auth_logoff();
+        send_redirect(wl($ID, array('do' => 'login')));
+
+        // should never be reached
+        throw new ActionException('login');
+    }
+
+}
diff --git a/inc/Action/Media.php b/inc/Action/Media.php
new file mode 100644
index 0000000000000000000000000000000000000000..77a2a6f0d45cbd3d21c0d0d60dca2c166fac70c3
--- /dev/null
+++ b/inc/Action/Media.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Media
+ *
+ * The full screen media manager
+ *
+ * @package dokuwiki\Action
+ */
+class Media extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        tpl_media();
+    }
+
+}
diff --git a/inc/Action/Plugin.php b/inc/Action/Plugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..c3e16bf875520e10df3bff225a7b76f1e78a041c
--- /dev/null
+++ b/inc/Action/Plugin.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Plugin
+ *
+ * Used to run action plugins
+ *
+ * @package dokuwiki\Action
+ */
+class Plugin extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /**
+     * Outputs nothing but a warning unless an action plugin overwrites it
+     *
+     * @inheritdoc
+     * @triggers TPL_ACT_UNKNOWN
+     */
+    public function tplContent() {
+        $evt = new \Doku_Event('TPL_ACT_UNKNOWN', $this->actionname);
+        if($evt->advise_before()) {
+            msg('Failed to handle action: ' . hsc($this->actionname), -1);
+        }
+        $evt->advise_after();
+    }
+}
diff --git a/inc/Action/Preview.php b/inc/Action/Preview.php
new file mode 100644
index 0000000000000000000000000000000000000000..850b2049afed7197a7884e6c648d346c2ab3334f
--- /dev/null
+++ b/inc/Action/Preview.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Preview
+ *
+ * preview during editing
+ *
+ * @package dokuwiki\Action
+ */
+class Preview extends Edit {
+
+    /** @inheritdoc */
+    public function preProcess() {
+        header('X-XSS-Protection: 0');
+        $this->savedraft();
+        parent::preProcess();
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        global $TEXT;
+        html_edit();
+        html_show($TEXT);
+    }
+
+    /**
+     * Saves a draft on preview
+     */
+    protected function savedraft() {
+        global $INFO;
+        global $ID;
+        global $INPUT;
+        global $conf;
+
+        if(!$conf['usedraft']) return;
+        if(!$INPUT->post->has('wikitext')) return;
+
+        // ensure environment (safeguard when used via AJAX)
+        assert(isset($INFO['client']), 'INFO.client should have been set');
+        assert(isset($ID), 'ID should have been set');
+
+        $draft = array(
+            'id' => $ID,
+            'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
+            'text' => $INPUT->post->str('wikitext'),
+            'suffix' => $INPUT->post->str('suffix'),
+            'date' => $INPUT->post->int('date'),
+            'client' => $INFO['client'],
+        );
+        $cname = getCacheName($draft['client'] . $ID, '.draft');
+        if(io_saveFile($cname, serialize($draft))) {
+            $INFO['draft'] = $cname;
+        }
+    }
+
+}
diff --git a/inc/Action/Profile.php b/inc/Action/Profile.php
new file mode 100644
index 0000000000000000000000000000000000000000..53d8d2ff361aa42ed19c515003bb53e787e7cbc9
--- /dev/null
+++ b/inc/Action/Profile.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionDisabledException;
+
+/**
+ * Class Profile
+ *
+ * Handle the profile form
+ *
+ * @package dokuwiki\Action
+ */
+class Profile extends AbstractUserAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        /** @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        if(!$auth->canDo('Profile')) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $lang;
+        if(updateprofile()) {
+            msg($lang['profchanged'], 1);
+            throw new ActionAbort('show');
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_updateprofile();
+    }
+
+}
diff --git a/inc/Action/ProfileDelete.php b/inc/Action/ProfileDelete.php
new file mode 100644
index 0000000000000000000000000000000000000000..995f813949f8bbb72faf1f8c7ead86bb22b5cd38
--- /dev/null
+++ b/inc/Action/ProfileDelete.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionDisabledException;
+
+/**
+ * Class ProfileDelete
+ *
+ * Delete a user account
+ *
+ * @package dokuwiki\Action
+ */
+class ProfileDelete extends AbstractUserAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        /** @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        if(!$auth->canDo('delUser')) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $lang;
+        if(auth_deleteprofile()) {
+            msg($lang['profdeleted'], 1);
+            throw new ActionAbort('show');
+        } else {
+            throw new ActionAbort('profile');
+        }
+    }
+
+}
diff --git a/inc/Action/Recent.php b/inc/Action/Recent.php
new file mode 100644
index 0000000000000000000000000000000000000000..4fb3e41544aed46413fa5967bef9c32450a2b8df
--- /dev/null
+++ b/inc/Action/Recent.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Recent
+ *
+ * The recent changes view
+ *
+ * @package dokuwiki\Action
+ */
+class Recent extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $INPUT;
+        $show_changes = $INPUT->str('show_changes');
+        if(!empty($show_changes)) {
+            set_doku_pref('show_changes', $show_changes);
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        global $INPUT;
+        html_recent((int) $INPUT->extract('first')->int('first'));
+    }
+
+}
diff --git a/inc/Action/Recover.php b/inc/Action/Recover.php
new file mode 100644
index 0000000000000000000000000000000000000000..7966396b90bb28ed94b2dea95660f91ee80b5c1f
--- /dev/null
+++ b/inc/Action/Recover.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Recover
+ *
+ * Recover a draft
+ *
+ * @package dokuwiki\Action
+ */
+class Recover extends AbstractAliasAction {
+
+    /** @inheritdoc */
+    public function preProcess() {
+        throw new ActionAbort('edit');
+    }
+
+}
diff --git a/inc/Action/Redirect.php b/inc/Action/Redirect.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e28f45508a4822867d893dd112ff72a5b3b72a9
--- /dev/null
+++ b/inc/Action/Redirect.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Redirect
+ *
+ * Used to redirect to the current page with the last edited section as a target if found
+ *
+ * @package dokuwiki\Action
+ */
+class Redirect extends AbstractAliasAction {
+
+    /**
+     * Redirect to the show action, trying to jump to the previously edited section
+     *
+     * @triggers ACTION_SHOW_REDIRECT
+     * @throws ActionAbort
+     */
+    public function preProcess() {
+        global $PRE;
+        global $TEXT;
+        global $INPUT;
+        global $ID;
+        global $ACT;
+
+        $opts = array(
+            'id' => $ID,
+            'preact' => $ACT
+        );
+        //get section name when coming from section edit
+        if($INPUT->has('hid')) {
+            // Use explicitly transmitted header id
+            $opts['fragment'] = $INPUT->str('hid');
+        } else if($PRE && preg_match('/^\s*==+([^=\n]+)/', $TEXT, $match)) {
+            // Fallback to old mechanism
+            $check = false; //Byref
+            $opts['fragment'] = sectionID($match[0], $check);
+        }
+
+        // execute the redirect
+        trigger_event('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect'));
+
+        // should never be reached
+        throw new ActionAbort('show');
+    }
+
+    /**
+     * Execute the redirect
+     *
+     * Default action for ACTION_SHOW_REDIRECT
+     *
+     * @param array $opts id and fragment for the redirect and the preact
+     */
+    public function redirect($opts) {
+        $go = wl($opts['id'], '', true);
+        if(isset($opts['fragment'])) $go .= '#' . $opts['fragment'];
+
+        //show it
+        send_redirect($go);
+    }
+}
diff --git a/inc/Action/Register.php b/inc/Action/Register.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d5415868d003ab3a222d7d86e113ea56a9df22e
--- /dev/null
+++ b/inc/Action/Register.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionDisabledException;
+
+/**
+ * Class Register
+ *
+ * Self registering a new user
+ *
+ * @package dokuwiki\Action
+ */
+class Register extends AbstractAclAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        /** @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        global $conf;
+        if(isset($conf['openregister']) && !$conf['openregister']) throw new ActionDisabledException();
+        if(!$auth->canDo('addUser')) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        if(register()) { // FIXME could be moved from auth to here
+            throw new ActionAbort('login');
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_register();
+    }
+
+}
diff --git a/inc/Action/Resendpwd.php b/inc/Action/Resendpwd.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab243b0425f4093aebf32959abb9b8408b2d83c3
--- /dev/null
+++ b/inc/Action/Resendpwd.php
@@ -0,0 +1,172 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionDisabledException;
+
+/**
+ * Class Resendpwd
+ *
+ * Handle password recovery
+ *
+ * @package dokuwiki\Action
+ */
+class Resendpwd extends AbstractAclAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        /** @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        global $conf;
+        if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) throw new ActionDisabledException(); //legacy option
+        if(!$auth->canDo('modPass')) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        if($this->resendpwd()) {
+            throw new ActionAbort('login');
+        }
+    }
+
+    /**
+     * Send a  new password
+     *
+     * This function handles both phases of the password reset:
+     *
+     *   - handling the first request of password reset
+     *   - validating the password reset auth token
+     *
+     * @author Benoit Chesneau <benoit@bchesneau.info>
+     * @author Chris Smith <chris@jalakai.co.uk>
+     * @author Andreas Gohr <andi@splitbrain.org>
+     * @fixme this should be split up into multiple methods
+     * @return bool true on success, false on any error
+     */
+    protected function resendpwd() {
+        global $lang;
+        global $conf;
+        /* @var \DokuWiki_Auth_Plugin $auth */
+        global $auth;
+        global $INPUT;
+
+        if(!actionOK('resendpwd')) {
+            msg($lang['resendna'], -1);
+            return false;
+        }
+
+        $token = preg_replace('/[^a-f0-9]+/', '', $INPUT->str('pwauth'));
+
+        if($token) {
+            // we're in token phase - get user info from token
+
+            $tfile = $conf['cachedir'] . '/' . $token{0} . '/' . $token . '.pwauth';
+            if(!file_exists($tfile)) {
+                msg($lang['resendpwdbadauth'], -1);
+                $INPUT->remove('pwauth');
+                return false;
+            }
+            // token is only valid for 3 days
+            if((time() - filemtime($tfile)) > (3 * 60 * 60 * 24)) {
+                msg($lang['resendpwdbadauth'], -1);
+                $INPUT->remove('pwauth');
+                @unlink($tfile);
+                return false;
+            }
+
+            $user = io_readfile($tfile);
+            $userinfo = $auth->getUserData($user, $requireGroups = false);
+            if(!$userinfo['mail']) {
+                msg($lang['resendpwdnouser'], -1);
+                return false;
+            }
+
+            if(!$conf['autopasswd']) { // we let the user choose a password
+                $pass = $INPUT->str('pass');
+
+                // password given correctly?
+                if(!$pass) return false;
+                if($pass != $INPUT->str('passchk')) {
+                    msg($lang['regbadpass'], -1);
+                    return false;
+                }
+
+                // change it
+                if(!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) {
+                    msg($lang['proffail'], -1);
+                    return false;
+                }
+
+            } else { // autogenerate the password and send by mail
+
+                $pass = auth_pwgen($user);
+                if(!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) {
+                    msg($lang['proffail'], -1);
+                    return false;
+                }
+
+                if(auth_sendPassword($user, $pass)) {
+                    msg($lang['resendpwdsuccess'], 1);
+                } else {
+                    msg($lang['regmailfail'], -1);
+                }
+            }
+
+            @unlink($tfile);
+            return true;
+
+        } else {
+            // we're in request phase
+
+            if(!$INPUT->post->bool('save')) return false;
+
+            if(!$INPUT->post->str('login')) {
+                msg($lang['resendpwdmissing'], -1);
+                return false;
+            } else {
+                $user = trim($auth->cleanUser($INPUT->post->str('login')));
+            }
+
+            $userinfo = $auth->getUserData($user, $requireGroups = false);
+            if(!$userinfo['mail']) {
+                msg($lang['resendpwdnouser'], -1);
+                return false;
+            }
+
+            // generate auth token
+            $token = md5(auth_randombytes(16)); // random secret
+            $tfile = $conf['cachedir'] . '/' . $token{0} . '/' . $token . '.pwauth';
+            $url = wl('', array('do' => 'resendpwd', 'pwauth' => $token), true, '&');
+
+            io_saveFile($tfile, $user);
+
+            $text = rawLocale('pwconfirm');
+            $trep = array(
+                'FULLNAME' => $userinfo['name'],
+                'LOGIN' => $user,
+                'CONFIRM' => $url
+            );
+
+            $mail = new \Mailer();
+            $mail->to($userinfo['name'] . ' <' . $userinfo['mail'] . '>');
+            $mail->subject($lang['regpwmail']);
+            $mail->setBody($text, $trep);
+            if($mail->send()) {
+                msg($lang['resendpwdconfirm'], 1);
+            } else {
+                msg($lang['regmailfail'], -1);
+            }
+            return true;
+        }
+        // never reached
+    }
+
+}
diff --git a/inc/Action/Revert.php b/inc/Action/Revert.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca35374f251858ae3e7148f4b8cefecafd403034
--- /dev/null
+++ b/inc/Action/Revert.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Revert
+ *
+ * Quick revert to an old revision
+ *
+ * @package dokuwiki\Action
+ */
+class Revert extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+        if($INFO['ismanager']) {
+            return AUTH_EDIT;
+        } else {
+            return AUTH_ADMIN;
+        }
+    }
+
+    /**
+     *
+     * @inheritdoc
+     * @throws ActionAbort
+     * @throws ActionException
+     * @todo check for writability of the current page ($INFO might do it wrong and check the attic version)
+     */
+    public function preProcess() {
+        if(!checkSecurityToken()) throw new ActionException();
+
+        global $ID;
+        global $REV;
+        global $lang;
+
+        // when no revision is given, delete current one
+        // FIXME this feature is not exposed in the GUI currently
+        $text = '';
+        $sum = $lang['deleted'];
+        if($REV) {
+            $text = rawWiki($ID, $REV);
+            if(!$text) throw new ActionException(); //something went wrong
+            $sum = sprintf($lang['restored'], dformat($REV));
+        }
+
+        // spam check
+        if(checkwordblock($text)) {
+            msg($lang['wordblock'], -1);
+            throw new ActionException('edit');
+        }
+
+        saveWikiText($ID, $text, $sum, false);
+        msg($sum, 1);
+        $REV = '';
+
+        // continue with draftdel -> redirect -> show
+        throw new ActionAbort('draftdel');
+    }
+
+}
diff --git a/inc/Action/Revisions.php b/inc/Action/Revisions.php
new file mode 100644
index 0000000000000000000000000000000000000000..b8db531c78ae88d69dbfd5b12c68ee717ef872aa
--- /dev/null
+++ b/inc/Action/Revisions.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Revisions
+ *
+ * Show the list of old revisions of the current page
+ *
+ * @package dokuwiki\Action
+ */
+class Revisions extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        global $INPUT;
+        html_revisions($INPUT->int('first'));
+    }
+}
diff --git a/inc/Action/Save.php b/inc/Action/Save.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b247298303e67d422914458b3dabd929113d7cc
--- /dev/null
+++ b/inc/Action/Save.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionException;
+
+/**
+ * Class Save
+ *
+ * Save at the end of an edit session
+ *
+ * @package dokuwiki\Action
+ */
+class Save extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        global $INFO;
+        if($INFO['exists']) {
+            return AUTH_EDIT;
+        } else {
+            return AUTH_CREATE;
+        }
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        if(!checkSecurityToken()) throw new ActionException('preview');
+
+        global $ID;
+        global $DATE;
+        global $PRE;
+        global $TEXT;
+        global $SUF;
+        global $SUM;
+        global $lang;
+        global $INFO;
+        global $INPUT;
+
+        //spam check
+        if(checkwordblock()) {
+            msg($lang['wordblock'], -1);
+            throw new ActionException('edit');
+        }
+        //conflict check
+        if($DATE != 0 && $INFO['meta']['date']['modified'] > $DATE) {
+            throw new ActionException('conflict');
+        }
+
+        //save it
+        saveWikiText($ID, con($PRE, $TEXT, $SUF, true), $SUM, $INPUT->bool('minor')); //use pretty mode for con
+        //unlock it
+        unlock($ID);
+
+        // continue with draftdel -> redirect -> show
+        throw new ActionAbort('draftdel');
+    }
+
+}
diff --git a/inc/Action/Search.php b/inc/Action/Search.php
new file mode 100644
index 0000000000000000000000000000000000000000..382fc47e61c2e2d6a811b3372ea2c9774539e8cf
--- /dev/null
+++ b/inc/Action/Search.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+
+/**
+ * Class Search
+ *
+ * Search for pages and content
+ *
+ * @package dokuwiki\Action
+ */
+class Search extends AbstractAction {
+
+    protected $pageLookupResults = array();
+    protected $fullTextResults = array();
+    protected $highlight = array();
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /**
+     * we only search if a search word was given
+     *
+     * @inheritdoc
+     */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+    }
+
+    public function preProcess()
+    {
+        global $QUERY, $ID, $conf, $INPUT;
+        $s = cleanID($QUERY);
+
+        if ($ID !== $conf['start'] && !$INPUT->has('q')) {
+            parse_str($INPUT->server->str('QUERY_STRING'), $urlParts);
+            $urlParts['q'] = $urlParts['id'];
+            $urlParts['id'] = $conf['start'];
+            $url = DOKU_URL . DOKU_SCRIPT . '?' . http_build_query($urlParts, null, '&');
+            send_redirect($url);
+        }
+
+        if ($s === '') throw new ActionAbort();
+        $this->adjustGlobalQuery();
+    }
+
+    /** @inheritdoc */
+    public function tplContent()
+    {
+        $this->execute();
+
+        $search = new \dokuwiki\Ui\Search($this->pageLookupResults, $this->fullTextResults, $this->highlight);
+        $search->show();
+    }
+
+
+    /**
+     * run the search
+     */
+    protected function execute()
+    {
+        global $INPUT, $QUERY;
+        $after = $INPUT->str('min');
+        $before = $INPUT->str('max');
+        $this->pageLookupResults = ft_pageLookup($QUERY, true, useHeading('navigation'), $after, $before);
+        $this->fullTextResults = ft_pageSearch($QUERY, $highlight, $INPUT->str('srt'), $after, $before);
+        $this->highlight = $highlight;
+    }
+
+    /**
+     * Adjust the global query accordingly to the config search_nslimit and search_fragment
+     *
+     * This will only do something if the search didn't originate from the form on the searchpage itself
+     */
+    protected function adjustGlobalQuery()
+    {
+        global $conf, $INPUT, $QUERY, $ID;
+
+        if ($INPUT->bool('sf')) {
+            return;
+        }
+
+        $Indexer = idx_get_indexer();
+        $parsedQuery = ft_queryParser($Indexer, $QUERY);
+
+        if (empty($parsedQuery['ns']) && empty($parsedQuery['notns'])) {
+            if ($conf['search_nslimit'] > 0) {
+                if (getNS($ID) !== false) {
+                    $nsParts = explode(':', getNS($ID));
+                    $ns = implode(':', array_slice($nsParts, 0, $conf['search_nslimit']));
+                    $QUERY .= " @$ns";
+                }
+            }
+        }
+
+        if ($conf['search_fragment'] !== 'exact') {
+            if (empty(array_diff($parsedQuery['words'], $parsedQuery['and']))) {
+                if (strpos($QUERY, '*') === false) {
+                    $queryParts = explode(' ', $QUERY);
+                    $queryParts = array_map(function ($part) {
+                        if (strpos($part, '@') === 0) {
+                            return $part;
+                        }
+                        if (strpos($part, 'ns:') === 0) {
+                            return $part;
+                        }
+                        if (strpos($part, '^') === 0) {
+                            return $part;
+                        }
+                        if (strpos($part, '-ns:') === 0) {
+                            return $part;
+                        }
+
+                        global $conf;
+
+                        if ($conf['search_fragment'] === 'starts_with') {
+                            return $part . '*';
+                        }
+                        if ($conf['search_fragment'] === 'ends_with') {
+                            return '*' . $part;
+                        }
+
+                        return '*' . $part . '*';
+
+                    }, $queryParts);
+                    $QUERY = implode(' ', $queryParts);
+                }
+            }
+        }
+    }
+}
diff --git a/inc/Action/Show.php b/inc/Action/Show.php
new file mode 100644
index 0000000000000000000000000000000000000000..6dbe9a15c253755484c7fc384bd4e1e660f46374
--- /dev/null
+++ b/inc/Action/Show.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Created by IntelliJ IDEA.
+ * User: andi
+ * Date: 2/10/17
+ * Time: 4:32 PM
+ */
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Show
+ *
+ * The default action of showing a page
+ *
+ * @package dokuwiki\Action
+ */
+class Show extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_show();
+    }
+
+}
diff --git a/inc/Action/Sitemap.php b/inc/Action/Sitemap.php
new file mode 100644
index 0000000000000000000000000000000000000000..025c5153c9d59a4f7bad216fc5554f8114ef08b4
--- /dev/null
+++ b/inc/Action/Sitemap.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\FatalException;
+
+/**
+ * Class Sitemap
+ *
+ * Generate an XML sitemap for search engines. Do not confuse with Index
+ *
+ * @package dokuwiki\Action
+ */
+class Sitemap extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_NONE;
+    }
+
+    /**
+     * Handle sitemap delivery
+     *
+     * @author Michael Hamann <michael@content-space.de>
+     * @throws FatalException
+     * @inheritdoc
+     */
+    public function preProcess() {
+        global $conf;
+
+        if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
+            throw new FatalException(404, 'Sitemap generation is disabled');
+        }
+
+        $sitemap = \Sitemapper::getFilePath();
+        if(\Sitemapper::sitemapIsCompressed()) {
+            $mime = 'application/x-gzip';
+        } else {
+            $mime = 'application/xml; charset=utf-8';
+        }
+
+        // Check if sitemap file exists, otherwise create it
+        if(!is_readable($sitemap)) {
+            \Sitemapper::generate();
+        }
+
+        if(is_readable($sitemap)) {
+            // Send headers
+            header('Content-Type: ' . $mime);
+            header('Content-Disposition: attachment; filename=' . utf8_basename($sitemap));
+
+            http_conditionalRequest(filemtime($sitemap));
+
+            // Send file
+            //use x-sendfile header to pass the delivery to compatible webservers
+            http_sendfile($sitemap);
+
+            readfile($sitemap);
+            exit;
+        }
+
+        throw new FatalException(500, 'Could not read the sitemap file - bad permissions?');
+    }
+
+}
diff --git a/inc/Action/Source.php b/inc/Action/Source.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b03fe98bfd523fa37877b00a032a1b9d70608e1
--- /dev/null
+++ b/inc/Action/Source.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace dokuwiki\Action;
+
+/**
+ * Class Source
+ *
+ * Show the source of a page
+ *
+ * @package dokuwiki\Action
+ */
+class Source extends AbstractAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        global $TEXT;
+        global $INFO;
+        global $ID;
+        global $REV;
+
+        if($INFO['exists']) {
+            $TEXT = rawWiki($ID, $REV);
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        html_edit();
+    }
+
+}
diff --git a/inc/Action/Subscribe.php b/inc/Action/Subscribe.php
new file mode 100644
index 0000000000000000000000000000000000000000..c16571022a82f383e3b079dae7597563c61d1912
--- /dev/null
+++ b/inc/Action/Subscribe.php
@@ -0,0 +1,166 @@
+<?php
+
+namespace dokuwiki\Action;
+
+use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Action\Exception\ActionDisabledException;
+
+/**
+ * Class Subscribe
+ *
+ * E-Mail subscription handling
+ *
+ * @package dokuwiki\Action
+ */
+class Subscribe extends AbstractUserAction {
+
+    /** @inheritdoc */
+    public function minimumPermission() {
+        return AUTH_READ;
+    }
+
+    /** @inheritdoc */
+    public function checkPreconditions() {
+        parent::checkPreconditions();
+
+        global $conf;
+        if(isset($conf['subscribers']) && !$conf['subscribers']) throw new ActionDisabledException();
+    }
+
+    /** @inheritdoc */
+    public function preProcess() {
+        try {
+            $this->handleSubscribeData();
+        } catch(ActionAbort $e) {
+            throw $e;
+        } catch(\Exception $e) {
+            msg($e->getMessage(), -1);
+        }
+    }
+
+    /** @inheritdoc */
+    public function tplContent() {
+        tpl_subscribe();
+    }
+
+    /**
+     * Handle page 'subscribe'
+     *
+     * @author Adrian Lang <lang@cosmocode.de>
+     * @throws \Exception if (un)subscribing fails
+     * @throws ActionAbort when (un)subscribing worked
+     */
+    protected function handleSubscribeData() {
+        global $lang;
+        global $INFO;
+        global $INPUT;
+
+        // get and preprocess data.
+        $params = array();
+        foreach(array('target', 'style', 'action') as $param) {
+            if($INPUT->has("sub_$param")) {
+                $params[$param] = $INPUT->str("sub_$param");
+            }
+        }
+
+        // any action given? if not just return and show the subscription page
+        if(empty($params['action']) || !checkSecurityToken()) return;
+
+        // Handle POST data, may throw exception.
+        trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, array($this, 'handlePostData'));
+
+        $target = $params['target'];
+        $style = $params['style'];
+        $action = $params['action'];
+
+        // Perform action.
+        $sub = new \Subscription();
+        if($action == 'unsubscribe') {
+            $ok = $sub->remove($target, $INPUT->server->str('REMOTE_USER'), $style);
+        } else {
+            $ok = $sub->add($target, $INPUT->server->str('REMOTE_USER'), $style);
+        }
+
+        if($ok) {
+            msg(
+                sprintf(
+                    $lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
+                    prettyprint_id($target)
+                ), 1
+            );
+            throw new ActionAbort('redirect');
+        } else {
+            throw new \Exception(
+                sprintf(
+                    $lang["subscr_{$action}_error"],
+                    hsc($INFO['userinfo']['name']),
+                    prettyprint_id($target)
+                )
+            );
+        }
+    }
+
+    /**
+     * Validate POST data
+     *
+     * Validates POST data for a subscribe or unsubscribe request. This is the
+     * default action for the event ACTION_HANDLE_SUBSCRIBE.
+     *
+     * @author Adrian Lang <lang@cosmocode.de>
+     *
+     * @param array &$params the parameters: target, style and action
+     * @throws \Exception
+     */
+    public function handlePostData(&$params) {
+        global $INFO;
+        global $lang;
+        global $INPUT;
+
+        // Get and validate parameters.
+        if(!isset($params['target'])) {
+            throw new \Exception('no subscription target given');
+        }
+        $target = $params['target'];
+        $valid_styles = array('every', 'digest');
+        if(substr($target, -1, 1) === ':') {
+            // Allow “list” subscribe style since the target is a namespace.
+            $valid_styles[] = 'list';
+        }
+        $style = valid_input_set(
+            'style', $valid_styles, $params,
+            'invalid subscription style given'
+        );
+        $action = valid_input_set(
+            'action', array('subscribe', 'unsubscribe'),
+            $params, 'invalid subscription action given'
+        );
+
+        // Check other conditions.
+        if($action === 'subscribe') {
+            if($INFO['userinfo']['mail'] === '') {
+                throw new \Exception($lang['subscr_subscribe_noaddress']);
+            }
+        } elseif($action === 'unsubscribe') {
+            $is = false;
+            foreach($INFO['subscribed'] as $subscr) {
+                if($subscr['target'] === $target) {
+                    $is = true;
+                }
+            }
+            if($is === false) {
+                throw new \Exception(
+                    sprintf(
+                        $lang['subscr_not_subscribed'],
+                        $INPUT->server->str('REMOTE_USER'),
+                        prettyprint_id($target)
+                    )
+                );
+            }
+            // subscription_set deletes a subscription if style = null.
+            $style = null;
+        }
+
+        $params = compact('target', 'style', 'action');
+    }
+
+}
diff --git a/inc/ActionRouter.php b/inc/ActionRouter.php
new file mode 100644
index 0000000000000000000000000000000000000000..edc45cfc40ca6e815b86f6b344c1cfa82bf91e5b
--- /dev/null
+++ b/inc/ActionRouter.php
@@ -0,0 +1,228 @@
+<?php
+
+namespace dokuwiki;
+
+use dokuwiki\Action\AbstractAction;
+use dokuwiki\Action\Exception\ActionDisabledException;
+use dokuwiki\Action\Exception\ActionException;
+use dokuwiki\Action\Exception\FatalException;
+use dokuwiki\Action\Exception\NoActionException;
+use dokuwiki\Action\Plugin;
+
+/**
+ * Class ActionRouter
+ * @package dokuwiki
+ */
+class ActionRouter {
+
+    /** @var  AbstractAction */
+    protected $action;
+
+    /** @var  ActionRouter */
+    protected static $instance = null;
+
+    /** @var int transition counter */
+    protected $transitions = 0;
+
+    /** maximum loop */
+    const MAX_TRANSITIONS = 5;
+
+    /** @var string[] the actions disabled in the configuration */
+    protected $disabled;
+
+    /**
+     * ActionRouter constructor. Singleton, thus protected!
+     *
+     * Sets up the correct action based on the $ACT global. Writes back
+     * the selected action to $ACT
+     */
+    protected function __construct() {
+        global $ACT;
+        global $conf;
+
+        $this->disabled = explode(',', $conf['disableactions']);
+        $this->disabled = array_map('trim', $this->disabled);
+        $this->transitions = 0;
+
+        $ACT = act_clean($ACT);
+        $this->setupAction($ACT);
+        $ACT = $this->action->getActionName();
+    }
+
+    /**
+     * Get the singleton instance
+     *
+     * @param bool $reinit
+     * @return ActionRouter
+     */
+    public static function getInstance($reinit = false) {
+        if((self::$instance === null) || $reinit) {
+            self::$instance = new ActionRouter();
+        }
+        return self::$instance;
+    }
+
+    /**
+     * Setup the given action
+     *
+     * Instantiates the right class, runs permission checks and pre-processing and
+     * sets $action
+     *
+     * @param string $actionname this is passed as a reference to $ACT, for plugin backward compatibility
+     * @triggers ACTION_ACT_PREPROCESS
+     */
+    protected function setupAction(&$actionname) {
+        $presetup = $actionname;
+
+        try {
+            // give plugins an opportunity to process the actionname
+            $evt = new \Doku_Event('ACTION_ACT_PREPROCESS', $actionname);
+            if ($evt->advise_before()) {
+                $this->action = $this->loadAction($actionname);
+                $this->checkAction($this->action);
+                $this->action->preProcess();
+            } else {
+                // event said the action should be kept, assume action plugin will handle it later
+                $this->action = new Plugin($actionname);
+            }
+            $evt->advise_after();
+
+        } catch(ActionException $e) {
+            // we should have gotten a new action
+            $actionname = $e->getNewAction();
+
+            // this one should trigger a user message
+            if(is_a($e, ActionDisabledException::class)) {
+                msg('Action disabled: ' . hsc($presetup), -1);
+            }
+
+            // some actions may request the display of a message
+            if($e->displayToUser()) {
+                msg(hsc($e->getMessage()), -1);
+            }
+
+            // do setup for new action
+            $this->transitionAction($presetup, $actionname);
+
+        } catch(NoActionException $e) {
+            msg('Action unknown: ' . hsc($actionname), -1);
+            $actionname = 'show';
+            $this->transitionAction($presetup, $actionname);
+        } catch(\Exception $e) {
+            $this->handleFatalException($e);
+        }
+    }
+
+    /**
+     * Transitions from one action to another
+     *
+     * Basically just calls setupAction() again but does some checks before.
+     *
+     * @param string $from current action name
+     * @param string $to new action name
+     * @param null|ActionException $e any previous exception that caused the transition
+     */
+    protected function transitionAction($from, $to, $e = null) {
+        $this->transitions++;
+
+        // no infinite recursion
+        if($from == $to) {
+            $this->handleFatalException(new FatalException('Infinite loop in actions', 500, $e));
+        }
+
+        // larger loops will be caught here
+        if($this->transitions >= self::MAX_TRANSITIONS) {
+            $this->handleFatalException(new FatalException('Maximum action transitions reached', 500, $e));
+        }
+
+        // do the recursion
+        $this->setupAction($to);
+    }
+
+    /**
+     * Aborts all processing with a message
+     *
+     * When a FataException instanc is passed, the code is treated as Status code
+     *
+     * @param \Exception|FatalException $e
+     * @throws FatalException during unit testing
+     */
+    protected function handleFatalException(\Exception $e) {
+        if(is_a($e, FatalException::class)) {
+            http_status($e->getCode());
+        } else {
+            http_status(500);
+        }
+        if(defined('DOKU_UNITTEST')) {
+            throw $e;
+        }
+        $msg = 'Something unforseen has happened: ' . $e->getMessage();
+        nice_die(hsc($msg));
+    }
+
+    /**
+     * Load the given action
+     *
+     * This translates the given name to a class name by uppercasing the first letter.
+     * Underscores translate to camelcase names. For actions with underscores, the different
+     * parts are removed beginning from the end until a matching class is found. The instatiated
+     * Action will always have the full original action set as Name
+     *
+     * Example: 'export_raw' -> ExportRaw then 'export' -> 'Export'
+     *
+     * @param $actionname
+     * @return AbstractAction
+     * @throws NoActionException
+     */
+    public function loadAction($actionname) {
+        $actionname = strtolower($actionname); // FIXME is this needed here? should we run a cleanup somewhere else?
+        $parts = explode('_', $actionname);
+        while(!empty($parts)) {
+            $load = join('_', $parts);
+            $class = 'dokuwiki\\Action\\' . str_replace('_', '', ucwords($load, '_'));
+            if(class_exists($class)) {
+                return new $class($actionname);
+            }
+            array_pop($parts);
+        }
+
+        throw new NoActionException();
+    }
+
+    /**
+     * Execute all the checks to see if this action can be executed
+     *
+     * @param AbstractAction $action
+     * @throws ActionDisabledException
+     * @throws ActionException
+     */
+    public function checkAction(AbstractAction $action) {
+        global $INFO;
+        global $ID;
+
+        if(in_array($action->getActionName(), $this->disabled)) {
+            throw new ActionDisabledException();
+        }
+
+        $action->checkPreconditions();
+
+        if(isset($INFO)) {
+            $perm = $INFO['perm'];
+        } else {
+            $perm = auth_quickaclcheck($ID);
+        }
+
+        if($perm < $action->minimumPermission()) {
+            throw new ActionException('denied');
+        }
+    }
+
+    /**
+     * Returns the action handling the current request
+     *
+     * @return AbstractAction
+     */
+    public function getAction() {
+        return $this->action;
+    }
+}
diff --git a/inc/Ajax.php b/inc/Ajax.php
new file mode 100644
index 0000000000000000000000000000000000000000..191d8f8ba98ccce1f17aa3eeac684d62720e6332
--- /dev/null
+++ b/inc/Ajax.php
@@ -0,0 +1,446 @@
+<?php
+
+namespace dokuwiki;
+
+/**
+ * Manage all builtin AJAX calls
+ *
+ * @todo The calls should be refactored out to their own proper classes
+ * @package dokuwiki
+ */
+class Ajax {
+
+    /**
+     * Execute the given call
+     *
+     * @param string $call name of the ajax call
+     */
+    public function __construct($call) {
+        $callfn = 'call_' . $call;
+        if(method_exists($this, $callfn)) {
+            $this->$callfn();
+        } else {
+            $evt = new \Doku_Event('AJAX_CALL_UNKNOWN', $call);
+            if($evt->advise_before()) {
+                print "AJAX call '" . hsc($call) . "' unknown!\n";
+            } else {
+                $evt->advise_after();
+                unset($evt);
+            }
+        }
+    }
+
+    /**
+     * Searches for matching pagenames
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_qsearch() {
+        global $lang;
+        global $INPUT;
+
+        $maxnumbersuggestions = 50;
+
+        $query = $INPUT->post->str('q');
+        if(empty($query)) $query = $INPUT->get->str('q');
+        if(empty($query)) return;
+
+        $query = urldecode($query);
+
+        $data = ft_pageLookup($query, true, useHeading('navigation'));
+
+        if(!count($data)) return;
+
+        print '<strong>' . $lang['quickhits'] . '</strong>';
+        print '<ul>';
+        $counter = 0;
+        foreach($data as $id => $title) {
+            if(useHeading('navigation')) {
+                $name = $title;
+            } else {
+                $ns = getNS($id);
+                if($ns) {
+                    $name = noNS($id) . ' (' . $ns . ')';
+                } else {
+                    $name = $id;
+                }
+            }
+            echo '<li>' . html_wikilink(':' . $id, $name) . '</li>';
+
+            $counter++;
+            if($counter > $maxnumbersuggestions) {
+                echo '<li>...</li>';
+                break;
+            }
+        }
+        print '</ul>';
+    }
+
+    /**
+     * Support OpenSearch suggestions
+     *
+     * @link   http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
+     * @author Mike Frysinger <vapier@gentoo.org>
+     */
+    protected function call_suggestions() {
+        global $INPUT;
+
+        $query = cleanID($INPUT->post->str('q'));
+        if(empty($query)) $query = cleanID($INPUT->get->str('q'));
+        if(empty($query)) return;
+
+        $data = ft_pageLookup($query);
+        if(!count($data)) return;
+        $data = array_keys($data);
+
+        // limit results to 15 hits
+        $data = array_slice($data, 0, 15);
+        $data = array_map('trim', $data);
+        $data = array_map('noNS', $data);
+        $data = array_unique($data);
+        sort($data);
+
+        /* now construct a json */
+        $suggestions = array(
+            $query,  // the original query
+            $data,   // some suggestions
+            array(), // no description
+            array()  // no urls
+        );
+        $json = new \JSON();
+
+        header('Content-Type: application/x-suggestions+json');
+        print $json->encode($suggestions);
+    }
+
+    /**
+     * Refresh a page lock and save draft
+     *
+     * Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_lock() {
+        global $conf;
+        global $lang;
+        global $ID;
+        global $INFO;
+        global $INPUT;
+
+        $ID = cleanID($INPUT->post->str('id'));
+        if(empty($ID)) return;
+
+        $INFO = pageinfo();
+
+        if(!$INFO['writable']) {
+            echo 'Permission denied';
+            return;
+        }
+
+        if(!checklock($ID)) {
+            lock($ID);
+            echo 1;
+        }
+
+        if($conf['usedraft'] && $INPUT->post->str('wikitext')) {
+            $client = $_SERVER['REMOTE_USER'];
+            if(!$client) $client = clientIP(true);
+
+            $draft = array(
+                'id' => $ID,
+                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
+                'text' => $INPUT->post->str('wikitext'),
+                'suffix' => $INPUT->post->str('suffix'),
+                'date' => $INPUT->post->int('date'),
+                'client' => $client,
+            );
+            $cname = getCacheName($draft['client'] . $ID, '.draft');
+            if(io_saveFile($cname, serialize($draft))) {
+                echo $lang['draftdate'] . ' ' . dformat();
+            }
+        }
+
+    }
+
+    /**
+     * Delete a draft
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_draftdel() {
+        global $INPUT;
+        $id = cleanID($INPUT->str('id'));
+        if(empty($id)) return;
+
+        $client = $_SERVER['REMOTE_USER'];
+        if(!$client) $client = clientIP(true);
+
+        $cname = getCacheName($client . $id, '.draft');
+        @unlink($cname);
+    }
+
+    /**
+     * Return subnamespaces for the Mediamanager
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_medians() {
+        global $conf;
+        global $INPUT;
+
+        // wanted namespace
+        $ns = cleanID($INPUT->post->str('ns'));
+        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
+
+        $lvl = count(explode(':', $ns));
+
+        $data = array();
+        search($data, $conf['mediadir'], 'search_index', array('nofiles' => true), $dir);
+        foreach(array_keys($data) as $item) {
+            $data[$item]['level'] = $lvl + 1;
+        }
+        echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
+    }
+
+    /**
+     * Return list of files for the Mediamanager
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_medialist() {
+        global $NS;
+        global $INPUT;
+
+        $NS = cleanID($INPUT->post->str('ns'));
+        $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
+        if($INPUT->post->str('do') == 'media') {
+            tpl_mediaFileList();
+        } else {
+            tpl_mediaContent(true, $sort);
+        }
+    }
+
+    /**
+     * Return the content of the right column
+     * (image details) for the Mediamanager
+     *
+     * @author Kate Arzamastseva <pshns@ukr.net>
+     */
+    protected function call_mediadetails() {
+        global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
+        $fullscreen = true;
+        require_once(DOKU_INC . 'lib/exe/mediamanager.php');
+
+        $image = '';
+        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
+        if(isset($IMG)) $image = $IMG;
+        if(isset($JUMPTO)) $image = $JUMPTO;
+        $rev = false;
+        if(isset($REV) && !$JUMPTO) $rev = $REV;
+
+        html_msgarea();
+        tpl_mediaFileDetails($image, $rev);
+    }
+
+    /**
+     * Returns image diff representation for mediamanager
+     *
+     * @author Kate Arzamastseva <pshns@ukr.net>
+     */
+    protected function call_mediadiff() {
+        global $NS;
+        global $INPUT;
+
+        $image = '';
+        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
+        $NS = getNS($image);
+        $auth = auth_quickaclcheck("$NS:*");
+        media_diff($image, $NS, $auth, true);
+    }
+
+    /**
+     * Manages file uploads
+     *
+     * @author Kate Arzamastseva <pshns@ukr.net>
+     */
+    protected function call_mediaupload() {
+        global $NS, $MSG, $INPUT;
+
+        $id = '';
+        if($_FILES['qqfile']['tmp_name']) {
+            $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
+        } elseif($INPUT->get->has('qqfile')) {
+            $id = $INPUT->get->str('qqfile');
+        }
+
+        $id = cleanID($id);
+
+        $NS = $INPUT->str('ns');
+        $ns = $NS . ':' . getNS($id);
+
+        $AUTH = auth_quickaclcheck("$ns:*");
+        if($AUTH >= AUTH_UPLOAD) {
+            io_createNamespace("$ns:xxx", 'media');
+        }
+
+        if($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
+
+        $res = false;
+        if($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
+        if($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
+
+        if($res) {
+            $result = array(
+                'success' => true,
+                'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
+                'id' => $NS . ':' . $id,
+                'ns' => $NS
+            );
+        } else {
+            $error = '';
+            if(isset($MSG)) {
+                foreach($MSG as $msg) {
+                    $error .= $msg['msg'];
+                }
+            }
+            $result = array(
+                'error' => $error,
+                'ns' => $NS
+            );
+        }
+        $json = new \JSON;
+        header('Content-Type: application/json');
+        echo $json->encode($result);
+    }
+
+    /**
+     * Return sub index for index view
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    protected function call_index() {
+        global $conf;
+        global $INPUT;
+
+        // wanted namespace
+        $ns = cleanID($INPUT->post->str('idx'));
+        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
+
+        $lvl = count(explode(':', $ns));
+
+        $data = array();
+        search($data, $conf['datadir'], 'search_index', array('ns' => $ns), $dir);
+        foreach(array_keys($data) as $item) {
+            $data[$item]['level'] = $lvl + 1;
+        }
+        echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index');
+    }
+
+    /**
+     * List matching namespaces and pages for the link wizard
+     *
+     * @author Andreas Gohr <gohr@cosmocode.de>
+     */
+    protected function call_linkwiz() {
+        global $conf;
+        global $lang;
+        global $INPUT;
+
+        $q = ltrim(trim($INPUT->post->str('q')), ':');
+        $id = noNS($q);
+        $ns = getNS($q);
+
+        $ns = cleanID($ns);
+        $id = cleanID($id);
+
+        $nsd = utf8_encodeFN(str_replace(':', '/', $ns));
+
+        $data = array();
+        if($q && !$ns) {
+
+            // use index to lookup matching pages
+            $pages = ft_pageLookup($id, true);
+
+            // result contains matches in pages and namespaces
+            // we now extract the matching namespaces to show
+            // them seperately
+            $dirs = array();
+
+            foreach($pages as $pid => $title) {
+                if(strpos(noNS($pid), $id) === false) {
+                    // match was in the namespace
+                    $dirs[getNS($pid)] = 1; // assoc array avoids dupes
+                } else {
+                    // it is a matching page, add it to the result
+                    $data[] = array(
+                        'id' => $pid,
+                        'title' => $title,
+                        'type' => 'f',
+                    );
+                }
+                unset($pages[$pid]);
+            }
+            foreach($dirs as $dir => $junk) {
+                $data[] = array(
+                    'id' => $dir,
+                    'type' => 'd',
+                );
+            }
+
+        } else {
+
+            $opts = array(
+                'depth' => 1,
+                'listfiles' => true,
+                'listdirs' => true,
+                'pagesonly' => true,
+                'firsthead' => true,
+                'sneakyacl' => $conf['sneaky_index'],
+            );
+            if($id) $opts['filematch'] = '^.*\/' . $id;
+            if($id) $opts['dirmatch'] = '^.*\/' . $id;
+            search($data, $conf['datadir'], 'search_universal', $opts, $nsd);
+
+            // add back to upper
+            if($ns) {
+                array_unshift(
+                    $data, array(
+                             'id' => getNS($ns),
+                             'type' => 'u',
+                         )
+                );
+            }
+        }
+
+        // fixme sort results in a useful way ?
+
+        if(!count($data)) {
+            echo $lang['nothingfound'];
+            exit;
+        }
+
+        // output the found data
+        $even = 1;
+        foreach($data as $item) {
+            $even *= -1; //zebra
+
+            if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
+            $link = wl($item['id']);
+
+            echo '<div class="' . (($even > 0) ? 'even' : 'odd') . ' type_' . $item['type'] . '">';
+
+            if($item['type'] == 'u') {
+                $name = $lang['upperns'];
+            } else {
+                $name = hsc($item['id']);
+            }
+
+            echo '<a href="' . $link . '" title="' . hsc($item['id']) . '" class="wikilink1">' . $name . '</a>';
+
+            if(!blank($item['title'])) {
+                echo '<span>' . hsc($item['title']) . '</span>';
+            }
+            echo '</div>';
+        }
+
+    }
+
+}
diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php
index 37b55e10daa8939b1be92102f6e97ceaccc41e5a..70877a4f2dee180a16e9a636175a0a958b6b8675 100644
--- a/inc/DifferenceEngine.php
+++ b/inc/DifferenceEngine.php
@@ -270,16 +270,9 @@ class _DiffEngine {
                 if (empty($ymatches[$line]))
                     continue;
                 $matches = $ymatches[$line];
-                reset($matches);
-                while (list ($junk, $y) = each($matches))
-                    if (empty($this->in_seq[$y])) {
-                        $k = $this->_lcs_pos($y);
-                        USE_ASSERTS && assert($k > 0);
-                        $ymids[$k] = $ymids[$k-1];
-                        break;
-                    }
-                while (list ($junk, $y) = each($matches)) {
-                    if ($y > $this->seq[$k-1]) {
+                $switch = false;
+                foreach ($matches as $y) {
+                    if ($switch && $y > $this->seq[$k-1]) {
                         USE_ASSERTS && assert($y < $this->seq[$k]);
                         // Optimization: this is a common case:
                         //  next match is just replacing previous match.
@@ -291,6 +284,7 @@ class _DiffEngine {
                         $k = $this->_lcs_pos($y);
                         USE_ASSERTS && assert($k > 0);
                         $ymids[$k] = $ymids[$k-1];
+                        $switch = true;
                     }
                 }
             }
@@ -414,7 +408,7 @@ class _DiffEngine {
         $i = 0;
         $j = 0;
 
-        USE_ASSERTS && assert('count($lines) == count($changed)');
+        USE_ASSERTS && assert(count($lines) == count($changed));
         $len = count($lines);
         $other_len = count($other_changed);
 
@@ -434,7 +428,7 @@ class _DiffEngine {
                 $j++;
 
             while ($i < $len && ! $changed[$i]) {
-                USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+                USE_ASSERTS && assert($j < $other_len && ! $other_changed[$j]);
                 $i++;
                 $j++;
                 while ($j < $other_len && $other_changed[$j])
@@ -467,10 +461,10 @@ class _DiffEngine {
                     $changed[--$i] = false;
                     while ($start > 0 && $changed[$start - 1])
                         $start--;
-                    USE_ASSERTS && assert('$j > 0');
+                    USE_ASSERTS && assert($j > 0);
                     while ($other_changed[--$j])
                         continue;
-                    USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+                    USE_ASSERTS && assert($j >= 0 && !$other_changed[$j]);
                 }
 
                 /*
@@ -493,7 +487,7 @@ class _DiffEngine {
                     while ($i < $len && $changed[$i])
                         $i++;
 
-                    USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+                    USE_ASSERTS && assert($j < $other_len && ! $other_changed[$j]);
                     $j++;
                     if ($j < $other_len && $other_changed[$j]) {
                         $corresponding = $i;
@@ -510,10 +504,10 @@ class _DiffEngine {
             while ($corresponding < $i) {
                 $changed[--$start] = 1;
                 $changed[--$i] = 0;
-                USE_ASSERTS && assert('$j > 0');
+                USE_ASSERTS && assert($j > 0);
                 while ($other_changed[--$j])
                     continue;
-                USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+                USE_ASSERTS && assert($j >= 0 && !$other_changed[$j]);
             }
         }
     }
@@ -876,10 +870,10 @@ class DiffFormatter {
 
     /**
      * Escape string
-     * 
+     *
      * Override this method within other formatters if escaping required.
      * Base class requires $str to be returned WITHOUT escaping.
-     * 
+     *
      * @param $str string Text string to escape
      * @return string The escaped string.
      */
diff --git a/inc/Form/Form.php b/inc/Form/Form.php
index 2d534aee5cc9f9dd355549f7fa8513025a2b8f89..92bbd30f4daf73087e4903190b9a2a15cf142d77 100644
--- a/inc/Form/Form.php
+++ b/inc/Form/Form.php
@@ -24,8 +24,9 @@ class Form extends Element {
      * Creates a new, empty form with some default attributes
      *
      * @param array $attributes
+     * @param bool  $unsafe     if true, then the security token is ommited
      */
-    public function __construct($attributes = array()) {
+    public function __construct($attributes = array(), $unsafe = false) {
         global $ID;
 
         parent::__construct('form', $attributes);
@@ -49,7 +50,9 @@ class Form extends Element {
         }
 
         // add the security token by default
-        $this->setHiddenField('sectok', getSecurityToken());
+        if (!$unsafe) {
+            $this->setHiddenField('sectok', getSecurityToken());
+        }
 
         // identify this as a new form based form in HTML
         $this->addClass('doku_form');
@@ -78,6 +81,20 @@ class Form extends Element {
         return count($this->elements);
     }
 
+    /**
+     * Get the position of the element in the form or false if it is not in the form
+     *
+     * Warning: This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
+     *
+     * @param Element $element
+     *
+     * @return false|int
+     */
+    public function getElementPosition(Element $element)
+    {
+        return array_search($element, $this->elements, true);
+    }
+
     /**
      * Returns a reference to the element at a position.
      * A position out-of-bounds will return either the
diff --git a/inc/Form/OptGroup.php b/inc/Form/OptGroup.php
index fa0b516db458f0a8dc25c373b6a60dee0e0ab5c1..791f0b3f6616885e198afed6e0d2216744b6cd40 100644
--- a/inc/Form/OptGroup.php
+++ b/inc/Form/OptGroup.php
@@ -52,6 +52,9 @@ class OptGroup extends Element {
         foreach($options as $key => $val) {
             if (is_array($val)) {
                 if (!key_exists('label', $val)) throw new \InvalidArgumentException('If option is given as array, it has to have a "label"-key!');
+                if (key_exists('attrs', $val) && is_array($val['attrs']) && key_exists('selected', $val['attrs'])) {
+                    throw new \InvalidArgumentException('Please use function "DropdownElement::val()" to set the selected option');
+                }
                 $this->options[$key] = $val;
             } elseif(is_int($key)) {
                 $this->options[$val] = array('label' => (string) $val);
@@ -85,7 +88,7 @@ class OptGroup extends Element {
     protected function renderOptions() {
         $html = '';
         foreach($this->options as $key => $val) {
-            $selected = ($key == $this->value) ? ' selected="selected"' : '';
+            $selected = ((string)$key === (string)$this->value) ? ' selected="selected"' : '';
             $attrs = '';
             if (!empty($val['attrs']) && is_array($val['attrs'])) {
                 $attrs = buildAttributes($val['attrs']);
diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php
index 88a86c6bc26e2e4c6b2c5d37a096fe7768d12d0f..7737878bd6c6e0a5859bfb3e43167487fa028217 100644
--- a/inc/HTTPClient.php
+++ b/inc/HTTPClient.php
@@ -9,77 +9,6 @@
 
 define('HTTP_NL',"\r\n");
 
-
-/**
- * Adds DokuWiki specific configs to the HTTP client
- *
- * @author Andreas Goetz <cpuidle@gmx.de>
- */
-class DokuHTTPClient extends HTTPClient {
-
-    /**
-     * Constructor.
-     *
-     * @author Andreas Gohr <andi@splitbrain.org>
-     */
-    function __construct(){
-        global $conf;
-
-        // call parent constructor
-        parent::__construct();
-
-        // set some values from the config
-        $this->proxy_host   = $conf['proxy']['host'];
-        $this->proxy_port   = $conf['proxy']['port'];
-        $this->proxy_user   = $conf['proxy']['user'];
-        $this->proxy_pass   = conf_decodeString($conf['proxy']['pass']);
-        $this->proxy_ssl    = $conf['proxy']['ssl'];
-        $this->proxy_except = $conf['proxy']['except'];
-
-        // allow enabling debugging via URL parameter (if debugging allowed)
-        if($conf['allowdebug']) {
-            if(
-                isset($_REQUEST['httpdebug']) ||
-                (
-                    isset($_SERVER['HTTP_REFERER']) &&
-                    strpos($_SERVER['HTTP_REFERER'], 'httpdebug') !== false
-                )
-            ) {
-                $this->debug = true;
-            }
-        }
-    }
-
-
-    /**
-     * Wraps an event around the parent function
-     *
-     * @triggers HTTPCLIENT_REQUEST_SEND
-     * @author   Andreas Gohr <andi@splitbrain.org>
-     */
-    /**
-     * @param string $url
-     * @param string|array $data the post data either as array or raw data
-     * @param string $method
-     * @return bool
-     */
-    function sendRequest($url,$data='',$method='GET'){
-        $httpdata = array('url'    => $url,
-                          'data'   => $data,
-                          'method' => $method);
-        $evt = new Doku_Event('HTTPCLIENT_REQUEST_SEND',$httpdata);
-        if($evt->advise_before()){
-            $url    = $httpdata['url'];
-            $data   = $httpdata['data'];
-            $method = $httpdata['method'];
-        }
-        $evt->advise_after();
-        unset($evt);
-        return parent::sendRequest($url,$data,$method);
-    }
-
-}
-
 /**
  * Class HTTPClientException
  */
@@ -297,10 +226,15 @@ class HTTPClient {
 
         if($method == 'POST'){
             if(is_array($data)){
-                if($headers['Content-Type'] == 'multipart/form-data'){
-                    $headers['Content-Type']   = 'multipart/form-data; boundary='.$this->boundary;
+                if (empty($headers['Content-Type'])) {
+                    $headers['Content-Type'] = null;
+                }
+                switch ($headers['Content-Type']) {
+                case 'multipart/form-data':
+                    $headers['Content-Type']   = 'multipart/form-data; boundary=' . $this->boundary;
                     $data = $this->_postMultipartEncode($data);
-                }else{
+                    break;
+                default:
                     $headers['Content-Type']   = 'application/x-www-form-urlencoded';
                     $data = $this->_postEncode($data);
                 }
@@ -599,18 +533,16 @@ class HTTPClient {
             // set correct peer name for verification (enabled since PHP 5.6)
             stream_context_set_option($socket, 'ssl', 'peer_name', $requestinfo['host']);
 
-            // because SSLv3 is mostly broken, we try TLS connections here first.
-            // according to  https://github.com/splitbrain/dokuwiki/commit/c05ef534 we had problems with certain
-            // setups with this solution before, but we have no usable test for that and TLS should be the more
-            // common crypto by now
-            if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
-                $requesturl = $requestinfo['path'].
-                  (!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
-                return true;
+            // SSLv3 is broken, use only TLS connections.
+            // @link https://bugs.php.net/69195
+            if (PHP_VERSION_ID >= 50600 && PHP_VERSION_ID <= 50606) {
+                $cryptoMethod = STREAM_CRYPTO_METHOD_TLS_CLIENT;
+            } else {
+                // actually means neither SSLv2 nor SSLv3
+                $cryptoMethod = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
             }
 
-            // if the above failed, this will most probably not work either, but we can try
-            if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)) {
+            if (@stream_socket_enable_crypto($socket, true, $cryptoMethod)) {
                 $requesturl = $requestinfo['path'].
                   (!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
                 return true;
@@ -935,4 +867,75 @@ class HTTPClient {
     }
 }
 
+
+/**
+ * Adds DokuWiki specific configs to the HTTP client
+ *
+ * @author Andreas Goetz <cpuidle@gmx.de>
+ */
+class DokuHTTPClient extends HTTPClient {
+
+    /**
+     * Constructor.
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    function __construct(){
+        global $conf;
+
+        // call parent constructor
+        parent::__construct();
+
+        // set some values from the config
+        $this->proxy_host   = $conf['proxy']['host'];
+        $this->proxy_port   = $conf['proxy']['port'];
+        $this->proxy_user   = $conf['proxy']['user'];
+        $this->proxy_pass   = conf_decodeString($conf['proxy']['pass']);
+        $this->proxy_ssl    = $conf['proxy']['ssl'];
+        $this->proxy_except = $conf['proxy']['except'];
+
+        // allow enabling debugging via URL parameter (if debugging allowed)
+        if($conf['allowdebug']) {
+            if(
+                isset($_REQUEST['httpdebug']) ||
+                (
+                    isset($_SERVER['HTTP_REFERER']) &&
+                    strpos($_SERVER['HTTP_REFERER'], 'httpdebug') !== false
+                )
+            ) {
+                $this->debug = true;
+            }
+        }
+    }
+
+
+    /**
+     * Wraps an event around the parent function
+     *
+     * @triggers HTTPCLIENT_REQUEST_SEND
+     * @author   Andreas Gohr <andi@splitbrain.org>
+     */
+    /**
+     * @param string $url
+     * @param string|array $data the post data either as array or raw data
+     * @param string $method
+     * @return bool
+     */
+    function sendRequest($url,$data='',$method='GET'){
+        $httpdata = array('url'    => $url,
+                          'data'   => $data,
+                          'method' => $method);
+        $evt = new Doku_Event('HTTPCLIENT_REQUEST_SEND',$httpdata);
+        if($evt->advise_before()){
+            $url    = $httpdata['url'];
+            $data   = $httpdata['data'];
+            $method = $httpdata['method'];
+        }
+        $evt->advise_after();
+        unset($evt);
+        return parent::sendRequest($url,$data,$method);
+    }
+
+}
+
 //Setup VIM: ex: et ts=4 :
diff --git a/inc/JpegMeta.php b/inc/JpegMeta.php
index d667ce303d88dd53fb429d6edc3f28412a6e90f0..94c276cfa7af94d0c6dbbd05567c17bc18921fb4 100644
--- a/inc/JpegMeta.php
+++ b/inc/JpegMeta.php
@@ -2522,13 +2522,13 @@ class JpegMeta {
             $pos = 14;
 
             reset($this->_info['adobe']['raw']);
-            while (list($key) = each($this->_info['adobe']['raw'])) {
+            foreach ($this->_info['adobe']['raw'] as $value){
                 $pos = $this->_write8BIM(
                         $data,
                         $pos,
-                        $this->_info['adobe']['raw'][$key]['type'],
-                        $this->_info['adobe']['raw'][$key]['header'],
-                        $this->_info['adobe']['raw'][$key]['data'] );
+                        $value['type'],
+                        $value['header'],
+                        $value['data'] );
             }
         }
 
diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php
index 9d078d06d79879cc58c337185e3b2a6e3f730d28..7968ce9fcbd63b10bc45e49fe9f75c6e8d0f0cff 100644
--- a/inc/Mailer.class.php
+++ b/inc/Mailer.class.php
@@ -28,8 +28,6 @@ class Mailer {
     protected $partid    = '';
     protected $sendparam = null;
 
-    /** @var EmailAddressValidator */
-    protected $validator = null;
     protected $allowhtml = true;
 
     protected $replacements = array('text'=> array(), 'html' => array());
@@ -56,6 +54,9 @@ class Mailer {
         $this->allowhtml = (bool)$conf['htmlmail'];
 
         // add some default headers for mailfiltering FS#2247
+        if(!empty($conf['mailreturnpath'])) {
+            $this->setHeader('Return-Path', $conf['mailreturnpath']);
+        }
         $this->setHeader('X-Mailer', 'DokuWiki');
         $this->setHeader('X-DokuWiki-User', $INPUT->server->str('REMOTE_USER'));
         $this->setHeader('X-DokuWiki-Title', $conf['title']);
@@ -185,7 +186,7 @@ class Mailer {
      *
      * @param string $text     plain text body
      * @param array  $textrep  replacements to apply on the text part
-     * @param array  $htmlrep  replacements to apply on the HTML part, leave null to use $textrep
+     * @param array  $htmlrep  replacements to apply on the HTML part, null to use $textrep (with urls wrapped in <a> tags)
      * @param string $html     the HTML body, leave null to create it from $text
      * @param bool   $wrap     wrap the HTML in the default header/Footer
      */
@@ -333,9 +334,6 @@ class Mailer {
      * @return false|string  the prepared header (can contain multiple lines)
      */
     public function cleanAddress($addresses) {
-        // No named recipients for To: in Windows (see FS#652)
-        $names = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true;
-
         $headers = '';
         if(!is_array($addresses)){
             $addresses = explode(',', $addresses);
@@ -359,21 +357,17 @@ class Mailer {
 
             // FIXME: is there a way to encode the localpart of a emailaddress?
             if(!utf8_isASCII($addr)) {
-                msg(htmlspecialchars("E-Mail address <$addr> is not ASCII"), -1);
+                msg(hsc("E-Mail address <$addr> is not ASCII"), -1);
                 continue;
             }
 
-            if(is_null($this->validator)) {
-                $this->validator                      = new EmailAddressValidator();
-                $this->validator->allowLocalAddresses = true;
-            }
-            if(!$this->validator->check_email_address($addr)) {
-                msg(htmlspecialchars("E-Mail address <$addr> is not valid"), -1);
+            if(!mail_isvalid($addr)) {
+                msg(hsc("E-Mail address <$addr> is not valid"), -1);
                 continue;
             }
 
             // text was given
-            if(!empty($text) && $names) {
+            if(!empty($text) && !isWindows()) { // No named recipients for To: in Windows (see FS#652)
                 // add address quotes
                 $addr = "<$addr>";
 
diff --git a/inc/Manifest.php b/inc/Manifest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0df9c2b81991be5c346494d8585c30b58b621d8a
--- /dev/null
+++ b/inc/Manifest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace dokuwiki;
+
+class Manifest
+{
+    public function sendManifest()
+    {
+        $manifest = retrieveConfig('manifest', 'jsonToArray');
+
+        global $conf;
+
+        $manifest['scope'] = DOKU_REL;
+
+        if (empty($manifest['name'])) {
+            $manifest['name'] = $conf['title'];
+        }
+
+        if (empty($manifest['short_name'])) {
+            $manifest['short_name'] = $conf['title'];
+        }
+
+        if (empty($manifest['description'])) {
+            $manifest['description'] = $conf['tagline'];
+        }
+
+        if (empty($manifest['start_url'])) {
+            $manifest['start_url'] = DOKU_REL;
+        }
+
+        $styleUtil = new \dokuwiki\StyleUtils();
+        $styleIni = $styleUtil->cssStyleini($conf['template']);
+        $replacements = $styleIni['replacements'];
+
+        if (empty($manifest['background_color'])) {
+            $manifest['background_color'] = $replacements['__background__'];
+        }
+
+        if (empty($manifest['theme_color'])) {
+            $manifest['theme_color'] = !empty($replacements['__theme_color__']) ? $replacements['__theme_color__'] : $replacements['__background_alt__'];
+        }
+
+        if (empty($manifest['icons'])) {
+            $manifest['icons'] = [];
+            if (file_exists(mediaFN(':wiki:favicon.ico'))) {
+                $url = ml(':wiki:favicon.ico', '', true, '', true);
+                $manifest['icons'][] = [
+                    'src' => $url,
+                    'sizes' => '16x16',
+                ];
+            }
+
+            $look = [
+                ':wiki:logo.svg',
+                ':logo.svg',
+                ':wiki:dokuwiki.svg'
+            ];
+
+            foreach ($look as $svgLogo) {
+
+                $svgLogoFN = mediaFN($svgLogo);
+
+                if (file_exists($svgLogoFN)) {
+                    $url = ml($svgLogo, '', true, '', true);
+                    $manifest['icons'][] = [
+                        'src' => $url,
+                        'sizes' => '17x17 512x512',
+                        'type' => 'image/svg+xml',
+                    ];
+                    break;
+                };
+            }
+        }
+
+        trigger_event('MANIFEST_SEND', $manifest);
+
+        header('Content-Type: application/manifest+json');
+        echo json_encode($manifest);
+    }
+}
diff --git a/inc/Menu/AbstractMenu.php b/inc/Menu/AbstractMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..ce021ab64711f702166efa95e734200541e32a0c
--- /dev/null
+++ b/inc/Menu/AbstractMenu.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+use dokuwiki\Menu\Item\AbstractItem;
+
+/**
+ * Class AbstractMenu
+ *
+ * Basic menu functionality. A menu defines a list of AbstractItem that shall be shown.
+ * It contains convenience functions to display the menu in HTML, but template authors can also
+ * just accesst the items via getItems() and create the HTML as however they see fit.
+ */
+abstract class AbstractMenu implements MenuInterface {
+
+    /** @var string[] list of Item classes to load */
+    protected $types = array();
+
+    /** @var int the context this menu is used in */
+    protected $context = AbstractItem::CTX_DESKTOP;
+
+    /** @var string view identifier to be set in the event */
+    protected $view = '';
+
+    /**
+     * AbstractMenu constructor.
+     *
+     * @param int $context the context this menu is used in
+     */
+    public function __construct($context = AbstractItem::CTX_DESKTOP) {
+        $this->context = $context;
+    }
+
+    /**
+     * Get the list of action items in this menu
+     *
+     * @return AbstractItem[]
+     * @triggers MENU_ITEMS_ASSEMBLY
+     */
+    public function getItems() {
+        $data = array(
+            'view' => $this->view,
+            'items' => array(),
+        );
+        trigger_event('MENU_ITEMS_ASSEMBLY', $data, array($this, 'loadItems'));
+        return $data['items'];
+    }
+
+    /**
+     * Default action for the MENU_ITEMS_ASSEMBLY event
+     *
+     * @see getItems()
+     * @param array $data The plugin data
+     */
+    public function loadItems(&$data) {
+        foreach($this->types as $class) {
+            try {
+                $class = "\\dokuwiki\\Menu\\Item\\$class";
+                /** @var AbstractItem $item */
+                $item = new $class();
+                if(!$item->visibleInContext($this->context)) continue;
+                $data['items'][] = $item;
+            } catch(\RuntimeException $ignored) {
+                // item not available
+            }
+        }
+    }
+
+    /**
+     * Generate HTML list items for this menu
+     *
+     * This is a convenience method for template authors. If you need more fine control over the
+     * output, use getItems() and build the HTML yourself
+     *
+     * @param string|false $classprefix create a class from type with this prefix, false for no class
+     * @param bool $svg add the SVG link
+     * @return string
+     */
+    public function getListItems($classprefix = '', $svg = true) {
+        $html = '';
+        foreach($this->getItems() as $item) {
+            if($classprefix !== false) {
+                $class = ' class="' . $classprefix . $item->getType() . '"';
+            } else {
+                $class = '';
+            }
+
+            $html .= "<li$class>";
+            $html .= $item->asHtmlLink(false, $svg);
+            $html .= '</li>';
+        }
+        return $html;
+    }
+
+}
diff --git a/inc/Menu/DetailMenu.php b/inc/Menu/DetailMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..27c0c6fce3e6fd249986a421d3eb88f7ff947c6f
--- /dev/null
+++ b/inc/Menu/DetailMenu.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+/**
+ * Class DetailMenu
+ *
+ * This menu offers options on an image detail view. It usually displayed similar to
+ * the PageMenu.
+ */
+class DetailMenu extends AbstractMenu {
+
+    protected $view = 'detail';
+
+    protected $types = array(
+        'MediaManager',
+        'ImgBackto',
+        'Top',
+    );
+
+}
diff --git a/inc/Menu/Item/AbstractItem.php b/inc/Menu/Item/AbstractItem.php
new file mode 100644
index 0000000000000000000000000000000000000000..45ead5562e564e91eb84f34dfa229969e74e92e7
--- /dev/null
+++ b/inc/Menu/Item/AbstractItem.php
@@ -0,0 +1,253 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class AbstractItem
+ *
+ * This class defines a single Item to be displayed in one of DokuWiki's menus. Plugins
+ * can extend those menus through action plugins and add their own instances of this class,
+ * overwriting some of its properties.
+ *
+ * Items may be shown multiple times in different contexts. Eg. for the default template
+ * all menus are shown in a Dropdown list on mobile, but are split into several places on
+ * desktop. The item's $context property can be used to hide the item depending on the current
+ * context.
+ *
+ * Children usually just need to overwrite the different properties, but for complex things
+ * the accessors may be overwritten instead.
+ */
+abstract class AbstractItem {
+
+    /** menu item is to be shown on desktop screens only */
+    const CTX_DESKTOP = 1;
+    /** menu item is to be shown on mobile screens only */
+    const CTX_MOBILE = 2;
+    /** menu item is to be shown in all contexts */
+    const CTX_ALL = 3;
+
+    /** @var string name of the action, usually the lowercase class name */
+    protected $type = '';
+    /** @var string optional keyboard shortcut */
+    protected $accesskey = '';
+    /** @var string the page id this action links to */
+    protected $id = '';
+    /** @var string the method to be used when this action is used in a form */
+    protected $method = 'get';
+    /** @var array parameters for the action (should contain the do parameter) */
+    protected $params = array();
+    /** @var bool when true, a rel=nofollow should be used */
+    protected $nofollow = true;
+    /** @var string this item's label may contain a placeholder, which is replaced with this */
+    protected $replacement = '';
+    /** @var string the full path to the SVG icon of this menu item */
+    protected $svg = DOKU_INC . 'lib/images/menu/00-default_checkbox-blank-circle-outline.svg';
+    /** @var string can be set to overwrite the default lookup in $lang.btn_* */
+    protected $label = '';
+    /** @var string the tooltip title, defaults to $label */
+    protected $title = '';
+    /** @var int the context this titme is shown in */
+    protected $context = self::CTX_ALL;
+
+    /**
+     * AbstractItem constructor.
+     *
+     * Sets the dynamic properties
+     *
+     * Children should always call the parent constructor!
+     *
+     * @throws \RuntimeException when the action is disabled
+     */
+    public function __construct() {
+        global $ID;
+        $this->id = $ID;
+        $this->type = $this->getType();
+        $this->params['do'] = $this->type;
+
+        if(!actionOK($this->type)) throw new \RuntimeException("action disabled: {$this->type}");
+    }
+
+    /**
+     * Return this item's label
+     *
+     * When the label property was set, it is simply returned. Otherwise, the action's type
+     * is used to look up the translation in the main language file and, if used, the replacement
+     * is applied.
+     *
+     * @return string
+     */
+    public function getLabel() {
+        if($this->label !== '') return $this->label;
+
+        /** @var array $lang */
+        global $lang;
+        $label = $lang['btn_' . $this->type];
+        if(strpos($label, '%s')) {
+            $label = sprintf($label, $this->replacement);
+        }
+        if($label === '') $label = '[' . $this->type . ']';
+        return $label;
+    }
+
+    /**
+     * Return this item's title
+     *
+     * This title should be used to display a tooltip (using the HTML title attribute). If
+     * a title property was not explicitly set, the label will be returned.
+     *
+     * @return string
+     */
+    public function getTitle() {
+        if($this->title === '') return $this->getLabel();
+        return $this->title;
+    }
+
+    /**
+     * Return the link this item links to
+     *
+     * Basically runs wl() on $id and $params. However if the ID is a hash it is used directly
+     * as the link
+     *
+     * Please note that the generated URL is *not* XML escaped.
+     *
+     * @see wl()
+     * @return string
+     */
+    public function getLink() {
+        if($this->id[0] == '#') {
+            return $this->id;
+        } else {
+            return wl($this->id, $this->params, false, '&');
+        }
+    }
+
+    /**
+     * Convenience method to get the attributes for constructing an <a> element
+     *
+     * @see buildAttributes()
+     * @param string|false $classprefix create a class from type with this prefix, false for no class
+     * @return array
+     */
+    public function getLinkAttributes($classprefix = 'menuitem ') {
+        $attr = array(
+            'href' => $this->getLink(),
+            'title' => $this->getTitle(),
+        );
+        if($this->isNofollow()) $attr['rel'] = 'nofollow';
+        if($this->getAccesskey()) {
+            $attr['accesskey'] = $this->getAccesskey();
+            $attr['title'] .= ' [' . $this->getAccesskey() . ']';
+        }
+        if($classprefix !== false) $attr['class'] = $classprefix . $this->getType();
+
+        return $attr;
+    }
+
+    /**
+     * Convenience method to create a full <a> element
+     *
+     * Wraps around the label and SVG image
+     *
+     * @param string|false $classprefix create a class from type with this prefix, false for no class
+     * @param bool $svg add SVG icon to the link
+     * @return string
+     */
+    public function asHtmlLink($classprefix = 'menuitem ', $svg = true) {
+        $attr = buildAttributes($this->getLinkAttributes($classprefix));
+        $html = "<a $attr>";
+        if($svg) {
+            $html .= '<span>' . hsc($this->getLabel()) . '</span>';
+            $html .= inlineSVG($this->getSvg());
+        } else {
+            $html .= hsc($this->getLabel());
+        }
+        $html .= "</a>";
+
+        return $html;
+    }
+
+    /**
+     * Convenience method to create a <button> element inside it's own form element
+     *
+     * Uses html_btn()
+     *
+     * @return string
+     */
+    public function asHtmlButton() {
+        return html_btn(
+            $this->getType(),
+            $this->id,
+            $this->getAccesskey(),
+            $this->getParams(),
+            $this->method,
+            $this->getTitle(),
+            $this->getLabel(),
+            $this->getSvg()
+        );
+    }
+
+    /**
+     * Should this item be shown in the given context
+     *
+     * @param int $ctx the current context
+     * @return bool
+     */
+    public function visibleInContext($ctx) {
+        return (bool) ($ctx & $this->context);
+    }
+
+    /**
+     * @return string the name of this item
+     */
+    public function getType() {
+        if($this->type === '') {
+            $this->type = strtolower(substr(strrchr(get_class($this), '\\'), 1));
+        }
+        return $this->type;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAccesskey() {
+        return $this->accesskey;
+    }
+
+    /**
+     * @return array
+     */
+    public function getParams() {
+        return $this->params;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isNofollow() {
+        return $this->nofollow;
+    }
+
+    /**
+     * @return string
+     */
+    public function getSvg() {
+        return $this->svg;
+    }
+
+    /**
+     * Return this Item's settings as an array as used in tpl_get_action()
+     *
+     * @return array
+     */
+    public function getLegacyData() {
+        return array(
+            'accesskey' => $this->accesskey ?: null,
+            'type' => $this->type,
+            'id' => $this->id,
+            'method' => $this->method,
+            'params' => $this->params,
+            'nofollow' => $this->nofollow,
+            'replacement' => $this->replacement
+        );
+    }
+}
diff --git a/inc/Menu/Item/Admin.php b/inc/Menu/Item/Admin.php
new file mode 100644
index 0000000000000000000000000000000000000000..7302f0f34fd42eabc96f886668d8efb691c8a0a1
--- /dev/null
+++ b/inc/Menu/Item/Admin.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Admin
+ *
+ * Opens the Admin screen. Only shown to managers or above
+ */
+class Admin extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INFO;
+        parent::__construct();
+
+        $this->svg = DOKU_INC . 'lib/images/menu/settings.svg';
+
+        if(!$INFO['ismanager']) {
+            throw new \RuntimeException("admin is for managers only");
+        }
+    }
+
+}
diff --git a/inc/Menu/Item/Back.php b/inc/Menu/Item/Back.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7cc1d976dbc82da820c8cad0e45b500dc982ceb
--- /dev/null
+++ b/inc/Menu/Item/Back.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Back
+ *
+ * Navigates back up one namepspace. This is currently not used in any menu. Templates
+ * would need to add this item manually.
+ */
+class Back extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $ID;
+        parent::__construct();
+
+        $parent = tpl_getparent($ID);
+        if(!$parent) {
+            throw new \RuntimeException("No parent for back action");
+        }
+
+        $this->id = $parent;
+        $this->params = array('do' => '');
+        $this->accesskey = 'b';
+        $this->svg = DOKU_INC . 'lib/images/menu/12-back_arrow-left.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Backlink.php b/inc/Menu/Item/Backlink.php
new file mode 100644
index 0000000000000000000000000000000000000000..6dc242bdd76a480ea87f7b1c43d7f25c53e3dee8
--- /dev/null
+++ b/inc/Menu/Item/Backlink.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Backlink
+ *
+ * Shows the backlinks for the current page
+ */
+class Backlink extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        parent::__construct();
+        $this->svg = DOKU_INC . 'lib/images/menu/08-backlink_link-variant.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Edit.php b/inc/Menu/Item/Edit.php
new file mode 100644
index 0000000000000000000000000000000000000000..5de1778fdec520b978dc9c09d61e63c192452626
--- /dev/null
+++ b/inc/Menu/Item/Edit.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Edit
+ *
+ * Most complex item. Shows the edit button but mutates to show, draft and create based on
+ * current state.
+ */
+class Edit extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $ACT;
+        global $INFO;
+        global $REV;
+
+        parent::__construct();
+
+        if($ACT === 'show') {
+            $this->method = 'post';
+            if($INFO['writable']) {
+                $this->accesskey = 'e';
+                if(!empty($INFO['draft'])) {
+                    $this->type = 'draft';
+                    $this->params['do'] = 'draft';
+                } else {
+                    $this->params['rev'] = $REV;
+                    if(!$INFO['exists']) {
+                        $this->type = 'create';
+                    }
+                }
+            } else {
+                if(!actionOK($this->type)) throw new \RuntimeException("action disabled: source");
+                $params['rev'] = $REV;
+                $this->type = 'source';
+                $this->accesskey = 'v';
+            }
+        } else {
+            $this->params = array('do' => '');
+            $this->type = 'show';
+            $this->accesskey = 'v';
+        }
+
+        $this->setIcon();
+    }
+
+    /**
+     * change the icon according to what type the edit button has
+     */
+    protected function setIcon() {
+        $icons = array(
+            'edit' => '01-edit_pencil.svg',
+            'create' => '02-create_pencil.svg',
+            'draft' => '03-draft_android-studio.svg',
+            'show' => '04-show_file-document.svg',
+            'source' => '05-source_file-xml.svg',
+        );
+        if(isset($icons[$this->type])) {
+            $this->svg = DOKU_INC . 'lib/images/menu/' . $icons[$this->type];
+        }
+    }
+
+}
diff --git a/inc/Menu/Item/ImgBackto.php b/inc/Menu/Item/ImgBackto.php
new file mode 100644
index 0000000000000000000000000000000000000000..72820a53a5cc8424554c07e7991fbae1a141a303
--- /dev/null
+++ b/inc/Menu/Item/ImgBackto.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class ImgBackto
+ *
+ * Links back to the originating page from a detail image view
+ */
+class ImgBackto extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $ID;
+        parent::__construct();
+
+        $this->svg = DOKU_INC . 'lib/images/menu/12-back_arrow-left.svg';
+        $this->type = 'img_backto';
+        $this->params = array();
+        $this->accesskey = 'b';
+        $this->replacement = $ID;
+    }
+
+}
diff --git a/inc/Menu/Item/Index.php b/inc/Menu/Item/Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..41326738b5ed0909070dca95338d1726873b825d
--- /dev/null
+++ b/inc/Menu/Item/Index.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Index
+ *
+ * Shows the sitemap
+ */
+class Index extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $conf;
+        global $ID;
+        parent::__construct();
+
+        $this->accesskey = 'x';
+        $this->svg = DOKU_INC . 'lib/images/menu/file-tree.svg';
+
+        // allow searchbots to get to the sitemap from the homepage (when dokuwiki isn't providing a sitemap.xml)
+        if($conf['start'] == $ID && !$conf['sitemap']) {
+            $this->nofollow = false;
+        }
+    }
+
+}
diff --git a/inc/Menu/Item/Login.php b/inc/Menu/Item/Login.php
new file mode 100644
index 0000000000000000000000000000000000000000..671f6a78a3cb4441f13d37f75baf4e9ccaeb3974
--- /dev/null
+++ b/inc/Menu/Item/Login.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Login
+ *
+ * Show a login or logout item, based on the current state
+ */
+class Login extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INPUT;
+        parent::__construct();
+
+        $this->svg = DOKU_INC . 'lib/images/menu/login.svg';
+        $this->params['sectok'] = getSecurityToken();
+        if($INPUT->server->has('REMOTE_USER')) {
+            if(!actionOK('logout')) {
+                throw new \RuntimeException("logout disabled");
+            }
+            $this->params['do'] = 'logout';
+            $this->type = 'logout';
+            $this->svg = DOKU_INC . 'lib/images/menu/logout.svg';
+        }
+    }
+
+}
diff --git a/inc/Menu/Item/Media.php b/inc/Menu/Item/Media.php
new file mode 100644
index 0000000000000000000000000000000000000000..0e5f47bae4bdce00a71f11375bcabb355cac5979
--- /dev/null
+++ b/inc/Menu/Item/Media.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Media
+ *
+ * Opens the media manager
+ */
+class Media extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $ID;
+        parent::__construct();
+
+        $this->svg = DOKU_INC . 'lib/images/menu/folder-multiple-image.svg';
+        $this->params['ns'] = getNS($ID);
+    }
+
+}
diff --git a/inc/Menu/Item/MediaManager.php b/inc/Menu/Item/MediaManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..8549d20053d57fbdd46f7487ec0fc6448d976ded
--- /dev/null
+++ b/inc/Menu/Item/MediaManager.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class MediaManager
+ *
+ * Opens the current image in the media manager. Used on image detail view.
+ */
+class MediaManager extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $IMG;
+        parent::__construct();
+
+        $imgNS = getNS($IMG);
+        $authNS = auth_quickaclcheck("$imgNS:*");
+        if($authNS < AUTH_UPLOAD) {
+            throw new \RuntimeException("media manager link only with upload permissions");
+        }
+
+        $this->svg = DOKU_INC . 'lib/images/menu/11-mediamanager_folder-image.svg';
+        $this->type = 'mediaManager';
+        $this->params = array(
+            'ns' => $imgNS,
+            'image' => $IMG,
+            'do' => 'media'
+        );
+    }
+
+}
diff --git a/inc/Menu/Item/Profile.php b/inc/Menu/Item/Profile.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b4ceeb77187223b129d239c12a6b9e2c1651190
--- /dev/null
+++ b/inc/Menu/Item/Profile.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Profile
+ *
+ * Open the user's profile
+ */
+class Profile extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INPUT;
+        parent::__construct();
+
+        if(!$INPUT->server->str('REMOTE_USER')) {
+            throw new \RuntimeException("profile is only for logged in users");
+        }
+
+        $this->svg = DOKU_INC . 'lib/images/menu/account-card-details.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Recent.php b/inc/Menu/Item/Recent.php
new file mode 100644
index 0000000000000000000000000000000000000000..ff90ce605cd1146fc2121a59cf9680040e94b8ba
--- /dev/null
+++ b/inc/Menu/Item/Recent.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Recent
+ *
+ * Show the site wide recent changes
+ */
+class Recent extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        parent::__construct();
+
+        $this->accesskey = 'r';
+        $this->svg = DOKU_INC . 'lib/images/menu/calendar-clock.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Register.php b/inc/Menu/Item/Register.php
new file mode 100644
index 0000000000000000000000000000000000000000..615146ea60289fd0b8208a22e682be6dcd8e9701
--- /dev/null
+++ b/inc/Menu/Item/Register.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Register
+ *
+ * Open the view to register a new account
+ */
+class Register extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INPUT;
+        parent::__construct();
+
+        if($INPUT->server->str('REMOTE_USER')) {
+            throw new \RuntimeException("no register when already logged in");
+        }
+
+        $this->svg = DOKU_INC . 'lib/images/menu/account-plus.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Resendpwd.php b/inc/Menu/Item/Resendpwd.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ddc6b02f34133f5ae12ed77d2d9379a7bd165c5
--- /dev/null
+++ b/inc/Menu/Item/Resendpwd.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Resendpwd
+ *
+ * Access the "forgot password" dialog
+ */
+class Resendpwd extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INPUT;
+        parent::__construct();
+
+        if($INPUT->server->str('REMOTE_USER')) {
+            throw new \RuntimeException("no resendpwd when already logged in");
+        }
+
+        $this->svg = DOKU_INC . 'lib/images/menu/lock-reset.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Revert.php b/inc/Menu/Item/Revert.php
new file mode 100644
index 0000000000000000000000000000000000000000..a360c68424346f425374c4e31bac01ed1e87c52f
--- /dev/null
+++ b/inc/Menu/Item/Revert.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Revert
+ *
+ * Quick revert to the currently shown page revision
+ */
+class Revert extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $REV;
+        global $INFO;
+        parent::__construct();
+
+        if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
+            throw new \RuntimeException('revert not available');
+        }
+        $this->params['rev'] = $REV;
+        $this->params['sectok'] = getSecurityToken();
+        $this->svg = DOKU_INC . 'lib/images/menu/06-revert_replay.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Revisions.php b/inc/Menu/Item/Revisions.php
new file mode 100644
index 0000000000000000000000000000000000000000..3009a7924e35c7699379b26666f69c2d1d431e64
--- /dev/null
+++ b/inc/Menu/Item/Revisions.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Revisions
+ *
+ * Access the old revisions of the current page
+ */
+class Revisions extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        parent::__construct();
+
+        $this->accesskey = 'o';
+        $this->type = 'revs';
+        $this->svg = DOKU_INC . 'lib/images/menu/07-revisions_history.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Subscribe.php b/inc/Menu/Item/Subscribe.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c9d335f8c428c1cd41110effecd45a09ed5430a
--- /dev/null
+++ b/inc/Menu/Item/Subscribe.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Subscribe
+ *
+ * Access the subscription management view
+ */
+class Subscribe extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        global $INPUT;
+        parent::__construct();
+
+        if(!$INPUT->server->str('REMOTE_USER')) {
+            throw new \RuntimeException("subscribe is only for logged in users");
+        }
+
+        $this->svg = DOKU_INC . 'lib/images/menu/09-subscribe_email-outline.svg';
+    }
+
+}
diff --git a/inc/Menu/Item/Top.php b/inc/Menu/Item/Top.php
new file mode 100644
index 0000000000000000000000000000000000000000..a05c4f11964af9867120a53b1e92324dd50c7a0c
--- /dev/null
+++ b/inc/Menu/Item/Top.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace dokuwiki\Menu\Item;
+
+/**
+ * Class Top
+ *
+ * Scroll back to the top. Uses a hash as $id which is handled special in getLink().
+ * Not shown in mobile context
+ */
+class Top extends AbstractItem {
+
+    /** @inheritdoc */
+    public function __construct() {
+        parent::__construct();
+
+        $this->svg = DOKU_INC . 'lib/images/menu/10-top_arrow-up.svg';
+        $this->accesskey = 't';
+        $this->params = array('do' => '');
+        $this->id = '#dokuwiki__top';
+        $this->context = self::CTX_DESKTOP;
+    }
+
+    /**
+     * Convenience method to create a <button> element
+     *
+     * Uses html_topbtn()
+     *
+     * @todo this does currently not support the SVG icon
+     * @return string
+     */
+    public function asHtmlButton() {
+        return html_topbtn();
+    }
+
+}
diff --git a/inc/Menu/MenuInterface.php b/inc/Menu/MenuInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..91dde9db6946faa27fcdd350cf2e45d332476c80
--- /dev/null
+++ b/inc/Menu/MenuInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+use dokuwiki\Menu\Item\AbstractItem;
+
+/**
+ * Interface MenuInterface
+ *
+ * Defines what a Menu provides
+ */
+Interface MenuInterface {
+
+    /**
+     * Get the list of action items in this menu
+     *
+     * @return AbstractItem[]
+     */
+    public function getItems();
+}
diff --git a/inc/Menu/MobileMenu.php b/inc/Menu/MobileMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..29e17d163942f026b75a087dfaed16db45a01558
--- /dev/null
+++ b/inc/Menu/MobileMenu.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+use dokuwiki\Menu\Item\AbstractItem;
+
+/**
+ * Class MobileMenu
+ *
+ * Note: this does not inherit from AbstractMenu because it is not working like the other
+ * menus. This is a meta menu, aggregating the items from the other menus and offering a combined
+ * view. The idea is to use this on mobile devices, thus the context is fixed to CTX_MOBILE
+ */
+class MobileMenu implements MenuInterface {
+
+    /**
+     * Returns all items grouped by view
+     *
+     * @return AbstractItem[][]
+     */
+    public function getGroupedItems() {
+        $pagemenu = new PageMenu(AbstractItem::CTX_MOBILE);
+        $sitemenu = new SiteMenu(AbstractItem::CTX_MOBILE);
+        $usermenu = new UserMenu(AbstractItem::CTX_MOBILE);
+
+        return array(
+            'page' => $pagemenu->getItems(),
+            'site' => $sitemenu->getItems(),
+            'user' => $usermenu->getItems()
+        );
+    }
+
+    /**
+     * Get all items in a flat array
+     *
+     * This returns the same format as AbstractMenu::getItems()
+     *
+     * @return AbstractItem[]
+     */
+    public function getItems() {
+        $menu = $this->getGroupedItems();
+        return call_user_func_array('array_merge', array_values($menu));
+    }
+
+    /**
+     * Print a dropdown menu with all DokuWiki actions
+     *
+     * Note: this will not use any pretty URLs
+     *
+     * @param string $empty empty option label
+     * @param string $button submit button label
+     * @return string
+     */
+    public function getDropdown($empty = '', $button = '&gt;') {
+        global $ID;
+        global $REV;
+        /** @var string[] $lang */
+        global $lang;
+        global $INPUT;
+
+        $html = '<form action="' . script() . '" method="get" accept-charset="utf-8">';
+        $html .= '<div class="no">';
+        $html .= '<input type="hidden" name="id" value="' . $ID . '" />';
+        if($REV) $html .= '<input type="hidden" name="rev" value="' . $REV . '" />';
+        if($INPUT->server->str('REMOTE_USER')) {
+            $html .= '<input type="hidden" name="sectok" value="' . getSecurityToken() . '" />';
+        }
+
+        $html .= '<select name="do" class="edit quickselect" title="' . $lang['tools'] . '">';
+        $html .= '<option value="">' . $empty . '</option>';
+
+        foreach($this->getGroupedItems() as $tools => $items) {
+            $html .= '<optgroup label="' . $lang[$tools . '_tools'] . '">';
+            foreach($items as $item) {
+                $params = $item->getParams();
+                $html .= '<option value="' . $params['do'] . '">';
+                $html .= hsc($item->getLabel());
+                $html .= '</option>';
+            }
+            $html .= '</optgroup>';
+        }
+
+        $html .= '</select>';
+        $html .= '<button type="submit">' . $button . '</button>';
+        $html .= '</div>';
+        $html .= '</form>';
+
+        return $html;
+    }
+
+}
diff --git a/inc/Menu/PageMenu.php b/inc/Menu/PageMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c0a55e2d634aaebc3eb5e6492b2721768da2918
--- /dev/null
+++ b/inc/Menu/PageMenu.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+/**
+ * Class PageMenu
+ *
+ * Actions manipulating the current page. Shown as a floating menu in the dokuwiki template
+ */
+class PageMenu extends AbstractMenu {
+
+    protected $view = 'page';
+
+    protected $types = array(
+        'Edit',
+        'Revert',
+        'Revisions',
+        'Backlink',
+        'Subscribe',
+        'Top',
+    );
+
+}
diff --git a/inc/Menu/SiteMenu.php b/inc/Menu/SiteMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..dba6888c7f0169d6c972452c2995afb198a2314d
--- /dev/null
+++ b/inc/Menu/SiteMenu.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+/**
+ * Class SiteMenu
+ *
+ * Actions that are not bound to an individual page but provide toolsfor the whole wiki.
+ */
+class SiteMenu extends AbstractMenu {
+
+    protected $view = 'site';
+
+    protected $types = array(
+        'Recent',
+        'Media',
+        'Index'
+    );
+
+}
diff --git a/inc/Menu/UserMenu.php b/inc/Menu/UserMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..01028d3ccbb4b6cb4b38debde12a2962d871bc45
--- /dev/null
+++ b/inc/Menu/UserMenu.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\Menu;
+
+/**
+ * Class UserMenu
+ *
+ * Actions related to the current user
+ */
+class UserMenu extends AbstractMenu {
+
+    protected $view = 'user';
+
+    protected $types = array(
+        'Profile',
+        'Admin',
+        'Register',
+        'Login',
+    );
+
+}
diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php
index d24cc75e52110660c1b142dde1102b7713b441a1..3d03c1e057969704e3397c0eeed8f0e2eb646e5a 100644
--- a/inc/PassHash.class.php
+++ b/inc/PassHash.class.php
@@ -91,7 +91,7 @@ class PassHash {
         //crypt and compare
         $call = 'hash_'.$method;
         $newhash = $this->$call($clear, $salt, $magic);
-        if($newhash === $hash) {
+        if(\hash_equals($newhash, $hash)) {
             return true;
         }
         return false;
@@ -530,7 +530,7 @@ class PassHash {
      * @throws Exception
      * @return string Hashed password
      */
-    public function hash_bcrypt($clear, $salt = null, $compute = 8) {
+    public function hash_bcrypt($clear, $salt = null, $compute = 10) {
         if(!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH != 1) {
             throw new Exception('This PHP installation has no bcrypt support');
         }
diff --git a/inc/Plugin.php b/inc/Plugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..9cd0ae80526287d78a9f72c343ebe8ffcbc001f2
--- /dev/null
+++ b/inc/Plugin.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * DokuWiki Plugin
+ *
+ * Most of DokuWiki's plugin types simply inherit from this. All it does is
+ * add the DokuWiki_PluginTrait to the class.
+ */
+class DokuWiki_Plugin implements DokuWiki_PluginInterface {
+    use DokuWiki_PluginTrait;
+}
diff --git a/inc/PluginInterface.php b/inc/PluginInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..60898909642891801d47d433b568cf87c9629fa3
--- /dev/null
+++ b/inc/PluginInterface.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * DokuWiki Plugin Interface
+ *
+ * Defines the public contract all DokuWiki plugins will adhere to. The actual code
+ * to do so is defined in DokuWiki_PluginTrait
+ *
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Christopher Smith <chris@jalakai.co.uk>
+ */
+interface DokuWiki_PluginInterface {
+    /**
+     * General Info
+     *
+     * Needs to return a associative array with the following values:
+     *
+     * base   - the plugin's base name (eg. the directory it needs to be installed in)
+     * author - Author of the plugin
+     * email  - Email address to contact the author
+     * date   - Last modified date of the plugin in YYYY-MM-DD format
+     * name   - Name of the plugin
+     * desc   - Short description of the plugin (Text only)
+     * url    - Website with more information on the plugin (eg. syntax description)
+     */
+    public function getInfo();
+
+    /**
+     * The type of the plugin inferred from the class name
+     *
+     * @return string  plugin type
+     */
+    public function getPluginType();
+
+    /**
+     * The name of the plugin inferred from the class name
+     *
+     * @return string  plugin name
+     */
+    public function getPluginName();
+
+    /**
+     * The component part of the plugin inferred from the class name
+     *
+     * @return string component name
+     */
+    public function getPluginComponent();
+
+    /**
+     * Access plugin language strings
+     *
+     * to try to minimise unnecessary loading of the strings when the plugin doesn't require them
+     * e.g. when info plugin is querying plugins for information about themselves.
+     *
+     * @param   string $id id of the string to be retrieved
+     * @return  string in appropriate language or english if not available
+     */
+    public function getLang($id);
+
+    /**
+     * retrieve a language dependent file and pass to xhtml renderer for display
+     * plugin equivalent of p_locale_xhtml()
+     *
+     * @param   string $id id of language dependent wiki page
+     * @return  string parsed contents of the wiki page in xhtml format
+     */
+    public function locale_xhtml($id);
+
+    /**
+     * Prepends appropriate path for a language dependent filename
+     * plugin equivalent of localFN()
+     *
+     * @param string $id id of localization file
+     * @param  string $ext The file extension (usually txt)
+     * @return string wiki text
+     */
+    public function localFN($id, $ext = 'txt');
+
+    /**
+     * Reads all the plugins language dependent strings into $this->lang
+     * this function is automatically called by getLang()
+     *
+     * @todo this could be made protected and be moved to the trait only
+     */
+    public function setupLocale();
+
+    /**
+     * use this function to access plugin configuration variables
+     *
+     * @param string $setting the setting to access
+     * @param mixed $notset what to return if the setting is not available
+     * @return mixed
+     */
+    public function getConf($setting, $notset = false);
+
+    /**
+     * merges the plugin's default settings with any local settings
+     * this function is automatically called through getConf()
+     *
+     * @todo this could be made protected and be moved to the trait only
+     */
+    public function loadConfig();
+
+    /**
+     * Loads a given helper plugin (if enabled)
+     *
+     * @author  Esther Brunner <wikidesign@gmail.com>
+     *
+     * @param   string $name name of plugin to load
+     * @param   bool $msg if a message should be displayed in case the plugin is not available
+     * @return  DokuWiki_PluginInterface|null helper plugin object
+     */
+    public function loadHelper($name, $msg = true);
+
+    /**
+     * email
+     * standardised function to generate an email link according to obfuscation settings
+     *
+     * @param string $email
+     * @param string $name
+     * @param string $class
+     * @param string $more
+     * @return string html
+     */
+    public function email($email, $name = '', $class = '', $more = '');
+
+    /**
+     * external_link
+     * standardised function to generate an external link according to conf settings
+     *
+     * @param string $link
+     * @param string $title
+     * @param string $class
+     * @param string $target
+     * @param string $more
+     * @return string
+     */
+    public function external_link($link, $title = '', $class = '', $target = '', $more = '');
+
+    /**
+     * output text string through the parser, allows dokuwiki markup to be used
+     * very ineffecient for small pieces of data - try not to use
+     *
+     * @param string $text wiki markup to parse
+     * @param string $format output format
+     * @return null|string
+     */
+    public function render_text($text, $format = 'xhtml');
+
+    /**
+     * Allow the plugin to prevent DokuWiki from reusing an instance
+     *
+     * @return bool   false if the plugin has to be instantiated
+     */
+    public function isSingleton();
+}
+
+
+
diff --git a/inc/PluginTrait.php b/inc/PluginTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..57b735e85423f75664780724e707bbff3c064d35
--- /dev/null
+++ b/inc/PluginTrait.php
@@ -0,0 +1,238 @@
+<?php
+
+/**
+ * Do not inherit directly from this class, instead inherit from the specialized
+ * ones in lib/plugin
+ */
+trait DokuWiki_PluginTrait {
+
+    protected $localised = false;        // set to true by setupLocale() after loading language dependent strings
+    protected $lang = array();           // array to hold language dependent strings, best accessed via ->getLang()
+    protected $configloaded = false;     // set to true by loadConfig() after loading plugin configuration variables
+    protected $conf = array();           // array to hold plugin settings, best accessed via ->getConf()
+
+    /**
+     * @see DokuWiki_PluginInterface::getInfo()
+     */
+    public function getInfo() {
+        $parts = explode('_', get_class($this));
+        $info = DOKU_PLUGIN . '/' . $parts[2] . '/plugin.info.txt';
+        if(file_exists($info)) return confToHash($info);
+
+        msg(
+            'getInfo() not implemented in ' . get_class($this) . ' and ' . $info . ' not found.<br />' .
+            'Verify you\'re running the latest version of the plugin. If the problem persists, send a ' .
+            'bug report to the author of the ' . $parts[2] . ' plugin.', -1
+        );
+        return array(
+            'date' => '0000-00-00',
+            'name' => $parts[2] . ' plugin',
+        );
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::isSingleton()
+     */
+    public function isSingleton() {
+        return true;
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::loadHelper()
+     */
+    public function loadHelper($name, $msg = true) {
+        $obj = plugin_load('helper', $name);
+        if(is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.", -1);
+        return $obj;
+    }
+
+    // region introspection methods
+
+    /**
+     * @see DokuWiki_PluginInterface::getPluginType()
+     */
+    public function getPluginType() {
+        list($t) = explode('_', get_class($this), 2);
+        return $t;
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::getPluginName()
+     */
+    public function getPluginName() {
+        list(/* $t */, /* $p */, $n) = explode('_', get_class($this), 4);
+        return $n;
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::getPluginComponent()
+     */
+    public function getPluginComponent() {
+        list(/* $t */, /* $p */, /* $n */, $c) = explode('_', get_class($this), 4);
+        return (isset($c) ? $c : '');
+    }
+
+    // endregion
+    // region localization methods
+
+    /**
+     * @see DokuWiki_PluginInterface::getLang()
+     */
+    public function getLang($id) {
+        if(!$this->localised) $this->setupLocale();
+
+        return (isset($this->lang[$id]) ? $this->lang[$id] : '');
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::locale_xhtml()
+     */
+    public function locale_xhtml($id) {
+        return p_cached_output($this->localFN($id));
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::localFN()
+     */
+    public function localFN($id, $ext = 'txt') {
+        global $conf;
+        $plugin = $this->getPluginName();
+        $file = DOKU_CONF . 'plugin_lang/' . $plugin . '/' . $conf['lang'] . '/' . $id . '.' . $ext;
+        if(!file_exists($file)) {
+            $file = DOKU_PLUGIN . $plugin . '/lang/' . $conf['lang'] . '/' . $id . '.' . $ext;
+            if(!file_exists($file)) {
+                //fall back to english
+                $file = DOKU_PLUGIN . $plugin . '/lang/en/' . $id . '.' . $ext;
+            }
+        }
+        return $file;
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::setupLocale()
+     */
+    public function setupLocale() {
+        if($this->localised) return;
+
+        global $conf, $config_cascade; // definitely don't invoke "global $lang"
+        $path = DOKU_PLUGIN . $this->getPluginName() . '/lang/';
+
+        $lang = array();
+
+        // don't include once, in case several plugin components require the same language file
+        @include($path . 'en/lang.php');
+        foreach($config_cascade['lang']['plugin'] as $config_file) {
+            if(file_exists($config_file . $this->getPluginName() . '/en/lang.php')) {
+                include($config_file . $this->getPluginName() . '/en/lang.php');
+            }
+        }
+
+        if($conf['lang'] != 'en') {
+            @include($path . $conf['lang'] . '/lang.php');
+            foreach($config_cascade['lang']['plugin'] as $config_file) {
+                if(file_exists($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php')) {
+                    include($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php');
+                }
+            }
+        }
+
+        $this->lang = $lang;
+        $this->localised = true;
+    }
+
+    // endregion
+    // region configuration methods
+
+    /**
+     * @see DokuWiki_PluginInterface::getConf()
+     */
+    public function getConf($setting, $notset = false) {
+
+        if(!$this->configloaded) {
+            $this->loadConfig();
+        }
+
+        if(isset($this->conf[$setting])) {
+            return $this->conf[$setting];
+        } else {
+            return $notset;
+        }
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::loadConfig()
+     */
+    public function loadConfig() {
+        global $conf;
+
+        $defaults = $this->readDefaultSettings();
+        $plugin = $this->getPluginName();
+
+        foreach($defaults as $key => $value) {
+            if(isset($conf['plugin'][$plugin][$key])) continue;
+            $conf['plugin'][$plugin][$key] = $value;
+        }
+
+        $this->configloaded = true;
+        $this->conf =& $conf['plugin'][$plugin];
+    }
+
+    /**
+     * read the plugin's default configuration settings from conf/default.php
+     * this function is automatically called through getConf()
+     *
+     * @return    array    setting => value
+     */
+    protected function readDefaultSettings() {
+
+        $path = DOKU_PLUGIN . $this->getPluginName() . '/conf/';
+        $conf = array();
+
+        if(file_exists($path . 'default.php')) {
+            include($path . 'default.php');
+        }
+
+        return $conf;
+    }
+
+    // endregion
+    // region output methods
+
+    /**
+     * @see DokuWiki_PluginInterface::email()
+     */
+    public function email($email, $name = '', $class = '', $more = '') {
+        if(!$email) return $name;
+        $email = obfuscate($email);
+        if(!$name) $name = $email;
+        $class = "class='" . ($class ? $class : 'mail') . "'";
+        return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::external_link()
+     */
+    public function external_link($link, $title = '', $class = '', $target = '', $more = '') {
+        global $conf;
+
+        $link = htmlentities($link);
+        if(!$title) $title = $link;
+        if(!$target) $target = $conf['target']['extern'];
+        if($conf['relnofollow']) $more .= ' rel="nofollow"';
+
+        if($class) $class = " class='$class'";
+        if($target) $target = " target='$target'";
+        if($more) $more = " " . trim($more);
+
+        return "<a href='$link'$class$target$more>$title</a>";
+    }
+
+    /**
+     * @see DokuWiki_PluginInterface::render_text()
+     */
+    public function render_text($text, $format = 'xhtml') {
+        return p_render($format, p_get_instructions($text), $info);
+    }
+
+    // endregion
+}
diff --git a/inc/StyleUtils.php b/inc/StyleUtils.php
new file mode 100644
index 0000000000000000000000000000000000000000..e584942c0f48a97e6556f81a2222f2d27337cc03
--- /dev/null
+++ b/inc/StyleUtils.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace dokuwiki;
+
+class StyleUtils
+{
+    /**
+     * Load style ini contents
+     *
+     * Loads and merges style.ini files from template and config and prepares
+     * the stylesheet modes
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     *
+     * @param string $tpl the used template
+     * @param bool   $preview load preview replacements
+     * @return array with keys 'stylesheets' and 'replacements'
+     */
+    public function cssStyleini($tpl, $preview=false) {
+        global $conf;
+
+        $stylesheets = array(); // mode, file => base
+        // guaranteed placeholder => value
+        $replacements = array(
+            '__text__' => "#000",
+            '__background__' => "#fff",
+            '__text_alt__' => "#999",
+            '__background_alt__' => "#eee",
+            '__text_neu__' => "#666",
+            '__background_neu__' => "#ddd",
+            '__border__' => "#ccc",
+            '__highlight__' => "#ff9",
+            '__link__' => "#00f",
+        );
+
+        // load template's style.ini
+        $incbase = tpl_incdir($tpl);
+        $webbase = tpl_basedir($tpl);
+        $ini = $incbase.'style.ini';
+        if(file_exists($ini)){
+            $data = parse_ini_file($ini, true);
+
+            // stylesheets
+            if(is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){
+                if (!file_exists($incbase . $file)) {
+                    list($extension, $basename) = array_map('strrev', explode('.', strrev($file), 2));
+                    $newExtension = $extension === 'css' ? 'less' : 'css';
+                    if (file_exists($incbase . $basename . '.' . $newExtension)) {
+                        $stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
+                        if ($conf['allowdebug']) {
+                            msg("Stylesheet $file not found, using $basename.$newExtension instead. Please contact developer of \"{$conf['template']}\" template.", 2);
+                        }
+                        continue;
+                    }
+                }
+                $stylesheets[$mode][$incbase . $file] = $webbase;
+            }
+
+            // replacements
+            if(is_array($data['replacements'])){
+                $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'],$webbase));
+            }
+        }
+
+        // load configs's style.ini
+        $webbase = DOKU_BASE;
+        $ini = DOKU_CONF."tpl/$tpl/style.ini";
+        $incbase = dirname($ini).'/';
+        if(file_exists($ini)){
+            $data = parse_ini_file($ini, true);
+
+            // stylesheets
+            if(isset($data['stylesheets']) && is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){
+                $stylesheets[$mode][$incbase.$file] = $webbase;
+            }
+
+            // replacements
+            if(isset($data['replacements']) && is_array($data['replacements'])){
+                $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'],$webbase));
+            }
+        }
+
+        // allow replacement overwrites in preview mode
+        if($preview) {
+            $webbase = DOKU_BASE;
+            $ini     = $conf['cachedir'].'/preview.ini';
+            if(file_exists($ini)) {
+                $data = parse_ini_file($ini, true);
+                // replacements
+                if(is_array($data['replacements'])) {
+                    $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'], $webbase));
+                }
+            }
+        }
+
+        return array(
+            'stylesheets' => $stylesheets,
+            'replacements' => $replacements
+        );
+    }
+
+
+    /**
+     * Amend paths used in replacement relative urls, refer FS#2879
+     *
+     * @author Chris Smith <chris@jalakai.co.uk>
+     *
+     * @param array $replacements with key-value pairs
+     * @param string $location
+     * @return array
+     */
+    protected function cssFixreplacementurls($replacements, $location) {
+        foreach($replacements as $key => $value) {
+            $replacements[$key] = preg_replace('#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#','\\1'.$location,$value);
+        }
+        return $replacements;
+    }
+}
diff --git a/inc/Ui/Admin.php b/inc/Ui/Admin.php
index ed2fa2564ab836971455704c41003e19898e659a..aa3b8b99e281c17e5c20b0a5b7159b495acc3e4c 100644
--- a/inc/Ui/Admin.php
+++ b/inc/Ui/Admin.php
@@ -104,7 +104,7 @@ class Admin extends Ui {
         if(substr($conf['savedir'], 0, 2) !== './') return;
         echo '<a style="border:none; float:right;"
                 href="http://www.dokuwiki.org/security#web_access_security">
-                <img src="' . DOKU_URL . $conf['savedir'] . '/security.png" alt="Your data directory seems to be protected properly."
+                <img src="' . DOKU_URL . $conf['savedir'] . '/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png" alt="Your data directory seems to be protected properly."
                 onerror="this.parentNode.style.display=\'none\'" /></a>';
     }
 
diff --git a/inc/Ui/Search.php b/inc/Ui/Search.php
new file mode 100644
index 0000000000000000000000000000000000000000..c27cd77642d56dd9d99648024d22b4ec836b0a49
--- /dev/null
+++ b/inc/Ui/Search.php
@@ -0,0 +1,636 @@
+<?php
+
+namespace dokuwiki\Ui;
+
+use \dokuwiki\Form\Form;
+
+class Search extends Ui
+{
+    protected $query;
+    protected $parsedQuery;
+    protected $searchState;
+    protected $pageLookupResults = array();
+    protected $fullTextResults = array();
+    protected $highlight = array();
+
+    /**
+     * Search constructor.
+     *
+     * @param array $pageLookupResults pagename lookup results in the form [pagename => pagetitle]
+     * @param array $fullTextResults fulltext search results in the form [pagename => #hits]
+     * @param array $highlight  array of strings to be highlighted
+     */
+    public function __construct(array $pageLookupResults, array $fullTextResults, $highlight)
+    {
+        global $QUERY;
+        $Indexer = idx_get_indexer();
+
+        $this->query = $QUERY;
+        $this->parsedQuery = ft_queryParser($Indexer, $QUERY);
+        $this->searchState = new SearchState($this->parsedQuery);
+
+        $this->pageLookupResults = $pageLookupResults;
+        $this->fullTextResults = $fullTextResults;
+        $this->highlight = $highlight;
+    }
+
+    /**
+     * display the search result
+     *
+     * @return void
+     */
+    public function show()
+    {
+        $searchHTML = '';
+
+        $searchHTML .= $this->getSearchIntroHTML($this->query);
+
+        $searchHTML .= $this->getSearchFormHTML($this->query);
+
+        $searchHTML .= $this->getPageLookupHTML($this->pageLookupResults);
+
+        $searchHTML .= $this->getFulltextResultsHTML($this->fullTextResults, $this->highlight);
+
+        echo $searchHTML;
+    }
+
+    /**
+     * Get a form which can be used to adjust/refine the search
+     *
+     * @param string $query
+     *
+     * @return string
+     */
+    protected function getSearchFormHTML($query)
+    {
+        global $lang, $ID, $INPUT;
+
+        $searchForm = (new Form(['method' => 'get'], true))->addClass('search-results-form');
+        $searchForm->setHiddenField('do', 'search');
+        $searchForm->setHiddenField('id', $ID);
+        $searchForm->setHiddenField('sf', '1');
+        if ($INPUT->has('min')) {
+            $searchForm->setHiddenField('min', $INPUT->str('min'));
+        }
+        if ($INPUT->has('max')) {
+            $searchForm->setHiddenField('max', $INPUT->str('max'));
+        }
+        if ($INPUT->has('srt')) {
+            $searchForm->setHiddenField('srt', $INPUT->str('srt'));
+        }
+        $searchForm->addFieldsetOpen()->addClass('search-form');
+        $searchForm->addTextInput('q')->val($query)->useInput(false);
+        $searchForm->addButton('', $lang['btn_search'])->attr('type', 'submit');
+
+        $this->addSearchAssistanceElements($searchForm);
+
+        $searchForm->addFieldsetClose();
+
+        trigger_event('FORM_SEARCH_OUTPUT', $searchForm);
+
+        return $searchForm->toHTML();
+    }
+
+    /**
+     * Add elements to adjust how the results are sorted
+     *
+     * @param Form $searchForm
+     */
+    protected function addSortTool(Form $searchForm)
+    {
+        global $INPUT, $lang;
+
+        $options = [
+            'hits' => [
+                'label' => $lang['search_sort_by_hits'],
+                'sort' => '',
+            ],
+            'mtime' => [
+                'label' => $lang['search_sort_by_mtime'],
+                'sort' => 'mtime',
+            ],
+        ];
+        $activeOption = 'hits';
+
+        if ($INPUT->str('srt') === 'mtime') {
+            $activeOption = 'mtime';
+        }
+
+        $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true');
+        // render current
+        $currentWrapper = $searchForm->addTagOpen('div')->addClass('current');
+        if ($activeOption !== 'hits') {
+            $currentWrapper->addClass('changed');
+        }
+        $searchForm->addHTML($options[$activeOption]['label']);
+        $searchForm->addTagClose('div');
+
+        // render options list
+        $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false');
+
+        foreach ($options as $key => $option) {
+            $listItem = $searchForm->addTagOpen('li');
+
+            if ($key === $activeOption) {
+                $listItem->addClass('active');
+                $searchForm->addHTML($option['label']);
+            } else {
+                $link = $this->searchState->withSorting($option['sort'])->getSearchLink($option['label']);
+                $searchForm->addHTML($link);
+            }
+            $searchForm->addTagClose('li');
+        }
+        $searchForm->addTagClose('ul');
+
+        $searchForm->addTagClose('div');
+
+    }
+
+    /**
+     * Check if the query is simple enough to modify its namespace limitations without breaking the rest of the query
+     *
+     * @param array $parsedQuery
+     *
+     * @return bool
+     */
+    protected function isNamespaceAssistanceAvailable(array $parsedQuery) {
+        if (preg_match('/[\(\)\|]/', $parsedQuery['query']) === 1) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Check if the query is simple enough to modify the fragment search behavior without breaking the rest of the query
+     *
+     * @param array $parsedQuery
+     *
+     * @return bool
+     */
+    protected function isFragmentAssistanceAvailable(array $parsedQuery) {
+        if (preg_match('/[\(\)\|]/', $parsedQuery['query']) === 1) {
+            return false;
+        }
+
+        if (!empty($parsedQuery['phrases'])) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Add the elements to be used for search assistance
+     *
+     * @param Form $searchForm
+     */
+    protected function addSearchAssistanceElements(Form $searchForm)
+    {
+        $searchForm->addTagOpen('div')
+            ->addClass('advancedOptions')
+            ->attr('style', 'display: none;')
+            ->attr('aria-hidden', 'true');
+
+        $this->addFragmentBehaviorLinks($searchForm);
+        $this->addNamespaceSelector($searchForm);
+        $this->addDateSelector($searchForm);
+        $this->addSortTool($searchForm);
+
+        $searchForm->addTagClose('div');
+    }
+
+    /**
+     *  Add the elements to adjust the fragment search behavior
+     *
+     * @param Form $searchForm
+     */
+    protected function addFragmentBehaviorLinks(Form $searchForm)
+    {
+        if (!$this->isFragmentAssistanceAvailable($this->parsedQuery)) {
+            return;
+        }
+        global $lang;
+
+        $options = [
+            'exact' => [
+                'label' => $lang['search_exact_match'],
+                'and' => array_map(function ($term) {
+                    return trim($term, '*');
+                }, $this->parsedQuery['and']),
+                'not' => array_map(function ($term) {
+                    return trim($term, '*');
+                }, $this->parsedQuery['not']),
+            ],
+            'starts' => [
+                'label' => $lang['search_starts_with'],
+                'and' => array_map(function ($term) {
+                    return trim($term, '*') . '*';
+                }, $this->parsedQuery['and']),
+                'not' => array_map(function ($term) {
+                    return trim($term, '*') . '*';
+                }, $this->parsedQuery['not']),
+            ],
+            'ends' => [
+                'label' => $lang['search_ends_with'],
+                'and' => array_map(function ($term) {
+                    return '*' . trim($term, '*');
+                }, $this->parsedQuery['and']),
+                'not' => array_map(function ($term) {
+                    return '*' . trim($term, '*');
+                }, $this->parsedQuery['not']),
+            ],
+            'contains' => [
+                'label' => $lang['search_contains'],
+                'and' => array_map(function ($term) {
+                    return '*' . trim($term, '*') . '*';
+                }, $this->parsedQuery['and']),
+                'not' => array_map(function ($term) {
+                    return '*' . trim($term, '*') . '*';
+                }, $this->parsedQuery['not']),
+            ]
+        ];
+
+        // detect current
+        $activeOption = 'custom';
+        foreach ($options as $key => $option) {
+            if ($this->parsedQuery['and'] === $option['and']) {
+                $activeOption = $key;
+            }
+        }
+        if ($activeOption === 'custom') {
+            $options = array_merge(['custom' => [
+                'label' => $lang['search_custom_match'],
+            ]], $options);
+        }
+
+        $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true');
+        // render current
+        $currentWrapper = $searchForm->addTagOpen('div')->addClass('current');
+        if ($activeOption !== 'exact') {
+            $currentWrapper->addClass('changed');
+        }
+        $searchForm->addHTML($options[$activeOption]['label']);
+        $searchForm->addTagClose('div');
+
+        // render options list
+        $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false');
+
+        foreach ($options as $key => $option) {
+            $listItem = $searchForm->addTagOpen('li');
+
+            if ($key === $activeOption) {
+                $listItem->addClass('active');
+                $searchForm->addHTML($option['label']);
+            } else {
+                $link = $this->searchState
+                    ->withFragments($option['and'], $option['not'])
+                    ->getSearchLink($option['label'])
+                ;
+                $searchForm->addHTML($link);
+            }
+            $searchForm->addTagClose('li');
+        }
+        $searchForm->addTagClose('ul');
+
+        $searchForm->addTagClose('div');
+
+        // render options list
+    }
+
+    /**
+     * Add the elements for the namespace selector
+     *
+     * @param Form $searchForm
+     */
+    protected function addNamespaceSelector(Form $searchForm)
+    {
+        if (!$this->isNamespaceAssistanceAvailable($this->parsedQuery)) {
+            return;
+        }
+
+        global $lang;
+
+        $baseNS = empty($this->parsedQuery['ns']) ? '' : $this->parsedQuery['ns'][0];
+        $extraNS = $this->getAdditionalNamespacesFromResults($baseNS);
+
+        $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true');
+        // render current
+        $currentWrapper = $searchForm->addTagOpen('div')->addClass('current');
+        if ($baseNS) {
+            $currentWrapper->addClass('changed');
+            $searchForm->addHTML('@' . $baseNS);
+        } else {
+            $searchForm->addHTML($lang['search_any_ns']);
+        }
+        $searchForm->addTagClose('div');
+
+        // render options list
+        $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false');
+
+        $listItem = $searchForm->addTagOpen('li');
+        if ($baseNS) {
+            $listItem->addClass('active');
+            $link = $this->searchState->withNamespace('')->getSearchLink($lang['search_any_ns']);
+            $searchForm->addHTML($link);
+        } else {
+            $searchForm->addHTML($lang['search_any_ns']);
+        }
+        $searchForm->addTagClose('li');
+
+        foreach ($extraNS as $ns => $count) {
+            $listItem = $searchForm->addTagOpen('li');
+            $label = $ns . ($count ? " <bdi>($count)</bdi>" : '');
+
+            if ($ns === $baseNS) {
+                $listItem->addClass('active');
+                $searchForm->addHTML($label);
+            } else {
+                $link = $this->searchState->withNamespace($ns)->getSearchLink($label);
+                $searchForm->addHTML($link);
+            }
+            $searchForm->addTagClose('li');
+        }
+        $searchForm->addTagClose('ul');
+
+        $searchForm->addTagClose('div');
+
+    }
+
+    /**
+     * Parse the full text results for their top namespaces below the given base namespace
+     *
+     * @param string $baseNS the namespace within which was searched, empty string for root namespace
+     *
+     * @return array an associative array with namespace => #number of found pages, sorted descending
+     */
+    protected function getAdditionalNamespacesFromResults($baseNS)
+    {
+        $namespaces = [];
+        $baseNSLength = strlen($baseNS);
+        foreach ($this->fullTextResults as $page => $numberOfHits) {
+            $namespace = getNS($page);
+            if (!$namespace) {
+                continue;
+            }
+            if ($namespace === $baseNS) {
+                continue;
+            }
+            $firstColon = strpos((string)$namespace, ':', $baseNSLength + 1) ?: strlen($namespace);
+            $subtopNS = substr($namespace, 0, $firstColon);
+            if (empty($namespaces[$subtopNS])) {
+                $namespaces[$subtopNS] = 0;
+            }
+            $namespaces[$subtopNS] += 1;
+        }
+        ksort($namespaces);
+        arsort($namespaces);
+        return $namespaces;
+    }
+
+    /**
+     * @ToDo: custom date input
+     *
+     * @param Form $searchForm
+     */
+    protected function addDateSelector(Form $searchForm)
+    {
+        global $INPUT, $lang;
+
+        $options = [
+            'any' => [
+                'before' => false,
+                'after' => false,
+                'label' => $lang['search_any_time'],
+            ],
+            'week' => [
+                'before' => false,
+                'after' => '1 week ago',
+                'label' => $lang['search_past_7_days'],
+            ],
+            'month' => [
+                'before' => false,
+                'after' => '1 month ago',
+                'label' => $lang['search_past_month'],
+            ],
+            'year' => [
+                'before' => false,
+                'after' => '1 year ago',
+                'label' => $lang['search_past_year'],
+            ],
+        ];
+        $activeOption = 'any';
+        foreach ($options as $key => $option) {
+            if ($INPUT->str('min') === $option['after']) {
+                $activeOption = $key;
+                break;
+            }
+        }
+
+        $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true');
+        // render current
+        $currentWrapper = $searchForm->addTagOpen('div')->addClass('current');
+        if ($INPUT->has('max') || $INPUT->has('min')) {
+            $currentWrapper->addClass('changed');
+        }
+        $searchForm->addHTML($options[$activeOption]['label']);
+        $searchForm->addTagClose('div');
+
+        // render options list
+        $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false');
+
+        foreach ($options as $key => $option) {
+            $listItem = $searchForm->addTagOpen('li');
+
+            if ($key === $activeOption) {
+                $listItem->addClass('active');
+                $searchForm->addHTML($option['label']);
+            } else {
+                $link = $this->searchState
+                    ->withTimeLimitations($option['after'], $option['before'])
+                    ->getSearchLink($option['label'])
+                ;
+                $searchForm->addHTML($link);
+            }
+            $searchForm->addTagClose('li');
+        }
+        $searchForm->addTagClose('ul');
+
+        $searchForm->addTagClose('div');
+    }
+
+
+    /**
+     * Build the intro text for the search page
+     *
+     * @param string $query the search query
+     *
+     * @return string
+     */
+    protected function getSearchIntroHTML($query)
+    {
+        global $lang;
+
+        $intro = p_locale_xhtml('searchpage');
+
+        $queryPagename = $this->createPagenameFromQuery($this->parsedQuery);
+        $createQueryPageLink = html_wikilink($queryPagename . '?do=edit', $queryPagename);
+
+        $pagecreateinfo = '';
+        if (auth_quickaclcheck($queryPagename) >= AUTH_CREATE) {
+            $pagecreateinfo = sprintf($lang['searchcreatepage'], $createQueryPageLink);
+        }
+        $intro = str_replace(
+            array('@QUERY@', '@SEARCH@', '@CREATEPAGEINFO@'),
+            array(hsc(rawurlencode($query)), hsc($query), $pagecreateinfo),
+            $intro
+        );
+
+        return $intro;
+    }
+
+    /**
+     * Create a pagename based the parsed search query
+     *
+     * @param array $parsedQuery
+     *
+     * @return string pagename constructed from the parsed query
+     */
+    protected function createPagenameFromQuery($parsedQuery)
+    {
+        $pagename = '';
+        if (!empty($parsedQuery['ns'])) {
+            $pagename .= cleanID($parsedQuery['ns'][0]);
+        }
+        $pagename .= ':' . cleanID(implode(' ' , $parsedQuery['highlight']));
+        return $pagename;
+    }
+
+    /**
+     * Build HTML for a list of pages with matching pagenames
+     *
+     * @param array $data search results
+     *
+     * @return string
+     */
+    protected function getPageLookupHTML($data)
+    {
+        if (empty($data)) {
+            return '';
+        }
+
+        global $lang;
+
+        $html = '<div class="search_quickresult">';
+        $html .= '<h3>' . $lang['quickhits'] . ':</h3>';
+        $html .= '<ul class="search_quickhits">';
+        foreach ($data as $id => $title) {
+            $link = html_wikilink(':' . $id);
+            $eventData = [
+                'listItemContent' => [$link],
+                'page' => $id,
+            ];
+            trigger_event('SEARCH_RESULT_PAGELOOKUP', $eventData);
+            $html .= '<li>' . implode('', $eventData['listItemContent']) . '</li>';
+        }
+        $html .= '</ul> ';
+        //clear float (see http://www.complexspiral.com/publications/containing-floats/)
+        $html .= '<div class="clearer"></div>';
+        $html .= '</div>';
+
+        return $html;
+    }
+
+    /**
+     * Build HTML for fulltext search results or "no results" message
+     *
+     * @param array $data      the results of the fulltext search
+     * @param array $highlight the terms to be highlighted in the results
+     *
+     * @return string
+     */
+    protected function getFulltextResultsHTML($data, $highlight)
+    {
+        global $lang;
+
+        if (empty($data)) {
+            return '<div class="nothing">' . $lang['nothingfound'] . '</div>';
+        }
+
+        $html = '<div class="search_fulltextresult">';
+        $html .= '<h3>' . $lang['search_fullresults'] . ':</h3>';
+
+        $html .= '<dl class="search_results">';
+        $num = 1;
+
+        foreach ($data as $id => $cnt) {
+            $resultLink = html_wikilink(':' . $id, null, $highlight);
+
+            $resultHeader = [$resultLink];
+
+
+            $restrictQueryToNSLink = $this->restrictQueryToNSLink(getNS($id));
+            if ($restrictQueryToNSLink) {
+                $resultHeader[] = $restrictQueryToNSLink;
+            }
+
+            $snippet = '';
+            $lastMod = '';
+            $mtime = filemtime(wikiFN($id));
+            if ($cnt !== 0) {
+                $resultHeader[] = $cnt . ' ' . $lang['hits'];
+                if ($num < FT_SNIPPET_NUMBER) { // create snippets for the first number of matches only
+                    $snippet = '<dd>' . ft_snippet($id, $highlight) . '</dd>';
+                    $lastMod = '<span class="search_results__lastmod">' . $lang['lastmod'] . ' ';
+                    $lastMod .= '<time datetime="' . date_iso8601($mtime) . '" title="'.dformat($mtime).'">' . dformat($mtime, '%f') . '</time>';
+                    $lastMod .= '</span>';
+                }
+                $num++;
+            }
+
+            $metaLine = '<div class="search_results__metaLine">';
+            $metaLine .= $lastMod;
+            $metaLine .= '</div>';
+
+
+            $eventData = [
+                'resultHeader' => $resultHeader,
+                'resultBody' => [$metaLine, $snippet],
+                'page' => $id,
+            ];
+            trigger_event('SEARCH_RESULT_FULLPAGE', $eventData);
+            $html .= '<div class="search_fullpage_result">';
+            $html .= '<dt>' . implode(' ', $eventData['resultHeader']) . '</dt>';
+            $html .= implode('', $eventData['resultBody']);
+            $html .= '</div>';
+        }
+        $html .= '</dl>';
+
+        $html .= '</div>';
+
+        return $html;
+    }
+
+    /**
+     * create a link to restrict the current query to a namespace
+     *
+     * @param false|string $ns the namespace to which to restrict the query
+     *
+     * @return false|string
+     */
+    protected function restrictQueryToNSLink($ns)
+    {
+        if (!$ns) {
+            return false;
+        }
+        if (!$this->isNamespaceAssistanceAvailable($this->parsedQuery)) {
+            return false;
+        }
+        if (!empty($this->parsedQuery['ns']) && $this->parsedQuery['ns'][0] === $ns) {
+            return false;
+        }
+
+        $name = '@' . $ns;
+        return $this->searchState->withNamespace($ns)->getSearchLink($name);
+    }
+}
diff --git a/inc/Ui/SearchState.php b/inc/Ui/SearchState.php
new file mode 100644
index 0000000000000000000000000000000000000000..f45156d282e18594d9be8fdc4aa8ec801c1b389f
--- /dev/null
+++ b/inc/Ui/SearchState.php
@@ -0,0 +1,141 @@
+<?php
+
+namespace dokuwiki\Ui;
+
+class SearchState
+{
+    /**
+     * @var array
+     */
+    protected $parsedQuery = [];
+
+    /**
+     * SearchState constructor.
+     *
+     * @param array $parsedQuery
+     */
+    public function __construct(array $parsedQuery)
+    {
+        global $INPUT;
+
+        $this->parsedQuery = $parsedQuery;
+        if (!isset($parsedQuery['after'])) {
+            $this->parsedQuery['after'] = $INPUT->str('min');
+        }
+        if (!isset($parsedQuery['before'])) {
+            $this->parsedQuery['before'] = $INPUT->str('max');
+        }
+        if (!isset($parsedQuery['sort'])) {
+            $this->parsedQuery['sort'] = $INPUT->str('srt');
+        }
+    }
+
+    /**
+     * Get a search state for the current search limited to a new namespace
+     *
+     * @param string $ns the namespace to which to limit the search, falsy to remove the limitation
+     * @param array  $notns
+     *
+     * @return SearchState
+     */
+    public function withNamespace($ns, array $notns = [])
+    {
+        $parsedQuery = $this->parsedQuery;
+        $parsedQuery['ns'] = $ns ? [$ns] : [];
+        $parsedQuery['notns'] = $notns;
+
+        return new SearchState($parsedQuery);
+    }
+
+    /**
+     * Get a search state for the current search with new search fragments and optionally phrases
+     *
+     * @param array $and
+     * @param array $not
+     * @param array $phrases
+     *
+     * @return SearchState
+     */
+    public function withFragments(array $and, array $not, array $phrases = [])
+    {
+        $parsedQuery = $this->parsedQuery;
+        $parsedQuery['and'] = $and;
+        $parsedQuery['not'] = $not;
+        $parsedQuery['phrases'] = $phrases;
+
+        return new SearchState($parsedQuery);
+    }
+
+    /**
+     * Get a search state for the current search with with adjusted time limitations
+     *
+     * @param $after
+     * @param $before
+     *
+     * @return SearchState
+     */
+    public function withTimeLimitations($after, $before)
+    {
+        $parsedQuery = $this->parsedQuery;
+        $parsedQuery['after'] = $after;
+        $parsedQuery['before'] = $before;
+
+        return new SearchState($parsedQuery);
+    }
+
+    /**
+     * Get a search state for the current search with adjusted sort preference
+     *
+     * @param $sort
+     *
+     * @return SearchState
+     */
+    public function withSorting($sort)
+    {
+        $parsedQuery = $this->parsedQuery;
+        $parsedQuery['sort'] = $sort;
+
+        return new SearchState($parsedQuery);
+    }
+
+    /**
+     * Get a link that represents the current search state
+     *
+     * Note that this represents only a simplified version of the search state.
+     * Grouping with braces and "OR" conditions are not supported.
+     *
+     * @param $label
+     *
+     * @return string
+     */
+    public function getSearchLink($label)
+    {
+        global $ID, $conf;
+        $parsedQuery = $this->parsedQuery;
+
+        $tagAttributes = [
+            'target' => $conf['target']['wiki'],
+        ];
+
+        $newQuery = ft_queryUnparser_simple(
+            $parsedQuery['and'],
+            $parsedQuery['not'],
+            $parsedQuery['phrases'],
+            $parsedQuery['ns'],
+            $parsedQuery['notns']
+        );
+        $hrefAttributes = ['do' => 'search', 'sf' => '1', 'q' => $newQuery];
+        if ($parsedQuery['after']) {
+            $hrefAttributes['min'] = $parsedQuery['after'];
+        }
+        if ($parsedQuery['before']) {
+            $hrefAttributes['max'] = $parsedQuery['before'];
+        }
+        if ($parsedQuery['sort']) {
+            $hrefAttributes['srt'] = $parsedQuery['sort'];
+        }
+
+        $href = wl($ID, $hrefAttributes, false, '&');
+        return "<a href='$href' " . buildAttributes($tagAttributes) . ">$label</a>";
+    }
+}
diff --git a/inc/actions.php b/inc/actions.php
index adba2aa3233108d2ea4b3044067e1d24f5a77ca9..9ba8878603ae9924102d902f46cf146866f84d03 100644
--- a/inc/actions.php
+++ b/inc/actions.php
@@ -9,193 +9,21 @@
 if(!defined('DOKU_INC')) die('meh.');
 
 /**
- * Call the needed action handlers
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @triggers ACTION_ACT_PREPROCESS
- * @triggers ACTION_HEADERS_SEND
+ * All action processing starts here
  */
 function act_dispatch(){
-    global $ACT;
-    global $ID;
-    global $INFO;
-    global $QUERY;
-    /* @var Input $INPUT */
-    global $INPUT;
-    global $lang;
-    global $conf;
-
-    $preact = $ACT;
-
-    // give plugins an opportunity to process the action
-    $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT);
-
-    $headers = array();
-    if ($evt->advise_before()) {
-
-        //sanitize $ACT
-        $ACT = act_validate($ACT);
-
-        //check if searchword was given - else just show
-        $s = cleanID($QUERY);
-        if($ACT == 'search' && empty($s)){
-            $ACT = 'show';
-        }
-
-        //login stuff
-        if(in_array($ACT,array('login','logout'))){
-            $ACT = act_auth($ACT);
-        }
-
-        //check if user is asking to (un)subscribe a page
-        if($ACT == 'subscribe') {
-            try {
-                $ACT = act_subscription($ACT);
-            } catch (Exception $e) {
-                msg($e->getMessage(), -1);
-            }
-        }
-
-        //display some info
-        if($ACT == 'check'){
-            check();
-            $ACT = 'show';
-        }
-
-        //check permissions
-        $ACT = act_permcheck($ACT);
-
-        //sitemap
-        if ($ACT == 'sitemap'){
-            act_sitemap($ACT);
-        }
-
-        //recent changes
-        if ($ACT == 'recent'){
-            $show_changes = $INPUT->str('show_changes');
-            if (!empty($show_changes)) {
-                set_doku_pref('show_changes', $show_changes);
-            }
-        }
-
-        //diff
-        if ($ACT == 'diff'){
-            $difftype = $INPUT->str('difftype');
-            if (!empty($difftype)) {
-                set_doku_pref('difftype', $difftype);
-            }
-        }
-
-        //register
-        if($ACT == 'register' && $INPUT->post->bool('save') && register()){
-            $ACT = 'login';
-        }
-
-        if ($ACT == 'resendpwd' && act_resendpwd()) {
-            $ACT = 'login';
-        }
-
-        // user profile changes
-        if (in_array($ACT, array('profile','profile_delete'))) {
-            if(!$INPUT->server->str('REMOTE_USER')) {
-                $ACT = 'login';
-            } else {
-                switch ($ACT) {
-                    case 'profile' :
-                        if(updateprofile()) {
-                            msg($lang['profchanged'],1);
-                            $ACT = 'show';
-                        }
-                        break;
-                    case 'profile_delete' :
-                        if(auth_deleteprofile()){
-                            msg($lang['profdeleted'],1);
-                            $ACT = 'show';
-                        } else {
-                            $ACT = 'profile';
-                        }
-                        break;
-                }
-            }
-        }
-
-        //revert
-        if($ACT == 'revert'){
-            if(checkSecurityToken()){
-                $ACT = act_revert($ACT);
-            }else{
-                $ACT = 'show';
-            }
-        }
-
-        //save
-        if($ACT == 'save'){
-            if(checkSecurityToken()){
-                $ACT = act_save($ACT);
-            }else{
-                $ACT = 'preview';
-            }
-        }
-
-        //cancel conflicting edit
-        if($ACT == 'cancel')
-            $ACT = 'show';
-
-        //draft deletion
-        if($ACT == 'draftdel')
-            $ACT = act_draftdel($ACT);
-
-        //draft saving on preview
-        if($ACT == 'preview') {
-            $headers[] = "X-XSS-Protection: 0";
-            $ACT = act_draftsave($ACT);
-        }
-
-        //edit
-        if(in_array($ACT, array('edit', 'preview', 'recover'))) {
-            $ACT = act_edit($ACT);
-        }else{
-            unlock($ID); //try to unlock
-        }
-
-        //handle export
-        if(substr($ACT,0,7) == 'export_')
-            $ACT = act_export($ACT);
-
-        //handle admin tasks
-        if($ACT == 'admin'){
-            // retrieve admin plugin name from $_REQUEST['page']
-            if (($page = $INPUT->str('page', '', true)) != '') {
-                /** @var $plugin DokuWiki_Admin_Plugin */
-                if ($plugin = plugin_getRequestAdminPlugin()){
-                    $plugin->handle();
-                }
-            }
-        }
-
-        // check permissions again - the action may have changed
-        $ACT = act_permcheck($ACT);
-    }  // end event ACTION_ACT_PREPROCESS default action
-    $evt->advise_after();
-    // Make sure plugs can handle 'denied'
-    if($conf['send404'] && $ACT == 'denied') {
-        http_status(403);
-    }
-    unset($evt);
-
-    // when action 'show', the intial not 'show' and POST, do a redirect
-    if($ACT == 'show' && $preact != 'show' && strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post'){
-        act_redirect($ID,$preact);
-    }
-
-    global $INFO;
-    global $conf;
-    global $license;
+    // always initialize on first dispatch (test request may dispatch mutliple times on one request)
+    $router = \dokuwiki\ActionRouter::getInstance(true);
 
-    //call template FIXME: all needed vars available?
-    $headers[] = 'Content-Type: text/html; charset=utf-8';
+    $headers = array('Content-Type: text/html; charset=utf-8');
     trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
 
+    // clear internal variables
+    unset($router);
+    unset($headers);
+    // make all globals available to the template
+    extract($GLOBALS);
+
     include(template('main.php'));
     // output for the commands is now handled in inc/templates.php
     // in function tpl_content()
@@ -234,628 +62,3 @@ function act_clean($act){
     if($act === '') $act = 'show';
     return $act;
 }
-
-/**
- * Sanitize and validate action commands.
- *
- * Add all allowed commands here.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param array|string $act
- * @return string
- */
-function act_validate($act) {
-    global $conf;
-    global $INFO;
-
-    $act = act_clean($act);
-
-    // check if action is disabled
-    if(!actionOK($act)){
-        msg('Command disabled: '.htmlspecialchars($act),-1);
-        return 'show';
-    }
-
-    //disable all acl related commands if ACL is disabled
-    if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
-                    'subscribe','unsubscribe','profile','revert',
-                    'resendpwd','profile_delete'))){
-        msg('Command unavailable: '.htmlspecialchars($act),-1);
-        return 'show';
-    }
-
-    //is there really a draft?
-    if($act == 'draft' && !file_exists($INFO['draft'])) return 'edit';
-
-    if(!in_array($act,array('login','logout','register','save','cancel','edit','draft',
-                    'preview','search','show','check','index','revisions',
-                    'diff','recent','backlink','admin','subscribe','revert',
-                    'unsubscribe','profile','profile_delete','resendpwd','recover',
-                    'draftdel','sitemap','media')) && substr($act,0,7) != 'export_' ) {
-        msg('Command unknown: '.htmlspecialchars($act),-1);
-        return 'show';
-    }
-    return $act;
-}
-
-/**
- * Run permissionchecks
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_permcheck($act){
-    global $INFO;
-
-    if(in_array($act,array('save','preview','edit','recover'))){
-        if($INFO['exists']){
-            if($act == 'edit'){
-                //the edit function will check again and do a source show
-                //when no AUTH_EDIT available
-                $permneed = AUTH_READ;
-            }else{
-                $permneed = AUTH_EDIT;
-            }
-        }else{
-            $permneed = AUTH_CREATE;
-        }
-    }elseif(in_array($act,array('login','search','recent','profile','profile_delete','index', 'sitemap'))){
-        $permneed = AUTH_NONE;
-    }elseif($act == 'revert'){
-        $permneed = AUTH_ADMIN;
-        if($INFO['ismanager']) $permneed = AUTH_EDIT;
-    }elseif($act == 'register'){
-        $permneed = AUTH_NONE;
-    }elseif($act == 'resendpwd'){
-        $permneed = AUTH_NONE;
-    }elseif($act == 'admin'){
-        if($INFO['ismanager']){
-            // if the manager has the needed permissions for a certain admin
-            // action is checked later
-            $permneed = AUTH_READ;
-        }else{
-            $permneed = AUTH_ADMIN;
-        }
-    }else{
-        $permneed = AUTH_READ;
-    }
-    if($INFO['perm'] >= $permneed) return $act;
-
-    return 'denied';
-}
-
-/**
- * Handle 'draftdel'
- *
- * Deletes the draft for the current page and user
- *
- * @param string $act action command
- * @return string action command
- */
-function act_draftdel($act){
-    global $INFO;
-    @unlink($INFO['draft']);
-    $INFO['draft'] = null;
-    return 'show';
-}
-
-/**
- * Saves a draft on preview
- *
- * @todo this currently duplicates code from ajax.php :-/
- *
- * @param string $act action command
- * @return string action command
- */
-function act_draftsave($act){
-    global $INFO;
-    global $ID;
-    global $INPUT;
-    global $conf;
-    if($conf['usedraft'] && $INPUT->post->has('wikitext')) {
-        $draft = array('id'     => $ID,
-                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
-                'text'   => $INPUT->post->str('wikitext'),
-                'suffix' => $INPUT->post->str('suffix'),
-                'date'   => $INPUT->post->int('date'),
-                'client' => $INFO['client'],
-                );
-        $cname = getCacheName($draft['client'].$ID,'.draft');
-        if(io_saveFile($cname,serialize($draft))){
-            $INFO['draft'] = $cname;
-        }
-    }
-    return $act;
-}
-
-/**
- * Handle 'save'
- *
- * Checks for spam and conflicts and saves the page.
- * Does a redirect to show the page afterwards or
- * returns a new action.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_save($act){
-    global $ID;
-    global $DATE;
-    global $PRE;
-    global $TEXT;
-    global $SUF;
-    global $SUM;
-    global $lang;
-    global $INFO;
-    global $INPUT;
-
-    //spam check
-    if(checkwordblock()) {
-        msg($lang['wordblock'], -1);
-        return 'edit';
-    }
-    //conflict check
-    if($DATE != 0 && $INFO['meta']['date']['modified'] > $DATE )
-        return 'conflict';
-
-    //save it
-    saveWikiText($ID,con($PRE,$TEXT,$SUF,true),$SUM,$INPUT->bool('minor')); //use pretty mode for con
-    //unlock it
-    unlock($ID);
-
-    //delete draft
-    act_draftdel($act);
-    session_write_close();
-
-    // when done, show page
-    return 'show';
-}
-
-/**
- * Revert to a certain revision
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_revert($act){
-    global $ID;
-    global $REV;
-    global $lang;
-    /* @var Input $INPUT */
-    global $INPUT;
-    // FIXME $INFO['writable'] currently refers to the attic version
-    // global $INFO;
-    // if (!$INFO['writable']) {
-    //     return 'show';
-    // }
-
-    // when no revision is given, delete current one
-    // FIXME this feature is not exposed in the GUI currently
-    $text = '';
-    $sum  = $lang['deleted'];
-    if($REV){
-        $text = rawWiki($ID,$REV);
-        if(!$text) return 'show'; //something went wrong
-        $sum = sprintf($lang['restored'], dformat($REV));
-    }
-
-    // spam check
-
-    if (checkwordblock($text)) {
-        msg($lang['wordblock'], -1);
-        return 'edit';
-    }
-
-    saveWikiText($ID,$text,$sum,false);
-    msg($sum,1);
-
-    //delete any draft
-    act_draftdel($act);
-    session_write_close();
-
-    // when done, show current page
-    $INPUT->server->set('REQUEST_METHOD','post'); //should force a redirect
-    $REV = '';
-    return 'show';
-}
-
-/**
- * Do a redirect after receiving post data
- *
- * Tries to add the section id as hash mark after section editing
- *
- * @param string $id page id
- * @param string $preact action command before redirect
- */
-function act_redirect($id,$preact){
-    global $PRE;
-    global $TEXT;
-
-    $opts = array(
-            'id'       => $id,
-            'preact'   => $preact
-            );
-    //get section name when coming from section edit
-    if($PRE && preg_match('/^\s*==+([^=\n]+)/',$TEXT,$match)){
-        $check = false; //Byref
-        $opts['fragment'] = sectionID($match[0], $check);
-    }
-
-    trigger_event('ACTION_SHOW_REDIRECT',$opts,'act_redirect_execute');
-}
-
-/**
- * Execute the redirect
- *
- * @param array $opts id and fragment for the redirect and the preact
- */
-function act_redirect_execute($opts){
-    $go = wl($opts['id'],'',true);
-    if(isset($opts['fragment'])) $go .= '#'.$opts['fragment'];
-
-    //show it
-    send_redirect($go);
-}
-
-/**
- * Handle 'login', 'logout'
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_auth($act){
-    global $ID;
-    global $INFO;
-    /* @var Input $INPUT */
-    global $INPUT;
-
-    //already logged in?
-    if($INPUT->server->has('REMOTE_USER') && $act=='login'){
-        return 'show';
-    }
-
-    //handle logout
-    if($act=='logout'){
-        $lockedby = checklock($ID); //page still locked?
-        if($lockedby == $INPUT->server->str('REMOTE_USER')){
-            unlock($ID); //try to unlock
-        }
-
-        // do the logout stuff
-        auth_logoff();
-
-        // rebuild info array
-        $INFO = pageinfo();
-
-        act_redirect($ID,'login');
-    }
-
-    return $act;
-}
-
-/**
- * Handle 'edit', 'preview', 'recover'
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_edit($act){
-    global $ID;
-    global $INFO;
-
-    global $TEXT;
-    global $RANGE;
-    global $PRE;
-    global $SUF;
-    global $REV;
-    global $SUM;
-    global $lang;
-    global $DATE;
-
-    if (!isset($TEXT)) {
-        if ($INFO['exists']) {
-            if ($RANGE) {
-                list($PRE,$TEXT,$SUF) = rawWikiSlices($RANGE,$ID,$REV);
-            } else {
-                $TEXT = rawWiki($ID,$REV);
-            }
-        } else {
-            $TEXT = pageTemplate($ID);
-        }
-    }
-
-    //set summary default
-    if(!$SUM){
-        if($REV){
-            $SUM = sprintf($lang['restored'], dformat($REV));
-        }elseif(!$INFO['exists']){
-            $SUM = $lang['created'];
-        }
-    }
-
-    // Use the date of the newest revision, not of the revision we edit
-    // This is used for conflict detection
-    if(!$DATE) $DATE = @filemtime(wikiFN($ID));
-
-    //check if locked by anyone - if not lock for my self
-    //do not lock when the user can't edit anyway
-    if ($INFO['writable']) {
-        $lockedby = checklock($ID);
-        if($lockedby) return 'locked';
-
-        lock($ID);
-    }
-
-    return $act;
-}
-
-/**
- * Export a wiki page for various formats
- *
- * Triggers ACTION_EXPORT_POSTPROCESS
- *
- *  Event data:
- *    data['id']      -- page id
- *    data['mode']    -- requested export mode
- *    data['headers'] -- export headers
- *    data['output']  -- export output
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param string $act action command
- * @return string action command
- */
-function act_export($act){
-    global $ID;
-    global $REV;
-    global $conf;
-    global $lang;
-
-    $pre = '';
-    $post = '';
-    $headers = array();
-
-    // search engines: never cache exported docs! (Google only currently)
-    $headers['X-Robots-Tag'] = 'noindex';
-
-    $mode = substr($act,7);
-    switch($mode) {
-        case 'raw':
-            $headers['Content-Type'] = 'text/plain; charset=utf-8';
-            $headers['Content-Disposition'] = 'attachment; filename='.noNS($ID).'.txt';
-            $output = rawWiki($ID,$REV);
-            break;
-        case 'xhtml':
-            $pre .= '<!DOCTYPE html>' . DOKU_LF;
-            $pre .= '<html lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF;
-            $pre .= '<head>' . DOKU_LF;
-            $pre .= '  <meta charset="utf-8" />' . DOKU_LF;
-            $pre .= '  <title>'.$ID.'</title>' . DOKU_LF;
-
-            // get metaheaders
-            ob_start();
-            tpl_metaheaders();
-            $pre .= ob_get_clean();
-
-            $pre .= '</head>' . DOKU_LF;
-            $pre .= '<body>' . DOKU_LF;
-            $pre .= '<div class="dokuwiki export">' . DOKU_LF;
-
-            // get toc
-            $pre .= tpl_toc(true);
-
-            $headers['Content-Type'] = 'text/html; charset=utf-8';
-            $output = p_wiki_xhtml($ID,$REV,false);
-
-            $post .= '</div>' . DOKU_LF;
-            $post .= '</body>' . DOKU_LF;
-            $post .= '</html>' . DOKU_LF;
-            break;
-        case 'xhtmlbody':
-            $headers['Content-Type'] = 'text/html; charset=utf-8';
-            $output = p_wiki_xhtml($ID,$REV,false);
-            break;
-        default:
-            $output = p_cached_output(wikiFN($ID,$REV), $mode, $ID);
-            $headers = p_get_metadata($ID,"format $mode");
-            break;
-    }
-
-    // prepare event data
-    $data = array();
-    $data['id'] = $ID;
-    $data['mode'] = $mode;
-    $data['headers'] = $headers;
-    $data['output'] =& $output;
-
-    trigger_event('ACTION_EXPORT_POSTPROCESS', $data);
-
-    if(!empty($data['output'])){
-        if(is_array($data['headers'])) foreach($data['headers'] as $key => $val){
-            header("$key: $val");
-        }
-        print $pre.$data['output'].$post;
-        exit;
-    }
-    return 'show';
-}
-
-/**
- * Handle sitemap delivery
- *
- * @author Michael Hamann <michael@content-space.de>
- *
- * @param string $act action command
- */
-function act_sitemap($act) {
-    global $conf;
-
-    if ($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
-        http_status(404);
-        print "Sitemap generation is disabled.";
-        exit;
-    }
-
-    $sitemap = Sitemapper::getFilePath();
-    if (Sitemapper::sitemapIsCompressed()) {
-        $mime = 'application/x-gzip';
-    }else{
-        $mime = 'application/xml; charset=utf-8';
-    }
-
-    // Check if sitemap file exists, otherwise create it
-    if (!is_readable($sitemap)) {
-        Sitemapper::generate();
-    }
-
-    if (is_readable($sitemap)) {
-        // Send headers
-        header('Content-Type: '.$mime);
-        header('Content-Disposition: attachment; filename='.utf8_basename($sitemap));
-
-        http_conditionalRequest(filemtime($sitemap));
-
-        // Send file
-        //use x-sendfile header to pass the delivery to compatible webservers
-        http_sendfile($sitemap);
-
-        readfile($sitemap);
-        exit;
-    }
-
-    http_status(500);
-    print "Could not read the sitemap file - bad permissions?";
-    exit;
-}
-
-/**
- * Handle page 'subscribe'
- *
- * Throws exception on error.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $act action command
- * @return string action command
- * @throws Exception if (un)subscribing fails
- */
-function act_subscription($act){
-    global $lang;
-    global $INFO;
-    global $ID;
-    /* @var Input $INPUT */
-    global $INPUT;
-
-    // subcriptions work for logged in users only
-    if(!$INPUT->server->str('REMOTE_USER')) return 'show';
-
-    // get and preprocess data.
-    $params = array();
-    foreach(array('target', 'style', 'action') as $param) {
-        if ($INPUT->has("sub_$param")) {
-            $params[$param] = $INPUT->str("sub_$param");
-        }
-    }
-
-    // any action given? if not just return and show the subscription page
-    if(empty($params['action']) || !checkSecurityToken()) return $act;
-
-    // Handle POST data, may throw exception.
-    trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, 'subscription_handle_post');
-
-    $target = $params['target'];
-    $style  = $params['style'];
-    $action = $params['action'];
-
-    // Perform action.
-    $sub = new Subscription();
-    if($action == 'unsubscribe'){
-        $ok = $sub->remove($target, $INPUT->server->str('REMOTE_USER'), $style);
-    }else{
-        $ok = $sub->add($target, $INPUT->server->str('REMOTE_USER'), $style);
-    }
-
-    if($ok) {
-        msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
-                    prettyprint_id($target)), 1);
-        act_redirect($ID, $act);
-    } else {
-        throw new Exception(sprintf($lang["subscr_{$action}_error"],
-                                    hsc($INFO['userinfo']['name']),
-                                    prettyprint_id($target)));
-    }
-
-    // Assure that we have valid data if act_redirect somehow fails.
-    $INFO['subscribed'] = $sub->user_subscription();
-    return 'show';
-}
-
-/**
- * Validate POST data
- *
- * Validates POST data for a subscribe or unsubscribe request. This is the
- * default action for the event ACTION_HANDLE_SUBSCRIBE.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param array &$params the parameters: target, style and action
- * @throws Exception
- */
-function subscription_handle_post(&$params) {
-    global $INFO;
-    global $lang;
-    /* @var Input $INPUT */
-    global $INPUT;
-
-    // Get and validate parameters.
-    if (!isset($params['target'])) {
-        throw new Exception('no subscription target given');
-    }
-    $target = $params['target'];
-    $valid_styles = array('every', 'digest');
-    if (substr($target, -1, 1) === ':') {
-        // Allow “list” subscribe style since the target is a namespace.
-        $valid_styles[] = 'list';
-    }
-    $style  = valid_input_set('style', $valid_styles, $params,
-                              'invalid subscription style given');
-    $action = valid_input_set('action', array('subscribe', 'unsubscribe'),
-                              $params, 'invalid subscription action given');
-
-    // Check other conditions.
-    if ($action === 'subscribe') {
-        if ($INFO['userinfo']['mail'] === '') {
-            throw new Exception($lang['subscr_subscribe_noaddress']);
-        }
-    } elseif ($action === 'unsubscribe') {
-        $is = false;
-        foreach($INFO['subscribed'] as $subscr) {
-            if ($subscr['target'] === $target) {
-                $is = true;
-            }
-        }
-        if ($is === false) {
-            throw new Exception(sprintf($lang['subscr_not_subscribed'],
-                                        $INPUT->server->str('REMOTE_USER'),
-                                        prettyprint_id($target)));
-        }
-        // subscription_set deletes a subscription if style = null.
-        $style = null;
-    }
-
-    $params = compact('target', 'style', 'action');
-}
-
-//Setup VIM: ex: et ts=2 :
diff --git a/inc/auth.php b/inc/auth.php
index 7fa61aa18af43a4d9760ed426f725217aa38e229..e1d7a645a6e5f74520aa73fc6a87bc0469e30548 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -308,6 +308,9 @@ function auth_browseruid() {
  * @return  string
  */
 function auth_cookiesalt($addsession = false, $secure = false) {
+    if (defined('SIMPLE_TEST')) {
+        return 'test';
+    }
     global $conf;
     $file = $conf['metadir'].'/_htcookiesalt';
     if ($secure || !file_exists($file)) {
diff --git a/inc/cli.php b/inc/cli.php
index 4c4403a394ae2053655bf9b767e86dfebc53a429..cb4fc587dd37a937851524429cde32c9c9c3f2f9 100644
--- a/inc/cli.php
+++ b/inc/cli.php
@@ -25,6 +25,9 @@ abstract class DokuCLI {
 
         $this->options = new DokuCLI_Options();
         $this->colors  = new DokuCLI_Colors();
+
+        dbg_deprecated('use \splitbrain\phpcli\CLI instead');
+        $this->error('DokuCLI is deprecated, use \splitbrain\phpcli\CLI instead.');
     }
 
     /**
diff --git a/inc/common.php b/inc/common.php
index 9a1da79075cd016ad371dd276aac49e306306bd7..1fd0154c2b740931d78e8c57abcfefb8704983b5 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -300,6 +300,23 @@ function pageinfo() {
     return $info;
 }
 
+/**
+ * Initialize and/or fill global $JSINFO with some basic info to be given to javascript
+ */
+function jsinfo() {
+    global $JSINFO, $ID, $INFO, $ACT;
+
+    if (!is_array($JSINFO)) {
+        $JSINFO = [];
+    }
+    //export minimal info to JS, plugins can add more
+    $JSINFO['id']                    = $ID;
+    $JSINFO['namespace']             = (string) $INFO['namespace'];
+    $JSINFO['ACT']                   = act_clean($ACT);
+    $JSINFO['useHeadingNavigation']  = (int) useHeading('navigation');
+    $JSINFO['useHeadingContent']     = (int) useHeading('content');
+}
+
 /**
  * Return information about the current media item as an associative array.
  *
@@ -382,9 +399,9 @@ function breadcrumbs() {
 
     //first visit?
     $crumbs = isset($_SESSION[DOKU_COOKIE]['bc']) ? $_SESSION[DOKU_COOKIE]['bc'] : array();
-    //we only save on show and existing wiki documents
+    //we only save on show and existing visible wiki documents
     $file = wikiFN($ID);
-    if($ACT != 'show' || !file_exists($file)) {
+    if($ACT != 'show' || isHiddenPage($ID) || !file_exists($file)) {
         $_SESSION[DOKU_COOKIE]['bc'] = $crumbs;
         return $crumbs;
     }
@@ -1111,6 +1128,7 @@ function parsePageTemplate(&$data) {
         array(
              '@ID@',
              '@NS@',
+             '@CURNS@',
              '@FILE@',
              '@!FILE@',
              '@!FILE!@',
@@ -1126,6 +1144,7 @@ function parsePageTemplate(&$data) {
         array(
              $id,
              getNS($id),
+             curNS($id),
              $file,
              utf8_ucfirst($file),
              utf8_strtoupper($file),
@@ -1924,7 +1943,16 @@ function send_redirect($url) {
         header('Location: '.$url);
     }
 
-    if(defined('DOKU_UNITTEST')) return; // no exits during unit tests
+    // no exits during unit tests
+    if(defined('DOKU_UNITTEST')) {
+        // pass info about the redirect back to the test suite
+        $testRequest = TestRequest::getRunning();
+        if($testRequest !== null) {
+            $testRequest->addData('send_redirect', $url);
+        }
+        return;
+    }
+
     exit;
 }
 
diff --git a/inc/config_cascade.php b/inc/config_cascade.php
index 2466290bc2fa0c3c40491786850fa0189cfefa0f..f0aa6cc7e4ec01b87fc92e540ecc130ac994d16a 100644
--- a/inc/config_cascade.php
+++ b/inc/config_cascade.php
@@ -28,6 +28,10 @@ $config_cascade = array_merge(
             'default'   => array(DOKU_CONF . 'license.php'),
             'local'     => array(DOKU_CONF . 'license.local.php'),
         ),
+        'manifest' => array(
+            'default'   => array(DOKU_CONF . 'manifest.json'),
+            'local'     => array(DOKU_CONF . 'manifest.local.json'),
+        ),
         'mediameta' => array(
             'default'   => array(DOKU_CONF . 'mediameta.php'),
             'local'     => array(DOKU_CONF . 'mediameta.local.php'),
diff --git a/inc/confutils.php b/inc/confutils.php
index fb9a3edd7a5b66cdb70cbcf82f8dc6e474258249..59147010f102a71ff6b3e4ccfbd598e40bba7090 100644
--- a/inc/confutils.php
+++ b/inc/confutils.php
@@ -208,22 +208,23 @@ function getSchemes() {
  *
  * @return array
  */
-function linesToHash($lines, $lower=false) {
+function linesToHash($lines, $lower = false) {
     $conf = array();
     // remove BOM
-    if (isset($lines[0]) && substr($lines[0],0,3) == pack('CCC',0xef,0xbb,0xbf))
-        $lines[0] = substr($lines[0],3);
-    foreach ( $lines as $line ) {
+    if(isset($lines[0]) && substr($lines[0], 0, 3) == pack('CCC', 0xef, 0xbb, 0xbf))
+        $lines[0] = substr($lines[0], 3);
+    foreach($lines as $line) {
         //ignore comments (except escaped ones)
-        $line = preg_replace('/(?<![&\\\\])#.*$/','',$line);
-        $line = str_replace('\\#','#',$line);
+        $line = preg_replace('/(?<![&\\\\])#.*$/', '', $line);
+        $line = str_replace('\\#', '#', $line);
         $line = trim($line);
-        if(empty($line)) continue;
-        $line = preg_split('/\s+/',$line,2);
+        if($line === '') continue;
+        $line = preg_split('/\s+/', $line, 2);
+        $line = array_pad($line, 2, '');
         // Build the associative array
-        if($lower){
+        if($lower) {
             $conf[strtolower($line[0])] = $line[1];
-        }else{
+        } else {
             $conf[$line[0]] = $line[1];
         }
     }
@@ -254,6 +255,25 @@ function confToHash($file,$lower=false) {
     return linesToHash($lines, $lower);
 }
 
+/**
+ * Read a json config file into an array
+ *
+ * @param string $file
+ * @return array
+ */
+function jsonToArray($file)
+{
+    $json = file_get_contents($file);
+
+    $conf = json_decode($json, true);
+
+    if ($conf === null) {
+        return [];
+    }
+
+    return $conf;
+}
+
 /**
  * Retrieve the requested configuration information
  *
diff --git a/inc/form.php b/inc/form.php
index caf12c019b2fa5028d5914f20b384ba10e02487a..7afb0ba3082aafa604c9adbe614e2c37ad95e2ba 100644
--- a/inc/form.php
+++ b/inc/form.php
@@ -28,17 +28,17 @@ if(!defined('DOKU_INC')) die('meh.');
 class Doku_Form {
 
     // Form id attribute
-    protected $params = array();
+    public $params = array();
 
     // Draw a border around form fields.
     // Adds <fieldset></fieldset> around the elements
-    protected $_infieldset = false;
+    public $_infieldset = false;
 
     // Hidden form fields.
-    protected $_hidden = array();
+    public $_hidden = array();
 
     // Array of pseudo-tags
-    protected $_content = array();
+    public $_content = array();
 
     /**
      * Constructor
diff --git a/inc/fulltext.php b/inc/fulltext.php
index a727a8b539459660a124686488e6e78129dce4d7..dba11d0e4f1996797d51f4685e25afab48dd27b6 100644
--- a/inc/fulltext.php
+++ b/inc/fulltext.php
@@ -20,14 +20,25 @@ if(!defined('FT_SNIPPET_NUMBER')) define('FT_SNIPPET_NUMBER',15);
  *
  * refactored into ft_pageSearch(), _ft_pageSearch() and trigger_event()
  *
- * @param string $query
- * @param array $highlight
+ * @param string     $query
+ * @param array      $highlight
+ * @param string     $sort
+ * @param int|string $after  only show results with an modified time after this date, accepts timestap or strtotime arguments
+ * @param int|string $before only show results with an modified time before this date, accepts timestap or strtotime arguments
+ *
  * @return array
  */
-function ft_pageSearch($query,&$highlight){
+function ft_pageSearch($query,&$highlight, $sort = null, $after = null, $before = null){
 
-    $data = array();
-    $data['query'] = $query;
+    if ($sort === null) {
+        $sort = 'hits';
+    }
+    $data = [
+        'query' => $query,
+        'sort' => $sort,
+        'after' => $after,
+        'before' => $before
+    ];
     $data['highlight'] =& $highlight;
 
     return trigger_event('SEARCH_QUERY_FULLPAGE', $data, '_ft_pageSearch');
@@ -100,7 +111,7 @@ function _ft_pageSearch(&$data) {
                 break;
             case 'N+:':
             case 'N-:': // namespace
-                $ns = substr($token, 3);
+                $ns = cleanID(substr($token, 3)) . ':';
                 $pages_matched = array();
                 foreach (array_keys($pages_all) as $id) {
                     if (strpos($id, $ns) === 0) {
@@ -134,8 +145,14 @@ function _ft_pageSearch(&$data) {
         }
     }
 
-    // sort docs by count
-    arsort($docs);
+    $docs = _ft_filterResultsByTime($docs, $data['after'], $data['before']);
+
+    if ($data['sort'] === 'mtime') {
+        uksort($docs, 'ft_pagemtimesorter');
+    } else {
+        // sort docs by count
+        arsort($docs);
+    }
 
     return $docs;
 }
@@ -199,7 +216,6 @@ function ft_mediause($id, $ignore_perms = false){
 }
 
 
-
 /**
  * Quicksearch for pagenames
  *
@@ -210,16 +226,25 @@ function ft_mediause($id, $ignore_perms = false){
  * The function always returns titles as well
  *
  * @triggers SEARCH_QUERY_PAGELOOKUP
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Adrian Lang <lang@cosmocode.de>
+ * @author   Andreas Gohr <andi@splitbrain.org>
+ * @author   Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string     $id       page id
+ * @param bool       $in_ns    match against namespace as well?
+ * @param bool       $in_title search in title?
+ * @param int|string $after    only show results with an modified time after this date, accepts timestap or strtotime arguments
+ * @param int|string $before   only show results with an modified time before this date, accepts timestap or strtotime arguments
  *
- * @param string $id        page id
- * @param bool   $in_ns     match against namespace as well?
- * @param bool   $in_title  search in title?
  * @return string[]
  */
-function ft_pageLookup($id, $in_ns=false, $in_title=false){
-    $data = compact('id', 'in_ns', 'in_title');
+function ft_pageLookup($id, $in_ns=false, $in_title=false, $after = null, $before = null){
+    $data = [
+        'id' => $id,
+        'in_ns' => $in_ns,
+        'in_title' => $in_title,
+        'after' => $after,
+        'before' => $before
+    ];
     $data['has_titles'] = true; // for plugin backward compatibility check
     return trigger_event('SEARCH_QUERY_PAGELOOKUP', $data, '_ft_pageLookup');
 }
@@ -233,9 +258,11 @@ function ft_pageLookup($id, $in_ns=false, $in_title=false){
 function _ft_pageLookup(&$data){
     // split out original parameters
     $id = $data['id'];
-    if (preg_match('/(?:^| )(?:@|ns:)([\w:]+)/', $id, $matches)) {
-        $ns = cleanID($matches[1]) . ':';
-        $id = str_replace($matches[0], '', $id);
+    $Indexer = idx_get_indexer();
+    $parsedQuery = ft_queryParser($Indexer, $id);
+    if (count($parsedQuery['ns']) > 0) {
+        $ns = cleanID($parsedQuery['ns'][0]) . ':';
+        $id = implode(' ', $parsedQuery['highlight']);
     }
 
     $in_ns    = $data['in_ns'];
@@ -279,10 +306,40 @@ function _ft_pageLookup(&$data){
         }
     }
 
+    $pages = _ft_filterResultsByTime($pages, $data['after'], $data['before']);
+
     uksort($pages,'ft_pagesorter');
     return $pages;
 }
 
+
+/**
+ * @param array      $results search results in the form pageid => value
+ * @param int|string $after   only returns results with an modified time after this date, accepts timestap or strtotime arguments
+ * @param int|string $before  only returns results with an modified time after this date, accepts timestap or strtotime arguments
+ *
+ * @return array
+ */
+function _ft_filterResultsByTime(array $results, $after, $before) {
+    if ($after || $before) {
+        $after = is_int($after) ? $after : strtotime($after);
+        $before = is_int($before) ? $before : strtotime($before);
+
+        foreach ($results as $id => $value) {
+            $mTime = filemtime(wikiFN($id));
+            if ($after && $after > $mTime) {
+                unset($results[$id]);
+                continue;
+            }
+            if ($before && $before < $mTime) {
+                unset($results[$id]);
+            }
+        }
+    }
+
+    return $results;
+}
+
 /**
  * Tiny helper function for comparing the searched title with the title
  * from the search index. This function is a wrapper around stripos with
@@ -316,6 +373,20 @@ function ft_pagesorter($a, $b){
     return strcmp ($a,$b);
 }
 
+/**
+ * Sort pages by their mtime, from newest to oldest
+ *
+ * @param string $a
+ * @param string $b
+ *
+ * @return int Returns < 0 if $a is newer than $b, > 0 if $b is newer than $a and 0 if they are of the same age
+ */
+function ft_pagemtimesorter($a, $b) {
+    $mtimeA = filemtime(wikiFN($a));
+    $mtimeB = filemtime(wikiFN($b));
+    return $mtimeB - $mtimeA;
+}
+
 /**
  * Creates a snippet extract
  *
@@ -813,4 +884,36 @@ function ft_termParser($Indexer, $term, $consider_asian = true, $phrase_mode = f
     return $parsed;
 }
 
+/**
+ * Recreate a search query string based on parsed parts, doesn't support negated phrases and `OR` searches
+ *
+ * @param array $and
+ * @param array $not
+ * @param array $phrases
+ * @param array $ns
+ * @param array $notns
+ *
+ * @return string
+ */
+function ft_queryUnparser_simple(array $and, array $not, array $phrases, array $ns, array $notns) {
+    $query = implode(' ', $and);
+    if (!empty($not)) {
+        $query .= ' -' . implode(' -', $not);
+    }
+
+    if (!empty($phrases)) {
+        $query .= ' "' . implode('" "', $phrases) . '"';
+    }
+
+    if (!empty($ns)) {
+        $query .= ' @' . implode(' @', $ns);
+    }
+
+    if (!empty($notns)) {
+        $query .= ' ^' . implode(' ^', $notns);
+    }
+
+    return $query;
+}
+
 //Setup VIM: ex: et ts=4 :
diff --git a/inc/html.php b/inc/html.php
index 2897d01c15e3f07bb99df75f3a279b57e773b90b..11a204eb8a72043eff69c2b0f07a390f49c2d543 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -8,6 +8,10 @@
 
 if(!defined('DOKU_INC')) die('meh.');
 if(!defined('NL')) define('NL',"\n");
+if (!defined('SEC_EDIT_PATTERN')) {
+    define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
+}
+
 
 /**
  * Convenience function to quickly build a wikilink
@@ -32,8 +36,10 @@ function html_wikilink($id,$name=null,$search=''){
  * The loginform
  *
  * @author   Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param bool $svg Whether to show svg icons in the register and resendpwd links or not
  */
-function html_login(){
+function html_login($svg = false){
     global $lang;
     global $conf;
     global $ID;
@@ -54,11 +60,13 @@ function html_login(){
     $form->endFieldset();
 
     if(actionOK('register')){
-        $form->addElement('<p>'.$lang['reghere'].': '.tpl_actionlink('register','','','',true).'</p>');
+        $registerLink = (new \dokuwiki\Menu\Item\Register())->asHtmlLink('', $svg);
+        $form->addElement('<p>'.$lang['reghere'].': '. $registerLink .'</p>');
     }
 
     if (actionOK('resendpwd')) {
-        $form->addElement('<p>'.$lang['pwdforget'].': '.tpl_actionlink('resendpwd','','','',true).'</p>');
+        $resendPwLink = (new \dokuwiki\Menu\Item\Resendpwd())->asHtmlLink('', $svg);
+        $form->addElement('<p>'.$lang['pwdforget'].': '. $resendPwLink .'</p>');
     }
 
     html_form('login', $form);
@@ -91,13 +99,11 @@ function html_denied() {
 function html_secedit($text,$show=true){
     global $INFO;
 
-    $regexp = '#<!-- EDIT(\d+) ([A-Z_]+) (?:"([^"]*)" )?\[(\d+-\d*)\] -->#';
-
     if(!$INFO['writable'] || !$show || $INFO['rev']){
-        return preg_replace($regexp,'',$text);
+        return preg_replace(SEC_EDIT_PATTERN,'',$text);
     }
 
-    return preg_replace_callback($regexp,
+    return preg_replace_callback(SEC_EDIT_PATTERN,
                 'html_secedit_button', $text);
 }
 
@@ -112,12 +118,12 @@ function html_secedit($text,$show=true){
  * @triggers HTML_SECEDIT_BUTTON
  */
 function html_secedit_button($matches){
-    $data = array('secid'  => $matches[1],
-                  'target' => strtolower($matches[2]),
-                  'range'  => $matches[count($matches) - 1]);
-    if (count($matches) === 5) {
-        $data['name'] = $matches[3];
+    $data = json_decode($matches[1], true);
+    if ($data == NULL) {
+        return;
     }
+    $data ['target'] = strtolower($data['target']);
+    $data ['hid'] = strtolower($data['hid']);
 
     return trigger_event('HTML_SECEDIT_BUTTON', $data,
                          'html_secedit_get_button');
@@ -163,7 +169,7 @@ function html_secedit_get_button($data) {
 function html_topbtn(){
     global $lang;
 
-    $ret  = '<a class="nolink" href="#dokuwiki__top"><input type="button" class="button" value="'.$lang['btn_top'].'" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'" /></a>';
+    $ret  = '<a class="nolink" href="#dokuwiki__top"><button class="button" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'">'.$lang['btn_top'].'</button></a>';
 
     return $ret;
 }
@@ -181,9 +187,10 @@ function html_topbtn(){
  * @param string         $method
  * @param string         $tooltip
  * @param bool|string    $label  label text, false: lookup btn_$name in localization
+ * @param string         $svg (optional) svg code, inserted into the button
  * @return string
  */
-function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false){
+function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false, $svg=null){
     global $conf;
     global $lang;
 
@@ -210,14 +217,14 @@ function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label
     if(is_array($params)){
         foreach($params as $key => $val) {
             $ret .= '<input type="hidden" name="'.$key.'" ';
-            $ret .= 'value="'.htmlspecialchars($val).'" />';
+            $ret .= 'value="'.hsc($val).'" />';
         }
     }
 
     if ($tooltip!='') {
-        $tip = htmlspecialchars($tooltip);
+        $tip = hsc($tooltip);
     }else{
-        $tip = htmlspecialchars($label);
+        $tip = hsc($label);
     }
 
     $ret .= '<button type="submit" ';
@@ -226,7 +233,12 @@ function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label
         $ret .= 'accesskey="'.$akey.'" ';
     }
     $ret .= 'title="'.$tip.'">';
-    $ret .= hsc($label);
+    if ($svg) {
+        $ret .= '<span>' . hsc($label) . '</span>';
+        $ret .= inlineSVG($svg);
+    } else {
+        $ret .= hsc($label);
+    }
     $ret .= '</button>';
     $ret .= '</div></form>';
 
@@ -298,10 +310,10 @@ function html_draft(){
     $text  = cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true));
 
     print p_locale_xhtml('draft');
+    html_diff($text, false);
     $form = new Doku_Form(array('id' => 'dw__editform'));
     $form->addHidden('id', $ID);
     $form->addHidden('date', $draft['date']);
-    $form->addElement(form_makeWikiText($text, array('readonly'=>'readonly')));
     $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
     $form->addElement($lang['draftdate'].' '. dformat(filemtime($INFO['draft'])));
     $form->addElement(form_makeCloseTag('div'));
@@ -350,94 +362,6 @@ function html_hilight_callback($m) {
     return $hlight;
 }
 
-/**
- * Run a search and display the result
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function html_search(){
-    global $QUERY, $ID;
-    global $lang;
-
-    $intro = p_locale_xhtml('searchpage');
-    // allow use of placeholder in search intro
-    $pagecreateinfo = (auth_quickaclcheck($ID) >= AUTH_CREATE) ? $lang['searchcreatepage'] : '';
-    $intro = str_replace(
-        array('@QUERY@', '@SEARCH@', '@CREATEPAGEINFO@'),
-        array(hsc(rawurlencode($QUERY)), hsc($QUERY), $pagecreateinfo),
-        $intro
-    );
-    echo $intro;
-    flush();
-
-    //show progressbar
-    print '<div id="dw__loading">'.NL;
-    print '<script type="text/javascript">/*<![CDATA[*/'.NL;
-    print 'showLoadBar();'.NL;
-    print '/*!]]>*/</script>'.NL;
-    print '</div>'.NL;
-    flush();
-
-    //do quick pagesearch
-    $data = ft_pageLookup($QUERY,true,useHeading('navigation'));
-    if(count($data)){
-        print '<div class="search_quickresult">';
-        print '<h3>'.$lang['quickhits'].':</h3>';
-        print '<ul class="search_quickhits">';
-        foreach($data as $id => $title){
-            print '<li> ';
-            if (useHeading('navigation')) {
-                $name = $title;
-            }else{
-                $ns = getNS($id);
-                if($ns){
-                    $name = shorten(noNS($id), ' ('.$ns.')',30);
-                }else{
-                    $name = $id;
-                }
-            }
-            print html_wikilink(':'.$id,$name);
-            print '</li> ';
-        }
-        print '</ul> ';
-        //clear float (see http://www.complexspiral.com/publications/containing-floats/)
-        print '<div class="clearer"></div>';
-        print '</div>';
-    }
-    flush();
-
-    //do fulltext search
-    $data = ft_pageSearch($QUERY,$regex);
-    if(count($data)){
-        print '<dl class="search_results">';
-        $num = 1;
-        foreach($data as $id => $cnt){
-            print '<dt>';
-            print html_wikilink(':'.$id,useHeading('navigation')?null:$id,$regex);
-            if($cnt !== 0){
-                print ': '.$cnt.' '.$lang['hits'].'';
-            }
-            print '</dt>';
-            if($cnt !== 0){
-                if($num < FT_SNIPPET_NUMBER){ // create snippets for the first number of matches only
-                    print '<dd>'.ft_snippet($id,$regex).'</dd>';
-                }
-                $num++;
-            }
-            flush();
-        }
-        print '</dl>';
-    }else{
-        print '<div class="nothing">'.$lang['nothingfound'].'</div>';
-    }
-
-    //hide progressbar
-    print '<script type="text/javascript">/*<![CDATA[*/'.NL;
-    print 'hideLoadBar("dw__loading");'.NL;
-    print '/*!]]>*/</script>'.NL;
-    flush();
-}
-
 /**
  * Display error on locked pages
  *
@@ -581,7 +505,7 @@ function html_revisions($first=0, $media_id = false){
         if($summary) {
             $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
             if(!$media_id) $form->addElement(' – ');
-            $form->addElement('<bdi>' . htmlspecialchars($summary) . '</bdi>');
+            $form->addElement('<bdi>' . hsc($summary) . '</bdi>');
             $form->addElement(form_makeCloseTag('span'));
         }
 
@@ -664,7 +588,7 @@ function html_revisions($first=0, $media_id = false){
         if ($info['sum']) {
             $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
             if(!$media_id) $form->addElement(' – ');
-            $form->addElement('<bdi>'.htmlspecialchars($info['sum']).'</bdi>');
+            $form->addElement('<bdi>'.hsc($info['sum']).'</bdi>');
             $form->addElement(form_makeCloseTag('span'));
         }
 
@@ -875,7 +799,7 @@ function html_recent($first = 0, $show_changes = 'both') {
             $form->addElement(html_wikilink(':' . $recent['id'], useHeading('navigation') ? null : $recent['id']));
         }
         $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
-        $form->addElement(' – ' . htmlspecialchars($recent['sum']));
+        $form->addElement(' – ' . hsc($recent['sum']));
         $form->addElement(form_makeCloseTag('span'));
 
         $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
@@ -948,7 +872,7 @@ function html_index($ns){
     $ns  = utf8_encodeFN(str_replace(':','/',$ns));
 
     echo p_locale_xhtml('index');
-    echo '<div id="index__tree">';
+    echo '<div id="index__tree" class="index__tree">';
 
     $data = array();
     search($data,$conf['datadir'],'search_index',array('ns' => $ns));
@@ -1061,7 +985,8 @@ function html_buildlist($data,$class,$func,$lifunc='html_li_default',$forcewrapp
         return '';
     }
 
-    $start_level = $data[0]['level'];
+    $firstElement = reset($data);
+    $start_level = $firstElement['level'];
     $level = $start_level;
     $ret   = '';
     $open  = 0;
@@ -1865,6 +1790,12 @@ function html_edit(){
     }
 
     $form->addHidden('target', $data['target']);
+    if ($INPUT->has('hid')) {
+        $form->addHidden('hid', $INPUT->str('hid'));
+    }
+    if ($INPUT->has('codeblockOffset')) {
+        $form->addHidden('codeblockOffset', $INPUT->str('codeblockOffset'));
+    }
     $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar', 'class'=>'editBar')));
     $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
     $form->addElement(form_makeCloseTag('div'));
@@ -1900,8 +1831,8 @@ function html_edit(){
     <div class="editBox" role="application">
 
     <div class="toolbar group">
-        <div id="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.dformat();?></div>
-        <div id="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
+        <div id="draft__status" class="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.dformat();?></div>
+        <div id="tool__bar" class="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
             target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
     </div>
     <?php
@@ -2108,7 +2039,7 @@ function html_TOC($toc){
     if(!count($toc)) return '';
     global $lang;
     $out  = '<!-- TOC START -->'.DOKU_LF;
-    $out .= '<div id="dw__toc">'.DOKU_LF;
+    $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF;
     $out .= '<h3 class="toggle">';
     $out .= $lang['toc'];
     $out .= '</h3>'.DOKU_LF;
diff --git a/inc/infoutils.php b/inc/infoutils.php
index 933eb7cceec02c8a79d7840cd3c9c3d583a24b0b..57f89e508c56663155b183c93bb54b60f8fbad58 100644
--- a/inc/infoutils.php
+++ b/inc/infoutils.php
@@ -6,7 +6,14 @@
  * @author     Andreas Gohr <andi@splitbrain.org>
  */
 if(!defined('DOKU_INC')) die('meh.');
-if(!defined('DOKU_MESSAGEURL')) define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/');
+
+if(!defined('DOKU_MESSAGEURL')){
+    if(in_array('ssl', stream_get_transports())) {
+        define('DOKU_MESSAGEURL','https://update.dokuwiki.org/check/');
+    }else{
+        define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/');
+    }
+}
 
 /**
  * Check for new messages from upstream
@@ -22,11 +29,12 @@ function checkUpdateMessages(){
 
     $cf = getCacheName($updateVersion, '.updmsg');
     $lm = @filemtime($cf);
+    $is_http = substr(DOKU_MESSAGEURL, 0, 5) != 'https';
 
     // check if new messages needs to be fetched
     if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_INC.DOKU_SCRIPT)){
         @touch($cf);
-        dbglog("checkUpdateMessages(): downloading messages to ".$cf);
+        dbglog("checkUpdateMessages(): downloading messages to ".$cf.($is_http?' (without SSL)':' (with SSL)'));
         $http = new DokuHTTPClient();
         $http->timeout = 12;
         $resp = $http->get(DOKU_MESSAGEURL.$updateVersion);
diff --git a/inc/init.php b/inc/init.php
index 4e4cd6450f6f158ac633aa060bf8242a59b3a9ca..ba6743f95f891ad2b79d1c745936c088cbf10728 100644
--- a/inc/init.php
+++ b/inc/init.php
@@ -3,6 +3,7 @@
  * Initialize some defaults needed for DokuWiki
  */
 
+
 /**
  * timing Dokuwiki execution
  *
@@ -41,6 +42,9 @@ if (!defined('DOKU_E_LEVEL')) {
     error_reporting(DOKU_E_LEVEL);
 }
 
+// avoid caching issues #1594
+header('Vary: Cookie');
+
 // init memory caches
 global $cache_revinfo;
        $cache_revinfo = array();
@@ -479,23 +483,31 @@ function getBaseURL($abs=null){
  *
  * @returns bool true when SSL is active
  */
-function is_ssl(){
+function is_ssl() {
     // check if we are behind a reverse proxy
-    if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
-        if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
-	    return true;
-	} else {
-	    return false;
-	}
+    if(isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
+        if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
+            return true;
+        } else {
+            return false;
+        }
     }
-    if (!isset($_SERVER['HTTPS']) ||
-        preg_match('/^(|off|false|disabled)$/i',$_SERVER['HTTPS'])){
+    if(!isset($_SERVER['HTTPS']) ||
+        preg_match('/^(|off|false|disabled)$/i', $_SERVER['HTTPS'])) {
         return false;
-    }else{
+    } else {
         return true;
     }
 }
 
+/**
+ * checks it is windows OS
+ * @return bool
+ */
+function isWindows() {
+    return (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false;
+}
+
 /**
  * print a nice message even if no styles are loaded yet.
  *
@@ -515,6 +527,9 @@ function nice_die($msg){
 </body>
 </html>
 EOT;
+    if(defined('DOKU_UNITTEST')) {
+        throw new RuntimeException('nice_die: '.$msg);
+    }
     exit(1);
 }
 
diff --git a/inc/lang/ar/lang.php b/inc/lang/ar/lang.php
index e25d0ee5da915ecd2caf9c04c7cb66a6b8d014a8..82ef5325fbc610bf24a113ab02766cde554eabe3 100644
--- a/inc/lang/ar/lang.php
+++ b/inc/lang/ar/lang.php
@@ -70,7 +70,6 @@ $lang['badpassconfirm']        = 'عذراً,كلمة السر غير صحيحة
 $lang['minoredit']             = 'تعديلات طفيفة';
 $lang['draftdate']             = 'حفظ المسودات آليا مفعّل';
 $lang['nosecedit']             = 'غُيرت الصفحة في هذه الأثناء، معلومات الجزء اصبحت قديمة. حُمُلت كل الصفحة بدلا.';
-$lang['searchcreatepage']      = 'إن لم تجد ما تبحث عنه، يمكنك إنشاء صفحة جديدة بعنوان ما تبحث عنة بالضغط على زر "حرر هذه الصفحة".';
 $lang['regmissing']            = 'عذرا، عليك ملء جميع الحقول.';
 $lang['reguexists']            = 'عذرا، يوجد مشترك بنفس الاسم.';
 $lang['regsuccess']            = 'أنشئ المستخدم و ارسلت كلمة السر بالبريد.';
diff --git a/inc/lang/ar/searchpage.txt b/inc/lang/ar/searchpage.txt
index 56355f85f809c6810aa423cd36436496fc0156fe..52537c3babef2eb535346e88b7da323b443519f5 100644
--- a/inc/lang/ar/searchpage.txt
+++ b/inc/lang/ar/searchpage.txt
@@ -2,4 +2,3 @@
 
 نتائج البحث .  @CREATEPAGEINFO@
 
-===== نتائج البحث =====
\ No newline at end of file
diff --git a/inc/lang/az/lang.php b/inc/lang/az/lang.php
index 4416215ddf0f9314d618d75801f63ea687768e77..f2c9aa662061a05fa0194d77640ee52f3bd456a5 100644
--- a/inc/lang/az/lang.php
+++ b/inc/lang/az/lang.php
@@ -59,7 +59,6 @@ $lang['badlogin']              = 'Təssüf ki istifadəçi adı və ya şifrə s
 $lang['minoredit']             = 'Az dəyişiklər';
 $lang['draftdate']             = 'Qaralama yadda saxlandı';
 $lang['nosecedit']             = 'Bu vaxt ərzində səhifə dəyişilmişdir, və bölmə haqqında məlumat köhnəlmişdir. Səhifənin tam versiyası yüklənmişdir.';
-$lang['searchcreatepage']      = 'Əgər Siz axtardığınızı tapa bilmədinizsə, onda Siz adı axtarışınız ilə uyğun düşən yeni səhifə yarada bilərsiniz. Bunu eləmək üçün, sadəcə \'\'Səhifəni yarat\'\' düyməsini sıxın.';
 $lang['regmissing']            = 'Təssüf ki Siz bütün xanələri doldurmalısınız.';
 $lang['reguexists']            = 'Təssüf ki bu ad ilə istifadəçi artıq mövcuddur.';
 $lang['regsuccess']            = 'İstivadəci yaradıldı və şifrə sizin e-maila göndərildi.';
diff --git a/inc/lang/az/searchpage.txt b/inc/lang/az/searchpage.txt
index 6b7fce7549582b8771ee78da9827f360909c13d0..9bf5a5b17031fbff32b1f52320ec52003a5e6220 100644
--- a/inc/lang/az/searchpage.txt
+++ b/inc/lang/az/searchpage.txt
@@ -2,4 +2,3 @@
 
 Qarşınızda - axtarışın nəticələridir. @CREATEPAGEINFO@
 
-===== Nəticələr =====
diff --git a/inc/lang/be/admin.txt b/inc/lang/be/admin.txt
new file mode 100644
index 0000000000000000000000000000000000000000..40fc5fbcd581f0fcb018dd0e9351e4b4e400ae69
--- /dev/null
+++ b/inc/lang/be/admin.txt
@@ -0,0 +1,3 @@
+====== Кіраванне ======
+
+Ніжэй вы зможаце знайсці спіс адміністрацыйных аперацый, даступных у «ДокуВікі».
\ No newline at end of file
diff --git a/inc/lang/be/adminplugins.txt b/inc/lang/be/adminplugins.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c5aa5d70dbdb8d766d21b435bf549a67825a8e18
--- /dev/null
+++ b/inc/lang/be/adminplugins.txt
@@ -0,0 +1 @@
+===== Дадатковыя ўбудовы =====
\ No newline at end of file
diff --git a/inc/lang/bg/lang.php b/inc/lang/bg/lang.php
index 6296070d44bd01fce925ab4d7179bc836151a776..fd4677c1adbc8f570ea8e81afbbc10cdb8507659 100644
--- a/inc/lang/bg/lang.php
+++ b/inc/lang/bg/lang.php
@@ -67,7 +67,6 @@ $lang['badpassconfirm']        = 'За съжаление паролата е г
 $lang['minoredit']             = 'Промените са незначителни';
 $lang['draftdate']             = 'Черновата е автоматично записана на';
 $lang['nosecedit']             = 'Страницата бе междувременно променена, презареждане на страницата поради неактуална информация.';
-$lang['searchcreatepage']      = 'Ако не намирате каквото сте търсили, може да създадете или редактирате страница, кръстена на вашата заявка, чрез съответния бутон.';
 $lang['regmissing']            = 'Моля, попълнете всички полета.';
 $lang['reguexists']            = 'Вече съществува потребител с избраното име.';
 $lang['regsuccess']            = 'Потребителят е създаден, а паролата е пратена по електронната поща.';
diff --git a/inc/lang/bg/searchpage.txt b/inc/lang/bg/searchpage.txt
index a44c648cab745d1a3198a4dbcb65af0cbf89e109..6da6042e9062478673ec001878a37fa7721c0440 100644
--- a/inc/lang/bg/searchpage.txt
+++ b/inc/lang/bg/searchpage.txt
@@ -2,4 +2,3 @@
 
 Резултата от търсенето ще намерите по-долу. @CREATEPAGEINFO@
 
-===== Резултати =====
diff --git a/inc/lang/ca-valencia/lang.php b/inc/lang/ca-valencia/lang.php
index 120f1ace06dea0e879d49781540997919eb2b8b6..da6bd67c19deed4b9ba3f915083ce3d4e0467c26 100644
--- a/inc/lang/ca-valencia/lang.php
+++ b/inc/lang/ca-valencia/lang.php
@@ -59,7 +59,6 @@ $lang['badlogin']              = 'Disculpe, pero el nom d\'usuari o la contrasen
 $lang['minoredit']             = 'Canvis menors';
 $lang['draftdate']             = 'Borrador gravat el';
 $lang['nosecedit']             = 'La pàgina ha canviat mentres tant, l\'informació de la secció no estava al dia, s\'ha carregat la pàgina sancera.';
-$lang['searchcreatepage']      = 'Si no ha trobat lo que buscava pot crear o editar una pàgina en el mateix nom que el text que ha buscat utilisant el botó corresponent.';
 $lang['regmissing']            = 'Disculpe, pero deu omplir tots els camps.';
 $lang['reguexists']            = 'Disculpe, pero ya existix un usuari en este nom.';
 $lang['regsuccess']            = 'S\'ha creat l\'usuari i se li ha enviat la contrasenya per correu electrònic.';
diff --git a/inc/lang/ca-valencia/searchpage.txt b/inc/lang/ca-valencia/searchpage.txt
index be8d3e1d7748be22749a7521554ef79d21588762..390d6064bbc6906659c2de6fd21158570222430f 100644
--- a/inc/lang/ca-valencia/searchpage.txt
+++ b/inc/lang/ca-valencia/searchpage.txt
@@ -2,4 +2,3 @@
 
 Pot vore els resultats de la busca ací baix.  @CREATEPAGEINFO@
 
-===== Resultats =====
diff --git a/inc/lang/ca/lang.php b/inc/lang/ca/lang.php
index ec353f770de9c017aa50d1c0a28b2fcf535b11e7..5133b37a30c5a1f4baec45344844dbd803de6815 100644
--- a/inc/lang/ca/lang.php
+++ b/inc/lang/ca/lang.php
@@ -71,7 +71,6 @@ $lang['badpassconfirm']        = 'Contrasenya incorrecta';
 $lang['minoredit']             = 'Canvis menors';
 $lang['draftdate']             = 'L\'esborrany s\'ha desat automàticament';
 $lang['nosecedit']             = 'Mentrestant la pàgina ha estat modificada. La informació de seccions estava obsoleta i ha calgut carregar la pàgina sencera.';
-$lang['searchcreatepage']      = 'Si no trobeu allò que buscàveu, podeu crear una pàgina nova per mitjà del botó \'\'Edita aquesta pàgina\'\'.';
 $lang['regmissing']            = 'Heu d\'omplir tots els camps.';
 $lang['reguexists']            = 'Ja existeix un altre usuari amb aquest nom.';
 $lang['regsuccess']            = 'S\'ha creat l\'usuari. La contrasenya s\'ha enviat per correu.';
diff --git a/inc/lang/ca/searchpage.txt b/inc/lang/ca/searchpage.txt
index 27efcdabfd98327ee2ce670a62de677cec7fed6c..68da58ca26404822bc7996a8d9428127fda222a0 100644
--- a/inc/lang/ca/searchpage.txt
+++ b/inc/lang/ca/searchpage.txt
@@ -2,4 +2,3 @@
 
 Heus ací els resultats de la cerca. @CREATEPAGEINFO@
 
-===== Resultats =====
\ No newline at end of file
diff --git a/inc/lang/cs/lang.php b/inc/lang/cs/lang.php
index fe2f893660196391d948a422936fbf7542799995..e6b008c4c7168aa8ad9a6bad75048e612320aeb6 100644
--- a/inc/lang/cs/lang.php
+++ b/inc/lang/cs/lang.php
@@ -83,7 +83,6 @@ $lang['badpassconfirm']        = 'Bohužel špatné heslo';
 $lang['minoredit']             = 'Drobné změny';
 $lang['draftdate']             = 'Koncept automaticky uložen v';
 $lang['nosecedit']             = 'Stránka byla v mezičase změněna. Informace o sekci již nebylo platné, byla načtena celá stránka.';
-$lang['searchcreatepage']      = 'Pokud jste nenašli, co hledáte, zkuste požadovanou stránku sami vytvořit stisknutím tlačítka \'\'Vytvořit stránku\'\'.';
 $lang['regmissing']            = 'Musíte vyplnit všechny údaje.';
 $lang['reguexists']            = 'Uživatel se stejným jménem už je zaregistrován.';
 $lang['regsuccess']            = 'Uživatelský účet byl vytvořen a heslo zasláno e-mailem.';
@@ -358,4 +357,3 @@ $lang['page_nonexist_rev']     = 'Stránka neexistovala na %s. Byla vytvořena d
 $lang['unable_to_parse_date']  = 'Nelze rozebrat parametr "%s".';
 $lang['email_signature_text']  = 'Tento e-mail byl automaticky vygenerován systémem DokuWiki
 @DOKUWIKIURL@';
-$lang['email_signature_html']  = ' ';
diff --git a/inc/lang/cs/searchpage.txt b/inc/lang/cs/searchpage.txt
index 2f5e89ff65f074ab0565bcbaad125f098beb5eff..800d61c27191c6f298a2ea7b62092a035e802785 100644
--- a/inc/lang/cs/searchpage.txt
+++ b/inc/lang/cs/searchpage.txt
@@ -2,4 +2,3 @@
 
 Výsledky hledání můžete vidět níže. @CREATEPAGEINFO@
 
-===== Výsledky =====
diff --git a/inc/lang/cy/lang.php b/inc/lang/cy/lang.php
index 7018e007115747c2e5ca48e8f1531ceacd0aab00..de407f80477abe5890ab01641e6b9fd27f10e903 100644
--- a/inc/lang/cy/lang.php
+++ b/inc/lang/cy/lang.php
@@ -70,7 +70,6 @@ $lang['badpassconfirm']        = 'Sori, roedd y cyfrinair yn anghywir';
 $lang['minoredit']             = 'Newidiadau Bach';
 $lang['draftdate']             = 'Awtogadwyd drafft ar'; // full dformat date will be added
 $lang['nosecedit']             = 'Newidiwyd y dudaen yn y cyfamser, roedd gwybodaeth yr adran wedi dyddio, felly llwythwyd y dudalen gyfan.';
-$lang['searchcreatepage']      = 'Os na wnaethoch chi ddod o hyd i\'r hyn roeddech chi am ddarganfod, gallwch chi greu neu golygu\'r dudalen wedi\'i henwi ar ôl eich ymholiad gyda\'r teclyn priodol.';
 
 $lang['regmissing']            = 'Sori, llenwch bob maes.';
 $lang['reguexists']            = 'Sori, mae defnyddiwr â\'r enw hwn yn bodoli eisoes.';
diff --git a/inc/lang/cy/searchpage.txt b/inc/lang/cy/searchpage.txt
index fd554e1e70ef61e28b4fec80c7b28bd8fe21a395..6a645cb57fd25257f6752f791f715942d4e30cb1 100644
--- a/inc/lang/cy/searchpage.txt
+++ b/inc/lang/cy/searchpage.txt
@@ -2,4 +2,3 @@
 
 Gallwch chi ddarganfod canlyniadau eich chwiliad isod. @CREATEPAGEINFO@
 
-===== Canlyniadau =====
diff --git a/inc/lang/da/lang.php b/inc/lang/da/lang.php
index 00f027045a251d7ce8799bfdc4c0801a4205d922..c9374f21ec4e6e68f75b86648b0a42008ffdff75 100644
--- a/inc/lang/da/lang.php
+++ b/inc/lang/da/lang.php
@@ -3,6 +3,8 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kenneth Schack Banner <kescba@gmail.com>
+ * @author Jon Theil Nielsen <jontheil@gmail.com>
  * @author koeppe <koeppe@kazur.dk>
  * @author Jon Bendtsen <bendtsen@diku.dk>
  * @author Lars Næsbye Christensen <larsnaesbye@stud.ku.dk>
@@ -11,14 +13,12 @@
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  * @author Soren Birk <soer9648@hotmail.com>
  * @author Jens Hyllegaard <jens.hyllegaard@gmail.com>
  * @author soer9648 <soer9648@eucl.dk>
  * @author Søren Birk <sbi@eucl.dk>
- * @author Søren Birk <soer9648@eucl.dk>
  * @author Jacob Palm <mail@jacobpalm.dk>
  */
 $lang['encoding']              = 'utf-8';
@@ -80,7 +80,6 @@ $lang['badpassconfirm']        = 'Adgangkode var desværre forkert';
 $lang['minoredit']             = 'Mindre ændringer';
 $lang['draftdate']             = 'Kladde automatisk gemt d.';
 $lang['nosecedit']             = 'Siden blev ændret i mellemtiden, sektions information var for gammel, hentede hele siden i stedet.';
-$lang['searchcreatepage']      = 'Hvis resultaterne ikke indeholder det du søgte efter kan du oprette et nyt dokument med samme navn som søgningen ved at trykke på knappen **\'\'[Opret dette dokument]\'\'**.';
 $lang['regmissing']            = 'Du skal udfylde alle felter.';
 $lang['reguexists']            = 'Dette brugernavn er allerede i brug.';
 $lang['regsuccess']            = 'Du er nu oprettet som bruger. Dit adgangskode bliver sendt til dig i en e-mail.';
diff --git a/inc/lang/da/searchpage.txt b/inc/lang/da/searchpage.txt
index 9cefd419ca2f78acb25522823f1729cc4adeed21..c4447852ffc9d79b1d36ba898c4b1bed2c4e986c 100644
--- a/inc/lang/da/searchpage.txt
+++ b/inc/lang/da/searchpage.txt
@@ -2,4 +2,3 @@
 
 Du kan se resultaterne af din søgning nedenunder. @CREATEPAGEINFO@
 
-===== Søgeresultater =====
diff --git a/inc/lang/de-informal/lang.php b/inc/lang/de-informal/lang.php
index 4cd819e2a05ecaeeeb8b41f03ac7437bf3853888..e4e5b4fa76f31ff2eeec69bed71e26a49a0ae262 100644
--- a/inc/lang/de-informal/lang.php
+++ b/inc/lang/de-informal/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
  * @author Andreas Gohr <andi@splitbrain.org>
  * @author Christof <gagi@fin.de>
  * @author Anika Henke <anika@selfthinker.org>
@@ -23,7 +24,6 @@
  * @author Volker Bödker <volker@boedker.de>
  * @author Janosch <janosch@moinzen.de>
  * @author rnck <dokuwiki@rnck.de>
- * @author Felix <j.felix@mueller-donath.de>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -84,7 +84,6 @@ $lang['badpassconfirm']        = 'Das Passwort war falsch.';
 $lang['minoredit']             = 'Kleine Änderung';
 $lang['draftdate']             = 'Entwurf gespeichert am';
 $lang['nosecedit']             = 'Diese Seite wurde in der Zwischenzeit geändert, da das Sektionsinfo veraltet ist. Die ganze Seite wird stattdessen geladen.';
-$lang['searchcreatepage']      = 'Falls der gesuchte Begriff nicht gefunden wurde, kannst du direkt eine neue Seite für den Suchbegriff anlegen, indem du auf den Knopf **\'\'[Seite anlegen]\'\'** drückst.';
 $lang['regmissing']            = 'Alle Felder müssen ausgefüllt werden';
 $lang['reguexists']            = 'Der Benutzername existiert leider schon.';
 $lang['regsuccess']            = 'Der neue Benutzer wurde angelegt und das Passwort per E-Mail versandt.';
@@ -155,7 +154,7 @@ $lang['js']['linkto']          = 'Link zu:';
 $lang['js']['del_confirm']     = 'Die ausgewählten Dateien wirklich löschen?';
 $lang['js']['restore_confirm'] = 'Wirklich diese Version wiederherstellen?';
 $lang['js']['media_diff']      = 'Unterschiede anzeigen:';
-$lang['js']['media_diff_both'] = 'Seite für Seite';
+$lang['js']['media_diff_both'] = 'Nebeneinander';
 $lang['js']['media_diff_opacity'] = 'Überblenden';
 $lang['js']['media_diff_portions'] = 'Übergang';
 $lang['js']['media_select']    = 'Dateien auswählen…';
@@ -199,7 +198,7 @@ $lang['diff2']                 = 'Zeige Unterschiede der ausgewählten Versionen
 $lang['difflink']              = 'Link zu der Vergleichsansicht';
 $lang['diff_type']             = 'Unterschiede anzeigen:';
 $lang['diff_inline']           = 'Inline';
-$lang['diff_side']             = 'Side by Side';
+$lang['diff_side']             = 'Nebeneinander';
 $lang['diffprevrev']           = 'Vorherige Überarbeitung';
 $lang['diffnextrev']           = 'Nächste Überarbeitung';
 $lang['difflastrev']           = 'Letzte Überarbeitung';
@@ -354,5 +353,6 @@ $lang['searchresult']          = 'Suchergebnis';
 $lang['plainhtml']             = 'Reines HTML';
 $lang['wikimarkup']            = 'Wiki Markup';
 $lang['page_nonexist_rev']     = 'Seite existierte nicht an der Stelle %s. Sie wurde an folgende Stelle erstellt: <a href="%s">%s</a>.';
+$lang['unable_to_parse_date']  = 'Parameter "%s" kann nicht geparsed werden.';
 $lang['email_signature_text']  = 'Diese E-Mail wurde erzeugt vom DokuWiki unter
 @DOKUWIKIURL@';
diff --git a/inc/lang/de-informal/searchpage.txt b/inc/lang/de-informal/searchpage.txt
index e78e4abddbc350075dc347ced691ca7bfa5d3183..5de550a7f83908e1e80644a303ecd04b6e34e1a3 100644
--- a/inc/lang/de-informal/searchpage.txt
+++ b/inc/lang/de-informal/searchpage.txt
@@ -2,6 +2,3 @@
 
 Unten sind die Ergebnisse deiner Suche gelistet. @CREATEPAGEINFO@
 
-===== Ergebnisse =====
-
-
diff --git a/inc/lang/de/conflict.txt b/inc/lang/de/conflict.txt
index dc44f71c0c5247418f19628971156eacd2f7241b..0d0283bf3ba8b1b1583baea97d5a212f379222fe 100644
--- a/inc/lang/de/conflict.txt
+++ b/inc/lang/de/conflict.txt
@@ -1,6 +1,6 @@
 ====== Es gibt eine neuere Version ======
 
-Eine neuere Version des aktuell in Bearbeitung befindlichen Dokuments existiert. Das heißt, jemand hat parallel an der selben Seite gearbeitet und zuerst gespeichert.
+Es existiert eine neuere Version des aktuell in Bearbeitung befindlichen Dokumentes. Das heißt, jemand hat parallel an der selben Seite gearbeitet und zuerst gespeichert.
 
 Die unten aufgeführten Unterschiede können bei der Entscheidung helfen, welchem Dokument Vorrang gewährt wird. Wählen Sie  **''[Speichern]''** zum Sichern Ihrer Version oder **''[Abbrechen]''**,  um Ihre Version zu verwerfen und die zuerst gespeicherte Seite zu behalten.
 
diff --git a/inc/lang/de/diff.txt b/inc/lang/de/diff.txt
index 82fbbc25294ed49e96febfb42f82be927d125c5e..3747da85ee309b3da1ceb4956211cd86b2a7aab6 100644
--- a/inc/lang/de/diff.txt
+++ b/inc/lang/de/diff.txt
@@ -1,5 +1,5 @@
 ====== Unterschiede ======
 
-Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
+Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
 
 
diff --git a/inc/lang/de/draft.txt b/inc/lang/de/draft.txt
index 77a55b1651c8c727d2a69810ce413045b17bc5ea..17d5d318efde84021248c4765cd72bffbb66df97 100644
--- a/inc/lang/de/draft.txt
+++ b/inc/lang/de/draft.txt
@@ -2,5 +2,5 @@
 
 Ihre letzte Bearbeitungssitzung wurde nicht ordnungsgemäß abgeschlossen. DokuWiki hat während Ihrer Arbeit automatisch einen Zwischenentwurf gespeichert, den Sie jetzt nutzen können, um Ihre Arbeit fortzusetzen. Unten sehen Sie die Daten, die bei Ihrer letzten Sitzung gespeichert wurden.
 
-Bitte entscheiden Sie, ob Sie den Entwurf //wiederherstellen// oder //löschen// wollen oder ob Sie die Bearbeitung abbrechen möchten.
+Bitte entscheiden Sie, ob Sie den Entwurf //wiederherstellen// oder //löschen// wollen, oder ob Sie die Bearbeitung abbrechen möchten.
 
diff --git a/inc/lang/de/edit.txt b/inc/lang/de/edit.txt
index 15e02c61ab314ab8fe8e1a35ce7407c2386734ff..6e56d25cb095f30493a4f0dccb376630a064d8f9 100644
--- a/inc/lang/de/edit.txt
+++ b/inc/lang/de/edit.txt
@@ -1,4 +1,4 @@
-Bitte nur editieren, falls das Dokument **verbessert** werden kann.
-
-Nach dem Bearbeiten den **''[Speichern]''**-Knopf drücken. Siehe [[wiki:syntax]] zur Wiki-Syntax. Zum Testen bitte erst im [[playground:playground|Spielplatz]] üben.
+Seite Bearbeiten und **''[Speichern]''** drücken. Siehe [[wiki:syntax]] zur Wiki-Syntax.
+Bitte nur editieren, falls das Dokument tatsächlich **verbessert** werden kann.
+Zum Testen bitte erst im [[playground:playground|Spielplatz]] üben.
 
diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php
index b77ef75adb947bb4548b1577005f792754a59dd3..7af01bc242891a4c4efc9fd7b89f05830e53c4d9 100644
--- a/inc/lang/de/lang.php
+++ b/inc/lang/de/lang.php
@@ -3,6 +3,9 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Joel Strasser <strasser999@gmail.com>
+ * @author Robert Riebisch <robert.riebisch@googlemail.com>
+ * @author Joerg <scooter22@gmx.de>
  * @author Andreas Gohr <andi@splitbrain.org>
  * @author Christof <gagi@fin.de>
  * @author Anika Henke <anika@selfthinker.org>
@@ -23,7 +26,6 @@
  * @author Pierre Corell <info@joomla-praxis.de>
  * @author Mateng Schimmerlos <mateng@firemail.de>
  * @author Benedikt Fey <spam@lifeisgoooood.de>
- * @author Joerg <scooter22@gmx.de>
  * @author Simon <st103267@stud.uni-stuttgart.de>
  * @author Hoisl <hoisl@gmx.at>
  * @author Marcel Eickhoff <eickhoff.marcel@gmail.com>
@@ -58,7 +60,7 @@ $lang['btn_secedit']           = 'Bearbeiten';
 $lang['btn_login']             = 'Anmelden';
 $lang['btn_logout']            = 'Abmelden';
 $lang['btn_admin']             = 'Admin';
-$lang['btn_update']            = 'Updaten';
+$lang['btn_update']            = 'Aktualisieren';
 $lang['btn_delete']            = 'Löschen';
 $lang['btn_back']              = 'Zurück';
 $lang['btn_backlink']          = 'Links hierher';
@@ -91,7 +93,7 @@ $lang['badpassconfirm']        = 'Das Passwort war falsch.';
 $lang['minoredit']             = 'kleine Änderung';
 $lang['draftdate']             = 'Entwurf gespeichert am';
 $lang['nosecedit']             = 'Diese Seite wurde in der Zwischenzeit geändert, der Seitenabschnitt ist veraltet, lade stattdessen volle Seite.';
-$lang['searchcreatepage']      = 'Falls der gesuchte Begriff nicht gefunden wurde, können Sie direkt eine neue Seite für den Suchbegriff anlegen, indem Sie auf den **\'\'[Seite anlegen]\'\'** Knopf drücken.';
+$lang['searchcreatepage']      = 'Falls der gesuchte Begriff nicht gefunden wurde, können Sie direkt eine neue, nach Ihrer Anfrage benannte Seite %s anlegen.';
 $lang['regmissing']            = 'Bitte alle Felder ausfüllen!';
 $lang['reguexists']            = 'Der Benutzername existiert leider schon.';
 $lang['regsuccess']            = 'Der neue Benutzer wurde angelegt und das Passwort per E-Mail versandt.';
@@ -106,11 +108,11 @@ $lang['profna']                = 'Änderung des Benutzerprofils in diesem Wiki n
 $lang['profnochange']          = 'Keine Änderungen, nichts zu tun.';
 $lang['profnoempty']           = 'Es muss ein Name und eine E-Mail-Adresse angegeben werden.';
 $lang['profchanged']           = 'Benutzerprofil erfolgreich geändert.';
-$lang['profnodelete']          = 'Dieses Wiki unterstützt nicht das Löschen von Benutzern.';
+$lang['profnodelete']          = 'Dieses Wiki unterstützt kein Löschen von Benutzern.';
 $lang['profdeleteuser']        = 'Benutzerprofil löschen';
 $lang['profdeleted']           = 'Ihr Benutzerprofil wurde im Wiki gelöscht.';
-$lang['profconfdelete']        = 'Ich möchte mein Benutzerprofil löschen.<br/> Diese Aktion ist nicht umkehrbar.';
-$lang['profconfdeletemissing'] = 'Bestätigung im Ankreuzkästchen fehlt';
+$lang['profconfdelete']        = 'Ich möchte mein Benutzerprofil löschen.<br/> Diese Aktion lässt sich nicht rückgängig machen,';
+$lang['profconfdeletemissing'] = 'Bestätigung in Kontrollkästchen fehlt';
 $lang['proffail']              = 'Das Benutzerkonto konnte nicht aktualisiert werden.';
 $lang['pwdforget']             = 'Passwort vergessen? Fordern Sie ein neues an';
 $lang['resendna']              = 'Passwörter versenden ist in diesem Wiki nicht möglich.';
diff --git a/inc/lang/de/searchpage.txt b/inc/lang/de/searchpage.txt
index 6cd8006ac3cc1ea9a903c98736040511b453a821..19fe84bcc589caa78a1049d9bcc132db6fbb4b66 100644
--- a/inc/lang/de/searchpage.txt
+++ b/inc/lang/de/searchpage.txt
@@ -1,7 +1,3 @@
 ====== Suche ======
 
 Unten sind die Ergebnisse Ihrer Suche gelistet. @CREATEPAGEINFO@
-
-===== Ergebnisse =====
-
-
diff --git a/inc/lang/el/lang.php b/inc/lang/el/lang.php
index 25910cbef6139984387b38757b727adc42727d0f..4533f414d6ea78aa5519b0a40088712dd253a4b6 100644
--- a/inc/lang/el/lang.php
+++ b/inc/lang/el/lang.php
@@ -73,7 +73,6 @@ $lang['badpassconfirm']        = 'Ο κωδικός που εισάγατε εί
 $lang['minoredit']             = 'Ασήμαντες αλλαγές';
 $lang['draftdate']             = 'Αυτόματη αποθήκευση πρόχειρης σελίδας στις';
 $lang['nosecedit']             = 'Η σελίδα τροποποιήθηκε στο μεταξύ και τα στοιχεία της ενότητας δεν ήταν συγχρονισμένα, οπότε φορτώθηκε η πλήρης σελίδα.  ';
-$lang['searchcreatepage']      = 'Αν δεν βρίσκεις αυτό που ψάχνεις, μπορείς να δημιουργήσεις ή να επεξεργαστείς τη σελίδα που ψάχνεις, χρησιμοποιώντας το κατάλληλο εργαλείο.';
 $lang['regmissing']            = 'Πρέπει να συμπληρώσετε όλα τα πεδία.';
 $lang['reguexists']            = 'Αυτός ο λογαριασμός υπάρχει ήδη.';
 $lang['regsuccess']            = 'Ο λογαριασμός δημιουργήθηκε και ο κωδικός εστάλει με e-mail.';
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php
index 2e7d368e228749a8fe4a461a4ba54a0c6dbe666e..4d11bac08d924ffb08c19d0d17d90606da555b98 100644
--- a/inc/lang/en/lang.php
+++ b/inc/lang/en/lang.php
@@ -69,7 +69,22 @@ $lang['badpassconfirm']        = 'Sorry, the password was wrong';
 $lang['minoredit']             = 'Minor Changes';
 $lang['draftdate']             = 'Draft autosaved on'; // full dformat date will be added
 $lang['nosecedit']             = 'The page was changed in the meantime, section info was out of date loaded full page instead.';
-$lang['searchcreatepage']      = 'If you didn\'t find what you were looking for, you can create or edit the page named after your query with the appropriate tool.';
+$lang['searchcreatepage']      = 'If you didn\'t find what you were looking for, you can create or edit the page %s, named after your query.';
+
+$lang['search_fullresults']    = 'Fulltext results';
+$lang['js']['search_toggle_tools']   = 'Toggle Search Tools';
+$lang['search_exact_match']    = 'Exact match';
+$lang['search_starts_with']    = 'Starts with';
+$lang['search_ends_with']      = 'Ends with';
+$lang['search_contains']       = 'Contains';
+$lang['search_custom_match']   = 'Custom';
+$lang['search_any_ns']         = 'Any namespace';
+$lang['search_any_time']       = 'Any time';
+$lang['search_past_7_days']    = 'Past week';
+$lang['search_past_month']     = 'Past month';
+$lang['search_past_year']      = 'Past year';
+$lang['search_sort_by_hits']   = 'Sort by hits';
+$lang['search_sort_by_mtime']  = 'Sort by last modified';
 
 $lang['regmissing']            = 'Sorry, you must fill in all fields.';
 $lang['reguexists']            = 'Sorry, a user with this login already exists.';
@@ -370,5 +385,5 @@ $lang['page_nonexist_rev']     = 'Page did not exist at %s. It was subsequently
 $lang['unable_to_parse_date']  = 'Unable to parse at parameter "%s".';
 $lang['email_signature_text'] = 'This mail was generated by DokuWiki at
 @DOKUWIKIURL@';
-$lang['email_signature_html'] = '';
-//Setup VIM: ex: et ts=2 :
+#$lang['email_signature_html'] = ''; # the empty default will copy the text signature, you can override it in a local lang file
+
diff --git a/inc/lang/en/searchpage.txt b/inc/lang/en/searchpage.txt
index ba0960aa682bcc3e5e6a87a7aecba5f913fc0c77..59cbec251994c0adaea1a965efd1dd35b46f1710 100644
--- a/inc/lang/en/searchpage.txt
+++ b/inc/lang/en/searchpage.txt
@@ -2,4 +2,3 @@
 
 You can find the results of your search below. @CREATEPAGEINFO@
 
-===== Results =====
diff --git a/inc/lang/eo/lang.php b/inc/lang/eo/lang.php
index fdccb899dd22280e8ca1e9a268364cc82152a156..26d3dd234e4b8599643cec6471d4f85fdbd02f38 100644
--- a/inc/lang/eo/lang.php
+++ b/inc/lang/eo/lang.php
@@ -3,13 +3,11 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
  * @author Antono Vasiljev <esperanto.minsk ĈE tut.by>
  * @author Felipe Castro <fefcas@yahoo.com.br>
- * @author Felipe Castro <fefcas@uol.com.br>
- * @author Felipe Castro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -70,11 +68,11 @@ $lang['badpassconfirm']        = 'Pardonu, la pasvorto malĝustis';
 $lang['minoredit']             = 'Etaj modifoj';
 $lang['draftdate']             = 'Lasta konservo de la skizo:';
 $lang['nosecedit']             = 'La paĝo ŝanĝiĝis intertempe, sekcio-informo estis malĝisdata, tial la tuta paĝo estas reŝargita.';
-$lang['searchcreatepage']      = 'Se vi ne trovis tion, kion vi serĉis, vi povas krei novan paĝon kun necesa nomo per la koresponda butono.';
 $lang['regmissing']            = 'Pardonu, vi devas plenigi ĉiujn kampojn.';
 $lang['reguexists']            = 'Pardonu, ĉi tiu uzanto-nomo jam ekzistas.';
 $lang['regsuccess']            = 'La uzanto kreiĝis kaj la pasvorto sendiĝis per retpoŝto.';
 $lang['regsuccess2']           = 'La uzanto kreiĝis.';
+$lang['regfail']               = 'Ne eblis krei uzanton.';
 $lang['regmailfail']           = 'Åœajne okazis eraro dum elsendo de la pasvorto. Bonvolu informi administranton pri tio!';
 $lang['regbadmail']            = 'Entajpita retpoŝta adreso ŝajnas ne valida. Se vi pensas, ke tio estas eraro, kontaktu la administranton.';
 $lang['regbadpass']            = 'La du pasvortoj ne samas, bonvolu provi refoje.';
@@ -89,6 +87,7 @@ $lang['profdeleteuser']        = 'Forigi aliĝon';
 $lang['profdeleted']           = 'Via uzant-aliĝo estis forigata de tiu ĉi vikio';
 $lang['profconfdelete']        = 'Mi deziras forigi mian aliĝon de tiu ĉi vikio. <br/> Tiu ĉi ago ne povos esti malfarata.';
 $lang['profconfdeletemissing'] = 'Konfirmilo ne estas markita';
+$lang['proffail']              = 'La uzantokonto ne estis aktualigita.';
 $lang['pwdforget']             = 'Ĉu vi forgesis vian pasvorton? Prenu novan';
 $lang['resendna']              = 'Tiu ĉi vikio ne ebligas resendon de la pasvortoj.';
 $lang['resendpwd']             = 'Sendi novan pasvorton al';
@@ -337,5 +336,5 @@ $lang['currentns']             = 'Aktuala nomspaco';
 $lang['searchresult']          = 'Serĉrezulto';
 $lang['plainhtml']             = 'Plena HTML';
 $lang['wikimarkup']            = 'Vikiteksto';
-$lang['email_signature_text'] = 'Tiu ĉi mesaĝo kreiĝis de DokuWiki ĉe
+$lang['email_signature_text']  = 'Tiu ĉi mesaĝo kreiĝis de DokuWiki ĉe
 @DOKUWIKIURL@';
diff --git a/inc/lang/eo/searchpage.txt b/inc/lang/eo/searchpage.txt
index bdefe7b59f328c0ef39c83a5752bbb66f90ff36a..20711c2417da09911d8209deb5f0eac82a561d37 100644
--- a/inc/lang/eo/searchpage.txt
+++ b/inc/lang/eo/searchpage.txt
@@ -1,5 +1,4 @@
 ====== Serĉo ======
 
-Sube estas rezultoj de serĉo en la retejo.\\ @CREATEPAGEINFO@
+Sube estas rezultoj de serĉo en la retejo. @CREATEPAGEINFO@
 
-===== Rezultoj =====
diff --git a/inc/lang/es/lang.php b/inc/lang/es/lang.php
index d3163c08281f21ccc5d4065ec6dcf16cdbe10ea5..55f8508b830ad91152d1a18785cbbf9da4f6b065 100644
--- a/inc/lang/es/lang.php
+++ b/inc/lang/es/lang.php
@@ -105,7 +105,6 @@ $lang['badpassconfirm']        = 'Lo siento, la contraseña es errónea';
 $lang['minoredit']             = 'Cambios menores';
 $lang['draftdate']             = 'Borrador guardado automáticamente:';
 $lang['nosecedit']             = 'La página ha cambiado en el lapso, la información de sección estaba anticuada, en su lugar se cargó la página completa.';
-$lang['searchcreatepage']      = 'Si no has encontrado lo que buscabas, puedes crear una nueva página con tu consulta utilizando el botón  \'\'Crea esta página\'\'.';
 $lang['regmissing']            = 'Lo siento, tienes que completar todos los campos.';
 $lang['reguexists']            = 'Lo siento, ya existe un usuario con este nombre.';
 $lang['regsuccess']            = 'El usuario ha sido creado y la contraseña se ha enviado por correo.';
diff --git a/inc/lang/es/searchpage.txt b/inc/lang/es/searchpage.txt
index 819815b15a045421c8e5da3ea436b269d19492da..9bc31616ace0f05908a7343f5e04506bbd30445c 100644
--- a/inc/lang/es/searchpage.txt
+++ b/inc/lang/es/searchpage.txt
@@ -2,4 +2,3 @@
 
 Puedes encontrar los resultados de tu búsqueda abajo. @CREATEPAGEINFO@
 
-===== Resultados =====
\ No newline at end of file
diff --git a/inc/lang/et/lang.php b/inc/lang/et/lang.php
index f8051d0fc0f38a26e9e6921392061adf8c4a13ef..0320812c9d7699abc7dd2a643b340aafd53b4f9b 100644
--- a/inc/lang/et/lang.php
+++ b/inc/lang/et/lang.php
@@ -68,7 +68,6 @@ $lang['badpassconfirm']        = 'Väär salasõna';
 $lang['minoredit']             = 'Ebaolulised muudatused';
 $lang['draftdate']             = 'Mustand automaatselt salvestatud';
 $lang['nosecedit']             = 'Leht on vahepeal muutunud, jaotiste teave osutus aegunuks sestap laeti tervelehekülg.';
-$lang['searchcreatepage']      = "Kui Sa otsitavat ei leidnud võid tekitada oma otsingu nimelise uue lehe kasutades ''Toimeta seda lehte'' nuppu.";
 $lang['regmissing']            = 'Kõik väljad tuleb ära täita.';
 $lang['reguexists']            = 'Tegelikult on sellise nimega kasutaja juba olemas.';
 $lang['regsuccess']            = 'Kasutaja sai tehtud. Parool saadeti Sulle e-posti aadressil.';
diff --git a/inc/lang/et/searchpage.txt b/inc/lang/et/searchpage.txt
index 6ba57324a4bb1374b2bb7729d62734a96f89df94..546ae0eea151be1c5c67259f76e9dc957cd787b2 100644
--- a/inc/lang/et/searchpage.txt
+++ b/inc/lang/et/searchpage.txt
@@ -2,4 +2,3 @@
 
 Leiad vasted oma otsingule. @CREATEPAGEINFO@
 
-===== Vasted =====
diff --git a/inc/lang/eu/lang.php b/inc/lang/eu/lang.php
index fc33830c30a91bdcbc4a3fe39fd84966b119766a..4e074f0e76bb4c4febf6c2c09cac29712717e50b 100644
--- a/inc/lang/eu/lang.php
+++ b/inc/lang/eu/lang.php
@@ -7,6 +7,7 @@
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
  * @author Yadav Gowda <yadav.gowda@gmail.com>
+ * @author Osoitz <oelkoro@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -63,14 +64,15 @@ $lang['fullname']              = 'Izen Deiturak';
 $lang['email']                 = 'E-Maila';
 $lang['profile']               = 'Erabiltzaile Profila';
 $lang['badlogin']              = 'Barkatu, prozesuak huts egin du; saiatu berriz';
+$lang['badpassconfirm']        = 'Pasahitz okerra';
 $lang['minoredit']             = 'Aldaketa Txikiak';
 $lang['draftdate']             = 'Zirriborroa automatikoki gorde da hemen:';
 $lang['nosecedit']             = 'Orria aldatua izan da bitartean, info atala zaharkituta geratu da, orri osoa kargatu da horren ordez.';
-$lang['searchcreatepage']      = 'Bilatzen zabiltzana aurkitu ez baduzu, zuk zeuk sortu dezakezu orri berri bat bilaketa ostean \'\'Sortu orri hau\'\' erabiliz.';
 $lang['regmissing']            = 'Barkatu, hutsune guztiak bete behar dituzu.';
 $lang['reguexists']            = 'Barkatu, izen bereko erabiltzailea existitzen da.';
 $lang['regsuccess']            = 'Erabiltzailea sortu da. Pasahitza mailez bidaliko zaizu.';
 $lang['regsuccess2']           = 'Erabiltzailea sortua izan da.';
+$lang['regfail']               = 'Ezin izan da erabiltzailea sortu';
 $lang['regmailfail']           = 'Badirudi arazoren bat egon dela pasahitza mailez bidaltzeko orduan. Administratzailearekin harremanetan jarri!';
 $lang['regbadmail']            = 'Emandako helbidea ez da zuzena - jarri harremanetan administratzailearekin hau akats bat dela uste baduzu';
 $lang['regbadpass']            = 'Idatzitako bi pasahitzak ez dira berdinak, berriz saiatu.';
@@ -80,7 +82,12 @@ $lang['profna']                = 'Wiki honek ez du profilaren aldaketa ahalbidet
 $lang['profnochange']          = 'Aldaketarik ez, ez dago egiteko ezer.';
 $lang['profnoempty']           = 'Izen edota e-posta hutsa ez dago onartua.';
 $lang['profchanged']           = 'Erabiltzaile profila arrakastaz eguneratua.';
+$lang['profnodelete']          = 'Wiki honek ez du erabiltzaileak ezabatzea onartzen';
 $lang['profdeleteuser']        = 'Kontua ezabatu';
+$lang['profdeleted']           = 'Zure erabiltzaile kontua wiki honetatik ezabatu da';
+$lang['profconfdelete']        = 'Nire kontua kendu nahi dut wiki honetatik. <br/>Ekintza hau ezin da desegin.';
+$lang['profconfdeletemissing'] = 'Ez da egiaztaketa-kutxa markatu';
+$lang['proffail']              = 'Erabiltzailearen perfila ez da eguneratu';
 $lang['pwdforget']             = 'Pasahitza ahaztu duzu? Eskuratu berri bat';
 $lang['resendna']              = 'Wiki honek ez du pasahitz berbidalketa onartzen.';
 $lang['resendpwd']             = '-entzat pasahitza berria ezarri';
@@ -96,6 +103,7 @@ $lang['searchmedia_in']        = 'Bilatu %s-n';
 $lang['txt_upload']            = 'Ireki nahi den fitxategia aukeratu:';
 $lang['txt_filename']          = 'Idatzi wikiname-a (aukerazkoa):';
 $lang['txt_overwrt']           = 'Oraingo fitxategiaren gainean idatzi';
+$lang['maxuploadsize']         = 'Igo gehienez %s fitxategiko';
 $lang['lockedby']              = 'Momentu honetan blokeatzen:';
 $lang['lockexpire']            = 'Blokeaketa iraungitzen da:';
 $lang['js']['willexpire']      = 'Zure blokeaketa orri hau aldatzeko minutu batean iraungitzen da.\nGatazkak saihesteko, aurreikusi botoia erabili blokeaketa denboragailua berrabiarazteko.';
@@ -133,6 +141,7 @@ $lang['js']['del_confirm']     = 'Benetan ezabatu aukeratutako fitxategia(k)?';
 $lang['js']['restore_confirm'] = 'Benetan bertsio hau berrezarri?';
 $lang['js']['media_diff']      = 'Diferentziak ikusi:';
 $lang['js']['media_diff_both'] = 'Ondoz ondo';
+$lang['js']['media_diff_portions'] = 'Pasatu hatza';
 $lang['js']['media_select']    = 'Fitxategiak hautatu';
 $lang['js']['media_upload_btn'] = 'Igo';
 $lang['js']['media_done_btn']  = 'Egina';
@@ -175,6 +184,11 @@ $lang['difflink']              = 'Estekatu konparaketa bista honetara';
 $lang['diff_type']             = 'Ikusi diferentziak:';
 $lang['diff_inline']           = 'Lerro tartean';
 $lang['diff_side']             = 'Ondoz ondo';
+$lang['diffprevrev']           = 'Aurreko errebisioa';
+$lang['diffnextrev']           = 'Hurrengo errebisioa';
+$lang['difflastrev']           = 'Azken errebisioa';
+$lang['diffbothprevrev']       = 'Alde biak aurreko errebisioa';
+$lang['diffbothnextrev']       = 'Alde biak hurrengo errebisioa';
 $lang['line']                  = 'Marra';
 $lang['breadcrumb']            = 'Traza:';
 $lang['youarehere']            = 'Hemen zaude:';
@@ -279,8 +293,12 @@ $lang['i_policy']              = 'Hasierako ACL politika';
 $lang['i_pol0']                = 'Wiki Irekia (irakurri, idatzi, fitxategiak igo edonorentzat)';
 $lang['i_pol1']                = 'Wiki Publikoa (irakurri edonorentzat, idatzi eta fitxategiak igo erregistratutako erabiltzaileentzat)';
 $lang['i_pol2']                = 'Wiki Itxia (irakurri, idatzi, fitxategiak igo erregistratutako erabiltzaileentzat soilik)';
+$lang['i_allowreg']            = 'Baimendu erabiltzaileei bere burua erregistratzea';
 $lang['i_retry']               = 'Berriz saiatu';
 $lang['i_license']             = 'Mesedez, aukeratu zein lizentzipean ezarri nahi duzun zure edukia:';
+$lang['i_license_none']        = 'Ez erakutsi lizentzia informaziorik';
+$lang['i_pop_field']           = 'Lagundu gaitzazu Dokuwiki esperientzia hobetzen:';
+$lang['i_pop_label']           = 'Hilean behin bidali erabilera datu anonimoak Dokuwiki garatzaileei';
 $lang['recent_global']         = 'Une honetan <b>%s</b> izen-espazioaren barneko aldaketak ikusten ari zara.<a href="%s"> Wiki osoaren azken aldaketak</a> ere ikusi ditzakezu.';
 $lang['years']                 = 'duela %d urte';
 $lang['months']                = 'duela %d hilabete';
@@ -296,6 +314,8 @@ $lang['media_file']            = 'Fitxategia';
 $lang['media_viewtab']         = 'Begiratu';
 $lang['media_edittab']         = 'Editatu';
 $lang['media_historytab']      = 'Historia';
+$lang['media_list_thumbs']     = 'Iruditxoak';
+$lang['media_list_rows']       = 'Errenkadak';
 $lang['media_sort_name']       = 'Izena';
 $lang['media_sort_date']       = 'Data';
 $lang['media_files']           = '%s -n fitxategiak';
@@ -304,7 +324,16 @@ $lang['media_search']          = 'Bilatu %s -n';
 $lang['media_view']            = '%s';
 $lang['media_viewold']         = '%s -n %s';
 $lang['media_edit']            = '%s editatu';
+$lang['media_history']         = '%s(a)ren historiala';
+$lang['media_meta_edited']     = 'metadatuak editatua';
+$lang['media_perm_read']       = 'Ez duzu fitxategiak irakurtzeko behar beste baimen.';
+$lang['media_perm_upload']     = 'Ez duzu fitxategiak igotzeko behar beste baimen.';
 $lang['media_update']          = 'Bertsio berria igo';
 $lang['media_restore']         = 'Bertsio hau berrezarri';
-$lang['email_signature_text'] = 'Email hau DokuWiki erabiliz sortu da
+$lang['media_acl_warning']     = 'Hau agian ez dago osorik SCL murrizketak eta ezkutuko orriak direla eta.';
+$lang['searchresult']          = 'Bilaketaren emaitza';
+$lang['plainhtml']             = 'HTML hutsa';
+$lang['wikimarkup']            = 'Wiki kodea';
+$lang['page_nonexist_rev']     = 'Ez zegoen %s izeneko orririk. Sortu egin da <a href="%s">%s</a> helbidean.';
+$lang['email_signature_text']  = 'Email hau DokuWiki erabiliz sortu da
 @DOKUWIKIURL@';
diff --git a/inc/lang/eu/searchpage.txt b/inc/lang/eu/searchpage.txt
index c632305b995005ab19436d71240c2b50af461c2c..ebd31d0deda8b92160b804444ea87ed2bbe2f369 100644
--- a/inc/lang/eu/searchpage.txt
+++ b/inc/lang/eu/searchpage.txt
@@ -2,4 +2,3 @@
 
 Emaitzak ondorengo aurkiketan bilatu ditzakezu. @CREATEPAGEINFO@
 
-===== Bilaketa emaitzak: =====
diff --git a/inc/lang/fa/lang.php b/inc/lang/fa/lang.php
index 529c9f82086df7c9bbbc59fc7b1daac085899415..d1e16e7fd75973dfcb4114437931214dc2120388 100644
--- a/inc/lang/fa/lang.php
+++ b/inc/lang/fa/lang.php
@@ -78,7 +78,6 @@ $lang['badpassconfirm']        = 'متاسفم، رمز عبور اشتباه ا
 $lang['minoredit']             = 'ویرایش‌های خُرد';
 $lang['draftdate']             = 'ذخیره خودکار پیش‌نویس در';
 $lang['nosecedit']             = 'این صفحه در این میان تغییر کرده است، اطلاعات بخش قدیمی شده است، در عوض محتوای کل نمایش داده می‌شود.';
-$lang['searchcreatepage']      = 'اگر به نتیجه‌ی مطلوبی نرسیده‌اید، می‌توانید صفحه‌ی مورد نظر را ایجاد کنید.';
 $lang['regmissing']            = 'متاسفم، شما باید همه قسمت‌ها را پر کنید.';
 $lang['reguexists']            = 'نام کاربری‌ای که وارد کردید قبلن استفاده شده است.';
 $lang['regsuccess']            = 'کاربر ساخته شد و گذرواژه به صورت ایمیل ارسال گردید.';
diff --git a/inc/lang/fa/searchpage.txt b/inc/lang/fa/searchpage.txt
index f7f1a53094a7e57bca4a65415d68c08f35d81c52..50d872e0553d1923bc4b8e881c7fffb2b2c3438f 100644
--- a/inc/lang/fa/searchpage.txt
+++ b/inc/lang/fa/searchpage.txt
@@ -2,4 +2,3 @@
 
 نتایج جستجو در زیر آمده است. @CREATEPAGEINFO@
 
-===== نتایج =====
\ No newline at end of file
diff --git a/inc/lang/fi/lang.php b/inc/lang/fi/lang.php
index d16c856fdd0a7326db7d96293b9c522881fbfa9e..ebcca3347fc979238a9546d8bac6269de649cf64 100644
--- a/inc/lang/fi/lang.php
+++ b/inc/lang/fi/lang.php
@@ -71,7 +71,6 @@ $lang['badpassconfirm']        = 'Valitan. Salasana oli väärin';
 $lang['minoredit']             = 'Pieni muutos';
 $lang['draftdate']             = 'Luonnos tallennettu automaattisesti';
 $lang['nosecedit']             = 'Sivu on muuttunut välillä ja kappaleen tiedot olivat vanhentuneet. Koko sivu ladattu.';
-$lang['searchcreatepage']      = 'Jos et löytänyt etsimääsi voit luoda uuden sivun tiedustelusi pohjalta käyttämällä \'\'Muokkaa tätä sivua\'\' -napilla.';
 $lang['regmissing']            = 'Kaikki kentät tulee täyttää.';
 $lang['reguexists']            = 'Käyttäjä tällä käyttäjänimellä on jo olemassa.';
 $lang['regsuccess']            = 'Käyttäjä luotiin ja salasana lähetettiin sähköpostilla.';
diff --git a/inc/lang/fi/searchpage.txt b/inc/lang/fi/searchpage.txt
index b2ad8cc986773e031487cbeef44af560e97150ab..8e61bf367a0849f355b18d07ce3e917ff3a07d25 100644
--- a/inc/lang/fi/searchpage.txt
+++ b/inc/lang/fi/searchpage.txt
@@ -2,4 +2,3 @@
 
 Löydät etsinnän tulokset alta. @CREATEPAGEINFO@
 
-===== Tulokset =====
diff --git a/inc/lang/fo/lang.php b/inc/lang/fo/lang.php
index 50f2faca7d25cfc6cea5c034e9f983432ebd3147..9b078d3b62b1d8fc9ec060f93353183fcf6bf4c3 100644
--- a/inc/lang/fo/lang.php
+++ b/inc/lang/fo/lang.php
@@ -58,7 +58,6 @@ $lang['badlogin']              = 'Skeivt brúkaranavn ella loyniorð.';
 $lang['minoredit']             = 'Smærri broytingar';
 $lang['draftdate']             = 'Goym kladdu sett frá';
 $lang['nosecedit']             = 'Hendan síðan var broytt undir tilevnan, brotið var ikki rætt dagfest, heintaði fulla síðu í staðin';
-$lang['searchcreatepage']      = "Um úrslitini ikki innihalda tað sum tú leitaði eftir kanst tú upprætta eitt nýtt skjal við sama navni sum leitingin við at trýsta á **''[Upprætta hetta skjal]''** knappin.";
 $lang['regmissing']            = 'Tú skalt fylla út øll øki.';
 $lang['reguexists']            = 'Hetta brúkaranavn er upptiki.';
 $lang['regsuccess']            = 'Tú ert nú stovnavur sum brúkari. Títt loyniorð verður sent til tín í einum T-posti.';
diff --git a/inc/lang/fo/searchpage.txt b/inc/lang/fo/searchpage.txt
index 33bcc320647ebee530b44b21c1ca3d5580ed6316..896102bfe5dd4040d63ddf5dade3521339053fdb 100644
--- a/inc/lang/fo/searchpage.txt
+++ b/inc/lang/fo/searchpage.txt
@@ -2,4 +2,3 @@
 
 Tú kanst síggja úrslitini av tíni leiting niðanfyri. @CREATEPAGEINFO@
 
-===== Leitiúrslit =====
diff --git a/inc/lang/fr/lang.php b/inc/lang/fr/lang.php
index 9f14918d2d759a7ea0232860707f892f5e7c17c1..13ae644f97c0f29aa3ff79591d9cd25686dbe9d7 100644
--- a/inc/lang/fr/lang.php
+++ b/inc/lang/fr/lang.php
@@ -3,6 +3,8 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Michael Bohn <mjbohn@gmail.com>
+ * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
  * @author Sébastien Bauer <sebastien.bauer@advalvas.be>
  * @author Antoine Fixary <antoine.fixary@freesbee.fr>
  * @author cumulus <pta-n56@myamail.com>
@@ -21,8 +23,6 @@
  * @author Florian Gaub <floriang@floriang.net>
  * @author Samuel Dorsaz <samuel.dorsaz@novelion.net>
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author schplurtz@laposte.net
- * @author skimpax@gmail.com
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
@@ -33,7 +33,6 @@
  * @author ggallon <gwenael.gallon@mac.com>
  * @author David VANTYGHEM <david.vantyghem@free.fr>
  * @author Caillot <remicaillot5@gmail.com>
- * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
  * @author YoBoY <yoboy@ubuntu-fr.org>
  * @author james <j.mccann@celcat.com>
  * @author Pietroni <pietroni@informatique.univ-paris-diderot.fr>
@@ -100,7 +99,6 @@ $lang['badpassconfirm']        = 'Désolé, le mot de passe est erroné';
 $lang['minoredit']             = 'Modification mineure';
 $lang['draftdate']             = 'Brouillon enregistré automatiquement le';
 $lang['nosecedit']             = 'La page a changé entre temps, les informations de la section sont obsolètes ; la page complète a été chargée à la place.';
-$lang['searchcreatepage']      = 'Si vous n\'avez pas trouvé ce que vous cherchiez, vous pouvez créer ou modifier la page correspondant à votre requête en cliquant sur le bouton approprié.';
 $lang['regmissing']            = 'Désolé, vous devez remplir tous les champs.';
 $lang['reguexists']            = 'Désolé, ce nom d\'utilisateur est déjà pris.';
 $lang['regsuccess']            = 'L\'utilisateur a été créé. Le mot de passe a été expédié par courriel.';
diff --git a/inc/lang/fr/searchpage.txt b/inc/lang/fr/searchpage.txt
index 5577a3a2a3fb1e2bd09014e7855857b70184c958..7866187d49a2aece48ecfddea8c160704ad8713d 100644
--- a/inc/lang/fr/searchpage.txt
+++ b/inc/lang/fr/searchpage.txt
@@ -2,4 +2,3 @@
 
 Voici les résultats de votre recherche. @CREATEPAGEINFO@
 
-===== Résultats =====
diff --git a/inc/lang/gl/lang.php b/inc/lang/gl/lang.php
index 941989a32aa7c3cb91619bbb70b7fc4b89c7ac9f..a83279e822160fc456a97601a47a9d3867f7f472 100644
--- a/inc/lang/gl/lang.php
+++ b/inc/lang/gl/lang.php
@@ -62,7 +62,6 @@ $lang['badlogin']              = 'Sentímolo, mais o nome de usuario ou o contra
 $lang['minoredit']             = 'Trocos Menores';
 $lang['draftdate']             = 'Borrador gardado automaticamente en';
 $lang['nosecedit']             = 'A páxina mudou entrementres, a información da sección estaba desfasada polo que se cargou a páxina completa no seu lugar.';
-$lang['searchcreatepage']      = "Se non atopaches o que estabas a procurar, podes crear ou editar a páxina co nome relacionado coa túa procura empregando o botón axeitado.";
 $lang['regmissing']            = 'Sentímolo, mais tes que cubrir todos os campos.';
 $lang['reguexists']            = 'Sentímolo, mais xa existe un usuario con ese nome.';
 $lang['regsuccess']            = 'O usuario foi creado e o contrasinal enviado por correo-e.';
diff --git a/inc/lang/gl/searchpage.txt b/inc/lang/gl/searchpage.txt
index e37ec46427c5f7a7933b051e16b5eeff9ced3dcc..6c884935541b8c66b7fb7279336d7067c0cfc46a 100644
--- a/inc/lang/gl/searchpage.txt
+++ b/inc/lang/gl/searchpage.txt
@@ -2,4 +2,3 @@
 
 Podes atopar os resultados da túa procura a continuación. @CREATEPAGEINFO@
 
-===== Resultados =====
diff --git a/inc/lang/he/lang.php b/inc/lang/he/lang.php
index 49f17c3e4306cfd566511e011baa068f520ee460..655bc5d8054807f557d28571a4f9ed2e102ab4fe 100644
--- a/inc/lang/he/lang.php
+++ b/inc/lang/he/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Guy Yakobovitch <guy.yakobovitch@gmail.com>
  * @author גיא שפר <guysoft@ort.org.il>
  * @author Denis Simakov <akinoame1@gmail.com>
  * @author Dotan Kamber <kamberd@yahoo.com>
@@ -76,7 +77,6 @@ $lang['badpassconfirm']        = 'מצטערים, הסיסמה שגויה';
 $lang['minoredit']             = 'שינוים מזעריים';
 $lang['draftdate']             = 'הטיוטה נשמרה אוטומטית ב־';
 $lang['nosecedit']             = 'הדף השתנה בינתיים, הקטע שערכת אינו מעודכן - העמוד כולו נטען במקום זאת.';
-$lang['searchcreatepage']      = 'אם לא נמצאו דפים בחיפוש, לחיצה על הכפתור "עריכה" תיצור דף חדש על שם מילת החיפוש שהוזנה.';
 $lang['regmissing']            = 'עליך למלא את כל השדות, עמך הסליחה.';
 $lang['reguexists']            = 'משתמש בשם זה כבר נרשם, עמך הסליחה.';
 $lang['regsuccess']            = 'ההרשמה הצליחה, המשתמש נרשם והודעה נשלחה בדוא״ל.';
@@ -349,5 +349,5 @@ $lang['searchresult']          = 'תוצאות חיפוש';
 $lang['plainhtml']             = 'HTML פשוט';
 $lang['page_nonexist_rev']     = 'העמוד לא קיים ב%s. העמוד נוצר במקום זאת ב<a href="%s">%s</a>.';
 $lang['unable_to_parse_date']  = 'לא ניתן לפענח פרמטר "%s".';
-$lang['email_signature_text'] = 'הודעת דוא״ל זו נוצרה על ידי ה־DokuWiki הזמין בכתובת
+$lang['email_signature_text']  = 'הודעת דוא״ל זו נוצרה על ידי ה־DokuWiki הזמין בכתובת
 @DOKUWIKIURL@';
diff --git a/inc/lang/he/searchpage.txt b/inc/lang/he/searchpage.txt
index 78839c371ba0d9fc6cf75251f98de2d7fc1d21ba..574629b172b5b12609d46ee10fdcc7dd94d39dd7 100644
--- a/inc/lang/he/searchpage.txt
+++ b/inc/lang/he/searchpage.txt
@@ -2,4 +2,3 @@
 
 ניתן לראות את תוצאות החיפוש למטה. @CREATEPAGEINFO@
 
-===== תוצאות =====
\ No newline at end of file
diff --git a/inc/lang/hr/lang.php b/inc/lang/hr/lang.php
index ce86b945784d873779d7e33711c44944289faa81..2694bd714db31230a04fc00d28537e76691ef4a3 100644
--- a/inc/lang/hr/lang.php
+++ b/inc/lang/hr/lang.php
@@ -3,11 +3,11 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Davor Turkalj <turki.bsc@gmail.com>
  * @author Tomo Krajina <aaa@puzz.info>
  * @author Branko Rihtman <theney@gmail.com>
  * @author Dražen Odobašić <dodobasic@gmail.com>
- * @author Dejan Igrec dejan.igrec@gmail.com
- * @author Davor Turkalj <turki.bsc@gmail.com>
+ * @author Dejan Igrec <dejan.igrec@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -68,7 +68,6 @@ $lang['badpassconfirm']        = 'Nažalost, lozinka nije ispravna';
 $lang['minoredit']             = 'Manje izmjene';
 $lang['draftdate']             = 'Nacrt promjena automatski spremljen u';
 $lang['nosecedit']             = 'Stranica se u međuvremenu promijenila. Informacija o odjeljku je ostarila pa je učitana kompletna stranica.';
-$lang['searchcreatepage']      = 'Ako ne možete naći što tražite, možete urediti ili stvoriti novu stranicu s odgovarajućim alatom.';
 $lang['regmissing']            = 'Morate popuniti sva polja.';
 $lang['reguexists']            = 'Korisnik s tim korisničkim imenom već postoji.';
 $lang['regsuccess']            = 'Korisnik je uspješno stvoren i poslana je lozinka emailom.';
diff --git a/inc/lang/hr/searchpage.txt b/inc/lang/hr/searchpage.txt
index 90d2ffdf4653e9634b258984aa589b0d5115c147..14c050960edb70665153ffa48ed400431734a0d6 100644
--- a/inc/lang/hr/searchpage.txt
+++ b/inc/lang/hr/searchpage.txt
@@ -2,4 +2,3 @@
 
 Možete naći rezultat vaše pretrage u nastavku. @CREATEPAGEINFO@
 
-====== Rezultati ======
diff --git a/inc/lang/hu/lang.php b/inc/lang/hu/lang.php
index cbb337488c709bdce1cadc5b25dd1ba1ed68bca3..e13c1ecd1bd44c6729596b0a6a02ebdd888c8d9b 100644
--- a/inc/lang/hu/lang.php
+++ b/inc/lang/hu/lang.php
@@ -74,7 +74,6 @@ $lang['badpassconfirm']        = 'Hibás jelszó';
 $lang['minoredit']             = 'Apróbb változások';
 $lang['draftdate']             = 'Piszkozat elmentve:';
 $lang['nosecedit']             = 'Időközben megváltozott az oldal, emiatt a szakasz nem friss. Töltsd újra az egész oldalt!';
-$lang['searchcreatepage']      = 'Ha nem találtad meg amit kerestél, akkor létrehozhatsz egy új oldalt a keresésed alapján \'\'Az oldal szerkesztése\'\' gombbal.';
 $lang['regmissing']            = 'Sajnáljuk, az összes mezőt ki kell töltened.';
 $lang['reguexists']            = 'Sajnáljuk, ilyen azonosítójú felhasználónk már van.';
 $lang['regsuccess']            = 'A felhasználói azonosítót létrehoztuk. A jelszót postáztuk.';
diff --git a/inc/lang/hu/searchpage.txt b/inc/lang/hu/searchpage.txt
index 7e186e5cbb1582077cb38269731218122783c153..6329a46d96a1591091c55d1e785bb1a716710603 100644
--- a/inc/lang/hu/searchpage.txt
+++ b/inc/lang/hu/searchpage.txt
@@ -2,4 +2,3 @@
 
 A keresés eredményét lentebb láthatod. @CREATEPAGEINFO@
 
-===== Eredmény(ek) =====
\ No newline at end of file
diff --git a/inc/lang/ia/lang.php b/inc/lang/ia/lang.php
index b40d99c48f88898fb28a668862b5887758ad7cb3..a00f8bfacce75be2ab673d32c56fd1e43f989068 100644
--- a/inc/lang/ia/lang.php
+++ b/inc/lang/ia/lang.php
@@ -63,7 +63,6 @@ $lang['badlogin']              = 'Le nomine de usator o le contrasigno es incorr
 $lang['minoredit']             = 'Modificationes minor';
 $lang['draftdate']             = 'Version provisori automaticamente salveguardate le';
 $lang['nosecedit']             = 'Le pagina ha essite modificate intertanto. Le informationes del section es ora obsolete, dunque le pagina complete ha essite cargate in su loco.';
-$lang['searchcreatepage']      = 'Si tu non ha trovate lo que tu cerca, tu pote crear o modificar le pagina nominate secundo tu consulta con le button appropriate.';
 $lang['regmissing']            = 'Es necessari completar tote le campos.';
 $lang['reguexists']            = 'Regrettabilemente, un usator con iste nomine ja existe.';
 $lang['regsuccess']            = 'Le conto ha essite create e le contrasigno ha essite inviate per e-mail.';
diff --git a/inc/lang/ia/searchpage.txt b/inc/lang/ia/searchpage.txt
index a8f7fce514c8a3b8ae1f049bf0f20e15a06de0cd..7e093d27f500327bf701b992b408ad780623ee66 100644
--- a/inc/lang/ia/searchpage.txt
+++ b/inc/lang/ia/searchpage.txt
@@ -2,4 +2,3 @@
 
 Le resultatos de tu recerca se trova hic infra. @CREATEPAGEINFO@
 
-===== Resultatos =====
\ No newline at end of file
diff --git a/inc/lang/id/lang.php b/inc/lang/id/lang.php
index fad99299c780f38bbbb46d10a4fe2b0ca379684e..dc9d66259f8b558540414b898fec87f82c393774 100644
--- a/inc/lang/id/lang.php
+++ b/inc/lang/id/lang.php
@@ -64,7 +64,6 @@ $lang['badlogin']              = 'Maaf, username atau password salah.';
 $lang['badpassconfirm']        = 'Maaf, password salah';
 $lang['minoredit']             = 'Perubahan Minor';
 $lang['draftdate']             = 'Simpan draft secara otomatis';
-$lang['searchcreatepage']      = 'Jika Anda tidak menemukan apa yang diinginkan, Anda dapat membuat halaman baru, dengan nama sesuai "text pencarian" Anda. Gunakan tombol "Edit halaman ini".';
 $lang['regmissing']            = 'Maaf, Anda harus mengisi semua field.';
 $lang['reguexists']            = 'Maaf, user dengan user login ini telah ada.';
 $lang['regsuccess']            = 'User telah didaftarkan dan password telah dikirim ke email Anda.';
diff --git a/inc/lang/id/searchpage.txt b/inc/lang/id/searchpage.txt
index b3fb56580057b838bca297d0c6896c9a91c0a68d..c03b6d729af2d1e919ac0cca72aca8f8bc7d935d 100644
--- a/inc/lang/id/searchpage.txt
+++ b/inc/lang/id/searchpage.txt
@@ -2,4 +2,3 @@
 
 Anda dapat menemukan hasil pencarian dibawah ini. @CREATEPAGEINFO@
 
-===== Hasil Pencarian =====
\ No newline at end of file
diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php
index 3792c615938971553083ea350be633007180ed0b..5d6a88c338cd24a3f910cf7b943a392db1ab4e2c 100644
--- a/inc/lang/it/lang.php
+++ b/inc/lang/it/lang.php
@@ -3,24 +3,22 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Torpedo <dgtorpedo@gmail.com>
  * @author Giorgio Vecchiocattivi <giorgio@vecchio.it>
  * @author Roberto Bolli [http://www.rbnet.it/]
  * @author Silvia Sargentoni <polinnia@tin.it>
  * @author Diego Pierotto <ita.translations@tiscali.it>
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
  * @author Matteo Carnevali <rekstorm@gmail.com>
  * @author Osman Tekin <osman.tekin93@hotmail.it>
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
  * @author Edmondo Di Tucci <snarchio@gmail.com>
  * @author Claudio Lanconelli <lancos@libero.it>
  * @author Mirko <malisan.mirko@gmail.com>
  * @author Francesco <francesco.cavalli@hotmail.com>
  * @author Fabio <fabioslurp@yahoo.it>
- * @author Torpedo <dgtorpedo@gmail.com>
  * @author Maurizio <mcannavo@katamail.com>
  * @author Riccardo <riccardofila@gmail.com>
  * @author Paolo <paolopoz12@gmail.com>
@@ -84,7 +82,6 @@ $lang['badpassconfirm']        = 'La password è errata';
 $lang['minoredit']             = 'Modifiche minori';
 $lang['draftdate']             = 'Bozza salvata in automatico il';
 $lang['nosecedit']             = 'La pagina è stata modificata nel frattempo; è impossibile modificare solo la sezione scelta, quindi è stata caricata la pagina intera.';
-$lang['searchcreatepage']      = 'Se non hai trovato quello che cercavi, puoi creare una nuova pagina con questo titolo usando il pulsante \'\'Crea questa pagina\'\'.';
 $lang['regmissing']            = 'Devi riempire tutti i campi.';
 $lang['reguexists']            = 'Il nome utente inserito esiste già.';
 $lang['regsuccess']            = 'L\'utente è stato creato. La password è stata spedita via email.';
diff --git a/inc/lang/it/searchpage.txt b/inc/lang/it/searchpage.txt
index 6f269da015e89c172a0ae7c4b2d2fd7f290b3e37..e997ebdb726315ebb49d01142624a02de45f7ce0 100644
--- a/inc/lang/it/searchpage.txt
+++ b/inc/lang/it/searchpage.txt
@@ -2,4 +2,3 @@
 
 Questi sono i risultati della ricerca. @CREATEPAGEINFO@
 
-===== Risultati =====
diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php
index 3f2101d1f8a86e86bd2d39e691215b7ac411bf7e..5f21a7e941682a79bd042faf881c192671bc9d81 100644
--- a/inc/lang/ja/lang.php
+++ b/inc/lang/ja/lang.php
@@ -72,7 +72,6 @@ $lang['badpassconfirm']        = 'パスワードが間違っています。';
 $lang['minoredit']             = '小変更';
 $lang['draftdate']             = 'ドラフト保存日時:';
 $lang['nosecedit']             = 'ページ内容が変更されていますがセクション情報が古いため、代わりにページ全体をロードしました。';
-$lang['searchcreatepage']      = 'もし、探しているものが見つからない場合、 検索キーワードにちなんだ名前の文書を作成もしくは編集を行ってください。';
 $lang['regmissing']            = '全ての項目を入力してください。';
 $lang['reguexists']            = 'このユーザー名は既に存在しています。';
 $lang['regsuccess']            = '新しいユーザーが作成されました。パスワードは登録したメールアドレス宛てに送付されます。';
diff --git a/inc/lang/ja/searchpage.txt b/inc/lang/ja/searchpage.txt
index 80b0950c6878357b2edd6d3425ce7996e5a8c1e9..3c8751a2d1e4e977e0e46c7a4bcf936dcf88bb47 100644
--- a/inc/lang/ja/searchpage.txt
+++ b/inc/lang/ja/searchpage.txt
@@ -2,4 +2,3 @@
 
 以下に検索結果を表示します。@CREATEPAGEINFO@
 
-===== 結果 =====
diff --git a/inc/lang/ka/lang.php b/inc/lang/ka/lang.php
index 72594efe3a8f10cd1a3a04d85ed986937f8a5c87..4ebb56a34619e23508803c4e2380cd54afdca4de 100644
--- a/inc/lang/ka/lang.php
+++ b/inc/lang/ka/lang.php
@@ -215,8 +215,6 @@ $lang['img_width']             = 'სიგანე:';
 $lang['img_height']            = 'სიმაღლე:';
 $lang['subscr_m_receive']      = 'მიღება';
 $lang['subscr_style_every']    = 'ფოსტა ყოველ ცვლილებაზე';
-$lang['subscr_style_digest']   = 'ფოსტა ყოველი გვერდის შეცვლაზე ';
-$lang['subscr_style_list']     = 'ფოსტა ყოველი გვერდის შეცვლაზე ';
 $lang['i_chooselang']          = 'ენსი არჩევა';
 $lang['i_installer']           = 'DokuWiki დამყენებელი';
 $lang['i_wikiname']            = 'Wiki სახელი';
diff --git a/inc/lang/kn/admin.txt b/inc/lang/kn/admin.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2897218da365c05f2fb1602e1db0bc22fbf95974
--- /dev/null
+++ b/inc/lang/kn/admin.txt
@@ -0,0 +1,2 @@
+====== ಆಡಳಿತಾತ್ಮಕ ======
+ಈ ಕೆಳಗೆ ಡಾಕುವಿಕಿ(DokuWiki)ಯಲ್ಲಿರುವ ಆಡಳಿತಾತ್ಮಕ ಕಾರ್ಯಗಳ ಪಟ್ಟಿಯನ್ನು ನೋಡಬಹುದು.
\ No newline at end of file
diff --git a/inc/lang/kn/adminplugins.txt b/inc/lang/kn/adminplugins.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b00527fbc4b17cd6d1df5c23459c103cf87b207
--- /dev/null
+++ b/inc/lang/kn/adminplugins.txt
@@ -0,0 +1 @@
+===== ಹೆಚ್ಚುವರಿ ಪ್ಲಗ್ ಇನ್ ಗಳು =====
\ No newline at end of file
diff --git a/inc/lang/kn/backlinks.txt b/inc/lang/kn/backlinks.txt
new file mode 100644
index 0000000000000000000000000000000000000000..68ef78bc792a023dcab3ff3712653ba03c2b234b
--- /dev/null
+++ b/inc/lang/kn/backlinks.txt
@@ -0,0 +1,2 @@
+====== ಹಿಂಕೊಂಡಿಗಳು ======
+ಹಾಲಿ ಪುಟಕ್ಕೆ ಹಿಂದಕ್ಕೆ ಕೊಂಡಿಯಿರಬಹುದಾದಂತಹ ಪುಟಗಳ ಪಟ್ಟಿಯಿದು.
\ No newline at end of file
diff --git a/inc/lang/kn/conflict.txt b/inc/lang/kn/conflict.txt
new file mode 100644
index 0000000000000000000000000000000000000000..880639f0666cb7aaf34786d98d40981419fc7389
--- /dev/null
+++ b/inc/lang/kn/conflict.txt
@@ -0,0 +1,4 @@
+====== ಹೊಸ ಅವತರಣಿಕೆ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ  ======
+ನೀವು ಸಂಪಾದಿಸಿದ ಕಡತದ ಇನ್ನೂ ಹೊಸ ಆವೃತ್ತಿ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ. ನೀವು ಸಂಪಾದಿಸುತ್ತಿರುವಾಗ ಬೇರೊಬ್ಬರು ಅದೇ ಕಡತವನ್ನು ಮಾರ್ಪಡಿಸಿದರೆ ಹೀಗಾಗುತ್ತದೆ.
+
+ಕೆಳಗೆ ತೋರಿಸಿರುವ ವ್ಯತ್ಯಾಸಗಳನ್ನು ಕೂಲಂಕುಶವಾಗಿ ಪರಿಶೀಲಿಸಿ, ನಂತರ ಯಾವ ಆವೃತ್ತಿಯನ್ನು ಇಟ್ಟುಕೊಳ್ಳಬೇಕೆಂದು ನಿರ್ಧರಿಸಿ. ನೀವು "ಉಳಿಸು" ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿಕೊಂಡರೆ ನಿಮ್ಮ ಆವೃತ್ತಿ ಉಳಿದುಕೊಳ್ಳುತ್ತದೆ. ನೀವು "ರದ್ದು ಮಾಡು" ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿಕೊಂಡರೆ ಹಾಲಿ ಆವೃತ್ತಿ ಉಳಿಯುತ್ತದೆ.
\ No newline at end of file
diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php
index 73b14e37222d6b91f36de7e6ff91816c3ad7d1b2..91bd8caaf580a5280cf349a1173832abd9581b73 100644
--- a/inc/lang/ko/lang.php
+++ b/inc/lang/ko/lang.php
@@ -3,18 +3,19 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Seungheon Song <esketch@gmail.com>
  * @author Hyun Kim <lawfully@gmail.com>
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
  * @author Gerrit Uitslag <klapinklapin@gmail.com>
  * @author Garam <rowain8@gmail.com>
  * @author Young gon Cha <garmede@gmail.com>
  * @author hyeonsoft <hyeonsoft@live.co.kr>
- * @author Erial <erial2@gmail.com>
+ * @author S.H. Lee <tuders@naver.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -75,7 +76,6 @@ $lang['badpassconfirm']        = '죄송하지만 비밀번호가 잘못되었
 $lang['minoredit']             = '사소한 바뀜';
 $lang['draftdate']             = '초안 자동 저장 시간';
 $lang['nosecedit']             = '한 동안 문서가 바뀌었으며, 문단 정보가 오래되어 문서 전체를 대신 열었습니다.';
-$lang['searchcreatepage']      = '만약 원하는 문서를 찾지 못했다면, \'\'문서 만들기\'\'나 \'\'문서 편집\'\'을 사용해 검색어와 같은 이름의 문서를 만들거나 편집할 수 있습니다.';
 $lang['regmissing']            = '죄송하지만 모든 필드를 채워야 합니다.';
 $lang['reguexists']            = '죄송하지만 같은 이름을 사용하는 사용자가 있습니다.';
 $lang['regsuccess']            = '사용자 계정을 만들었으며 비밀번호는 이메일로 보냈습니다.';
diff --git a/inc/lang/ko/searchpage.txt b/inc/lang/ko/searchpage.txt
index bb834277fa0cf6d6595a861ad9422c2f92d1b0d5..9a3d2f3560df6442923150f6461ad390f86ff341 100644
--- a/inc/lang/ko/searchpage.txt
+++ b/inc/lang/ko/searchpage.txt
@@ -2,4 +2,3 @@
 
 아래에서 검색 결과를 찾을 수 있습니다. @CREATEPAGEINFO@
 
-===== ê²°ê³¼ =====
\ No newline at end of file
diff --git a/inc/lang/ku/lang.php b/inc/lang/ku/lang.php
index 460b5e8a304b87102e70da37d22961dd4c002560..3bfb5e645df81c1f506985bbd0c029e73b311525 100644
--- a/inc/lang/ku/lang.php
+++ b/inc/lang/ku/lang.php
@@ -41,6 +41,5 @@ $lang['lastmod']    = 'Guherandina dawî:';
 $lang['deleted']    = 'hat jê birin';
 $lang['created']    = 'hat afirandin';
 $lang['summary']    = 'Kurteya guhartinê';
-$lang['searchcreatepage']      = "Heke tiştek nehatibe dîtin, tu dikarî dest bi nivîsandina rûpelekê nû bikî. Ji bo vê, ''Vê rûpelê biguherîne'' bitikîne.";
 
 //Setup VIM: ex: et ts=2 :
diff --git a/inc/lang/ku/searchpage.txt b/inc/lang/ku/searchpage.txt
index f762b9873c7f9422eb5871c0b4c168ec90059911..90055b1f7a52384a51b3cfebc0c09aa79f2e7dc2 100644
--- a/inc/lang/ku/searchpage.txt
+++ b/inc/lang/ku/searchpage.txt
@@ -2,4 +2,3 @@
 
 Jêr encamên lêgerandina te tên nîşan dan. @CREATEPAGEINFO@
 
-===== Encam =====
\ No newline at end of file
diff --git a/inc/lang/la/searchpage.txt b/inc/lang/la/searchpage.txt
index 75fd7cd5bcc924e1b699c623e6abce8b10cb60f6..76255d5390cb7bfda8283f70fbc0ae387106450e 100644
--- a/inc/lang/la/searchpage.txt
+++ b/inc/lang/la/searchpage.txt
@@ -2,4 +2,3 @@
 
 Responsiones in hac pagina uidere potes. @CREATEPAGEINFO@
 
-===== Responsiones =====
\ No newline at end of file
diff --git a/inc/lang/lb/lang.php b/inc/lang/lb/lang.php
index f15e878b467c1b7380f51ebb9feb8440e83f69fe..d4d0fb47feeebdad4fd60116833d4412fa704360 100644
--- a/inc/lang/lb/lang.php
+++ b/inc/lang/lb/lang.php
@@ -54,7 +54,6 @@ $lang['badlogin']              = 'Entschëllegt, de Benotzernumm oder d\'Passwue
 $lang['minoredit']             = 'Kleng Ännerungen';
 $lang['draftdate']             = 'Entworf automatesch gespäichert den';
 $lang['nosecedit']             = 'D\'Säit gouf an Zwëschenzäit g\'ännert, Sektiounsinfo veralt. Ganz Säit gouf aplaz gelueden.';
-$lang['searchcreatepage']      = 'Wanns de net fënns wats de gesicht hues kanns de eng nei Säit mam Numm vun denger Sich uleeën.';
 $lang['regmissing']            = 'Du muss all d\'Felder ausfëllen.';
 $lang['reguexists']            = 'Et get schonn e Benotzer mat deem Numm.';
 $lang['regsuccess']            = 'De Benotzer gouf erstallt an d\'Passwuert via Email geschéckt.';
diff --git a/inc/lang/lb/searchpage.txt b/inc/lang/lb/searchpage.txt
index 9f4e5475e5548a69e881aae34a0b9c49f1563d15..c2e76eb7b8499016359ed0251b92e771266e2597 100644
--- a/inc/lang/lb/searchpage.txt
+++ b/inc/lang/lb/searchpage.txt
@@ -2,4 +2,3 @@
 
 Hei ënnendrënner sinn d'Resultater vun der Sich. @CREATEPAGEINFO@
 
-=====Resultater=====
\ No newline at end of file
diff --git a/inc/lang/lt/lang.php b/inc/lang/lt/lang.php
index dcf0985ec04c9bc5abb53a6f616f6d8ae7801735..67fabef92e6f328618875b77135743175f171455 100644
--- a/inc/lang/lt/lang.php
+++ b/inc/lang/lt/lang.php
@@ -61,7 +61,6 @@ $lang['badlogin']              = 'NurodÄ—te blogÄ… vartotojo vardÄ… arba slapta
 $lang['minoredit']             = 'Nedidelis pataisymas';
 $lang['draftdate']             = 'Juodraštis automatiškai išsaugotas';
 $lang['nosecedit']             = 'Puslapis buvo kažkieno pataisytas, teksto dalies informacija tapo pasenusi, todėl pakrautas visas puslapis.';
-$lang['searchcreatepage']      = 'Jeigu neradote to, ko ieškojote, galite sukurti naują puslapį šiuo pavadinimu paspausdami "Redaguoti šį puslapį".';
 $lang['regmissing']            = 'Turite užpildyti visus laukus.';
 $lang['reguexists']            = 'Vartotojas su pasirinktu prisijungimo vardu jau egzistuoja.';
 $lang['regsuccess']            = 'Vartotojas sukurtas, slaptažodis išsiųstas el. paštu.';
diff --git a/inc/lang/lt/searchpage.txt b/inc/lang/lt/searchpage.txt
index f03f5f17b290d87e21cccd0b925ae6bb6f073825..111029d042919e660f2fd1660d46805c326977c8 100644
--- a/inc/lang/lt/searchpage.txt
+++ b/inc/lang/lt/searchpage.txt
@@ -2,4 +2,3 @@
 
 Žemiau matote Jūsų atliktos paieškos rezultatus. @CREATEPAGEINFO@
 
-===== Rezultatai =====
\ No newline at end of file
diff --git a/inc/lang/lv/lang.php b/inc/lang/lv/lang.php
index 88f8e5f94348f4b3c2485644b06fb635cac91963..1a101ad8b2b3ab85c9c43fba4b07b4a4963e3a0b 100644
--- a/inc/lang/lv/lang.php
+++ b/inc/lang/lv/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Oskars Pakers <oskars.pakers@gmail.com>
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
@@ -64,11 +65,11 @@ $lang['badpassconfirm']        = 'Atvaino, aplama parole';
 $lang['minoredit']             = 'Sīki labojumi';
 $lang['draftdate']             = 'Melnraksts automātiski saglabāts';
 $lang['nosecedit']             = 'Lapa pa šo laiku ir mainījusies, sekcijas informācija novecojusi. Ielādēta lapas  pilnās versija.';
-$lang['searchcreatepage']      = 'Ja neatradi meklēto, nospiežot pogu "Labot lapu", vari izveidot jaunu lapu ar tevis meklētajiem atslēgvārdiem nosaukumā.';
 $lang['regmissing']            = 'Atvaino, jāaizpilda visas ailes.';
 $lang['reguexists']            = 'Atvaino, tāds lietotājs jau ir.';
 $lang['regsuccess']            = 'Lietotājs izveidots. Parole nosūtīta pa pastu.';
 $lang['regsuccess2']           = 'Lietotājs izveidots.';
+$lang['regfail']               = 'Neizdevās izveidot lietotāju.';
 $lang['regmailfail']           = 'Šķiet, ka ir problēmas nosūtīt pastu. Lūdzu sazinies ar administratoru!';
 $lang['regbadmail']            = 'Uzdotā epasta adrese izskatās aplama. Ja tas nav tiesa, sazinies ar administratoru.';
 $lang['regbadpass']            = 'Abas ierakstītās paroles nav vienādas, lūdzu atkārto.';
@@ -83,6 +84,7 @@ $lang['profdeleteuser']        = 'Dzēst kontu';
 $lang['profdeleted']           = 'Jūsu lietotāja konts ir izdzēsts';
 $lang['profconfdelete']        = 'Es vēlos dzēst savu kontu no viki. <br/> Šo darbību vairs nevarēs atsaukt.';
 $lang['profconfdeletemissing'] = 'Nav atzīmēta apstiprinājuma rūtiņa.';
+$lang['proffail']              = 'Neizdevās atjaunot profilu.';
 $lang['pwdforget']             = 'Aizmirsi paroli? Saņem jaunu';
 $lang['resendna']              = 'Paroļu izsūtīšanu nepiedāvāju.';
 $lang['resendpwd']             = 'Uzstādīt jaunu paroli lietotājam';
@@ -333,5 +335,5 @@ $lang['currentns']             = 'Pašreizējā sadaļa';
 $lang['searchresult']          = 'Meklēšanas rezultāti';
 $lang['plainhtml']             = 'Tīrs HTML';
 $lang['wikimarkup']            = 'Viki iezīmēšana valoda';
-$lang['email_signature_text'] = 'Vēstuli nosūtījusi DokuWiki programma no
+$lang['email_signature_text']  = 'Vēstuli nosūtījusi DokuWiki programma no
 @DOKUWIKIURL@';
diff --git a/inc/lang/lv/searchpage.txt b/inc/lang/lv/searchpage.txt
index a67f9f166a5627671519a9db03097b01fb3259d6..a4b5aae35fde8331659abbf55cd266c150ade575 100644
--- a/inc/lang/lv/searchpage.txt
+++ b/inc/lang/lv/searchpage.txt
@@ -2,4 +2,3 @@
 
 Te vari redzēt meklēšanas rezultātus. @CREATEPAGEINFO@
 
-===== Atrasts =====
diff --git a/inc/lang/mg/lang.php b/inc/lang/mg/lang.php
index 240133f29e60de42fd3b0189c873690a9285f2f3..aea3942364d779373a116575b4f4ec32ba2c6670 100644
--- a/inc/lang/mg/lang.php
+++ b/inc/lang/mg/lang.php
@@ -114,7 +114,6 @@ $lang['qb_sig']     = 'Manisy sonia';
 
 $lang['js']['del_confirm']= 'Hofafana ilay andalana?';
 
-$lang['searchcreatepage']      = "Raha tsy nahita izay notadiavinao ianao, dia afaka mamorona pejy vaovao avy amin'ny teny nanaovanao fikarohana; Ampiasao ny bokotra ''Hanova ny pejy''.";
 //Setup VIM: ex: et ts=2 :
 $lang['email_signature_text'] = 'Ity imailaka ity dia navoakan\'ny wiki tao amin\'ny
 @DOKUWIKIURL@';
diff --git a/inc/lang/mg/searchpage.txt b/inc/lang/mg/searchpage.txt
index ef3ed8b19139476703b1853ecf9fabb9d1b0fa58..43fc402d40ea20c8a969e9608b83ecdc698f3973 100644
--- a/inc/lang/mg/searchpage.txt
+++ b/inc/lang/mg/searchpage.txt
@@ -1,7 +1,4 @@
 ====== Karoka ======
 
-Ireto ambany ireto ny valin'ny fikarohanao.
+Ireto ambany ireto ny valin'ny fikarohanao.  @CREATEPAGEINFO@
 
-@CREATEPAGEINFO@
-
-===== Vokatry ny fikarohana =====
\ No newline at end of file
diff --git a/inc/lang/mr/lang.php b/inc/lang/mr/lang.php
index 4b6d1bd69e912de8c89a9894b96fb094e90ffe04..5aa22f30f3466146c66d463824f26b0a84e0f8ed 100644
--- a/inc/lang/mr/lang.php
+++ b/inc/lang/mr/lang.php
@@ -67,7 +67,6 @@ $lang['badlogin']              = 'माफ़ करा, वापरकर्
 $lang['minoredit']             = 'छोटे बदल';
 $lang['draftdate']             = 'प्रत आपोआप सुरक्षित केल्याची तारीख';
 $lang['nosecedit']             = 'मध्यंतरीच्या काळात हे पृष्ठ बदलले आहे.विभागाची माहिती जुनी झाली होती. त्याऐवजी सबंध पृष्ठ परत लोड केले आहे.';
-$lang['searchcreatepage']      = 'जर तुमची शोधत असलेली गोष्ट तुम्हाला सापडली नाही, तर योग्य बटण वापरून तुम्ही शोधत असलेल्या गोष्टीविषयी तुम्ही एखादे पान निर्माण किंवा संपादित करू शकता.';
 $lang['regmissing']            = 'कृपया सर्व रकाने भरा.';
 $lang['reguexists']            = 'या नावाने सदस्याची नोंदणी झालेली आहे, कृपया दुसरे सदस्य नाव निवडा.';
 $lang['regsuccess']            = 'सदस्याची नोंदणी झाली आहे आणि परवलीचा शब्द इमेल केला आहे.';
diff --git a/inc/lang/mr/searchpage.txt b/inc/lang/mr/searchpage.txt
index d41954b4a632c6bc8e3237f06b7afbf3fd820952..707e69939ccbfaf5543b2adfedf77778f03a4ebe 100644
--- a/inc/lang/mr/searchpage.txt
+++ b/inc/lang/mr/searchpage.txt
@@ -2,4 +2,3 @@
 
 तुम्हाला खाली तुमच्या शोधाचे फलित दिसतील. @CREATEPAGEINFO@
 
-====== फलित ======
\ No newline at end of file
diff --git a/inc/lang/ne/lang.php b/inc/lang/ne/lang.php
index fae403f234a9b47ba936f91f6160833ccbd778c7..c0daf29b590f12cab65a4972aac93fc21a8d69c3 100644
--- a/inc/lang/ne/lang.php
+++ b/inc/lang/ne/lang.php
@@ -66,7 +66,6 @@ $lang['badpassconfirm']        = 'माफ गर्नुहोस् , पा
 $lang['minoredit']             = 'सामान्य परिवर्तन';
 $lang['draftdate']             = 'ड्राफ्ट स्वचालित रुपमा वचत भएको';
 $lang['nosecedit']             = 'यो पृष्ठ यसै बखतमा परिवर्तन भयो, खण्ड जानकारी अध्यावधिक हुन सकेन र पूरै पृष्ठ लोड भयो । ';
-$lang['searchcreatepage']      = 'यदि तपाईले आफुले खोजेको पाउनुभएन भने, तपाईलेको उपयुक्त बटन प्रयोग गरी खोज सँग सम्बन्धित शिर्षकहरु भएका पृष्ठ सृजना या सम्पादन गर्न सक्नुहुन्छ ।';
 $lang['regmissing']            = 'माफ गर्नुहोला , सबै ठाउमा भर्नुपर्नेछ ।';
 $lang['reguexists']            = 'यो नामको प्रयोगकर्ता पहिले देखि रहेको छ।';
 $lang['regsuccess']            = 'यो प्रयोगकर्ता बनाइएको छ र प्रवेशशव्द इमेलमा पठइएको छ।';
diff --git a/inc/lang/ne/searchpage.txt b/inc/lang/ne/searchpage.txt
index 021306b4b83c5fa856241dfba673087ce3726d69..02219e72bdcbe83f268b5e85d7904a49a562c74b 100644
--- a/inc/lang/ne/searchpage.txt
+++ b/inc/lang/ne/searchpage.txt
@@ -2,4 +2,3 @@
 
 तपाईले आफ्नो खोजको निम्न नतिजा  पाउन सक्नुहुन्छ। @CREATEPAGEINFO@
 
-===== नतिजा =====
\ No newline at end of file
diff --git a/inc/lang/nl/lang.php b/inc/lang/nl/lang.php
index 76c99bc061c8be22d8962f1b64799c7ca2b4a513..41fa169779e5674a97cf1e32dc4471d79dc925fa 100644
--- a/inc/lang/nl/lang.php
+++ b/inc/lang/nl/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author mark prins <mprins@users.sf.net>
  * @author François Kooman <fkooman.tuxed.net>
  * @author Jack van Klaren <dokuwiki@afentoe.xs4all.nl>
  * @author Riny Heijdendael <riny@heijdendael.nl>
@@ -17,9 +18,6 @@
  * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit <klapinklapin@gmail.com>
- * @author mprins <mprins@users.sf.net>
- * @author Gerrit Uitslag <klapinklapin@gmail.com>
- * @author Klap-in <klapinklapin@gmail.com>
  * @author Remon <no@email.local>
  * @author gicalle <gicalle@hotmail.com>
  * @author Rene <wllywlnt@yahoo.com>
@@ -27,11 +25,9 @@
  * @author Mijndert <mijndert@mijndertstuij.nl>
  * @author Johan Wijnker <johan@wijnker.eu>
  * @author Hugo Smet <hugo.smet@scarlet.be>
- * @author Mark C. Prins <mprins@users.sf.net>
  * @author Wesley de Weerd <wesleytiel@gmail.com>
  * @author Sjoerd <sjoerd@sjomar.eu>
  * @author Joachim David <joa_david@hotmail.com>
- * @author mark prins <mprins@users.sf.net>
  * @author stafmans <dokuwiki@stafmans.net>
  */
 $lang['encoding']              = 'utf-8';
@@ -93,7 +89,6 @@ $lang['badpassconfirm']        = 'Sorry, het wachtwoord was onjuist';
 $lang['minoredit']             = 'Kleine wijziging';
 $lang['draftdate']             = 'Concept automatisch opgeslagen op';
 $lang['nosecedit']             = 'De pagina is tussentijds veranderd, sectie-informatie was verouderd, volledige pagina geladen.';
-$lang['searchcreatepage']      = 'Niks gevonden? Maak een nieuwe pagina met als naam je zoekopdracht. Klik hiervoor op \'\'Maak deze pagina aan\'\'.';
 $lang['regmissing']            = 'Vul alle velden in';
 $lang['reguexists']            = 'Er bestaat al een gebruiker met deze loginnaam.';
 $lang['regsuccess']            = 'De gebruiker is aangemaakt. Het wachtwoord is per e-mail verzonden.';
diff --git a/inc/lang/nl/searchpage.txt b/inc/lang/nl/searchpage.txt
index e03679b2b75ded7d597e2fc887ae69d49cb19e3b..b9d1236554c47fe0f316d0346c4226764d818f85 100644
--- a/inc/lang/nl/searchpage.txt
+++ b/inc/lang/nl/searchpage.txt
@@ -2,4 +2,3 @@
 
 Hieronder zijn de resultaten van de zoekopdracht. @CREATEPAGEINFO@
 
-===== Resultaten =====
diff --git a/inc/lang/no/lang.php b/inc/lang/no/lang.php
index bc946366df5cb1366523a811ba2abc536e29e19f..b8d3d3b1626b45be148515ff64ee0b9ce8ab7b26 100644
--- a/inc/lang/no/lang.php
+++ b/inc/lang/no/lang.php
@@ -86,7 +86,6 @@ $lang['badpassconfirm']        = 'Beklager, passordet var feil';
 $lang['minoredit']             = 'Mindre endringer';
 $lang['draftdate']             = 'Kladd autolagret';
 $lang['nosecedit']             = 'Siden er i mellomtiden endret, seksjonsinfo har blitt foreldet - lastet full side istedet.';
-$lang['searchcreatepage']      = 'Hvis du ikke finner det du leter etter, så kan du skape en ny side med samme navn som ditt søk ved å klikke på \'\'**Lag denne siden**\'\'-knappen.';
 $lang['regmissing']            = 'Vennligst fyll ut alle felt.';
 $lang['reguexists']            = 'Det finnes allerede en konto med dette brukernavnet.';
 $lang['regsuccess']            = 'Brukerkonto har blitt laget og passord har blitt sendt via e-post.';
diff --git a/inc/lang/no/searchpage.txt b/inc/lang/no/searchpage.txt
index 2e7b0d887a62cf92696df7f3c5309050d3abb73f..b8d9f01697e2aa45a97f4c353755148270d7402f 100644
--- a/inc/lang/no/searchpage.txt
+++ b/inc/lang/no/searchpage.txt
@@ -2,4 +2,3 @@
 
 Du ser resultatet av dette søket nedenfor. @CREATEPAGEINFO@
 
-===== Resultat =====
diff --git a/inc/lang/pl/lang.php b/inc/lang/pl/lang.php
index 6d96b1dc0a33f91c4465896a268d6068cab88ac8..f8e3fe83b07a5f55d505a0f7a61de2b0ac8373ae 100644
--- a/inc/lang/pl/lang.php
+++ b/inc/lang/pl/lang.php
@@ -3,11 +3,13 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Grzegorz Żur <grzegorz.zur@gmail.com>
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
@@ -79,7 +81,6 @@ $lang['badpassconfirm']        = 'Niestety, hasło jest niepoprawne.';
 $lang['minoredit']             = 'Mniejsze zmiany';
 $lang['draftdate']             = 'Czas zachowania szkicu';
 $lang['nosecedit']             = 'Strona została zmodyfikowana, sekcje zostały zmienione. Załadowano całą stronę.';
-$lang['searchcreatepage']      = 'Jeśli nie znaleziono szukanego hasła, możesz utworzyć nową stronę, której tytułem będzie poszukiwane hasło.';
 $lang['regmissing']            = 'Wypełnij wszystkie pola.';
 $lang['reguexists']            = 'Użytkownik o tej nazwie już istnieje.';
 $lang['regsuccess']            = 'Utworzono użytkownika. Hasło zostało przesłane pocztą.';
@@ -200,6 +201,8 @@ $lang['diff_side']             = 'Jeden obok drugiego';
 $lang['diffprevrev']           = 'Poprzednia wersja';
 $lang['diffnextrev']           = 'Nowa wersja';
 $lang['difflastrev']           = 'Ostatnia wersja';
+$lang['diffbothprevrev']       = 'Poprzednia rewizja po obu stronach';
+$lang['diffbothnextrev']       = 'Następna rewizja po obu stronach';
 $lang['line']                  = 'Linia';
 $lang['breadcrumb']            = 'Åšlad:';
 $lang['youarehere']            = 'JesteÅ› tutaj:';
@@ -349,5 +352,7 @@ $lang['currentns']             = 'Obecny katalog';
 $lang['searchresult']          = 'Wyniki wyszukiwania';
 $lang['plainhtml']             = 'Czysty HTML';
 $lang['wikimarkup']            = 'Znaczniki';
+$lang['page_nonexist_rev']     = 'Strona nie istnieje w %s. Została następnie utworzony w <a href="%s">%s</a>.';
+$lang['unable_to_parse_date']  = 'Nie można przeanalizować parametru "%s".';
 $lang['email_signature_text']  = 'List został wygenerowany przez DokuWiki pod adresem
 @DOKUWIKIURL@';
diff --git a/inc/lang/pl/searchpage.txt b/inc/lang/pl/searchpage.txt
index 442975fe10e06dd04198d314cb2d42b4f4ae1894..70e1de6497d0917009b89348e0444e0f2b9e1ac0 100644
--- a/inc/lang/pl/searchpage.txt
+++ b/inc/lang/pl/searchpage.txt
@@ -2,4 +2,3 @@
 
 Wyniki wyszukiwania. @CREATEPAGEINFO@
 
-===== Wyniki =====
diff --git a/inc/lang/pt-br/lang.php b/inc/lang/pt-br/lang.php
index 1074914cc7289249996811acde322474b140597e..f671f9c689143f294aae581899eaff128b14123c 100644
--- a/inc/lang/pt-br/lang.php
+++ b/inc/lang/pt-br/lang.php
@@ -3,21 +3,18 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Frederico Gonçalves Guimarães <frederico@teia.bio.br>
  * @author Luis Fernando Enciso <lfenciso@certto.com.br>
  * @author Alauton/Loug
- * @author Frederico Gonçalves Guimarães <frederico@teia.bio.br>
  * @author Felipe Castro <fefcas@gmail.com>
  * @author Lucien Raven <lucienraven@yahoo.com.br>
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Jair Henrique <jair.henrique@gmail.com>
  * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
- * @author Frederico Guimarães <frederico@teia.bio.br>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
  * @author Leone Lisboa Magevski <leone1983@gmail.com>
@@ -87,7 +84,6 @@ $lang['badpassconfirm']        = 'Desculpe, mas a senha está errada ';
 $lang['minoredit']             = 'Alterações mínimas';
 $lang['draftdate']             = 'O rascunho foi salvo automaticamente em';
 $lang['nosecedit']             = 'A página foi modificada nesse intervalo de tempo. Como a informação da seção estava desatualizada, foi carregada a página inteira.';
-$lang['searchcreatepage']      = 'Se você não encontrou o que está procurando, pode criar ou editar a página com o nome que você especificou, usando o botão apropriado.';
 $lang['regmissing']            = 'Desculpe, mas você precisa preencher todos os campos.';
 $lang['reguexists']            = 'Desculpe, mas já existe um usuário com esse nome.';
 $lang['regsuccess']            = 'O usuário foi criado e a senha enviada para seu e-mail.';
diff --git a/inc/lang/pt-br/searchpage.txt b/inc/lang/pt-br/searchpage.txt
index 636bfeb7aef96b79031def5d209b9293a5d9aabf..2e8dd59aa326ee71fcacc359d9700c3acd77e01c 100644
--- a/inc/lang/pt-br/searchpage.txt
+++ b/inc/lang/pt-br/searchpage.txt
@@ -2,4 +2,3 @@
 
 Você pode encontrar os resultados da sua pesquisa abaixo. @CREATEPAGEINFO@
 
-===== Resultados =====
diff --git a/inc/lang/pt/lang.php b/inc/lang/pt/lang.php
index 890a6fd572152bcdc9f6134d0c030ebb796a9a54..64c25fa9f0ee8dc54df9f500727d252491c391c8 100644
--- a/inc/lang/pt/lang.php
+++ b/inc/lang/pt/lang.php
@@ -15,6 +15,7 @@
  * @author Romulo Pereira <romuloccomp@gmail.com>
  * @author Paulo Carmino <contato@paulocarmino.com>
  * @author Alfredo Silva <alfredo.silva@sky.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -75,7 +76,6 @@ $lang['badpassconfirm']        = 'Infelizmente a palavra-passe não é a correct
 $lang['minoredit']             = 'Alterações Menores';
 $lang['draftdate']             = 'Rascunho automaticamente gravado em';
 $lang['nosecedit']             = 'A página foi modificada entretanto. Como a informação da secção estava desactualizada, foi carregada a página inteira.';
-$lang['searchcreatepage']      = 'Se não encontrou o que procurava pode criar uma nova página com o nome da sua pesquisa, usando o botão apropriado.';
 $lang['regmissing']            = 'Por favor, preencha todos os campos.';
 $lang['reguexists']            = 'Este utilizador já está inscrito. Por favor escolha outro nome de utilizador.';
 $lang['regsuccess']            = 'O utilizador foi criado e a senha foi enviada para o endereço de correio electrónico usado na inscrição.';
@@ -346,5 +346,5 @@ $lang['plainhtml']             = 'HTML simples';
 $lang['wikimarkup']            = 'Markup de Wiki';
 $lang['page_nonexist_rev']     = 'Página não existia no %s. Posteriormente, foi criado em <a href="%s">%s</a>.';
 $lang['unable_to_parse_date']  = 'Não é possível analisar o parâmetro "%s".';
-$lang['email_signature_text'] = 'Este email foi gerado por DokuWiki em
+$lang['email_signature_text']  = 'Este email foi gerado por DokuWiki em
 @DOKUWIKIURL@';
diff --git a/inc/lang/pt/searchpage.txt b/inc/lang/pt/searchpage.txt
index 563ce28343796e8c3781c06f817c765542d9ed00..27a6baafdea3bb10d19e1166b8c08b792da75ea0 100644
--- a/inc/lang/pt/searchpage.txt
+++ b/inc/lang/pt/searchpage.txt
@@ -2,4 +2,3 @@
 
 Pode encontrar os resultados da sua pesquisa abaixo. @CREATEPAGEINFO@
 
-===== Resultados =====
diff --git a/inc/lang/ro/lang.php b/inc/lang/ro/lang.php
index 721785ae4f4a69a61f08703ed2f87f5d6ee559c6..69d04abba2e89307b0c990d8814c6cf817c7a5be 100644
--- a/inc/lang/ro/lang.php
+++ b/inc/lang/ro/lang.php
@@ -72,7 +72,6 @@ $lang['badpassconfirm']        = 'Ne pare rau, parola este gresita';
 $lang['minoredit']             = 'Modificare minoră';
 $lang['draftdate']             = 'Schiță salvată automat la';
 $lang['nosecedit']             = 'Pagina s-a modificat între timp, secțiunea info a expirat, s-a încărcat pagina întreagă în loc.';
-$lang['searchcreatepage']      = 'Dacă nu ai găsit ce ai căutat, poți crea o pagină nouă prin folosirea butonului \'\'Editează această pagină\'\'.';
 $lang['regmissing']            = 'Ne pare rău, trebuie să completezi toate cîmpurile.';
 $lang['reguexists']            = 'Ne pare rău, un utilizator cu acest nume este deja autentificat.';
 $lang['regsuccess']            = 'Utilizatorul a fost creat. Parola a fost trimisă prin e-mail.';
@@ -107,7 +106,7 @@ $lang['searchmedia_in']        = 'Caută în %s';
 $lang['txt_upload']            = 'Selectează fișierul de încărcat:';
 $lang['txt_filename']          = 'Încarcă fișierul ca (opțional):';
 $lang['txt_overwrt']           = 'Suprascrie fișierul existent';
-$lang['maxuploadsize']         = 'Incarcare maxima % per fisier.';
+$lang['maxuploadsize']         = 'Incarcare maxima %s per fisier.';
 $lang['lockedby']              = 'Momentan blocat de:';
 $lang['lockexpire']            = 'Blocarea expiră la:';
 $lang['js']['willexpire']      = 'Blocarea pentru editarea paginii expiră intr-un minut.\nPentru a preveni conflictele folosește butonul de previzualizare pentru resetarea blocării.';
diff --git a/inc/lang/ro/searchpage.txt b/inc/lang/ro/searchpage.txt
index d4e3df2ee7a1001458367ec8820bc5d7fceb2469..5b262fe03c0a129259405b2432769f1645f47bc6 100644
--- a/inc/lang/ro/searchpage.txt
+++ b/inc/lang/ro/searchpage.txt
@@ -2,4 +2,3 @@
 
 Rezultatele căutării sunt afișate mai jos. @CREATEPAGEINFO@
 
-===== Rezultate =====
diff --git a/inc/lang/ru/editrev.txt b/inc/lang/ru/editrev.txt
index ac2464db9e9e70a5ad5a2a7f2ab5f43fb2464b58..d46f07bc8c1f66e17d676cfff4bc90451771f55e 100644
--- a/inc/lang/ru/editrev.txt
+++ b/inc/lang/ru/editrev.txt
@@ -1,2 +1,2 @@
-**Вы загрузили старую ревизию документа.** Сохранив её, вы создадите новую текущую версию с этим содержимым.
+**Вы загрузили старую ревизию документа!** Сохранив её, вы создадите новую текущую версию с этим содержимым.
 ----
diff --git a/inc/lang/ru/lang.php b/inc/lang/ru/lang.php
index fec19c859ff1de9aa3652f0ed42441da959ec0ee..4712b4c6f51d7864f6939cf8fb4dc883744b1aed 100644
--- a/inc/lang/ru/lang.php
+++ b/inc/lang/ru/lang.php
@@ -3,6 +3,9 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
+ * @author Zhassulan <zyesmukanov@gmail.com>
+ * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Yuri Pimenov <up@ftpsearch.lv>
  * @author Igor Tarasov <tigr@mail15.com>
  * @author Denis Simakov <akinoame1@gmail.com>
@@ -16,7 +19,6 @@
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
  * @author Aleksey Osadchiy <rfc@nm.ru>
- * @author Aleksandr Selivanov <alexgearbox@gmail.com>
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
@@ -24,7 +26,6 @@
  * @author Pavel <ivanovtsk@mail.ru>
  * @author Artur <ncuxxx@gmail.com>
  * @author Erli Moen <evseev.jr@gmail.com>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Владимир <id37736@yandex.ru>
  * @author Igor Degraf <igordegraf@gmail.com>
  * @author Type-kun <workwork-1@yandex.ru>
@@ -93,25 +94,24 @@ $lang['email']                 = 'Эл. адрес';
 $lang['profile']               = 'Профиль пользователя';
 $lang['badlogin']              = 'Извините, неверное имя пользователя или пароль.';
 $lang['badpassconfirm']        = 'Простите, пароль неверный';
-$lang['minoredit']             = 'Небольшие изменения';
+$lang['minoredit']             = 'Незначительные изменения';
 $lang['draftdate']             = 'Черновик сохранён';
 $lang['nosecedit']             = 'За это время страница была изменена и информация о секции устарела. Загружена полная версия страницы.';
-$lang['searchcreatepage']      = 'Если вы не нашли то, что искали, вы можете создать новую страницу с именем, совпадающим с запросом. Чтобы сделать это, просто нажмите на кнопку «Создать страницу».';
 $lang['regmissing']            = 'Извините, вам следует заполнить все поля.';
 $lang['reguexists']            = 'Извините, пользователь с таким логином уже существует.';
 $lang['regsuccess']            = 'Пользователь создан; пароль выслан на адрес электронной почты.';
 $lang['regsuccess2']           = 'Пользователь создан.';
 $lang['regfail']               = 'Пользователь не может быть создан.';
-$lang['regmailfail']           = 'Похоже есть проблема с отправкой пароля по почте. Пожалуйста, сообщите об этом администратору.';
+$lang['regmailfail']           = 'Похоже есть проблема с отправкой пароля по почте. Пожалуйста, сообщите об этом администратору!';
 $lang['regbadmail']            = 'Данный вами адрес электронной почты выглядит неправильным. Если вы считаете это ошибкой, сообщите администратору.';
-$lang['regbadpass']            = 'Два введённых пароля не идентичны. Пожалуйста, попробуйте ещё раз.';
+$lang['regbadpass']            = 'Два введённых пароля не совпадают. Пожалуйста, попробуйте ещё раз.';
 $lang['regpwmail']             = 'Ваш пароль для системы «Докувики»';
 $lang['reghere']               = 'У вас ещё нет аккаунта? Зарегистрируйтесь';
 $lang['profna']                = 'Данная вики не поддерживает изменение профиля';
 $lang['profnochange']          = 'Изменений не было внесено, профиль не обновлён.';
 $lang['profnoempty']           = 'Логин и адрес электронной почты не могут быть пустыми.';
 $lang['profchanged']           = 'Профиль пользователя успешно обновлён.';
-$lang['profnodelete']          = 'Удалённый пользователь не может работать с этим документом';
+$lang['profnodelete']          = 'Данная вики не поддерживает удаление пользователей.';
 $lang['profdeleteuser']        = 'Удалить аккаунт';
 $lang['profdeleted']           = 'Ваш аккаунт был удалён из этой вики';
 $lang['profconfdelete']        = 'Я хочу удалить свой аккаунт из этой вики. <br />
@@ -126,14 +126,14 @@ $lang['resendpwdnouser']       = 'Пользователь с таким лог
 $lang['resendpwdbadauth']      = 'Извините, неверный код авторизации. Убедитесь, что вы полностью скопировали ссылку.';
 $lang['resendpwdconfirm']      = 'Ссылка для подтверждения пароля была выслана по электронной почте.';
 $lang['resendpwdsuccess']      = 'Ваш новый пароль был выслан по электронной почте.';
-$lang['license']               = 'За исключением случаев, когда указано иное, содержимое этой вики предоставляется на условиях следующей лицензии:';
+$lang['license']               = 'Если не указано иное, содержимое этой вики предоставляется на условиях следующей лицензии:';
 $lang['licenseok']             = 'Примечание: редактируя эту страницу, вы соглашаетесь на использование своего вклада на условиях следующей лицензии:';
-$lang['searchmedia']           = 'Поиск по имени файла';
+$lang['searchmedia']           = 'Поиск по имени файла:';
 $lang['searchmedia_in']        = 'Поиск в %s';
 $lang['txt_upload']            = 'Выберите файл для загрузки:';
 $lang['txt_filename']          = 'Введите имя файла в вики (необязательно):';
 $lang['txt_overwrt']           = 'Перезаписать существующий файл';
-$lang['maxuploadsize']         = 'Макс. размер загружаемого файла %s';
+$lang['maxuploadsize']         = 'Макс. размер загружаемого файла %s.';
 $lang['lockedby']              = 'В данный момент заблокировано пользователем';
 $lang['lockexpire']            = 'Блокировка истекает в';
 $lang['js']['willexpire']      = 'Ваша блокировка этой страницы на редактирование истекает в течение минуты.\nЧтобы предотвратить конфликты используйте кнопку «Просмотр» для сброса таймера блокировки.';
@@ -143,8 +143,7 @@ $lang['js']['keepopen']        = 'Не закрывать окно после в
 $lang['js']['hidedetails']     = 'Скрыть детали';
 $lang['js']['mediatitle']      = 'Настройка ссылки';
 $lang['js']['mediadisplay']    = 'Тип ссылки';
-$lang['js']['mediaalign']      = 'Выравнивание
-';
+$lang['js']['mediaalign']      = 'Выравнивание';
 $lang['js']['mediasize']       = 'Размер';
 $lang['js']['mediatarget']     = 'Целевая ссылка';
 $lang['js']['mediaclose']      = 'Закрыть';
@@ -171,27 +170,27 @@ $lang['js']['restore_confirm'] = 'Действительно восстанов
 $lang['js']['media_diff']      = 'Просмотр отличий:';
 $lang['js']['media_diff_both'] = 'рядом';
 $lang['js']['media_diff_opacity'] = 'наложением';
-$lang['js']['media_diff_portions'] = 'Частями';
+$lang['js']['media_diff_portions'] = 'частями';
 $lang['js']['media_select']    = 'Выбрать файлы…';
 $lang['js']['media_upload_btn'] = 'Загрузить';
 $lang['js']['media_done_btn']  = 'Готово';
 $lang['js']['media_drop']      = 'Переместите файлы сюда для загрузки';
-$lang['js']['media_cancel']    = 'отменить';
+$lang['js']['media_cancel']    = 'убрать';
 $lang['js']['media_overwrt']   = 'Перезаписать существующие файлы';
 $lang['rssfailed']             = 'Произошла ошибка при получении следующей новостной ленты: ';
 $lang['nothingfound']          = 'Ничего не найдено.';
 $lang['mediaselect']           = 'Выбор медиафайла';
 $lang['uploadsucc']            = 'Загрузка произведена успешно';
 $lang['uploadfail']            = 'Загрузка не удалась. Возможно, проблемы с правами доступа?';
-$lang['uploadwrong']           = 'В загрузке отказано. Файлы с таким расширением запрещены. ';
+$lang['uploadwrong']           = 'В загрузке отказано. Файлы с таким расширением запрещены!';
 $lang['uploadexist']           = 'Файл с таким именем существует. Загрузка не произведена.';
 $lang['uploadbadcontent']      = 'Содержание файла не соответствует расширению %s.';
 $lang['uploadspam']            = 'Загрузка заблокирована спам-фильтром.';
 $lang['uploadxss']             = 'Загрузка заблокирована по соображениям безопасности.';
-$lang['uploadsize']            = 'Загруженный файл был слишком большой. (Макс. %s)';
-$lang['deletesucc']            = 'Файл %s был удалён.';
-$lang['deletefail']            = 'Невозможно удалить файл %s. Проверьте права доступа к файлу.';
-$lang['mediainuse']            = 'Файл %s не был удалён — файл всё ещё используется.';
+$lang['uploadsize']            = 'Загруженный файл был слишком большой (макс. %s).';
+$lang['deletesucc']            = 'Файл "%s" был удалён.';
+$lang['deletefail']            = 'Невозможно удалить файл "%s" — проверьте права доступа к нему.';
+$lang['mediainuse']            = 'Файл "%s" не был удалён — он всё ещё используется.';
 $lang['namespaces']            = 'Пространства имён';
 $lang['mediafiles']            = 'Доступные файлы';
 $lang['accessdenied']          = 'Вы не можете просмотреть эту страницу.';
@@ -209,7 +208,7 @@ $lang['toc']                   = 'Содержание';
 $lang['current']               = 'текущий';
 $lang['yours']                 = 'Ваша версия';
 $lang['diff']                  = 'Показать отличия от текущей версии';
-$lang['diff2']                 = 'Показать различия между ревизиями  ';
+$lang['diff2']                 = 'Показать различия между выбранными версиями';
 $lang['difflink']              = 'Ссылка на это сравнение';
 $lang['diff_type']             = 'Посмотреть различия';
 $lang['diff_inline']           = 'внутри текста';
@@ -230,7 +229,7 @@ $lang['restored']              = 'старая версия восстановл
 $lang['external_edit']         = 'внешнее изменение';
 $lang['summary']               = 'Сводка изменений';
 $lang['noflash']               = 'Для просмотра этого содержимого требуется <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
-$lang['download']              = 'Скачать код';
+$lang['download']              = 'Скачать фрагмент кода';
 $lang['tools']                 = 'Инструменты';
 $lang['user_tools']            = 'Инструменты пользователя';
 $lang['site_tools']            = 'Инструменты сайта';
@@ -263,7 +262,7 @@ $lang['qb_hminus']             = 'Заголовок более низкого 
 $lang['qb_hequal']             = 'Заголовок текущего уровня';
 $lang['qb_link']               = 'Внутренняя ссылка';
 $lang['qb_extlink']            = 'Внешняя ссылка';
-$lang['qb_hr']                 = 'Разделитель';
+$lang['qb_hr']                 = 'Горизонтальная линия';
 $lang['qb_ol']                 = 'Элемент нумерованного списка';
 $lang['qb_ul']                 = 'Элемент ненумерованного списка';
 $lang['qb_media']              = 'Добавить изображения или другие файлы (откроется в новом окне)';
@@ -282,7 +281,7 @@ $lang['img_fsize']             = 'Размер:';
 $lang['img_artist']            = 'Фотограф:';
 $lang['img_copyr']             = 'Авторские права:';
 $lang['img_format']            = 'Формат:';
-$lang['img_camera']            = 'Модель:';
+$lang['img_camera']            = 'Модель камеры:';
 $lang['img_keywords']          = 'Ключевые слова:';
 $lang['img_width']             = 'Ширина:';
 $lang['img_height']            = 'Высота:';
@@ -302,8 +301,8 @@ $lang['subscr_m_receive']      = 'Получить';
 $lang['subscr_style_every']    = 'уведомлять о каждом изменении';
 $lang['subscr_style_digest']   = 'информационное электронное письмо со списком изменений для каждой страницы (каждые %.2f дн.)';
 $lang['subscr_style_list']     = 'список изменённых страниц со времени последнего отправленного электронного письма (каждые %.2f дн.)';
-$lang['authtempfail']          = 'Аутентификация пользователей временно недоступна. Если проблема продолжается какое-то время, пожалуйста, сообщите об этом своему администратору вики.';
-$lang['i_chooselang']          = 'Выберите свой язык/Choose your language';
+$lang['authtempfail']          = 'Аутентификация пользователей временно недоступна. Если проблема продолжается какое-то время, пожалуйста, сообщите об этом администратору вики.';
+$lang['i_chooselang']          = 'Выберите свой язык / Choose your language';
 $lang['i_installer']           = 'Установка «Докувики»';
 $lang['i_wikiname']            = 'Название вики';
 $lang['i_enableacl']           = 'Разрешить ограничение прав доступа (рекомендуется)';
@@ -352,7 +351,7 @@ $lang['media_list_thumbs']     = 'Миниатюры';
 $lang['media_list_rows']       = 'Строки';
 $lang['media_sort_name']       = 'Сортировка по имени';
 $lang['media_sort_date']       = 'Сортировка по дате';
-$lang['media_namespaces']      = 'Выберите каталог';
+$lang['media_namespaces']      = 'Выберите пространство имён';
 $lang['media_files']           = 'Файлы в %s';
 $lang['media_upload']          = 'Загрузка в пространство имён %s';
 $lang['media_search']          = 'Поиск в пространстве имён %s';
diff --git a/inc/lang/ru/password.txt b/inc/lang/ru/password.txt
index bee594e5f6b60c993b2381a73f727f564982eae6..52ed4b575f8e0a70988e2d7dd610bec92fcf7cdf 100644
--- a/inc/lang/ru/password.txt
+++ b/inc/lang/ru/password.txt
@@ -2,5 +2,5 @@
 
 Ваши данные для @TITLE@ (@DOKUWIKIURL@)
 
-Имя пользователя: @LOGIN@
+Логин: @LOGIN@
 Пароль: @PASSWORD@
diff --git a/inc/lang/ru/preview.txt b/inc/lang/ru/preview.txt
index 401827607aff2c2e05b0a82c38021b904c224073..2bc383eb2eeb62d9709c9d270e80bca648d264af 100644
--- a/inc/lang/ru/preview.txt
+++ b/inc/lang/ru/preview.txt
@@ -1,4 +1,4 @@
 ====== Просмотр ======
 
-Здесь показано, как ваш текст будет выглядеть. Внимание: текст ещё **не сохранён.**
+Здесь показано, как ваш текст будет выглядеть. Внимание: текст ещё **не сохранён!**
 
diff --git a/inc/lang/ru/read.txt b/inc/lang/ru/read.txt
index fd52d1a520e9ee9638fea81226f5e0979f3b1608..08c3afa7d198a55cacd9bfa7a5b2495a4a2c7459 100644
--- a/inc/lang/ru/read.txt
+++ b/inc/lang/ru/read.txt
@@ -1,2 +1,2 @@
-Эта страница только для чтения. Вы можете посмотреть исходный текст, но не можете его изменить. Сообщите администратору, если считаете, что это неправильно.
+Эта страница только для чтения. Вы можете посмотреть её исходный текст, но не можете его изменить. Сообщите администратору, если считаете, что это неправильно.
 
diff --git a/inc/lang/ru/resendpwd.txt b/inc/lang/ru/resendpwd.txt
index 3cd05049a89ffef981d1d0901b8fa4b55d122007..bc24c49b5043bb71869ab6bd9408925e3fe80742 100644
--- a/inc/lang/ru/resendpwd.txt
+++ b/inc/lang/ru/resendpwd.txt
@@ -1,3 +1,3 @@
 ====== Выслать новый пароль ======
 
-Для получения нового пароля введите требуемые данные ниже. Ваш новый пароль будет послан по адресу электронной почты, зарегистрированному на ваше имя. Указанное ниже имя должно быть вашим логином в этой вики.
+Для получения нового пароля введите ваш логин. Ваш новый пароль будет отправлен по адресу электронной почты, зарегистрированному на ваше имя.
\ No newline at end of file
diff --git a/inc/lang/ru/resetpwd.txt b/inc/lang/ru/resetpwd.txt
index 81a46a7d35e580f9ea86f2063f885648e90e0a44..f7c9d356453765425aab9ea93656f960554de83a 100644
--- a/inc/lang/ru/resetpwd.txt
+++ b/inc/lang/ru/resetpwd.txt
@@ -1,3 +1,3 @@
 ====== Установка нового пароля ======
 
-Пожалуйста введите новый пароль для вашей учетной записи для этой вики.
+Пожалуйста введите новый пароль для вашей учетной записи в этой вики.
diff --git a/inc/lang/ru/revisions.txt b/inc/lang/ru/revisions.txt
index 40fbedf0e0db6cbe837f514e40a88e3a58090695..d5faf3d66c1e87253b2056d77790e2af3c0540f8 100644
--- a/inc/lang/ru/revisions.txt
+++ b/inc/lang/ru/revisions.txt
@@ -1,3 +1,3 @@
 ====== История страницы ======
 
-Перед вами история правок текущего документа. Чтобы вернуться к одной из предыдущих версий, выберите нужную, нажмите «Править страницу» и сохраните.
+Перед вами история правок текущего документа. Чтобы вернуться к одной из предыдущих версий, выберите нужную, нажмите «Править страницу» и сохраните её.
\ No newline at end of file
diff --git a/inc/lang/ru/searchpage.txt b/inc/lang/ru/searchpage.txt
index d12a848c65c07e261af220abfcd17abbbc78c52b..deea577ed2b07e08ad25d592b7e88ada394272b6 100644
--- a/inc/lang/ru/searchpage.txt
+++ b/inc/lang/ru/searchpage.txt
@@ -2,4 +2,3 @@
 
 Перед вами результаты поиска. @CREATEPAGEINFO@
 
-===== Результаты =====
\ No newline at end of file
diff --git a/inc/lang/ru/showrev.txt b/inc/lang/ru/showrev.txt
index 596815870c3d820b44e9a4d1fb8a64d9dcff957f..b3f3852ebc914e18d4ecc75589e1091762ac9c3c 100644
--- a/inc/lang/ru/showrev.txt
+++ b/inc/lang/ru/showrev.txt
@@ -1,2 +1,2 @@
-**Это старая версия документа.**
+**Это старая версия документа!**
 ----
diff --git a/inc/lang/ru/stopwords.txt b/inc/lang/ru/stopwords.txt
index a6df13902bbc5f97defa795372a79b83c7268f93..826a89e0655d873fe28b97631a35faa1fdb57a73 100644
--- a/inc/lang/ru/stopwords.txt
+++ b/inc/lang/ru/stopwords.txt
@@ -1,6 +1,6 @@
-# This is a list of words the indexer ignores, one word per line
-# When you edit this file be sure to use UNIX line endings (single newline)
-# No need to include words shorter than 3 chars - these are ignored anyway
+# Это список слов, которые индексатор игнорирует, по одному слову в строке
+# При редактировании этого файла обязательно используйте окончания строк UNIX (только newline)
+# Не нужно включать слова короче 3 символов - они игнорируются в любом случае
 более
 больше
 будет
diff --git a/inc/lang/ru/subscr_digest.txt b/inc/lang/ru/subscr_digest.txt
index ee313b95b3a8c1e9df9ffe56101cdc6b1f934fc1..afc34ef3b0fde7bc40ac6c688ea4f38873f301bf 100644
--- a/inc/lang/ru/subscr_digest.txt
+++ b/inc/lang/ru/subscr_digest.txt
@@ -1,4 +1,4 @@
-Привет.
+Привет!
 
 Страница @PAGE@ в вики @TITLE@ изменилась.
 Список изменений:
@@ -11,6 +11,5 @@
 Новая версия: @NEWPAGE@
 
 Чтобы отписаться от уведомлений об изменениях, войдите в вики
-@DOKUWIKIURL@ в раздел
-@SUBSCRIBE@
-и отмените подписку на страницу и/или пространство имен.
+@DOKUWIKIURL@ в раздел @SUBSCRIBE@
+и отмените подписку на страницу и/или пространство имён.
diff --git a/inc/lang/ru/subscr_list.txt b/inc/lang/ru/subscr_list.txt
index bff328218547c191851d9b4ef9df99149d7d524f..cf3ef5d10eba67b793dae9c3378da308419ab5c2 100644
--- a/inc/lang/ru/subscr_list.txt
+++ b/inc/lang/ru/subscr_list.txt
@@ -1,4 +1,4 @@
-Привет.
+Привет!
 
 Страницы в пространстве имён @PAGE@ в вики @TITLE@ были изменены.
 
@@ -9,6 +9,5 @@
 --------------------------------------------------------
 
 Чтобы отписаться от уведомлений об изменениях, войдите в вики
-@DOKUWIKIURL@ в раздел
-@SUBSCRIBE@
+@DOKUWIKIURL@ в раздел @SUBSCRIBE@
 и отмените подписку на страницу и/или пространство имён.
diff --git a/inc/lang/ru/subscr_single.txt b/inc/lang/ru/subscr_single.txt
index 744da56ccc252e5c852290de7867620b46f51857..9b7d9075149993f8f795b830f405cc59ca3a5ea4 100644
--- a/inc/lang/ru/subscr_single.txt
+++ b/inc/lang/ru/subscr_single.txt
@@ -1,4 +1,4 @@
-Привет.
+Привет!
 
 Страница @PAGE@ в вики @TITLE@ изменилась.
 Список изменений:
@@ -15,6 +15,5 @@
 Новая версия: @NEWPAGE@
 
 Чтобы отписаться от уведомлений об изменениях, войдите в вики
-@DOKUWIKIURL@ в раздел
-@SUBSCRIBE@
+@DOKUWIKIURL@ в раздел @SUBSCRIBE@
 и отмените подписку на страницу и/или пространство имён.
diff --git a/inc/lang/ru/updateprofile.txt b/inc/lang/ru/updateprofile.txt
index b1f9f56ef1ac908329b91a2428513059faab2c77..824916c65aca9297f93ff64c53b5d7fd330a2670 100644
--- a/inc/lang/ru/updateprofile.txt
+++ b/inc/lang/ru/updateprofile.txt
@@ -1,5 +1,5 @@
 ====== Обновить профиль ======
 
-Необходимо заполнить только те поля, которые вы хотите изменить. Имя пользователя не может быть изменено.
+Необходимо заполнить только те поля, которые вы хотите изменить. Ваш логин не может быть изменён.
 
 
diff --git a/inc/lang/sk/lang.php b/inc/lang/sk/lang.php
index 6ab3184383bf31ee738e62c0bbc2a4356f8a9058..bd8d1c9a3409583830eff0778944d4e0b67ab009 100644
--- a/inc/lang/sk/lang.php
+++ b/inc/lang/sk/lang.php
@@ -3,11 +3,10 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Martin Michalek <michalek.dev@gmail.com>
  * @author Ondrej Vegh <ov@vsieti.sk> with help of the scholars from Zdruzena stredna skola polygraficka in Bratislava
  * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
- * @author Martin Michalek <michalek.dev@gmail.com>
- * @author Michalek <michalek.dev@gmail.com>
+ * @author exusik <exusik@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -68,7 +67,6 @@ $lang['badpassconfirm']        = 'Ľutujem, heslo bolo nesprávne.';
 $lang['minoredit']             = 'Menšie zmeny';
 $lang['draftdate']             = 'Koncept automaticky uložený';
 $lang['nosecedit']             = 'Stránka bola medzičasom zmenená, informácie o sekcii sú zastaralé a z tohto dôvodu bola nahraná celá stránka.';
-$lang['searchcreatepage']      = 'Pokiaľ ste nenašli, čo hľadáte, skúste požadovanú stránku sami vytvoriť stlačením tlačidla \'\'Vytvoriť stránku\'\'.';
 $lang['regmissing']            = 'Musíte vyplniť všetky údaje.';
 $lang['reguexists']            = 'Používateľ s rovnakým menom je už zaregistrovaný.';
 $lang['regsuccess']            = 'Používateľský účet bol vytvorený a heslo zaslané emailom.';
@@ -282,6 +280,7 @@ $lang['i_problems']            = 'Inštalátor narazil na nižšie uvedené prob
 $lang['i_modified']            = 'Z bezpečnostných dôvodov bude tento skript fungovať iba s novou, neupravenou inštaláciou Dokuwiki. Môžete buď znovu rozbaliť stiahnutý inštalačný balík alebo preštudovať <a href="http://dokuwiki.org/install"> inštalačné inštrukcie Dokuwiki</a>';
 $lang['i_funcna']              = 'PHP funkcia <code>%s</code> nie je dostupná. Je možné, že ju z určitých dôvodov zablokoval váš poskytovateľ webhostingu?';
 $lang['i_phpver']              = 'Vaša verzia PHP <code>%s</code> je nižšia ako požadovaná <code>%s</code>. Potrebujete aktualizovať Vašu inštaláciu PHP.';
+$lang['i_mbfuncoverload']      = 'mbstring.func_overload musí byt zakázaná v php.ini pre bezproblémový chod DokuWiki.';
 $lang['i_permfail']            = '<code>%s</code> nie je zapisovateľný pre DokuWiki. Musíte zmeniť prístupové práva pre tento adresár!';
 $lang['i_confexists']          = '<code>%s</code> už existuje';
 $lang['i_writeerr']            = 'Nie je možné vytvoriť <code>%s</code>. Potrebujete skontrolovať prístupové práva pre adresár/súbor a vytvoriť ho manuálne.';
@@ -331,9 +330,11 @@ $lang['media_perm_read']       = 'Prepáčte, ale nemáte dostatočné oprávnen
 $lang['media_perm_upload']     = 'Prepáčte, ale nemáte dostatočné oprávnenie na nahrávanie súborov.';
 $lang['media_update']          = 'Nahrať novú verziu';
 $lang['media_restore']         = 'Obnoviť túto verziu';
+$lang['media_acl_warning']     = 'Tento zoznam nemusí byť úplný z dôvodu ACL obmedzení alebo skratých stránok.';
 $lang['currentns']             = 'Aktuálny menný priestor';
 $lang['searchresult']          = 'Výsledky hľadania';
 $lang['plainhtml']             = 'Jednoduché HTML';
 $lang['wikimarkup']            = 'Wiki formát';
+$lang['unable_to_parse_date']  = 'Nie je možné spracovať parameter "%s".';
 $lang['email_signature_text']  = 'Táto správa bola zaslaná DokuWiki
 @DOKUWIKIURL@';
diff --git a/inc/lang/sk/searchpage.txt b/inc/lang/sk/searchpage.txt
index 3684f1c6c38562f9dbae0910cd93e0b2596479a3..5905db6646b76a7f8258710025f5fa067cfbf1ec 100644
--- a/inc/lang/sk/searchpage.txt
+++ b/inc/lang/sk/searchpage.txt
@@ -2,4 +2,3 @@
 
 Výsledky hľadania môžete vidieť nižšie. @CREATEPAGEINFO@
 
-===== Výsledky =====
diff --git a/inc/lang/sl/lang.php b/inc/lang/sl/lang.php
index 9baa9dd090ecf9d1afa8ecd88b8b66400a82eb46..213e0f83a70e2827eb4d7085a2b78f8a1460e7eb 100644
--- a/inc/lang/sl/lang.php
+++ b/inc/lang/sl/lang.php
@@ -3,13 +3,13 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Simon <sbx@protonmail.ch>
  * @author Jaka Kranjc <lynxlupodian@hotmail.com>
  * @author Boštjan Seničar <senicar@gmail.com>
  * @author Dejan Levec <webphp@gmail.com>
  * @author Gregor Skumavc (grega.skumavc@gmail.com)
  * @author Matej Urbančič (mateju@svn.gnome.org)
  * @author Matej Urbančič <mateju@svn.gnome.org>
- * @author matej <mateju@svn.gnome.org>
  * @author Jernej Vidmar <jernej.vidmar@vidmarboehm.com>
  */
 $lang['encoding']              = 'utf-8';
@@ -50,7 +50,7 @@ $lang['btn_draft']             = 'Uredi osnutek';
 $lang['btn_recover']           = 'Obnovi osnutek';
 $lang['btn_draftdel']          = 'Izbriši osnutek';
 $lang['btn_revert']            = 'Povrni';
-$lang['btn_register']          = 'Prijava';
+$lang['btn_register']          = 'Registracija';
 $lang['btn_apply']             = 'Uveljavi';
 $lang['btn_media']             = 'Urejevalnik predstavnih vsebin';
 $lang['btn_deleteuser']        = 'Odstrani račun';
@@ -71,7 +71,6 @@ $lang['badpassconfirm']        = 'Napaka! Geslo ni pravo.';
 $lang['minoredit']             = 'Manjše spremembe';
 $lang['draftdate']             = 'Samodejno shranjevanje osnutka je omogočeno';
 $lang['nosecedit']             = 'Stran je bila v vmesnem času spremenjena. Podatki strani so bili zastareli, zato se je celotna vsebina naložila znova.';
-$lang['searchcreatepage']      = "V kolikor rezultati niso skladni z zahtevami iskanja, je mogoče ustvariti  novo stran z nazivom vaše poizvedbe preko povezave ''Uredi stran''.";
 $lang['regmissing']            = 'Izpolniti je treba vsa polja.';
 $lang['reguexists']            = 'Uporabnik s tem imenom že obstaja.';
 $lang['regsuccess']            = 'Uporabniški račun je uspešno ustvarjen. Geslo je bilo poslano na naveden elektronski naslov.';
@@ -331,5 +330,5 @@ $lang['currentns']             = 'Trenutni imenski prostor';
 $lang['searchresult']          = 'Rezultati iskanja';
 $lang['plainhtml']             = 'Zapis HTML';
 $lang['wikimarkup']            = 'Oblikovni jezik Wiki';
-$lang['email_signature_text'] = 'Sporočilo je samodejno ustvarjeno na spletišču
+$lang['email_signature_text']  = 'Sporočilo je samodejno ustvarjeno na spletišču
 @DOKUWIKIURL@';
diff --git a/inc/lang/sl/searchpage.txt b/inc/lang/sl/searchpage.txt
index 6ccfa96a4563666875b62d1f824901dada4b15b7..d19d5e275b519fd85149566d34671652bf0bf1f6 100644
--- a/inc/lang/sl/searchpage.txt
+++ b/inc/lang/sl/searchpage.txt
@@ -2,4 +2,3 @@
 
 Spodaj so izpisani rezultati iskanja. @CREATEPAGEINFO@
 
-===== Rezultati =====
\ No newline at end of file
diff --git a/inc/lang/sq/lang.php b/inc/lang/sq/lang.php
index 6de6af81ec7044f00c5eb801116fdca8a3d76371..5313ddd221f6cfc0b0a6e86e173524a98ea8dd38 100644
--- a/inc/lang/sq/lang.php
+++ b/inc/lang/sq/lang.php
@@ -62,7 +62,6 @@ $lang['badlogin']              = 'Na vjen keq, emri ose fjalëkalimi është gab
 $lang['minoredit']             = 'Ndryshime të Vogla';
 $lang['draftdate']             = 'Skica u ruajt automatikisht në';
 $lang['nosecedit']             = 'Faqja u ndryshua ndëwrkohë, informacioni i kwtij seksioni ishte i vjetër, u ngarkua faqja e tërë në vend të saj.';
-$lang['searchcreatepage']      = 'Nëse nuk e gjetët atë që po kërkonit, mund të krijoni ose redaktoni një faqe pas pyetjes suaj me butonin përkatës.';
 $lang['regmissing']            = 'Na vjen keq, duhet të plotësoni të gjitha fushat.';
 $lang['reguexists']            = 'Na vjen keq, ekziston një përdorues tjetër me të njëjtin emër.';
 $lang['regsuccess']            = 'Përdoruesi u regjistrua dhe fjalëkalimi u dërgua me email.';
diff --git a/inc/lang/sq/searchpage.txt b/inc/lang/sq/searchpage.txt
index b0d6d1f31fb57826ca2048461dd55d5f1b430d3d..4c72f22dbab231617fc109961231b07e3285b063 100644
--- a/inc/lang/sq/searchpage.txt
+++ b/inc/lang/sq/searchpage.txt
@@ -2,4 +2,3 @@
 
 Mund të gjeni rezultatet e kërkimit tuaj më poshtë. @CREATEPAGEINFO@
 
-===== Rezultate =====
\ No newline at end of file
diff --git a/inc/lang/sr/lang.php b/inc/lang/sr/lang.php
index 1856f66b1d9d7df0bc1327ebf5755257b15446ca..9182c1b7f637967121071f57765d21953e6401da 100644
--- a/inc/lang/sr/lang.php
+++ b/inc/lang/sr/lang.php
@@ -7,6 +7,7 @@
  * @author Иван Петровић (Ivan Petrovic) <petrovicivan@ubuntusrbija.org>
  * @author Miroslav Å olti <solti.miroslav@gmail.com>
  * @author Жељко Тодоровић <zeljko_todorovic@mail.com>
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -41,13 +42,17 @@ $lang['btn_backlink']          = 'Повратне везе';
 $lang['btn_subscribe']         = 'Пријави се на измене';
 $lang['btn_profile']           = 'Ажурирај профил';
 $lang['btn_reset']             = 'Поништи';
+$lang['btn_resendpwd']         = 'Поставите нови лозинку';
 $lang['btn_draft']             = 'Измени нацрт';
 $lang['btn_recover']           = 'Опорави нацрт';
 $lang['btn_draftdel']          = 'Обриши нацрт';
 $lang['btn_revert']            = 'Врати на пређашњу верзију';
 $lang['btn_register']          = 'Региструј се';
+$lang['btn_apply']             = 'Примени';
+$lang['btn_media']             = 'Управник мултимедије';
 $lang['btn_deleteuser']        = 'Уклони мој налог';
 $lang['btn_img_backto']        = 'Натраг на %s';
+$lang['btn_mediaManager']      = 'Погледај у управнику мултимедије';
 $lang['loggedinas']            = 'Пријављен као:';
 $lang['user']                  = 'Корисничко име';
 $lang['pass']                  = 'Лозинка';
@@ -58,28 +63,34 @@ $lang['remember']              = 'Запамти ме';
 $lang['fullname']              = 'Име и презиме';
 $lang['email']                 = 'Е-адреса';
 $lang['profile']               = 'Кориснички профил';
-$lang['badlogin']              = 'Извините, није добро корисничко име или шифра.';
+$lang['badlogin']              = 'Нажалост, није добро корисничко име или лозинка.';
+$lang['badpassconfirm']        = 'Нажалост, лозинка је била погрешна';
 $lang['minoredit']             = 'Мала измена';
 $lang['draftdate']             = 'Нацрт је аутоматски сачуван';
 $lang['nosecedit']             = 'Страна је у међувремену промењена, поглавље је застарело и поново се учитава цела страна.';
-$lang['searchcreatepage']      = 'Ако нисте нашли то што сте тражили, можете да направите нову страницу названу по Вашем упиту користећи дугме \'\'Измени ову страницу\'\'.';
 $lang['regmissing']            = 'Извините, морате да попуните сва поља.';
 $lang['reguexists']            = 'Извините, корисник са истим именом већ постоји.';
 $lang['regsuccess']            = 'Корисник је направљен и лозинка је послата путем е-поште.';
 $lang['regsuccess2']           = 'Корисник је направљен.';
-$lang['regmailfail']           = 'Изгледа да је дошло до грешке приликом слања лозинке е-поштом. Молим Вас, контактирајте администратора!';
+$lang['regfail']               = 'Нисам могао да направим корисника.';
+$lang['regmailfail']           = 'Изгледа да је дошло до грешке приликом слања лозинке е-поштом. Контактирајте администратора!';
 $lang['regbadmail']            = 'Дата е-адреса није у реду - ако мислите да је ово грешка, контактирајте администратора';
-$lang['regbadpass']            = 'Две задате лозинке нису исте. Молим Вас, пробајте поново.';
+$lang['regbadpass']            = 'Две унете лозинке нису исте. Пробајте поново.';
 $lang['regpwmail']             = 'Ваша DokuWiki лозинка';
 $lang['reghere']               = 'Још увек немате налог? Само направите један';
 $lang['profna']                = 'Овај вики не дозвољава измену профила';
 $lang['profnochange']          = 'Нема промена.';
 $lang['profnoempty']           = 'Није дозвољено оставити празно поље имена или е-адресе.';
 $lang['profchanged']           = 'Кориснички профил је ажуриран.';
+$lang['profnodelete']          = 'Овај вики не подржава брисање корисника';
 $lang['profdeleteuser']        = 'Избриши налог';
 $lang['profdeleted']           = 'Ваш кориснички налог је избрисан са овог викија';
+$lang['profconfdelete']        = 'Желим да уклоним свој налог са овог викија. <br/> Ова радња се не може опозвати.';
+$lang['profconfdeletemissing'] = 'Није штиклирано поље за потврду';
+$lang['proffail']              = 'Кориснички профил није ажуриран.';
 $lang['pwdforget']             = 'Заборавили сте лозинку? Направите нову';
 $lang['resendna']              = 'Овај вики не дозвољава слање лозинки.';
+$lang['resendpwd']             = 'Поставите нову лозинку за';
 $lang['resendpwdmissing']      = 'Жао ми је, сва поља морају бити попуњена.';
 $lang['resendpwdnouser']       = 'Жао ми је, овај корисник не постоји у нашој бази.';
 $lang['resendpwdbadauth']      = 'Жао ми је, потврдни код није исправан. Проверите да ли сте користили комплетан потврдни линк.';
@@ -92,6 +103,7 @@ $lang['searchmedia_in']        = 'Претражи у %s';
 $lang['txt_upload']            = 'Изаберите датотеку за слање:';
 $lang['txt_filename']          = 'Унесите вики-име (опционо):';
 $lang['txt_overwrt']           = 'Препишите тренутни фајл';
+$lang['maxuploadsize']         = 'Отпреми највише %s по датотеци.';
 $lang['lockedby']              = 'Тренутно закључано од стране:';
 $lang['lockexpire']            = 'Закључавање истиче:';
 $lang['js']['willexpire']      = 'Ваше закључавање за измену ове странице ће да истекне за један минут.\nДа би сте избегли конфликте, искористите дугме за преглед како би сте ресетовали тајмер закључавања.';
@@ -126,6 +138,15 @@ $lang['js']['nosmblinks']      = 'Повезивање са Windows дељени
 $lang['js']['linkwiz']         = 'Чаробњак за стварање везе';
 $lang['js']['linkto']          = 'Повежи ка:';
 $lang['js']['del_confirm']     = 'Обриши овај унос?';
+$lang['js']['restore_confirm'] = 'Заиста желите да вратите ово издање?';
+$lang['js']['media_diff']      = 'Погледај разлике:';
+$lang['js']['media_diff_both'] = 'Једно до другог';
+$lang['js']['media_select']    = 'Изабери датотеке…';
+$lang['js']['media_upload_btn'] = 'Отпреми';
+$lang['js']['media_done_btn']  = 'Готово';
+$lang['js']['media_drop']      = 'Превуците датотеке овде да бисте их отпремили';
+$lang['js']['media_cancel']    = 'уклони';
+$lang['js']['media_overwrt']   = 'Препиши постојеће датотеке';
 $lang['rssfailed']             = 'Дошло је до грешке приликом преузимања овог довода: ';
 $lang['nothingfound']          = 'Ништа није нађено.';
 $lang['mediaselect']           = 'Избор медијске датотеке';
@@ -159,6 +180,14 @@ $lang['yours']                 = 'Ваша верзија';
 $lang['diff']                  = 'прикажи разлике до тренутне верзије';
 $lang['diff2']                 = 'Прикажи разлике између одабраних ревизија';
 $lang['difflink']              = 'Постави везу ка овом компаративном приказу';
+$lang['diff_type']             = 'Погледај разлике:';
+$lang['diff_inline']           = 'У линији';
+$lang['diff_side']             = 'Једно до другог';
+$lang['diffprevrev']           = 'Претходна ревизија';
+$lang['diffnextrev']           = 'Следећа ревизија';
+$lang['difflastrev']           = 'Последња ревизија';
+$lang['diffbothprevrev']       = 'Обе стране последње ревизије';
+$lang['diffbothnextrev']       = 'Обе стране следеће ревизије';
 $lang['line']                  = 'Линија';
 $lang['breadcrumb']            = 'Траг:';
 $lang['youarehere']            = 'Сада сте овде:';
@@ -171,13 +200,21 @@ $lang['external_edit']         = 'спољна измена';
 $lang['summary']               = 'Сажетак измене';
 $lang['noflash']               = 'За приказивање ове врсте материјала потребан вам је <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
 $lang['download']              = 'Преузми снипет';
+$lang['tools']                 = 'Алатке';
+$lang['user_tools']            = 'Корисничке алатке';
+$lang['site_tools']            = 'Алатке сајта';
+$lang['page_tools']            = 'Алатке странице';
+$lang['skip_to_content']       = 'скочи на садржај';
+$lang['sidebar']               = 'Страничник';
 $lang['mail_newpage']          = 'страница додата:';
 $lang['mail_changed']          = 'страница измењена:';
 $lang['mail_subscribe_list']   = 'Странице промењене у именском простору:';
 $lang['mail_new_user']         = 'нови корисник:';
 $lang['mail_upload']           = 'послата датотека:';
+$lang['changes_type']          = 'Прикажи измене';
 $lang['pages_changes']         = 'Странице';
-$lang['both_changes']          = 'И странице и датотеке';
+$lang['media_changes']         = 'датотека';
+$lang['both_changes']          = 'И страница и датотека';
 $lang['qb_bold']               = 'Мастан текст';
 $lang['qb_italic']             = 'Курзивни текст';
 $lang['qb_underl']             = 'Подвучени текст';
@@ -216,6 +253,8 @@ $lang['img_copyr']             = 'Права копирања:';
 $lang['img_format']            = 'Формат:';
 $lang['img_camera']            = 'Камера:';
 $lang['img_keywords']          = 'Кључне речи:';
+$lang['img_width']             = 'Ширина:';
+$lang['img_height']            = 'Висина:';
 $lang['subscr_subscribe_success'] = '%s је додат на списак претплатника %s';
 $lang['subscr_subscribe_error'] = 'Грешка приликом додавања %s на списак претплатника %s';
 $lang['subscr_subscribe_noaddress'] = 'Не постоји адреса повезана са вашим подацима, стога вас не можемо додати на списак претплатника.';
@@ -242,6 +281,7 @@ $lang['i_problems']            = 'Инсталација је наишла на
 $lang['i_modified']            = 'Из сигурносних разлога ова скрипта ради само са новом Dokuwiki инсталацијом. Требало би или да опет распакујете архиву преузету са сајта или да погледате <a href="http://dokuwiki.org/install">Dokuwiki инструкције за инсталацију</a>';
 $lang['i_funcna']              = 'ПХП функција <code>%s</code> није доступна. Можда је Ваш хостинг провајдер забранио из неког разлога?';
 $lang['i_phpver']              = '<code>%s</code> Верзија Вашег ПХПа је нижа од неопходне <code>%s</code>. Требало би да надоградите ПХП инсталацију.';
+$lang['i_mbfuncoverload']      = 'mbstring.func_overload мора бити искључен у датотеци php.ini да бисте користили Докувики.';
 $lang['i_permfail']            = 'DokuWiki нема дозволу писања у <code>%s</code>. Потребно је да поправите дозволе за ову фасциклу!';
 $lang['i_confexists']          = '<code>%s</code> већ постоји';
 $lang['i_writeerr']            = 'Не могу да направим <code>%s</code>. Проверите дозволе а затим ручно направите ову датотеку.';
@@ -253,8 +293,12 @@ $lang['i_policy']              = 'Иницијалне корисничке до
 $lang['i_pol0']                = 'Отворени вики (читање, писање, слање датотека за све)';
 $lang['i_pol1']                = 'Јавни вики (читање за све, писање и слање датотека само за регистроване кориснике)';
 $lang['i_pol2']                = 'Затворени вики (читање, писање и слање датотека само за регистроване кориснике)';
+$lang['i_allowreg']            = 'Дозволи корисницима да се региструју';
 $lang['i_retry']               = 'Понови';
 $lang['i_license']             = 'Молимо вас, одаберите лиценцу под коју желите да ставите свој садржај:';
+$lang['i_license_none']        = 'Не приказуј податке о лиценци';
+$lang['i_pop_field']           = 'Помозите нам да побољшамо Докувики:';
+$lang['i_pop_label']           = 'Једном месечно шаљи анонимне податке о коришћењу програмерима Докувикија';
 $lang['recent_global']         = 'Тренутно пратите промене у именском простору <b>%s</b>. Такође, можете пратити <a href="%s">прмене на целом викију</a>.';
 $lang['years']                 = 'Пре %d година';
 $lang['months']                = 'Пре %d месеци';
@@ -264,5 +308,35 @@ $lang['hours']                 = 'Пре %d сати';
 $lang['minutes']               = 'Пре %d минута';
 $lang['seconds']               = 'Пре %d секунди';
 $lang['wordblock']             = 'Ваше измене нису сачуване јер садрже забрањен текст (спам)';
+$lang['media_uploadtab']       = 'Отпреми';
+$lang['media_searchtab']       = 'Претрага';
+$lang['media_file']            = 'Датотека';
+$lang['media_viewtab']         = 'Погледај';
+$lang['media_edittab']         = 'Уреди';
+$lang['media_historytab']      = 'Историјат';
+$lang['media_list_thumbs']     = 'Сличице';
+$lang['media_list_rows']       = 'Редови';
+$lang['media_sort_name']       = 'Име';
+$lang['media_sort_date']       = 'Датум';
+$lang['media_namespaces']      = 'Изабери именски простор';
+$lang['media_files']           = 'Датотеке у %s';
+$lang['media_upload']          = 'Отпреми на %s';
+$lang['media_search']          = 'Претражи у %s';
+$lang['media_view']            = '%s';
+$lang['media_viewold']         = '%s у %s';
+$lang['media_edit']            = 'Уреди %s';
+$lang['media_history']         = 'Историјат од %s';
+$lang['media_meta_edited']     = 'промењени мета-подаци';
+$lang['media_perm_read']       = 'Нажалост, немате довољно овлашћења за читање датотека.';
+$lang['media_perm_upload']     = 'Нажалост, немате довољно овлашћења за отпремање датотека.';
+$lang['media_update']          = 'Отпреми ново издање';
+$lang['media_restore']         = 'Поврати ово издање';
+$lang['media_acl_warning']     = 'Овај списак је можда непотпун због забрана на списку контроле приступа и скривених страница.';
+$lang['currentns']             = 'Тренутни именски простор';
+$lang['searchresult']          = 'Резултати претраге';
+$lang['plainhtml']             = 'Обичан HTML';
+$lang['wikimarkup']            = 'Вики маркап';
+$lang['page_nonexist_rev']     = 'Страница не постоји у %s. Касније је направљена у <a href="%s">%s</a>.';
+$lang['unable_to_parse_date']  = 'Не могу да обрадим код параметра "%s".';
 $lang['email_signature_text']  = 'Ову поруку је генерисао DokuWiki sa
 @DOKUWIKIURL@';
diff --git a/inc/lang/sr/password.txt b/inc/lang/sr/password.txt
index 453b9b6870b9bbc26b2db6c642819afcbf786be1..bd2cf3202d876372ef6fdb42eb12505caf93e901 100644
--- a/inc/lang/sr/password.txt
+++ b/inc/lang/sr/password.txt
@@ -3,4 +3,4 @@
 Ево Ваших података за @TITLE@ на @DOKUWIKIURL@
 
 Корисничко име : @LOGIN@
-Шифра          : @PASSWORD@
+Лозинка          : @PASSWORD@
diff --git a/inc/lang/sr/resetpwd.txt b/inc/lang/sr/resetpwd.txt
new file mode 100644
index 0000000000000000000000000000000000000000..642de9882046efbc4a27422d96ddea528c1bd841
--- /dev/null
+++ b/inc/lang/sr/resetpwd.txt
@@ -0,0 +1,3 @@
+====== Поставите нову лозинку ======
+
+Унесите нову лозинку за ваш налог на овом викију.
\ No newline at end of file
diff --git a/inc/lang/sr/searchpage.txt b/inc/lang/sr/searchpage.txt
index 458c5b1fc9e9e9e358922b3383b5d8393ca18a8c..4663f47fc03f81d88476826042d83b3842fe70de 100644
--- a/inc/lang/sr/searchpage.txt
+++ b/inc/lang/sr/searchpage.txt
@@ -2,4 +2,3 @@
 
 Испод можете да нађете резултате Ваше претраге. @CREATEPAGEINFO@
 
-===== Резултати =====
diff --git a/inc/lang/sv/adminplugins.txt b/inc/lang/sv/adminplugins.txt
index 0af37c769e456a71eb119e8b5ad174502f641802..2429b932a0c3160462d17971990776e934155846 100644
--- a/inc/lang/sv/adminplugins.txt
+++ b/inc/lang/sv/adminplugins.txt
@@ -1,2 +1 @@
-	
 ===== Ytterligare Tillägg =====
\ No newline at end of file
diff --git a/inc/lang/sv/lang.php b/inc/lang/sv/lang.php
index b2bb0734728e65bc33a23a57eb7bb6ba352016be..14864212e6ee1f5ce61b57c82d1b9918ecb06a4c 100644
--- a/inc/lang/sv/lang.php
+++ b/inc/lang/sv/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Joaquim Homrighausen <joho@webbplatsen.se>
  * @author Per Foreby <per@foreby.se>
  * @author Nicklas Henriksson <nicklas[at]nihe.se>
@@ -10,15 +11,11 @@
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
  * @author Tormod Johansson <tormod.otter.johansson@gmail.com>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
  * @author Henrik <henrik@idealis.se>
- * @author Tor Härnqvist <tor.harnqvist@gmail.com>
  * @author Hans Iwan Bratt <hibratt@gmail.com>
  * @author Mikael Bergström <krank23@gmail.com>
  */
@@ -81,11 +78,11 @@ $lang['badpassconfirm']        = 'Ledsen, lösenordet var felaktigt';
 $lang['minoredit']             = 'Små ändringar';
 $lang['draftdate']             = 'Utkast automatiskt sparat';
 $lang['nosecedit']             = 'Sidan ändrades medan du skrev, sektionsinformationen var inte uppdaterad. Laddar hela sidan istället.';
-$lang['searchcreatepage']      = 'Om du inte hittar det du letar efter, så kan du skapa eller redigera sidan med någon av knapparna.';
 $lang['regmissing']            = 'Du måste fylla i alla fälten.';
 $lang['reguexists']            = 'Det finns redan en användare med det användarnamnet.';
 $lang['regsuccess']            = 'Användarkontot skapat, lösenordet har skickats via e-post.';
 $lang['regsuccess2']           = 'Användarkontot skapat.';
+$lang['regfail']               = 'Användaren kunde inte skapas.';
 $lang['regmailfail']           = 'Ett fel uppstod när ditt lösenord skulle skickas via e-post. Var god kontakta administratören!';
 $lang['regbadmail']            = 'Den angivna e-postadressen verkar vara ogiltig - om du anser detta felaktigt, var god kontakta administratören';
 $lang['regbadpass']            = 'De två angivna lösenorden är inte identiska. Försök igen.';
@@ -100,6 +97,7 @@ $lang['profdeleteuser']        = 'Radera kontot';
 $lang['profdeleted']           = 'Ditt användarkonto har raderats från den här wiki:n';
 $lang['profconfdelete']        = 'Jag vill ta bort mitt konto/inlogg på den här wiki:n <br/> Denna åtgärd går ej att ångra.';
 $lang['profconfdeletemissing'] = 'Bekräftelse-kryssrutan är ej markerad';
+$lang['proffail']              = 'Användarprofilen uppdaterades ej.';
 $lang['pwdforget']             = 'Glömt ditt lösenord? Ordna ett nytt';
 $lang['resendna']              = 'Den här wikin stödjer inte utskick av lösenord.';
 $lang['resendpwd']             = 'Sätt lösenord för';
@@ -195,6 +193,9 @@ $lang['diff2']                 = 'Visa skillnader mellan valda versioner';
 $lang['difflink']              = 'Länk till den här jämförelsesidan';
 $lang['diff_type']             = 'Visa skillnader:';
 $lang['diff_side']             = 'Sida vid sida';
+$lang['diffprevrev']           = 'Föregående version.';
+$lang['diffnextrev']           = 'Nästa version.';
+$lang['difflastrev']           = 'Senaste version.';
 $lang['line']                  = 'Rad';
 $lang['breadcrumb']            = 'Spår:';
 $lang['youarehere']            = 'Här är du:';
@@ -263,6 +264,7 @@ $lang['img_keywords']          = 'Nyckelord:';
 $lang['img_width']             = 'Bredd:';
 $lang['img_height']            = 'Höjd:';
 $lang['subscr_subscribe_success'] = 'La till %s till prenumerationslista %s';
+$lang['subscr_subscribe_error'] = 'Error att lägga till %s till prenumerationslista för %s';
 $lang['subscr_subscribe_noaddress'] = 'Det finns ingen adress associerad med din inloggning, du kan inte bli tillagd i prenumerationslistan';
 $lang['subscr_unsubscribe_success'] = '%s borttagen från prenumerationslistan för %s';
 $lang['subscr_unsubscribe_error'] = 'Fel vid borttagning av %s från prenumerationslista %s';
@@ -275,6 +277,7 @@ $lang['subscr_m_unsubscribe']  = 'Avsluta prenumeration';
 $lang['subscr_m_subscribe']    = 'Prenumerera';
 $lang['subscr_m_receive']      = 'Ta emot';
 $lang['subscr_style_every']    = 'skicka epost vid varje ändring';
+$lang['subscr_style_digest']   = 'Samlings-e-brev av ändringar för varje sida (var %.2f dag)';
 $lang['subscr_style_list']     = 'lista över ändrade sidor sedan senaste e-post (varje %.2f dag)';
 $lang['authtempfail']          = 'Tillfälligt fel på användarautentisering. Om felet kvarstår, var vänlig meddela wikiadministratören.';
 $lang['i_chooselang']          = 'Välj språk';
@@ -339,7 +342,10 @@ $lang['media_perm_read']       = 'Du har tyvärr inte tillräckliga behörighete
 $lang['media_perm_upload']     = 'Du har tyvärr inte tillräckliga behörigheter för att ladda upp filer.';
 $lang['media_update']          = 'Ladda upp ny version';
 $lang['media_restore']         = 'Återställ denna version';
+$lang['media_acl_warning']     = 'Listan kanske inte är ';
+$lang['currentns']             = 'Nuvarande namnrymd.';
 $lang['searchresult']          = 'Sökresultat';
 $lang['plainhtml']             = 'Ren HTML';
-$lang['email_signature_text'] = 'Detta meddelande har skapats av DokuWiki på
+$lang['page_nonexist_rev']     = 'Sidan fanns inte på %s. Den blev sedermera skapad på <a href="%s">%s</a>.';
+$lang['email_signature_text']  = 'Detta meddelande har skapats av DokuWiki på
 @DOKUWIKIURL@';
diff --git a/inc/lang/sv/searchpage.txt b/inc/lang/sv/searchpage.txt
index 7b2d3bca36155f1a9014088901a22b4b0e12f2ab..d01bf23e4467bde166f89771aaedbc1f08b4d4b2 100644
--- a/inc/lang/sv/searchpage.txt
+++ b/inc/lang/sv/searchpage.txt
@@ -2,4 +2,3 @@
 
 Nedan ser du resultatet av sökningen. @CREATEPAGEINFO@
 
-===== Resultat =====
diff --git a/inc/lang/sv/subscr_list.txt b/inc/lang/sv/subscr_list.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4621917547c0b3da45b4e566d5b94919b4743957
--- /dev/null
+++ b/inc/lang/sv/subscr_list.txt
@@ -0,0 +1,9 @@
+Hej!
+
+Sidorna i namnrymden @PAGE@ för wikin @TITLE@ har ändrats. Följande sidor har ändrats: 
+
+--------------------------------------------------------
+@DIFF@
+--------------------------------------------------------
+
+För att inaktivera sidnotifieringar, logga in på wikin (@DOKUWIKIURL@), gå till @SUBSCRIBE@ och avanmäl dig från sid-och/eller namnrymd-ändringar.
\ No newline at end of file
diff --git a/inc/lang/th/lang.php b/inc/lang/th/lang.php
index 570d92968d0fa18b1f16f49a05656e1ba277e090..b2b2fd852f09df767a9c85892dae15293a2930f6 100644
--- a/inc/lang/th/lang.php
+++ b/inc/lang/th/lang.php
@@ -69,7 +69,6 @@ $lang['badpassconfirm']        = 'พาสเวิร์ดไม่ถูก
 $lang['minoredit']             = 'เป็นการแก้ไขเล็กน้อย';
 $lang['draftdate']             = 'บันทึกฉบับร่างเมื่อ';
 $lang['nosecedit']             = 'ในช่วงเวลาที่ผ่านมานี้เพจถูกแก้ไขไปแล้ว, เนื้อหาในเซคชั่นนี้ไม่ทันสมัย กรุณาโหลดเพจใหม่ทั้งหน้าแทน';
-$lang['searchcreatepage']      = 'ถ้าคุณไม่พบสิ่งที่คนมองหา คุณสามารถเลือกที่จะสร้าง หรือแก้ไขชื่อเพจหลังจากดูผลสืบค้นแล้วด้วยปุ่มที่เหมาะสม';
 $lang['regmissing']            = 'ขออภัย คุณต้องกรอกให้ครบทุกช่อง';
 $lang['reguexists']            = 'ชื่อบัญชีที่ใส่นั้นมีผู้อื่นได้ใช้แล้ว กรุณาเลือกชื่อผู้ใช้อื่น';
 $lang['regsuccess']            = 'ผู้ใช้ถูกสร้างแล้ว และรหัสผ่านได้ถูกส่งไปทางอีเมลแล้ว';
diff --git a/inc/lang/th/searchpage.txt b/inc/lang/th/searchpage.txt
index 263c656abf91c7081b1b0c5594c4c57b319dc126..87153b08a946a0452b3c98dc7c0f2cd9ddea867a 100644
--- a/inc/lang/th/searchpage.txt
+++ b/inc/lang/th/searchpage.txt
@@ -2,4 +2,3 @@
 
 คุณสามารถพบผลลัพธ์การสืบค้นของคุณด้านล่าง @CREATEPAGEINFO@
 
-====== ผลลัพธ์ ======
\ No newline at end of file
diff --git a/inc/lang/tr/lang.php b/inc/lang/tr/lang.php
index 49236c5f9e37e73429fe0665e78c60384cd75759..4147a13578b263902b7be25f3d70641cd9255dca 100644
--- a/inc/lang/tr/lang.php
+++ b/inc/lang/tr/lang.php
@@ -74,7 +74,6 @@ $lang['badpassconfirm']        = 'Üzgünüz, parolanız yanlış';
 $lang['minoredit']             = 'Küçük Değişiklikler';
 $lang['draftdate']             = 'Taslak ÅŸu saatte otomatik kaydedildi:';
 $lang['nosecedit']             = 'Sayfa yakın zamanda değiştirilmiştir, bölüm bilgisi eski kalmıştır. Bunun için bölüm yerine tüm sayfa yüklenmiştir.';
-$lang['searchcreatepage']      = 'Aradığınız şeyi bulamadıysanız, \'\'Sayfayı değiştir\'\' tuşuna tıklayarak girdiğiniz sorgu adıyla yeni bir sayfa oluşturabilirsiniz .';
 $lang['regmissing']            = 'Üzgünüz, tüm alanları doldurmalısınız.';
 $lang['reguexists']            = 'Üzgünüz, bu isime sahip bir kullanıcı zaten mevcut.';
 $lang['regsuccess']            = 'Kullanıcı oluşturuldu ve şifre e-posta adresine gönderildi.';
diff --git a/inc/lang/tr/searchpage.txt b/inc/lang/tr/searchpage.txt
index bdb3ddf17494ee7044f84ff082d9c692b5cad428..05660eb4fe0ce6467e01b2f8a295fcff7659539b 100644
--- a/inc/lang/tr/searchpage.txt
+++ b/inc/lang/tr/searchpage.txt
@@ -2,4 +2,3 @@
 
 Aşağıda aramanın sonuçları listelenmiştir. @CREATEPAGEINFO@
 
-===== Sonuçlar =====
diff --git a/inc/lang/uk/lang.php b/inc/lang/uk/lang.php
index 2fe447b0fbbbf2511bc6276e6905c099a099afb3..e9ed28aa3a05ca81f4e0d6229f26555ba1046c36 100644
--- a/inc/lang/uk/lang.php
+++ b/inc/lang/uk/lang.php
@@ -3,16 +3,19 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Oleksii <alexey.furashev@gmail.com>
+ * @author Vitaly <vitaly.balashov@smuzzy.com.ua>
  * @author Oleksiy Voronin <ovoronin@gmail.com>
- * @author serg_stetsuk@ukr.net
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
  * @author Uko <uko@uar.net>
  * @author Ulrikhe Lukoie <lukoie@gmail.com>
- * @author Kate Arzamastseva pshns@ukr.net
  * @author Egor Smkv <egorsmkv@gmail.com>
  * @author Max Lyashuk <m_lyashuk@ukr.net>
  * @author Pavel <pavelholovko@yandex.ru>
  * @author Maksim <nikropol@yandex.ru>
+ * @author Nina Zolotova <nina-z@i.ua>
+ * @author Roman <vsmemorial@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -73,7 +76,6 @@ $lang['badpassconfirm']        = 'Вибачте, але пароль невір
 $lang['minoredit']             = 'Незначні зміни';
 $lang['draftdate']             = 'Чернетка збережена';
 $lang['nosecedit']             = 'Сторінку змінено, дані розділу застарілі. Завантажено сторінку повністю.';
-$lang['searchcreatepage']      = 'Якщо ви не знайшли те, що ви шукали, ви можете створити або редагувати сторінку, що має таке ж ім’я, що і пошуковий запит за допомогою відповідної кнопки.';
 $lang['regmissing']            = 'Необхідно заповнити всі поля.';
 $lang['reguexists']            = 'Користувач з таким іменем вже існує.';
 $lang['regsuccess']            = 'Користувача створено. Пароль відправлено на e-mail.';
@@ -88,8 +90,11 @@ $lang['profna']                = 'Ця Вікі не підтримує змін
 $lang['profnochange']          = 'Немає змін, немає що робити.';
 $lang['profnoempty']           = 'Ім’я або e-mail не можуть бути пустими.';
 $lang['profchanged']           = 'Профіль успішно змінено.';
+$lang['profnodelete']          = 'Ця вікі не підтримує видалення користувачів.';
 $lang['profdeleteuser']        = 'Видалити аккаунт';
 $lang['profdeleted']           = 'Ваш профіль користувача буде видалено з цієї wiki.';
+$lang['profconfdelete']        = 'Я хочу видалити мій акаунт з цієї вікі.';
+$lang['profconfdeletemissing'] = 'Галочка на "Підтверджено" не поставлена';
 $lang['proffail']              = 'Профіль користувача не вдалося поновити.';
 $lang['pwdforget']             = 'Забули пароль? Отримайте новий';
 $lang['resendna']              = 'Ця Вікі не підтримує повторне відправлення пароля.';
@@ -143,6 +148,7 @@ $lang['js']['linkto']          = 'Посилання на:';
 $lang['js']['del_confirm']     = 'Дійсно знищити обрані елементи?';
 $lang['js']['restore_confirm'] = 'Дійсно відновити цю версію?';
 $lang['js']['media_diff']      = 'Переглянути різницю:';
+$lang['js']['media_diff_both'] = 'Крок за кроком';
 $lang['js']['media_diff_portions'] = 'Прогорнути';
 $lang['js']['media_select']    = 'Оберіть файли';
 $lang['js']['media_upload_btn'] = 'Завантажити';
@@ -189,10 +195,13 @@ $lang['diff_side']             = 'Поряд';
 $lang['diffprevrev']           = 'Попередня ревізія';
 $lang['diffnextrev']           = 'Наступна ревізія';
 $lang['difflastrev']           = 'Остання ревізія';
+$lang['diffbothprevrev']       = 'Порівняння попередніх версій';
+$lang['diffbothnextrev']       = 'По сторонах наступні версії';
 $lang['line']                  = 'Рядок';
 $lang['breadcrumb']            = 'Відвідано:';
 $lang['youarehere']            = 'Ви тут:';
-$lang['lastmod']               = 'В останнє змінено:';
+$lang['lastmod']               = 'Востаннє змінено:';
+$lang['by']                    = 'повз';
 $lang['deleted']               = 'знищено';
 $lang['created']               = 'створено';
 $lang['restored']              = 'відновлено стару ревізію (%s)';
@@ -204,6 +213,7 @@ $lang['tools']                 = 'Налаштування';
 $lang['user_tools']            = 'Користувальницькькі налаштування';
 $lang['site_tools']            = 'Налаштування сайту';
 $lang['page_tools']            = 'Налаштування сторінки';
+$lang['skip_to_content']       = 'Перейти до змісту';
 $lang['sidebar']               = 'Сайдбар';
 $lang['mail_newpage']          = 'сторінку додано:';
 $lang['mail_changed']          = 'сторінку змінено:';
@@ -213,6 +223,7 @@ $lang['mail_upload']           = 'завантажено файл:';
 $lang['changes_type']          = 'Переглянути зміни ';
 $lang['pages_changes']         = 'Сторінок';
 $lang['media_changes']         = 'Медіа-файли';
+$lang['both_changes']          = 'Сторінки та медіа-файли';
 $lang['qb_bold']               = 'Напівжирний текст';
 $lang['qb_italic']             = 'Курсив';
 $lang['qb_underl']             = 'Підкреслений текст';
@@ -280,6 +291,7 @@ $lang['i_modified']            = 'З причин безпеки цей скри
 Вам слід або ще раз розпакувати файли із завантаженого пакету, або звернутися до повної <a href="http://dokuwiki.org/install">інструкції з установки ДокуВікі</a>';
 $lang['i_funcna']              = 'Функція PHP <code>%s</code> не доступна. Можливо, хостинг-провайдер відключив її з якихось причин?';
 $lang['i_phpver']              = 'Версія PHP <code>%s</code> менша, ніж необхідно - <code>%s</code>. Необхідно оновити PHP.';
+$lang['i_mbfuncoverload']      = 'mbstring.func_overload має бути вимкнена у php.ini щоб запустити DokuWiki.';
 $lang['i_permfail']            = 'ДокуВікі не має прав на запис <code>%s</code>. Необхідно змінити права доступа для цієї папки!';
 $lang['i_confexists']          = '<code>%s</code> вже існує';
 $lang['i_writeerr']            = 'Неможливо створити <code>%s</code>. Необхідно перевірити права доступа для файлу/папки та створити файл вручну.';
@@ -293,9 +305,12 @@ $lang['i_policy']              = 'Початкова політика ACL';
 $lang['i_pol0']                = 'Відкрита Вікі (читання, запис та завантаження файлів для всіх)';
 $lang['i_pol1']                = 'Публічна Вікі (читання для всіх, запис та завантаження для зареєстрованих користувачів)';
 $lang['i_pol2']                = 'Закрита Вікі (читання, запис та завантаження тільки для зареєстрованих користувачів)';
+$lang['i_allowreg']            = 'Дозволити користувачам реєструватися самостійно.';
 $lang['i_retry']               = 'Повторити';
 $lang['i_license']             = 'Будь ласка, виберіть тип ліцензії, під якою Ві бажаєте опублікувати матеріал:';
 $lang['i_license_none']        = 'Не показувати жодної інформації про ліцензії.';
+$lang['i_pop_field']           = 'Будь ласка, допоможіть нам покращити DokuWiki:';
+$lang['i_pop_label']           = 'Одного разу на місяць надсилати дані про використання розробникам DokuWiki.';
 $lang['recent_global']         = 'Ви переглядаєте зміни в межах простору імен <b>%s</b>. Також можна <a href="%s">переглянути зміни в межах усієї Вікі</a>.';
 $lang['years']                 = '%d років тому';
 $lang['months']                = '%d місяців тому';
@@ -305,20 +320,35 @@ $lang['hours']                 = '%d годин тому';
 $lang['minutes']               = '%d хвилин тому';
 $lang['seconds']               = '%d секунд тому';
 $lang['wordblock']             = 'Ваші зміни не збережено, тому що вони розпізнані як такі, що містять заблокований текст(спам).';
-$lang['email_signature_text']       = 'Це повідомлення було створене ДокуВікі з
-@DOKUWIKIURL@';
+$lang['media_uploadtab']       = 'Завантажити';
 $lang['media_searchtab']       = 'Пошук';
 $lang['media_file']            = 'Файл';
 $lang['media_viewtab']         = 'Огляд';
 $lang['media_edittab']         = 'Редагувати';
 $lang['media_historytab']      = 'Історія';
+$lang['media_list_thumbs']     = 'Іконки';
+$lang['media_list_rows']       = 'Рядки';
 $lang['media_sort_name']       = 'Ім’я';
 $lang['media_sort_date']       = 'Дата';
+$lang['media_namespaces']      = 'Оберіть простір назв';
+$lang['media_files']           = 'Файли у %s';
+$lang['media_upload']          = 'Завантажити до %s';
+$lang['media_search']          = 'Шукати у %s';
+$lang['media_view']            = '%s';
+$lang['media_viewold']         = '%s до %s';
+$lang['media_edit']            = 'Редагувати %s';
+$lang['media_history']         = 'Історія %s';
 $lang['media_meta_edited']     = 'метаданні відредаговано';
 $lang['media_perm_read']       = 'Вибачте, у вас не достатньо прав для читання цього файлу.';
+$lang['media_perm_upload']     = 'Вибачте, у вас недостатньо прав, щоб завантажувати файли.';
 $lang['media_update']          = 'Завантажити нову версію';
 $lang['media_restore']         = 'Відновити цю версію';
+$lang['media_acl_warning']     = 'Список може бути не повним через обмеження ACL та приховані сторінки.';
 $lang['currentns']             = 'Поточний діапазон імен';
 $lang['searchresult']          = 'Результати пошуку';
 $lang['plainhtml']             = 'Простий HTML';
 $lang['wikimarkup']            = 'Wiki розмітка';
+$lang['page_nonexist_rev']     = 'Сторінка %s відсутня. Може бути створена як <a href="%s">%s</a>.';
+$lang['unable_to_parse_date']  = 'Не можливо розібрати параметр "%s" ';
+$lang['email_signature_text']  = 'Це повідомлення було створене ДокуВікі з
+@DOKUWIKIURL@';
diff --git a/inc/lang/uk/searchpage.txt b/inc/lang/uk/searchpage.txt
index 3889a7618c3814595700af0087875b3e461129f5..f323c4ae4c1108fb8510f37735b1c3e6b9e87be0 100644
--- a/inc/lang/uk/searchpage.txt
+++ b/inc/lang/uk/searchpage.txt
@@ -2,4 +2,3 @@
 
 Дивіться результати пошуку нижче. @CREATEPAGEINFO@
 
-===== Результати =====
diff --git a/inc/lang/vi/lang.php b/inc/lang/vi/lang.php
index ea1d053a8443ffe85207d1d226d157c156f37836..8e49dec375e3196dd4b140f4de87ec3f157a1034 100644
--- a/inc/lang/vi/lang.php
+++ b/inc/lang/vi/lang.php
@@ -59,7 +59,6 @@ $lang['badlogin']              = 'Username hoặc password không đúng.';
 $lang['minoredit']             = 'Minor Changes';
 $lang['draftdate']             = 'Bản nháp được tự động lưu lúc';
 $lang['nosecedit']             = 'Các trang web đã được thay đổi trong khi chờ đợi, phần thông tin quá hạn đã được thay thế bằng trang đầy đủ.';
-$lang['searchcreatepage']      = "Nếu bạn không thấy được những gì bạn đang tìm, bạn có thể tạo một trang mới bằng cách bấm vào nút ''Biên soạn trang này'', khi đó bạn sẽ có 1 trang mới với tên trang chính là tuwfw khóa bạn đã tìm kiếm.";
 $lang['regmissing']            = 'Bạn cần điền vào tất cả các trường';
 $lang['reguexists']            = 'Bạn khác đã dùng username này rồi.';
 $lang['regsuccess']            = 'Đã tạo username, và đã gởi password.';
diff --git a/inc/lang/vi/searchpage.txt b/inc/lang/vi/searchpage.txt
index c0c748545f08eebe6379742fd4c0eefa4da8be10..cbba3fa4825e1e986a86f7a8de0dd8d260bbb122 100644
--- a/inc/lang/vi/searchpage.txt
+++ b/inc/lang/vi/searchpage.txt
@@ -2,4 +2,3 @@
 
 Sau đây là kết quả mà bạn đã tìm. @CREATEPAGEINFO@
 
-===== Kết quả =====
diff --git a/inc/lang/zh-tw/lang.php b/inc/lang/zh-tw/lang.php
index bc49b33dcafbcd69eab4915dc556ffda17aef802..e7384cffb81d4bd1023dfb427aa7deb933c8e700 100644
--- a/inc/lang/zh-tw/lang.php
+++ b/inc/lang/zh-tw/lang.php
@@ -77,7 +77,6 @@ $lang['badpassconfirm']        = '抱歉,這密碼是錯的';
 $lang['minoredit']             = '小修改';
 $lang['draftdate']             = '草稿已自動存檔於';
 $lang['nosecedit']             = '在您編輯期間,其他使用者修改過本頁面。區段資料已逾時,因此系統載入了全頁,以取代之。';
-$lang['searchcreatepage']      = '若沒找到您想要的,可按下按鈕建立或編輯和查詢關鍵字同名的頁面。';
 $lang['regmissing']            = '很抱歉,所有欄位都要填寫。';
 $lang['reguexists']            = '很抱歉,有人已使用了這個帳號。';
 $lang['regsuccess']            = '使用者帳號已建立,密碼已寄發至該電郵。';
diff --git a/inc/lang/zh-tw/searchpage.txt b/inc/lang/zh-tw/searchpage.txt
index 96680019d5c878401fe212bb77e117a19b49248a..9e2c13ac7c0224d4ac527550dc127c963d584a57 100644
--- a/inc/lang/zh-tw/searchpage.txt
+++ b/inc/lang/zh-tw/searchpage.txt
@@ -2,4 +2,3 @@
 
 提示:您可以在下面找到您的搜尋結果。@CREATEPAGEINFO@
 
-===== 搜尋結果 =====
diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php
index ca29231b52cce199d9013a2dc7ddebb535b70da5..3de6a2f1cee98ed6fa96c29ced62476f3fc95e78 100644
--- a/inc/lang/zh/lang.php
+++ b/inc/lang/zh/lang.php
@@ -3,17 +3,15 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author lempel <riverlempel@hotmail.com>
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
  * @author George Sheraton <guxd@163.com>
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author Rachel <rzhang0802@gmail.com>
  * @author Donald <donaldtcong@gmail.com>
@@ -92,7 +90,6 @@ $lang['badpassconfirm']        = '对不起,密码错误';
 $lang['minoredit']             = '细微修改';
 $lang['draftdate']             = '草稿自动保存于';
 $lang['nosecedit']             = '在您编辑期间本页刚被他人修改过,局部信息已过期,故载入全页。';
-$lang['searchcreatepage']      = '如果没有找到您想要的东西,您可以使用相应的按钮来创建或编辑该页面。';
 $lang['regmissing']            = '对不起,您必须填写所有的字段。';
 $lang['reguexists']            = '对不起,该用户名已经存在。';
 $lang['regsuccess']            = '新用户已建立,密码将通过电子邮件发送给您。';
diff --git a/inc/lang/zh/searchpage.txt b/inc/lang/zh/searchpage.txt
index be7ae7909262120e1e3c25a514f0e6c25297f2c5..0ea6cb5e4352b83de22e8fa6675560e669e4862e 100644
--- a/inc/lang/zh/searchpage.txt
+++ b/inc/lang/zh/searchpage.txt
@@ -2,4 +2,3 @@
 
 下面将显示您的搜索结果。@CREATEPAGEINFO@
 
-===== 搜索结果 =====
\ No newline at end of file
diff --git a/inc/load.php b/inc/load.php
index d2a0e34427cde39a3079472e2f9cc10756d56921..2131b9d62b14a8f29ea705cf9cdbdc42ab9b4598 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -15,7 +15,6 @@ require_once(DOKU_INC.'inc/changelog.php');
 require_once(DOKU_INC.'inc/common.php');
 require_once(DOKU_INC.'inc/confutils.php');
 require_once(DOKU_INC.'inc/pluginutils.php');
-require_once(DOKU_INC.'inc/plugin.php');
 require_once(DOKU_INC.'inc/events.php');
 require_once(DOKU_INC.'inc/form.php');
 require_once(DOKU_INC.'inc/fulltext.php');
@@ -64,7 +63,6 @@ function load_autoload($name){
         'cache_renderer'        => DOKU_INC.'inc/cache.php',
         'Doku_Event'            => DOKU_INC.'inc/events.php',
         'Doku_Event_Handler'    => DOKU_INC.'inc/events.php',
-        'EmailAddressValidator' => DOKU_INC.'inc/EmailAddressValidator.php',
         'Input'                 => DOKU_INC.'inc/Input.class.php',
         'JpegMeta'              => DOKU_INC.'inc/JpegMeta.php',
         'SimplePie'             => DOKU_INC.'inc/SimplePie.php',
@@ -74,8 +72,6 @@ function load_autoload($name){
         'IXR_Error'             => DOKU_INC.'inc/IXR_Library.php',
         'IXR_IntrospectionServer' => DOKU_INC.'inc/IXR_Library.php',
         'Doku_Plugin_Controller'=> DOKU_INC.'inc/plugincontroller.class.php',
-        'Tar'                   => DOKU_INC.'inc/Tar.class.php',
-        'ZipLib'                => DOKU_INC.'inc/ZipLib.class.php',
         'Doku_Parser_Mode'      => DOKU_INC.'inc/parser/parser.php',
         'Doku_Parser_Mode_Plugin' => DOKU_INC.'inc/parser/parser.php',
         'SafeFN'                => DOKU_INC.'inc/SafeFN.class.php',
@@ -85,13 +81,18 @@ function load_autoload($name){
         'RemoteAPI'             => DOKU_INC.'inc/remote.php',
         'RemoteAPICore'         => DOKU_INC.'inc/RemoteAPICore.php',
         'Subscription'          => DOKU_INC.'inc/subscription.php',
-        'lessc'                 => DOKU_INC.'inc/lessc.inc.php',
+
+        'DokuWiki_PluginInterface' => DOKU_INC.'inc/PluginInterface.php',
+        'DokuWiki_PluginTrait'     => DOKU_INC.'inc/PluginTrait.php',
+        'DokuWiki_Plugin'          => DOKU_INC.'inc/Plugin.php',
+
 
         'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
         'DokuWiki_Admin_Plugin'  => DOKU_PLUGIN.'admin.php',
         'DokuWiki_Syntax_Plugin' => DOKU_PLUGIN.'syntax.php',
         'DokuWiki_Remote_Plugin' => DOKU_PLUGIN.'remote.php',
         'DokuWiki_Auth_Plugin'   => DOKU_PLUGIN.'auth.php',
+        'DokuWiki_CLI_Plugin'    => DOKU_PLUGIN.'cli.php',
 
         'Doku_Renderer'          => DOKU_INC.'inc/parser/renderer.php',
         'Doku_Renderer_xhtml'    => DOKU_INC.'inc/parser/xhtml.php',
@@ -135,12 +136,15 @@ function load_autoload($name){
 
     // our own namespace
     if(substr($name, 0, 9) == 'dokuwiki/') {
-        require substr($name, 9) . '.php';
-        return true;
+        $file = DOKU_INC . 'inc/' . substr($name, 9) . '.php';
+        if(file_exists($file)) {
+            require $file;
+            return true;
+        }
     }
 
     // Plugin loading
-    if(preg_match('/^(auth|helper|syntax|action|admin|renderer|remote)_plugin_('.DOKU_PLUGIN_NAME_REGEX.')(?:_([^_]+))?$/',
+    if(preg_match('/^(auth|helper|syntax|action|admin|renderer|remote|cli)_plugin_('.DOKU_PLUGIN_NAME_REGEX.')(?:_([^_]+))?$/',
                   $name, $m)) {
         // try to load the wanted plugin file
         $c = ((count($m) === 4) ? "/{$m[3]}" : '');
diff --git a/inc/mail.php b/inc/mail.php
index 1d02fd6891000ddc9089dc013b1293a9c0cbe5de..f72dbdeec3519b454cbdad44aafedfff2ecb93d0 100644
--- a/inc/mail.php
+++ b/inc/mail.php
@@ -210,12 +210,12 @@ function mail_encode_address($string,$header='',$names=true){
 
         // FIXME: is there a way to encode the localpart of a emailaddress?
         if(!utf8_isASCII($addr)){
-            msg(htmlspecialchars("E-Mail address <$addr> is not ASCII"),-1);
+            msg(hsc("E-Mail address <$addr> is not ASCII"),-1);
             continue;
         }
 
         if(!mail_isvalid($addr)){
-            msg(htmlspecialchars("E-Mail address <$addr> is not valid"),-1);
+            msg(hsc("E-Mail address <$addr> is not valid"),-1);
             continue;
         }
 
@@ -267,10 +267,8 @@ function mail_encode_address($string,$header='',$names=true){
  * @param   string $email the address to check
  * @return  bool          true if address is valid
  */
-function mail_isvalid($email){
-    $validator = new EmailAddressValidator;
-    $validator->allowLocalAddresses = true;
-    return $validator->check_email_address($email);
+function mail_isvalid($email) {
+    return EmailAddressValidator::checkEmailAddress($email, true);
 }
 
 /**
diff --git a/inc/media.php b/inc/media.php
index 45565db083b7577b159c0f43f71e8a98111c045a..1284660612238036124208676005d5a47dfb61fd 100644
--- a/inc/media.php
+++ b/inc/media.php
@@ -1486,11 +1486,18 @@ function media_searchlist($query,$ns,$auth=null,$fullscreen=false,$sort='natural
         'data'  => array(),
         'query' => $query
     );
-    if ($query) {
+    if (!blank($query)) {
         $evt = new Doku_Event('MEDIA_SEARCH', $evdata);
         if ($evt->advise_before()) {
             $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
-            $pattern = '/'.preg_quote($evdata['query'],'/').'/i';
+            $quoted = preg_quote($evdata['query'],'/');
+            //apply globbing
+            $quoted = str_replace(array('\*', '\?'), array('.*', '.'), $quoted, $count);
+
+            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
+            if ($count > 0) $quoted = '^([^:]*:)*'.$quoted.'$';
+
+            $pattern = '/'.$quoted.'/i';
             search($evdata['data'],
                     $conf['mediadir'],
                     'search_media',
@@ -1734,9 +1741,9 @@ function media_printimgdetail($item, $fullscreen=false){
     // print EXIF/IPTC data
     if($t || $d || $k ){
         echo '<p>';
-        if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />';
-        if($d) echo htmlspecialchars($d).'<br />';
-        if($t) echo '<em>'.htmlspecialchars($k).'</em>';
+        if($t) echo '<strong>'.hsc($t).'</strong><br />';
+        if($d) echo hsc($d).'<br />';
+        if($t) echo '<em>'.hsc($k).'</em>';
         echo '</p>';
     }
     echo '</div>';
@@ -2453,4 +2460,39 @@ function media_supportedav($mime, $type=NULL){
     return in_array($mime, $supportedAv);
 }
 
+/**
+ * Return track media files with the same base name
+ * but extensions that indicate kind and lang.
+ * ie for foo.webm search foo.sub.lang.vtt, foo.cap.lang.vtt...
+ *
+ * @param string   $src     - ID of media file
+ * @return array            - array(mediaID => array( kind, srclang ))
+ *
+ * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
+ */
+function media_trackfiles($src){
+    $kinds=array(
+        'sub' => 'subtitles',
+        'cap' => 'captions',
+        'des' => 'descriptions',
+        'cha' => 'chapters',
+        'met' => 'metadata'
+    );
+
+    $files = array();
+    $re='/\\.(sub|cap|des|cha|met)\\.([^.]+)\\.vtt$/';
+    $baseid=pathinfo($src, PATHINFO_FILENAME);
+    $pattern=mediaFN($baseid).'.*.*.vtt';
+    $list=glob($pattern);
+    foreach($list as $track) {
+        if(preg_match($re, $track, $matches)){
+            $files[$baseid.'.'.$matches[1].'.'.$matches[2].'.vtt']=array(
+                $kinds[$matches[1]],
+                $matches[2],
+            );
+        }
+    }
+    return $files;
+}
+
 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
diff --git a/inc/parser/code.php b/inc/parser/code.php
index fe93273e53968ae85d5950796a74c76460484735..f91f1d2289161ad0453970e4471bda0c6b2fba89 100644
--- a/inc/parser/code.php
+++ b/inc/parser/code.php
@@ -21,6 +21,7 @@ class Doku_Renderer_code extends Doku_Renderer {
     function code($text, $language = null, $filename = '') {
         global $INPUT;
         if(!$language) $language = 'txt';
+        $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
         if(!$filename) $filename = 'snippet.'.$language;
         $filename = utf8_basename($filename);
         $filename = utf8_stripspecials($filename, '_');
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index 5ffb5cc009612536aa9c0004ad9f6aa223d9ce2f..8cff2b8be46c0c1bb14800f5094994d194987564 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -903,7 +903,7 @@ class Doku_Parser_Mode_internallink extends Doku_Parser_Mode {
 
     function connectTo($mode) {
         // Word boundaries?
-        $this->Lexer->addSpecialPattern("\[\[(?:(?:[^[\]]*?\[.*?\])|.*?)\]\]",$mode,'internallink');
+        $this->Lexer->addSpecialPattern("\[\[.*?\]\](?!\])",$mode,'internallink');
     }
 
     function getSort() {
@@ -955,8 +955,8 @@ class Doku_Parser_Mode_externallink extends Doku_Parser_Mode {
             $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
         }
 
-        $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
-        $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
+        $this->patterns[] = '(?<=\s)(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
+        $this->patterns[] = '(?<=\s)(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
     }
 
     function connectTo($mode) {
@@ -1004,7 +1004,7 @@ class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode {
     var $pattern;
 
     function preConnect() {
-        $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w-$]+)+";
+        $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w\-$]+)+";
     }
 
     function connectTo($mode) {
diff --git a/inc/parser/renderer.php b/inc/parser/renderer.php
index 8142a4107eb8280ab44d183c8d0a9c2ee4a82287..83b51d4b13ffbd12c85220bd0016f20066410adf 100644
--- a/inc/parser/renderer.php
+++ b/inc/parser/renderer.php
@@ -7,6 +7,12 @@
  */
 if(!defined('DOKU_INC')) die('meh.');
 
+/**
+ * Allowed chars in $language for code highlighting
+ * @see GeSHi::set_language()
+ */
+define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#');
+
 /**
  * An empty renderer, produces no output
  *
@@ -839,19 +845,29 @@ class Doku_Renderer extends DokuWiki_Plugin {
                                     return rawurlencode($match[0]);
                                   }, $reference), $url);
             $parsed = parse_url($reference);
-            if(!$parsed['port']) $parsed['port'] = 80;
-            $url = str_replace('{SCHEME}', $parsed['scheme'], $url);
-            $url = str_replace('{HOST}', $parsed['host'], $url);
-            $url = str_replace('{PORT}', $parsed['port'], $url);
-            $url = str_replace('{PATH}', $parsed['path'], $url);
-            $url = str_replace('{QUERY}', $parsed['query'], $url);
+            if (empty($parsed['scheme'])) $parsed['scheme'] = '';
+            if (empty($parsed['host'])) $parsed['host'] = '';
+            if (empty($parsed['port'])) $parsed['port'] = 80;
+            if (empty($parsed['path'])) $parsed['path'] = '';
+            if (empty($parsed['query'])) $parsed['query'] = '';
+            $url = strtr($url,[
+                '{SCHEME}' => $parsed['scheme'],
+                '{HOST}' => $parsed['host'],
+                '{PORT}' => $parsed['port'],
+                '{PATH}' => $parsed['path'],
+                '{QUERY}' => $parsed['query'] ,
+            ]);
         } else {
             //default
             $url = $url.rawurlencode($reference);
         }
         //handle as wiki links
         if($url{0} === ':') {
-            list($id, $urlparam) = explode('?', $url, 2);
+            $urlparam = null;
+            $id = $url;
+            if (strpos($url, '?') !== false) {
+                list($id, $urlparam) = explode('?', $url, 2);
+            }
             $url    = wl(cleanID($id), $urlparam);
             $exists = page_exists($id);
         }
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 2ff12f0d914906c1365b2124ac41d1fc81027f5e..606d0816e7a7a5291f2b598a325505ee96592f76 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -59,16 +59,31 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     /**
      * Register a new edit section range
      *
-     * @param string $type   The section type identifier
-     * @param string $title  The section title
      * @param int    $start  The byte position for the edit start
+     * @param array  $data   Associative array with section data:
+     *                       Key 'name': the section name/title
+     *                       Key 'target': the target for the section edit,
+     *                                     e.g. 'section' or 'table'
+     *                       Key 'hid': header id
+     *                       Key 'codeblockOffset': actual code block index
+     *                       Key 'start': set in startSectionEdit(),
+     *                                    do not set yourself
+     *                       Key 'range': calculated from 'start' and
+     *                                    $key in finishSectionEdit(),
+     *                                    do not set yourself
      * @return string  A marker class for the starting HTML element
      *
      * @author Adrian Lang <lang@cosmocode.de>
      */
-    public function startSectionEdit($start, $type, $title = null) {
-        $this->sectionedits[] = array(++$this->lastsecid, $start, $type, $title);
-        return 'sectionedit'.$this->lastsecid;
+    public function startSectionEdit($start, $data) {
+        if (!is_array($data)) {
+            msg('startSectionEdit: $data is NOT an array!', -1);
+            return '';
+        }
+        $data['secid'] = ++$this->lastsecid;
+        $data['start'] = $start;
+        $this->sectionedits[] = $data;
+        return 'sectionedit'.$data['secid'];
     }
 
     /**
@@ -78,16 +93,17 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      *
      * @author Adrian Lang <lang@cosmocode.de>
      */
-    public function finishSectionEdit($end = null) {
-        list($id, $start, $type, $title) = array_pop($this->sectionedits);
-        if(!is_null($end) && $end <= $start) {
+    public function finishSectionEdit($end = null, $hid = null) {
+        $data = array_pop($this->sectionedits);
+        if(!is_null($end) && $end <= $data['start']) {
             return;
         }
-        $this->doc .= "<!-- EDIT$id ".strtoupper($type).' ';
-        if(!is_null($title)) {
-            $this->doc .= '"'.str_replace('"', '', $title).'" ';
+        if(!is_null($hid)) {
+            $data['hid'] .= $hid;
         }
-        $this->doc .= "[$start-".(is_null($end) ? '' : $end).'] -->';
+        $data['range'] = $data['start'].'-'.(is_null($end) ? '' : $end);
+        unset($data['start']);
+        $this->doc .= '<!-- EDIT'.json_encode ($data).' -->';
     }
 
     /**
@@ -114,7 +130,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     function document_end() {
         // Finish open section edits.
         while(count($this->sectionedits) > 0) {
-            if($this->sectionedits[count($this->sectionedits) - 1][1] <= 1) {
+            if($this->sectionedits[count($this->sectionedits) - 1]['start'] <= 1) {
                 // If there is only one section, do not write a section edit
                 // marker.
                 array_pop($this->sectionedits);
@@ -209,7 +225,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
         if($level <= $conf['maxseclevel'] &&
             count($this->sectionedits) > 0 &&
-            $this->sectionedits[count($this->sectionedits) - 1][2] === 'section'
+            $this->sectionedits[count($this->sectionedits) - 1]['target'] === 'section'
         ) {
             $this->finishSectionEdit($pos - 1);
         }
@@ -217,7 +233,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
         // write the header
         $this->doc .= DOKU_LF.'<h'.$level;
         if($level <= $conf['maxseclevel']) {
-            $this->doc .= ' class="'.$this->startSectionEdit($pos, 'section', $text).'"';
+            $data = array();
+            $data['target'] = 'section';
+            $data['name'] = $text;
+            $data['hid'] = $hid;
+            $data['codeblockOffset'] = $this->_codeblock;
+            $this->doc .= ' class="'.$this->startSectionEdit($pos, $data).'"';
         }
         $this->doc .= ' id="'.$hid.'">';
         $this->doc .= $this->_xmlEntities($text);
@@ -632,6 +653,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     function _highlight($type, $text, $language = null, $filename = null, $options = null) {
         global $ID;
         global $lang;
+        global $INPUT;
+
+        $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
 
         if($filename) {
             // add icon
@@ -639,8 +663,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
             $class = 'mediafile mf_'.$class;
 
+            $offset = 0;
+            if ($INPUT->has('codeblockOffset')) {
+                $offset = $INPUT->str('codeblockOffset');
+            }
             $this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
-            $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
+            $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $offset+$this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
             $this->doc .= hsc($filename);
             $this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
         }
@@ -652,7 +680,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $text = substr($text, 0, -1);
         }
 
-        if(is_null($language)) {
+        if(empty($language)) { // empty is faster than is_null and can prevent '' string
             $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
         } else {
             $class = 'code'; //we always need the code class to make the syntax highlighting apply
@@ -887,7 +915,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
         $link['more']   = '';
         $link['class']  = $class;
         if($this->date_at) {
-            $params['at'] = $this->date_at;
+            $params = $params.'&at='.rawurlencode($this->date_at);
         }
         $link['url']    = wl($id, $params);
         $link['name']   = $name;
@@ -1136,7 +1164,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     function internalmedia($src, $title = null, $align = null, $width = null,
                            $height = null, $cache = null, $linking = null, $return = false) {
         global $ID;
-        list($src, $hash) = explode('#', $src, 2);
+        if (strpos($src, '#') !== false) {
+            list($src, $hash) = explode('#', $src, 2);
+        }
         resolve_mediaid(getNS($ID), $src, $exists, $this->date_at, true);
 
         $noLink = false;
@@ -1157,7 +1187,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
         }
 
-        if($hash) $link['url'] .= '#'.$hash;
+        if (!empty($hash)) $link['url'] .= '#'.$hash;
 
         //markup non existing files
         if(!$exists) {
@@ -1288,7 +1318,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
                     if($author) {
                         $name = $author->get_name();
                         if(!$name) $name = $author->get_email();
-                        if($name) $this->doc .= ' '.$lang['by'].' '.$name;
+                        if($name) $this->doc .= ' '.$lang['by'].' '.hsc($name);
                     }
                 }
                 if($params['date']) {
@@ -1335,7 +1365,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $class .= ' ' . $classes;
         }
         if($pos !== null) {
-            $class .= ' '.$this->startSectionEdit($pos, 'table');
+            $hid = $this->_headerToLink($class, true);
+            $data = array();
+            $data['target'] = 'table';
+            $data['name'] = '';
+            $data['hid'] = $hid;
+            $class .= ' '.$this->startSectionEdit($pos, $data);
         }
         $this->doc .= '<div class="'.$class.'"><table class="inline">'.
             DOKU_LF;
@@ -1778,6 +1813,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * Embed video(s) in HTML
      *
      * @author Anika Henke <anika@selfthinker.org>
+     * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
      *
      * @param string $src         - ID of video to embed
      * @param int    $width       - width of the video in pixels
@@ -1795,6 +1831,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
         $posterUrl = '';
         $files = array();
+        $tracks = array();
         $isExternal = media_isexternal($src);
 
         if ($isExternal) {
@@ -1806,6 +1843,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $extensions   = array('webm', 'ogv', 'mp4');
             $files        = media_alternativefiles($src, $extensions);
             $poster       = media_alternativefiles($src, array('jpg', 'png'));
+            $tracks       = media_trackfiles($src);
             if(!empty($poster)) {
                 $posterUrl = ml(reset($poster), '', true, '&');
             }
@@ -1834,6 +1872,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
         }
 
+        // output each track if any
+        foreach( $tracks as $trackid => $info ) {
+            list( $kind, $srclang ) = array_map( 'hsc', $info );
+            $out .= "<track kind=\"$kind\" srclang=\"$srclang\" ";
+            $out .= "label=\"$srclang\" ";
+            $out .= 'src="'.ml($trackid, '', true).'">'.NL;
+        }
+
         // finish
         $out .= $fallback;
         $out .= '</video>'.NL;
diff --git a/inc/parserutils.php b/inc/parserutils.php
index 7933adaf3dde235fc0c89540b09806bd37e7a430..5b0cab06ede2f501d1888925cbea93e371863d99 100644
--- a/inc/parserutils.php
+++ b/inc/parserutils.php
@@ -337,13 +337,13 @@ function p_set_metadata($id, $data, $render=false, $persistent=true){
 
             foreach ($value as $subkey => $subvalue){
                 if(isset($meta['current'][$key][$subkey]) && is_array($meta['current'][$key][$subkey])) {
-                    $meta['current'][$key][$subkey] = array_merge($meta['current'][$key][$subkey], (array)$subvalue);
+                    $meta['current'][$key][$subkey] = array_replace($meta['current'][$key][$subkey], (array)$subvalue);
                 } else {
                     $meta['current'][$key][$subkey] = $subvalue;
                 }
                 if($persistent) {
                     if(isset($meta['persistent'][$key][$subkey]) && is_array($meta['persistent'][$key][$subkey])) {
-                        $meta['persistent'][$key][$subkey] = array_merge($meta['persistent'][$key][$subkey], (array)$subvalue);
+                        $meta['persistent'][$key][$subkey] = array_replace($meta['persistent'][$key][$subkey], (array)$subvalue);
                     } else {
                         $meta['persistent'][$key][$subkey] = $subvalue;
                     }
@@ -355,10 +355,10 @@ function p_set_metadata($id, $data, $render=false, $persistent=true){
 
             // these keys, must have subkeys - a legitimate value must be an array
             if (is_array($value)) {
-                $meta['current'][$key] = !empty($meta['current'][$key]) ? array_merge((array)$meta['current'][$key],$value) : $value;
+                $meta['current'][$key] = !empty($meta['current'][$key]) ? array_replace((array)$meta['current'][$key],$value) : $value;
 
                 if ($persistent) {
-                    $meta['persistent'][$key] = !empty($meta['persistent'][$key]) ? array_merge((array)$meta['persistent'][$key],$value) : $value;
+                    $meta['persistent'][$key] = !empty($meta['persistent'][$key]) ? array_replace((array)$meta['persistent'][$key],$value) : $value;
                 }
             }
 
diff --git a/inc/plugin.php b/inc/plugin.php
deleted file mode 100644
index 8a90c0a6efedf06c7c3dad3ef8aa0edaa57fa897..0000000000000000000000000000000000000000
--- a/inc/plugin.php
+++ /dev/null
@@ -1,300 +0,0 @@
-<?php
-/**
- * DokuWiki Plugin base class
- *
- * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author     Christopher Smith <chris@jalakai.co.uk>
- */
-
-/**
- * Do not inherit directly from this class, instead inherit from the specialized
- * ones in lib/plugin
- */
-class DokuWiki_Plugin {
-
-    protected $localised = false;        // set to true by setupLocale() after loading language dependent strings
-    protected $lang = array();           // array to hold language dependent strings, best accessed via ->getLang()
-    protected $configloaded = false;     // set to true by loadConfig() after loading plugin configuration variables
-    protected $conf = array();           // array to hold plugin settings, best accessed via ->getConf()
-
-    /**
-     * General Info
-     *
-     * Needs to return a associative array with the following values:
-     *
-     * base   - the plugin's base name (eg. the directory it needs to be installed in)
-     * author - Author of the plugin
-     * email  - Email address to contact the author
-     * date   - Last modified date of the plugin in YYYY-MM-DD format
-     * name   - Name of the plugin
-     * desc   - Short description of the plugin (Text only)
-     * url    - Website with more information on the plugin (eg. syntax description)
-     */
-    public function getInfo(){
-        $parts = explode('_', get_class($this));
-        $info = DOKU_PLUGIN . '/' . $parts[2] . '/plugin.info.txt';
-        if(file_exists($info)) return confToHash($info);
-
-        msg(
-            'getInfo() not implemented in ' . get_class($this) . ' and ' . $info . ' not found.<br />' .
-            'Verify you\'re running the latest version of the plugin. If the problem persists, send a ' .
-            'bug report to the author of the ' . $parts[2] . ' plugin.', -1
-        );
-        return array(
-            'date' => '0000-00-00',
-            'name' => $parts[2] . ' plugin',
-        );
-    }
-
-    // plugin introspection methods
-    // extract from class name, format = <plugin type>_plugin_<name>[_<component name>]
-    /**
-     * @return string  plugin type
-     */
-    public function getPluginType() {
-        list($t) = explode('_', get_class($this), 2);
-        return $t;
-    }
-
-    /**
-     * @return string  plugin name
-     */
-    public function getPluginName() {
-        list(/* $t */, /* $p */, $n) = explode('_', get_class($this), 4);
-        return $n;
-    }
-
-    /**
-     * @return string  component name
-     */
-    public function getPluginComponent() {
-        list(/* $t */, /* $p */, /* $n */, $c) = explode('_', get_class($this), 4);
-        return (isset($c)?$c:'');
-    }
-
-    // localisation methods
-    /**
-     * getLang($id)
-     * use this function to access plugin language strings
-     * to try to minimise unnecessary loading of the strings when the plugin doesn't require them
-     * e.g. when info plugin is querying plugins for information about themselves.
-     *
-     * @param   string  $id     id of the string to be retrieved
-     * @return  string  string in appropriate language or english if not available
-     */
-    public function getLang($id) {
-        if (!$this->localised) $this->setupLocale();
-
-        return (isset($this->lang[$id]) ? $this->lang[$id] : '');
-    }
-
-    /**
-     * locale_xhtml($id)
-     *
-     * retrieve a language dependent file and pass to xhtml renderer for display
-     * plugin equivalent of p_locale_xhtml()
-     *
-     * @param   string $id id of language dependent wiki page
-     * @return  string     parsed contents of the wiki page in xhtml format
-     */
-    public function locale_xhtml($id) {
-        return p_cached_output($this->localFN($id));
-    }
-
-    /**
-     * Prepends appropriate path for a language dependent filename
-     * plugin equivalent of localFN()
-     *
-     * @param string $id id of localization file
-     * @param  string $ext The file extension (usually txt)
-     * @return string wiki text
-     */
-    public function localFN($id,$ext='txt') {
-        global $conf;
-        $plugin = $this->getPluginName();
-        $file = DOKU_CONF.'plugin_lang/'.$plugin.'/'.$conf['lang'].'/'.$id.'.'.$ext;
-        if (!file_exists($file)){
-            $file = DOKU_PLUGIN.$plugin.'/lang/'.$conf['lang'].'/'.$id.'.'.$ext;
-            if(!file_exists($file)){
-                //fall back to english
-                $file = DOKU_PLUGIN.$plugin.'/lang/en/'.$id.'.'.$ext;
-            }
-        }
-        return $file;
-    }
-
-    /**
-     * Reads all the plugins language dependent strings into $this->lang
-     * this function is automatically called by getLang()
-     */
-    function setupLocale() {
-        if($this->localised) return;
-
-        global $conf, $config_cascade; // definitely don't invoke "global $lang"
-        $path = DOKU_PLUGIN . $this->getPluginName() . '/lang/';
-
-        $lang = array();
-
-        // don't include once, in case several plugin components require the same language file
-        @include($path . 'en/lang.php');
-        foreach($config_cascade['lang']['plugin'] as $config_file) {
-            if(file_exists($config_file . $this->getPluginName() . '/en/lang.php')) {
-                include($config_file . $this->getPluginName() . '/en/lang.php');
-            }
-        }
-
-        if($conf['lang'] != 'en') {
-            @include($path . $conf['lang'] . '/lang.php');
-            foreach($config_cascade['lang']['plugin'] as $config_file) {
-                if(file_exists($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php')) {
-                    include($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php');
-                }
-            }
-        }
-
-        $this->lang = $lang;
-        $this->localised = true;
-    }
-
-    // configuration methods
-    /**
-     * getConf($setting)
-     *
-     * use this function to access plugin configuration variables
-     *
-     * @param string $setting the setting to access
-     * @param mixed  $notset  what to return if the setting is not available
-     * @return mixed
-     */
-    public function getConf($setting, $notset=false){
-
-        if (!$this->configloaded){ $this->loadConfig(); }
-
-        if(isset($this->conf[$setting])){
-            return $this->conf[$setting];
-        }else{
-            return $notset;
-        }
-    }
-
-    /**
-     * loadConfig()
-     * merges the plugin's default settings with any local settings
-     * this function is automatically called through getConf()
-     */
-    function loadConfig(){
-        global $conf;
-
-        $defaults = $this->readDefaultSettings();
-        $plugin = $this->getPluginName();
-
-        foreach ($defaults as $key => $value) {
-            if (isset($conf['plugin'][$plugin][$key])) continue;
-            $conf['plugin'][$plugin][$key] = $value;
-        }
-
-        $this->configloaded = true;
-        $this->conf =& $conf['plugin'][$plugin];
-    }
-
-    /**
-     * read the plugin's default configuration settings from conf/default.php
-     * this function is automatically called through getConf()
-     *
-     * @return    array    setting => value
-     */
-    protected function readDefaultSettings() {
-
-        $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
-        $conf = array();
-
-        if (file_exists($path.'default.php')) {
-            include($path.'default.php');
-        }
-
-        return $conf;
-    }
-
-    /**
-     * Loads a given helper plugin (if enabled)
-     *
-     * @author  Esther Brunner <wikidesign@gmail.com>
-     *
-     * @param   string $name   name of plugin to load
-     * @param   bool   $msg    if a message should be displayed in case the plugin is not available
-     * @return  DokuWiki_Plugin|null helper plugin object
-     */
-    public function loadHelper($name, $msg = true){
-        $obj = plugin_load('helper',$name);
-        if (is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.",-1);
-        return $obj;
-    }
-
-    // standard functions for outputing email addresses and links
-    // use these to avoid having to duplicate code to produce links in line with the installation configuration
-
-    /**
-     * email
-     * standardised function to generate an email link according to obfuscation settings
-     *
-     * @param string $email
-     * @param string $name
-     * @param string $class
-     * @param string $more
-     * @return string html
-     */
-    public function email($email, $name='', $class='', $more='') {
-        if (!$email) return $name;
-        $email = obfuscate($email);
-        if (!$name) $name = $email;
-        $class = "class='".($class ? $class : 'mail')."'";
-        return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
-    }
-
-    /**
-     * external_link
-     * standardised function to generate an external link according to conf settings
-     *
-     * @param string $link
-     * @param string $title
-     * @param string $class
-     * @param string $target
-     * @param string $more
-     * @return string
-     */
-    public function external_link($link, $title='', $class='', $target='', $more='') {
-        global $conf;
-
-        $link = htmlentities($link);
-        if (!$title) $title = $link;
-        if (!$target) $target = $conf['target']['extern'];
-        if ($conf['relnofollow']) $more .= ' rel="nofollow"';
-
-        if ($class) $class = " class='$class'";
-        if ($target) $target = " target='$target'";
-        if ($more) $more = " ".trim($more);
-
-        return "<a href='$link'$class$target$more>$title</a>";
-    }
-
-    /**
-     * output text string through the parser, allows dokuwiki markup to be used
-     * very ineffecient for small pieces of data - try not to use
-     *
-     * @param string $text   wiki markup to parse
-     * @param string $format output format
-     * @return null|string
-     */
-    public function render_text($text, $format='xhtml') {
-        return p_render($format, p_get_instructions($text),$info);
-    }
-
-    /**
-     * Allow the plugin to prevent DokuWiki from reusing an instance
-     *
-     * @return bool   false if the plugin has to be instantiated
-     */
-    public function isSingleton() {
-        return true;
-    }
-}
diff --git a/inc/plugincontroller.class.php b/inc/plugincontroller.class.php
index 5bb07531e919fd772b1872d0e349753e4353080f..fd8cd9663289922177a202ce27c2060474b4dd09 100644
--- a/inc/plugincontroller.class.php
+++ b/inc/plugincontroller.class.php
@@ -66,7 +66,7 @@ class Doku_Plugin_Controller {
      * @param  $name     string name of the plugin to load
      * @param  $new      bool   true to return a new instance of the plugin, false to use an already loaded instance
      * @param  $disabled bool   true to load even disabled plugins
-     * @return DokuWiki_Plugin|DokuWiki_Syntax_Plugin|DokuWiki_Auth_Plugin|DokuWiki_Admin_Plugin|DokuWiki_Action_Plugin|DokuWiki_Remote_Plugin|null  the plugin object or null on failure
+     * @return DokuWiki_PluginInterface|null  the plugin object or null on failure
      */
     public function load($type,$name,$new=false,$disabled=false){
 
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
index 60f79869fa3a62633e15a7c58d070f81d3868963..a395be43512ba5c4afe766353797200f67582ca3 100644
--- a/inc/pluginutils.php
+++ b/inc/pluginutils.php
@@ -37,7 +37,7 @@ function plugin_list($type='',$all=false) {
  * @param  $name     string name of the plugin to load
  * @param  $new      bool   true to return a new instance of the plugin, false to use an already loaded instance
  * @param  $disabled bool   true to load even disabled plugins
- * @return DokuWiki_Plugin|null  the plugin object or null on failure
+ * @return DokuWiki_PluginInterface|null  the plugin object or null on failure
  */
 function plugin_load($type,$name,$new=false,$disabled=false) {
     /** @var $plugin_controller Doku_Plugin_Controller */
diff --git a/inc/search.php b/inc/search.php
index 3c1d435f5e4903b30a96f3e0f64fbdd163fbae1b..14cd0f89c04910120306bafd6ea2449ff30e57e1 100644
--- a/inc/search.php
+++ b/inc/search.php
@@ -333,14 +333,14 @@ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){
 
     $item = array();
     $item['id']   = pathID($file);
-    if(!$opts['skipacl'] && auth_quickaclcheck($item['id']) < AUTH_READ){
+    if(isset($opts['skipacl']) && !$opts['skipacl'] && auth_quickaclcheck($item['id']) < AUTH_READ){
         return false;
     }
 
     $item['rev']   = filemtime($base.'/'.$file);
     $item['mtime'] = $item['rev'];
     $item['size']  = filesize($base.'/'.$file);
-    if($opts['hash']){
+    if(!empty($opts['hash'])){
         $item['hash'] = md5(trim(rawWiki($item['id'])));
     }
 
diff --git a/inc/template.php b/inc/template.php
index 19c36abedfcc6ebe154ed6f9327708cbb8c6189d..3c828812b0c0d0260d63eb4df4359c03bf03dc49 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -93,90 +93,13 @@ function tpl_content($prependTOC = true) {
  * @return bool
  */
 function tpl_content_core() {
-    global $ACT;
-    global $TEXT;
-    global $PRE;
-    global $SUF;
-    global $SUM;
-    global $IDX;
-    global $INPUT;
-
-    switch($ACT) {
-        case 'show':
-            html_show();
-            break;
-        /** @noinspection PhpMissingBreakStatementInspection */
-        case 'locked':
-            html_locked();
-        case 'edit':
-        case 'recover':
-            html_edit();
-            break;
-        case 'preview':
-            html_edit();
-            html_show($TEXT);
-            break;
-        case 'draft':
-            html_draft();
-            break;
-        case 'search':
-            html_search();
-            break;
-        case 'revisions':
-            html_revisions($INPUT->int('first'));
-            break;
-        case 'diff':
-            html_diff();
-            break;
-        case 'recent':
-            $show_changes = $INPUT->str('show_changes');
-            if (empty($show_changes)) {
-                $show_changes = get_doku_pref('show_changes', $show_changes);
-            }
-            html_recent($INPUT->extract('first')->int('first'), $show_changes);
-            break;
-        case 'index':
-            html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly?
-            break;
-        case 'backlink':
-            html_backlinks();
-            break;
-        case 'conflict':
-            html_conflict(con($PRE, $TEXT, $SUF), $SUM);
-            html_diff(con($PRE, $TEXT, $SUF), false);
-            break;
-        case 'login':
-            html_login();
-            break;
-        case 'register':
-            html_register();
-            break;
-        case 'resendpwd':
-            html_resendpwd();
-            break;
-        case 'denied':
-            html_denied();
-            break;
-        case 'profile' :
-            html_updateprofile();
-            break;
-        case 'admin':
-            tpl_admin();
-            break;
-        case 'subscribe':
-            tpl_subscribe();
-            break;
-        case 'media':
-            tpl_media();
-            break;
-        default:
-            $evt = new Doku_Event('TPL_ACT_UNKNOWN', $ACT);
-            if($evt->advise_before()) {
-                msg("Failed to handle command: ".hsc($ACT), -1);
-            }
-            $evt->advise_after();
-            unset($evt);
-            return false;
+    $router = \dokuwiki\ActionRouter::getInstance();
+    try {
+        $router->getAction()->tplContent();
+    } catch(\dokuwiki\Action\Exception\FatalException $e) {
+        // there was no content for the action
+        msg(hsc($e->getMessage()), -1);
+        return false;
     }
     return true;
 }
@@ -319,6 +242,17 @@ function tpl_metaheaders($alt = true) {
         );
     }
 
+    if (actionOK('manifest')) {
+        $head['link'][] = array('rel'=> 'manifest', 'href'=> DOKU_BASE.'lib/exe/manifest.php');
+    }
+
+    $styleUtil = new \dokuwiki\StyleUtils();
+    $styleIni = $styleUtil->cssStyleini($conf['template']);
+    $replacements = $styleIni['replacements'];
+    if (!empty($replacements['__theme_color__'])) {
+        $head['meta'][] = array('name' => 'theme-color', 'content' => $replacements['__theme_color__']);
+    }
+
     if($alt) {
         if(actionOK('rss')) {
             $head['link'][] = array(
@@ -366,7 +300,7 @@ function tpl_metaheaders($alt = true) {
     if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
         if($INFO['exists']) {
             //delay indexing:
-            if((time() - $INFO['lastmod']) >= $conf['indexdelay']) {
+            if((time() - $INFO['lastmod']) >= $conf['indexdelay'] && !isHiddenPage($ID) ) {
                 $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
             } else {
                 $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
@@ -401,13 +335,12 @@ function tpl_metaheaders($alt = true) {
         'href'=> DOKU_BASE.'lib/exe/css.php?t='.rawurlencode($conf['template']).'&tseed='.$tseed
     );
 
-    // make $INFO and other vars available to JavaScripts
-    $json   = new JSON();
     $script = "var NS='".$INFO['namespace']."';";
     if($conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
         $script .= "var SIG='".toolbar_signature()."';";
     }
-    $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
+    jsinfo();
+    $script .= 'var JSINFO = ' . json_encode($JSINFO).';';
     $head['script'][] = array('type'=> 'text/javascript', '_data'=> $script);
 
     // load jquery
@@ -500,10 +433,13 @@ function tpl_link($url, $name, $more = '', $return = false) {
  *
  * @param string      $id   page id
  * @param string|null $name the name of the link
- * @return bool true
+ * @param bool        $return
+ * @return true|string
  */
-function tpl_pagelink($id, $name = null) {
-    print '<bdi>'.html_wikilink($id, $name).'</bdi>';
+function tpl_pagelink($id, $name = null, $return = false) {
+    $out = '<bdi>'.html_wikilink($id, $name).'</bdi>';
+    if($return) return $out;
+    print $out;
     return true;
 }
 
@@ -539,8 +475,10 @@ function tpl_getparent($id) {
  * @param string $type
  * @param bool $return
  * @return bool|string html, or false if no data, true if printed
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_button($type, $return = false) {
+    dbg_deprecated('see devel:menus');
     $data = tpl_get_action($type);
     if($data === false) {
         return false;
@@ -577,8 +515,10 @@ function tpl_button($type, $return = false) {
  * @param string $inner   innerHML of link
  * @param bool   $return  if true it returns html, otherwise prints
  * @return bool|string html or false if no data, true if printed
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
+    dbg_deprecated('see devel:menus');
     global $lang;
     $data = tpl_get_action($type);
     if($data === false) {
@@ -625,179 +565,44 @@ function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = fals
 /**
  * Check the actions and get data for buttons and links
  *
- * Available actions are
- *
- *  edit        - edit/create/show/draft
- *  history     - old revisions
- *  recent      - recent changes
- *  login       - login/logout - if ACL enabled
- *  profile     - user profile (if logged in)
- *  index       - The index
- *  admin       - admin page - if enough rights
- *  top         - back to top
- *  back        - back to parent - if available
- *  backlink    - links to the list of backlinks
- *  subscribe/subscription- subscribe/unsubscribe
- *
  * @author Andreas Gohr <andi@splitbrain.org>
  * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
  * @author Adrian Lang <mail@adrianlang.de>
  *
  * @param string $type
  * @return array|bool|string
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_get_action($type) {
-    global $ID;
-    global $INFO;
-    global $REV;
-    global $ACT;
-    global $conf;
-    /** @var Input $INPUT */
-    global $INPUT;
-
-    // check disabled actions and fix the badly named ones
+    dbg_deprecated('see devel:menus');
     if($type == 'history') $type = 'revisions';
-    if ($type == 'subscription') $type = 'subscribe';
-    if(!actionOK($type)) return false;
-
-    $accesskey   = null;
-    $id          = $ID;
-    $method      = 'get';
-    $params      = array('do' => $type);
-    $nofollow    = true;
-    $replacement = '';
-
-    $unknown = false;
-    switch($type) {
-        case 'edit':
-            // most complicated type - we need to decide on current action
-            if($ACT == 'show' || $ACT == 'search') {
-                $method = 'post';
-                if($INFO['writable']) {
-                    $accesskey = 'e';
-                    if(!empty($INFO['draft'])) {
-                        $type         = 'draft';
-                        $params['do'] = 'draft';
-                    } else {
-                        $params['rev'] = $REV;
-                        if(!$INFO['exists']) {
-                            $type = 'create';
-                        }
-                    }
-                } else {
-                    if(!actionOK('source')) return false; //pseudo action
-                    $params['rev'] = $REV;
-                    $type          = 'source';
-                    $accesskey     = 'v';
-                }
-            } else {
-                $params    = array('do' => '');
-                $type      = 'show';
-                $accesskey = 'v';
-            }
-            break;
-        case 'revisions':
-            $type      = 'revs';
-            $accesskey = 'o';
-            break;
-        case 'recent':
-            $accesskey = 'r';
-            break;
-        case 'index':
-            $accesskey = 'x';
-            // allow searchbots to get to the sitemap from the homepage (when dokuwiki isn't providing a sitemap.xml)
-            if ($conf['start'] == $ID && !$conf['sitemap']) {
-                $nofollow = false;
-            }
-            break;
-        case 'top':
-            $accesskey = 't';
-            $params    = array('do' => '');
-            $id        = '#dokuwiki__top';
-            break;
-        case 'back':
-            $parent = tpl_getparent($ID);
-            if(!$parent) {
-                return false;
-            }
-            $id        = $parent;
-            $params    = array('do' => '');
-            $accesskey = 'b';
-            break;
-        case 'img_backto':
-            $params = array();
-            $accesskey = 'b';
-            $replacement = $ID;
-            break;
-        case 'login':
-            $params['sectok'] = getSecurityToken();
-            if($INPUT->server->has('REMOTE_USER')) {
-                if(!actionOK('logout')) {
-                    return false;
-                }
-                $params['do'] = 'logout';
-                $type         = 'logout';
-            }
-            break;
-        case 'register':
-            if($INPUT->server->str('REMOTE_USER')) {
-                return false;
-            }
-            break;
-        case 'resendpwd':
-            if($INPUT->server->str('REMOTE_USER')) {
-                return false;
-            }
-            break;
-        case 'admin':
-            if(!$INFO['ismanager']) {
-                return false;
-            }
-            break;
-        case 'revert':
-            if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
-                return false;
-            }
-            $params['rev']    = $REV;
-            $params['sectok'] = getSecurityToken();
-            break;
-        case 'subscribe':
-            if(!$INPUT->server->str('REMOTE_USER')) {
-                return false;
-            }
-            break;
-        case 'backlink':
-            break;
-        case 'profile':
-            if(!$INPUT->server->has('REMOTE_USER')) {
-                return false;
-            }
-            break;
-        case 'media':
-            $params['ns'] = getNS($ID);
-            break;
-        case 'mediaManager':
-            // View image in media manager
-            global $IMG;
-            $imgNS = getNS($IMG);
-            $authNS = auth_quickaclcheck("$imgNS:*");
-            if ($authNS < AUTH_UPLOAD) {
-                return false;
-            }
-            $params = array(
-                'ns' => $imgNS,
-                'image' => $IMG,
-                'do' => 'media'
-            );
-            //$type = 'media';
-            break;
-        default:
-            //unknown type
-            $unknown = true;
+    if($type == 'subscription') $type = 'subscribe';
+    if($type == 'img_backto') $type = 'imgBackto';
+
+    $class = '\\dokuwiki\\Menu\\Item\\' . ucfirst($type);
+    if(class_exists($class)) {
+        try {
+            /** @var \dokuwiki\Menu\Item\AbstractItem $item */
+            $item = new $class;
+            $data = $item->getLegacyData();
+            $unknown = false;
+        } catch(\RuntimeException $ignored) {
+            return false;
+        }
+    } else {
+        global $ID;
+        $data = array(
+            'accesskey' => null,
+            'type' => $type,
+            'id' => $ID,
+            'method' => 'get',
+            'params' => array('do' => $type),
+            'nofollow' => true,
+            'replacement' => '',
+        );
+        $unknown = true;
     }
 
-    $data = compact('accesskey', 'type', 'id', 'method', 'params', 'nofollow', 'replacement');
-
     $evt = new Doku_Event('TPL_ACTION_GET', $data);
     if($evt->advise_before()) {
         //handle unknown types
@@ -824,8 +629,10 @@ function tpl_get_action($type) {
  * @param string        $suf suffix for links
  * @param string        $inner inner HTML for links
  * @return bool|string
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
+    dbg_deprecated('see devel:menus');
     $out = '';
     if($link) {
         $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
@@ -859,20 +666,46 @@ function tpl_searchform($ajax = true, $autocomplete = true) {
     global $lang;
     global $ACT;
     global $QUERY;
+    global $ID;
 
     // don't print the search form if search action has been disabled
     if(!actionOK('search')) return false;
 
-    print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get" role="search"><div class="no">';
-    print '<input type="hidden" name="do" value="search" />';
-    print '<input type="text" ';
-    if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
-    print 'placeholder="'.$lang['btn_search'].'" ';
-    if(!$autocomplete) print 'autocomplete="off" ';
-    print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
-    print '<button type="submit" title="'.$lang['btn_search'].'">'.$lang['btn_search'].'</button>';
-    if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
-    print '</div></form>';
+    $searchForm = new dokuwiki\Form\Form([
+        'action' => wl(),
+        'method' => 'get',
+        'role' => 'search',
+        'class' => 'search',
+        'id' => 'dw__search',
+    ], true);
+    $searchForm->addTagOpen('div')->addClass('no');
+    $searchForm->setHiddenField('do', 'search');
+    $searchForm->setHiddenField('id', $ID);
+    $searchForm->addTextInput('q')
+        ->addClass('edit')
+        ->attrs([
+            'title' => '[F]',
+            'accesskey' => 'f',
+            'placeholder' => $lang['btn_search'],
+            'autocomplete' => $autocomplete ? 'on' : 'off',
+        ])
+        ->id('qsearch__in')
+        ->val($ACT === 'search' ? $QUERY : '')
+        ->useInput(false)
+    ;
+    $searchForm->addButton('', $lang['btn_search'])->attrs([
+        'type' => 'submit',
+        'title' => $lang['btn_search'],
+    ]);
+    if ($ajax) {
+        $searchForm->addTagOpen('div')->id('qsearch__out')->addClass('ajax_qsearch JSpopup');
+        $searchForm->addTagClose('div');
+    }
+    $searchForm->addTagClose('div');
+    trigger_event('FORM_QUICKSEARCH_OUTPUT', $searchForm);
+
+    echo $searchForm->toHTML();
+
     return true;
 }
 
@@ -882,33 +715,39 @@ function tpl_searchform($ajax = true, $autocomplete = true) {
  * @author Andreas Gohr <andi@splitbrain.org>
  *
  * @param string $sep Separator between entries
- * @return bool
+ * @param bool   $return return or print
+ * @return bool|string
  */
-function tpl_breadcrumbs($sep = '•') {
+function tpl_breadcrumbs($sep = null, $return = false) {
     global $lang;
     global $conf;
 
     //check if enabled
     if(!$conf['breadcrumbs']) return false;
 
+    //set default
+    if(is_null($sep)) $sep = '•';
+
+    $out='';
+
     $crumbs = breadcrumbs(); //setup crumb trace
 
     $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
 
     //render crumbs, highlight the last one
-    print '<span class="bchead">'.$lang['breadcrumb'].'</span>';
+    $out .= '<span class="bchead">'.$lang['breadcrumb'].'</span>';
     $last = count($crumbs);
     $i    = 0;
     foreach($crumbs as $id => $name) {
         $i++;
-        echo $crumbs_sep;
-        if($i == $last) print '<span class="curid">';
-        print '<bdi>';
-        tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"');
-        print '</bdi>';
-        if($i == $last) print '</span>';
+        $out .= $crumbs_sep;
+        if($i == $last) $out .= '<span class="curid">';
+        $out .= '<bdi>' . tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"', true) .  '</bdi>';
+        if($i == $last) $out .= '</span>';
     }
-    return true;
+    if($return) return $out;
+    print $out;
+    return $out ? true : false;
 }
 
 /**
@@ -924,9 +763,10 @@ function tpl_breadcrumbs($sep = '•') {
  * @todo   May behave strangely in RTL languages
  *
  * @param string $sep Separator between entries
- * @return bool
+ * @param bool   $return return or print
+ * @return bool|string
  */
-function tpl_youarehere($sep = ' » ') {
+function tpl_youarehere($sep = null, $return = false) {
     global $conf;
     global $ID;
     global $lang;
@@ -934,15 +774,18 @@ function tpl_youarehere($sep = ' » ') {
     // check if enabled
     if(!$conf['youarehere']) return false;
 
+    //set default
+    if(is_null($sep)) $sep = ' » ';
+
+    $out = '';
+
     $parts = explode(':', $ID);
     $count = count($parts);
 
-    echo '<span class="bchead">'.$lang['youarehere'].' </span>';
+    $out .= '<span class="bchead">'.$lang['youarehere'].' </span>';
 
     // always print the startpage
-    echo '<span class="home">';
-    tpl_pagelink(':'.$conf['start']);
-    echo '</span>';
+    $out .= '<span class="home">' . tpl_pagelink(':'.$conf['start'], null, true) . '</span>';
 
     // print intermediate namespace links
     $part = '';
@@ -952,8 +795,7 @@ function tpl_youarehere($sep = ' » ') {
         if($page == $conf['start']) continue; // Skip startpage
 
         // output
-        echo $sep;
-        tpl_pagelink($page);
+        $out .= $sep . tpl_pagelink($page, null, true);
     }
 
     // print current page, skipping start page, skipping for namespace index
@@ -961,9 +803,11 @@ function tpl_youarehere($sep = ' » ') {
     if(isset($page) && $page == $part.$parts[$i]) return true;
     $page = $part.$parts[$i];
     if($page == $conf['start']) return true;
-    echo $sep;
-    tpl_pagelink($page);
-    return true;
+    $out .= $sep;
+    $out .= tpl_pagelink($page, null, true);
+    if($return) return $out;
+    print $out;
+    return $out ? true : false;
 }
 
 /**
@@ -1597,7 +1441,8 @@ function tpl_mediaFileDetails($image, $rev) {
     list($ext) = mimetype($image, false);
     $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
     $class    = 'select mediafile mf_'.$class;
-    $tabTitle = '<strong><a href="'.ml($image).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
+    $attributes = $rev ? ['rev' => $rev] : [];
+    $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
     if($opened_tab === 'view' && $rev) {
         printf($lang['media_viewold'], $tabTitle, dformat($rev));
     } else {
@@ -1644,44 +1489,12 @@ function tpl_mediaTree() {
  *
  * @param string $empty empty option label
  * @param string $button submit button label
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_actiondropdown($empty = '', $button = '&gt;') {
-    global $ID;
-    global $REV;
-    global $lang;
-    /** @var Input $INPUT */
-    global $INPUT;
-
-    $action_structure = array(
-        'page_tools' => array('edit', 'revert', 'revisions', 'backlink', 'subscribe'),
-        'site_tools' => array('recent', 'media', 'index'),
-        'user_tools' => array('login', 'register', 'profile', 'admin'),
-    );
-
-    echo '<form action="'.script().'" method="get" accept-charset="utf-8">';
-    echo '<div class="no">';
-    echo '<input type="hidden" name="id" value="'.$ID.'" />';
-    if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
-    if ($INPUT->server->str('REMOTE_USER')) {
-        echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
-    }
-
-    echo '<select name="do" class="edit quickselect" title="'.$lang['tools'].'">';
-    echo '<option value="">'.$empty.'</option>';
-
-    foreach($action_structure as $tools => $actions) {
-        echo '<optgroup label="'.$lang[$tools].'">';
-        foreach($actions as $action) {
-            $act = tpl_get_action($action);
-            if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
-        }
-        echo '</optgroup>';
-    }
-
-    echo '</select>';
-    echo '<button type="submit">'.$button.'</button>';
-    echo '</div>';
-    echo '</form>';
+    dbg_deprecated('see devel:menus');
+    $menu = new \dokuwiki\Menu\MobileMenu();
+    echo $menu->getDropdown($empty, $button);
 }
 
 /**
@@ -2031,8 +1844,10 @@ function tpl_classes() {
  * @param string $toolsname name of menu
  * @param array $items
  * @param string $view e.g. 'main', 'detail', ...
+ * @deprecated 2017-09-01 see devel:menus
  */
 function tpl_toolsevent($toolsname, $items, $view = 'main') {
+    dbg_deprecated('see devel:menus');
     $data = array(
         'view' => $view,
         'items' => $items
diff --git a/inc/utf8.php b/inc/utf8.php
index f82a663e46af0904184776ac9d29a17e4dad0c32..4de28742923b1b2f05304c6b0bd64b11f579112f 100644
--- a/inc/utf8.php
+++ b/inc/utf8.php
@@ -148,8 +148,16 @@ if(!function_exists('utf8_strlen')){
      * @param string $string
      * @return int
      */
-    function utf8_strlen($string){
-        return strlen(utf8_decode($string));
+    function utf8_strlen($string) {
+        if (function_exists('utf8_decode')) {
+            return strlen(utf8_decode($string));
+        } elseif (UTF8_MBSTRING) {
+            return mb_strlen($string, 'UTF-8');
+        } elseif (function_exists('iconv_strlen')) {
+            return iconv_strlen($string, 'UTF-8');
+        } else {
+            return strlen($string);
+        }
     }
 }
 
@@ -204,7 +212,7 @@ if(!function_exists('utf8_substr')){
 
         // normalise -ve offsets (we could use a tail anchored pattern, but they are horribly slow!)
         if ($offset < 0) {
-            $strlen = strlen(utf8_decode($str));        // see notes
+            $strlen = utf8_strlen($str);        // see notes
             $offset = $strlen + $offset;
             if ($offset < 0) $offset = 0;
         }
@@ -225,7 +233,7 @@ if(!function_exists('utf8_substr')){
             $length_pattern = '(.*)$';                  // the rest of the string
         } else {
 
-            if (!isset($strlen)) $strlen = strlen(utf8_decode($str));    // see notes
+            if (!isset($strlen)) $strlen = utf8_strlen($str);    // see notes
             if ($offset > $strlen) return '';           // another trivial case
 
             if ($length > 0) {
diff --git a/install.php b/install.php
index 6398b199f986580dc4766496eae9f7f2f01d6ad0..1f53ed57ade26cd056ae7c66a7e24dfb782d42dc 100644
--- a/install.php
+++ b/install.php
@@ -1,4 +1,13 @@
 <?php
+/*><div style="width:60%; margin: auto; background-color: #fcc;
+                border: 1px solid #faa; padding: 0.5em 1em;">
+    <h1 style="font-size: 120%">No PHP Support</h1>
+
+    It seems this server has no PHP support enabled. You will need to
+    enable PHP before you can install and run DokuWiki. Contact your hosting
+    provider if you're unsure what this means.
+
+</div>*/
 /**
  * Dokuwiki installation assistance
  *
@@ -29,30 +38,6 @@ if($LC && $LC != 'en' ) {
 // initialise variables ...
 $error = array();
 
-$dokuwiki_hash = array(
-    '2005-09-22'   => 'e33223e957b0b0a130d0520db08f8fb7',
-    '2006-03-05'   => '51295727f79ab9af309a2fd9e0b61acc',
-    '2006-03-09'   => '51295727f79ab9af309a2fd9e0b61acc',
-    '2006-11-06'   => 'b3a8af76845977c2000d85d6990dd72b',
-    '2007-05-24'   => 'd80f2740c84c4a6a791fd3c7a353536f',
-    '2007-06-26'   => 'b3ca19c7a654823144119980be73cd77',
-    '2008-05-04'   => '1e5c42eac3219d9e21927c39e3240aad',
-    '2009-02-14'   => 'ec8c04210732a14fdfce0f7f6eead865',
-    '2009-12-25'   => '993c4b2b385643efe5abf8e7010e11f4',
-    '2010-11-07'   => '7921d48195f4db21b8ead6d9bea801b8',
-    '2011-05-25'   => '4241865472edb6fa14a1227721008072',
-    '2011-11-10'   => 'b46ff19a7587966ac4df61cbab1b8b31',
-    '2012-01-25'   => '72c083c73608fc43c586901fd5dabb74',
-    '2012-09-10'   => 'eb0b3fc90056fbc12bac6f49f7764df3',
-    '2013-05-10'   => '7b62b75245f57f122d3e0f8ed7989623',
-    '2013-12-08'   => '263c76af309fbf083867c18a34ff5214',
-    '2014-05-05'   => '263c76af309fbf083867c18a34ff5214',
-    '2015-08-10'   => '263c76af309fbf083867c18a34ff5214',
-    '2016-06-26'   => 'fd3abb6d89853dacb032907e619fbd73',
-    '2017-02-19'   => 'e4f2f5a34c9dbcd96a5ecc8f2df25bd9'
-);
-
-
 // begin output
 header('Content-Type: text/html; charset=utf-8');
 ?>
@@ -110,7 +95,7 @@ header('Content-Type: text/html; charset=utf-8');
                 print "</div>\n";
             }
         ?>
-        <a style="background: transparent url(data/security.png) left top no-repeat;
+        <a style="background: transparent url(data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png) left top no-repeat;
                   display: block; width:380px; height:73px; border:none; clear:both;"
            target="_blank"
            href="http://www.dokuwiki.org/security#web_access_security"></a>
@@ -161,7 +146,7 @@ function print_form($d){
     include(DOKU_CONF.'license.php');
 
     if(!is_array($d)) $d = array();
-    $d = array_map('htmlspecialchars',$d);
+    $d = array_map('hsc',$d);
 
     if(!isset($d['acl'])) $d['acl']=1;
     if(!isset($d['pop'])) $d['pop']=1;
@@ -216,9 +201,9 @@ function print_form($d){
             if(empty($d['license'])) $d['license'] = 'cc-by-sa';
             foreach($license as $key => $lic){
                 echo '<label for="lic_'.$key.'">';
-                echo '<input type="radio" name="d[license]" value="'.htmlspecialchars($key).'" id="lic_'.$key.'"'.
+                echo '<input type="radio" name="d[license]" value="'.hsc($key).'" id="lic_'.$key.'"'.
                      (($d['license'] === $key)?' checked="checked"':'').'>';
-                echo htmlspecialchars($lic['name']);
+                echo hsc($lic['name']);
                 if($lic['url']) echo ' <a href="'.$lic['url'].'" target="_blank"><sup>[?]</sup></a>';
                 echo '</label>';
             }
@@ -469,7 +454,6 @@ function fileWrite($filename, $data) {
 function check_configs(){
     global $error;
     global $lang;
-    global $dokuwiki_hash;
 
     $ok = true;
 
@@ -479,14 +463,6 @@ function check_configs(){
         'auth'  => DOKU_LOCAL.'acl.auth.php'
     );
 
-    // main dokuwiki config file (conf/dokuwiki.php) must not have been modified
-    $installation_hash = md5(preg_replace("/(\015\012)|(\015)/","\012",
-                             @file_get_contents(DOKU_CONF.'dokuwiki.php')));
-    if (!in_array($installation_hash, $dokuwiki_hash)) {
-        $error[] = sprintf($lang['i_badhash'],$installation_hash);
-        $ok = false;
-    }
-
     // configs shouldn't exist
     foreach ($config_files as $file) {
         if (file_exists($file) && filesize($file)) {
diff --git a/lib/exe/ajax.php b/lib/exe/ajax.php
index b3e9a618f565143707904fd89770accba787111f..55f1c87c571bd0f5f75f4bfac6c1d3e4f3944a73 100644
--- a/lib/exe/ajax.php
+++ b/lib/exe/ajax.php
@@ -6,435 +6,20 @@
  * @author     Andreas Gohr <andi@splitbrain.org>
  */
 
-if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
-require_once(DOKU_INC.'inc/init.php');
+if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../');
+require_once(DOKU_INC . 'inc/init.php');
+
 //close session
 session_write_close();
 
+// default header, ajax call may overwrite it later
 header('Content-Type: text/html; charset=utf-8');
 
 //call the requested function
-if($INPUT->post->has('call')){
-    $call = $INPUT->post->str('call');
-}else if($INPUT->get->has('call')){
-    $call = $INPUT->get->str('call');
-}else{
-    exit;
-}
-$callfn = 'ajax_'.$call;
-
-if(function_exists($callfn)){
-    $callfn();
-}else{
-    $evt = new Doku_Event('AJAX_CALL_UNKNOWN', $call);
-    if ($evt->advise_before()) {
-        print "AJAX call '".htmlspecialchars($call)."' unknown!\n";
-        exit;
-    }
-    $evt->advise_after();
-    unset($evt);
-}
-
-/**
- * Searches for matching pagenames
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_qsearch(){
-    global $lang;
-    global $INPUT;
-
-    $maxnumbersuggestions = 50;
-
-    $query = $INPUT->post->str('q');
-    if(empty($query)) $query = $INPUT->get->str('q');
-    if(empty($query)) return;
-
-    $query = urldecode($query);
-
-    $data = ft_pageLookup($query, true, useHeading('navigation'));
-
-    if(!count($data)) return;
-
-    print '<strong>'.$lang['quickhits'].'</strong>';
-    print '<ul>';
-    $counter = 0;
-    foreach($data as $id => $title){
-        if (useHeading('navigation')) {
-            $name = $title;
-        } else {
-            $ns = getNS($id);
-            if($ns){
-                $name = noNS($id).' ('.$ns.')';
-            }else{
-                $name = $id;
-            }
-        }
-        echo '<li>' . html_wikilink(':'.$id,$name) . '</li>';
-
-        $counter ++;
-        if($counter > $maxnumbersuggestions) {
-            echo '<li>...</li>';
-            break;
-        }
-    }
-    print '</ul>';
-}
-
-/**
- * Support OpenSearch suggestions
- *
- * @link   http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
- * @author Mike Frysinger <vapier@gentoo.org>
- */
-function ajax_suggestions() {
-    global $INPUT;
-
-    $query = cleanID($INPUT->post->str('q'));
-    if(empty($query)) $query = cleanID($INPUT->get->str('q'));
-    if(empty($query)) return;
-
-    $data = ft_pageLookup($query);
-    if(!count($data)) return;
-    $data = array_keys($data);
-
-    // limit results to 15 hits
-    $data = array_slice($data, 0, 15);
-    $data = array_map('trim',$data);
-    $data = array_map('noNS',$data);
-    $data = array_unique($data);
-    sort($data);
-
-    /* now construct a json */
-    $suggestions = array(
-                        $query,  // the original query
-                        $data,   // some suggestions
-                        array(), // no description
-                        array()  // no urls
-                   );
-    $json = new JSON();
-
-    header('Content-Type: application/x-suggestions+json');
-    print $json->encode($suggestions);
-}
-
-/**
- * Refresh a page lock and save draft
- *
- * Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_lock(){
-    global $conf;
-    global $lang;
-    global $ID;
-    global $INFO;
-    global $INPUT;
-
-    $ID = cleanID($INPUT->post->str('id'));
-    if(empty($ID)) return;
-
-    $INFO = pageinfo();
-
-    if (!$INFO['writable']) {
-        echo 'Permission denied';
-        return;
-    }
-
-    if(!checklock($ID)){
-        lock($ID);
-        echo 1;
-    }
-
-    if($conf['usedraft'] && $INPUT->post->str('wikitext')){
-        $client = $_SERVER['REMOTE_USER'];
-        if(!$client) $client = clientIP(true);
-
-        $draft = array('id'     => $ID,
-                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
-                'text'   => $INPUT->post->str('wikitext'),
-                'suffix' => $INPUT->post->str('suffix'),
-                'date'   => $INPUT->post->int('date'),
-                'client' => $client,
-                );
-        $cname = getCacheName($draft['client'].$ID,'.draft');
-        if(io_saveFile($cname,serialize($draft))){
-            echo $lang['draftdate'].' '.dformat();
-        }
-    }
-
-}
-
-/**
- * Delete a draft
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_draftdel(){
-    global $INPUT;
-    $id = cleanID($INPUT->str('id'));
-    if(empty($id)) return;
-
-    $client = $_SERVER['REMOTE_USER'];
-    if(!$client) $client = clientIP(true);
-
-    $cname = getCacheName($client.$id,'.draft');
-    @unlink($cname);
-}
-
-/**
- * Return subnamespaces for the Mediamanager
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_medians(){
-    global $conf;
-    global $INPUT;
-
-    // wanted namespace
-    $ns  = cleanID($INPUT->post->str('ns'));
-    $dir  = utf8_encodeFN(str_replace(':','/',$ns));
-
-    $lvl = count(explode(':',$ns));
-
-    $data = array();
-    search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir);
-    foreach(array_keys($data) as $item){
-        $data[$item]['level'] = $lvl+1;
-    }
-    echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
-}
-
-/**
- * Return list of files for the Mediamanager
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_medialist(){
-    global $NS;
-    global $INPUT;
-
-    $NS = cleanID($INPUT->post->str('ns'));
-    $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
-    if ($INPUT->post->str('do') == 'media') {
-        tpl_mediaFileList();
-    } else {
-        tpl_mediaContent(true, $sort);
-    }
-}
-
-/**
- * Return the content of the right column
- * (image details) for the Mediamanager
- *
- * @author Kate Arzamastseva <pshns@ukr.net>
- */
-function ajax_mediadetails(){
-    global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
-    $fullscreen = true;
-    require_once(DOKU_INC.'lib/exe/mediamanager.php');
-
-    $image = '';
-    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
-    if (isset($IMG)) $image = $IMG;
-    if (isset($JUMPTO)) $image = $JUMPTO;
-    $rev = false;
-    if (isset($REV) && !$JUMPTO) $rev = $REV;
-
-    html_msgarea();
-    tpl_mediaFileDetails($image, $rev);
-}
-
-/**
- * Returns image diff representation for mediamanager
- * @author Kate Arzamastseva <pshns@ukr.net>
- */
-function ajax_mediadiff(){
-    global $NS;
-    global $INPUT;
-
-    $image = '';
-    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
-    $NS = getNS($image);
-    $auth = auth_quickaclcheck("$NS:*");
-    media_diff($image, $NS, $auth, true);
-}
-
-function ajax_mediaupload(){
-    global $NS, $MSG, $INPUT;
-
-    $id = '';
-    if ($_FILES['qqfile']['tmp_name']) {
-        $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
-    } elseif ($INPUT->get->has('qqfile')) {
-        $id = $INPUT->get->str('qqfile');
-    }
-
-    $id = cleanID($id);
-
-    $NS = $INPUT->str('ns');
-    $ns = $NS.':'.getNS($id);
-
-    $AUTH = auth_quickaclcheck("$ns:*");
-    if($AUTH >= AUTH_UPLOAD) { io_createNamespace("$ns:xxx", 'media'); }
-
-    if ($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
-
-    $res = false;
-    if ($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
-    if ($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
-
-    if($res) {
-        $result = array(
-            'success' => true,
-            'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
-            'id' => $NS . ':' . $id,
-            'ns' => $NS
-        );
-    } else {
-        $error = '';
-        if(isset($MSG)) {
-            foreach($MSG as $msg) {
-                $error .= $msg['msg'];
-            }
-        }
-        $result = array(
-            'error' => $error,
-            'ns' => $NS
-        );
-    }
-    $json = new JSON;
-    header('Content-Type: application/json');
-    echo $json->encode($result);
-}
-
-/**
- * Return sub index for index view
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function ajax_index(){
-    global $conf;
-    global $INPUT;
-
-    // wanted namespace
-    $ns  = cleanID($INPUT->post->str('idx'));
-    $dir  = utf8_encodeFN(str_replace(':','/',$ns));
-
-    $lvl = count(explode(':',$ns));
-
-    $data = array();
-    search($data,$conf['datadir'],'search_index',array('ns' => $ns),$dir);
-    foreach(array_keys($data) as $item){
-        $data[$item]['level'] = $lvl+1;
-    }
-    echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index');
-}
-
-/**
- * List matching namespaces and pages for the link wizard
- *
- * @author Andreas Gohr <gohr@cosmocode.de>
- */
-function ajax_linkwiz(){
-    global $conf;
-    global $lang;
-    global $INPUT;
-
-    $q  = ltrim(trim($INPUT->post->str('q')),':');
-    $id = noNS($q);
-    $ns = getNS($q);
-
-    $ns = cleanID($ns);
-    $id = cleanID($id);
-
-    $nsd  = utf8_encodeFN(str_replace(':','/',$ns));
-
-    $data = array();
-    if($q && !$ns){
-
-        // use index to lookup matching pages
-        $pages = ft_pageLookup($id,true);
-
-        // result contains matches in pages and namespaces
-        // we now extract the matching namespaces to show
-        // them seperately
-        $dirs  = array();
-
-        foreach($pages as $pid => $title){
-            if(strpos(noNS($pid),$id) === false){
-                // match was in the namespace
-                $dirs[getNS($pid)] = 1; // assoc array avoids dupes
-            }else{
-                // it is a matching page, add it to the result
-                $data[] = array(
-                        'id'    => $pid,
-                        'title' => $title,
-                        'type'  => 'f',
-                        );
-            }
-            unset($pages[$pid]);
-        }
-        foreach($dirs as $dir => $junk){
-            $data[] = array(
-                    'id'   => $dir,
-                    'type' => 'd',
-                    );
-        }
-
-    }else{
-
-        $opts = array(
-                'depth' => 1,
-                'listfiles' => true,
-                'listdirs'  => true,
-                'pagesonly' => true,
-                'firsthead' => true,
-                'sneakyacl' => $conf['sneaky_index'],
-                );
-        if($id) $opts['filematch'] = '^.*\/'.$id;
-        if($id) $opts['dirmatch']  = '^.*\/'.$id;
-        search($data,$conf['datadir'],'search_universal',$opts,$nsd);
-
-        // add back to upper
-        if($ns){
-            array_unshift($data,array(
-                        'id'   => getNS($ns),
-                        'type' => 'u',
-                        ));
-        }
-    }
-
-    // fixme sort results in a useful way ?
-
-    if(!count($data)){
-        echo $lang['nothingfound'];
-        exit;
-    }
-
-    // output the found data
-    $even = 1;
-    foreach($data as $item){
-        $even *= -1; //zebra
-
-        if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
-        $link = wl($item['id']);
-
-        echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">';
-
-        if($item['type'] == 'u'){
-            $name = $lang['upperns'];
-        }else{
-            $name = htmlspecialchars($item['id']);
-        }
-
-        echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>';
-
-        if(!blank($item['title'])){
-            echo '<span>'.htmlspecialchars($item['title']).'</span>';
-        }
-        echo '</div>';
-    }
-
+global $INPUT;
+if($INPUT->has('call')) {
+    $call = $INPUT->filter('utf8_stripspecials')->str('call');
+    new \dokuwiki\Ajax($call);
+} else {
+    http_status(404);
 }
-
-//Setup VIM: ex: et ts=2 :
diff --git a/lib/exe/css.php b/lib/exe/css.php
index 81e6a39baafa4231677d81b2c998f39b71c9c4dc..40eaf99a663baffa92777ac4c57c114e96e2523e 100644
--- a/lib/exe/css.php
+++ b/lib/exe/css.php
@@ -36,7 +36,7 @@ function css_out(){
         $mediatypes = array('feed');
         $type = 'feed';
     } else {
-        $mediatypes = array('screen', 'all', 'print');
+        $mediatypes = array('screen', 'all', 'print', 'speech');
         $type = '';
     }
 
@@ -44,11 +44,9 @@ function css_out(){
     $tpl = trim(preg_replace('/[^\w-]+/','',$INPUT->str('t')));
     if(!$tpl) $tpl = $conf['template'];
 
-    // The generated script depends on some dynamic options
-    $cache = new cache('styles'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].$INPUT->int('preview').DOKU_BASE.$tpl.$type,'.css');
-
-    // load styl.ini
-    $styleini = css_styleini($tpl, $INPUT->bool('preview'));
+    // load style.ini
+    $styleUtil = new \dokuwiki\StyleUtils();
+    $styleini = $styleUtil->cssStyleini($tpl, $INPUT->bool('preview'));
 
     // cache influencers
     $tplinc = tpl_incdir($tpl);
@@ -60,72 +58,92 @@ function css_out(){
 
     // Array of needed files and their web locations, the latter ones
     // are needed to fix relative paths in the stylesheets
-    $files = array();
+    $media_files = array();
     foreach($mediatypes as $mediatype) {
-        $files[$mediatype] = array();
+        $files = array();
+
         // load core styles
-        $files[$mediatype][DOKU_INC.'lib/styles/'.$mediatype.'.css'] = DOKU_BASE.'lib/styles/';
+        $files[DOKU_INC.'lib/styles/'.$mediatype.'.css'] = DOKU_BASE.'lib/styles/';
 
         // load jQuery-UI theme
         if ($mediatype == 'screen') {
-            $files[$mediatype][DOKU_INC.'lib/scripts/jquery/jquery-ui-theme/smoothness.css'] = DOKU_BASE.'lib/scripts/jquery/jquery-ui-theme/';
+            $files[DOKU_INC.'lib/scripts/jquery/jquery-ui-theme/smoothness.css'] = DOKU_BASE.'lib/scripts/jquery/jquery-ui-theme/';
         }
         // load plugin styles
-        $files[$mediatype] = array_merge($files[$mediatype], css_pluginstyles($mediatype));
+        $files = array_merge($files, css_pluginstyles($mediatype));
         // load template styles
         if (isset($styleini['stylesheets'][$mediatype])) {
-            $files[$mediatype] = array_merge($files[$mediatype], $styleini['stylesheets'][$mediatype]);
+            $files = array_merge($files, $styleini['stylesheets'][$mediatype]);
         }
         // load user styles
         if(!empty($config_cascade['userstyle'][$mediatype])) {
             foreach($config_cascade['userstyle'][$mediatype] as $userstyle) {
-                $files[$mediatype][$userstyle] = DOKU_BASE;
+                $files[$userstyle] = DOKU_BASE;
             }
         }
 
-        $cache_files = array_merge($cache_files, array_keys($files[$mediatype]));
+        // Let plugins decide to either put more styles here or to remove some
+        $media_files[$mediatype] = css_filewrapper($mediatype, $files);
+        $CSSEvt = new Doku_Event('CSS_STYLES_INCLUDED', $media_files[$mediatype]);
+
+        // Make it preventable.
+        if ( $CSSEvt->advise_before() ) {
+            $cache_files = array_merge($cache_files, array_keys($media_files[$mediatype]['files']));
+        } else {
+            // unset if prevented. Nothing will be printed for this mediatype.
+            unset($media_files[$mediatype]);
+        }
+
+        // finish event.
+        $CSSEvt->advise_after();
     }
 
+    // The generated script depends on some dynamic options
+    $cache = new cache('styles'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].$INPUT->bool('preview').DOKU_BASE.$tpl.$type,'.css');
+    $cache->_event = 'CSS_CACHE_USE';
+
     // check cache age & handle conditional request
     // This may exit if a cache can be used
-    http_cached($cache->cache,
-                $cache->useCache(array('files' => $cache_files)));
+    $cache_ok = $cache->useCache(array('files' => $cache_files));
+    http_cached($cache->cache, $cache_ok);
 
     // start output buffering
     ob_start();
 
+    // Fire CSS_STYLES_INCLUDED for one last time to let the
+    // plugins decide whether to include the DW default styles.
+    // This can be done by preventing the Default.
+    $media_files['DW_DEFAULT'] = css_filewrapper('DW_DEFAULT');
+    trigger_event('CSS_STYLES_INCLUDED', $media_files['DW_DEFAULT'], 'css_defaultstyles');
+
     // build the stylesheet
     foreach ($mediatypes as $mediatype) {
 
-        // print the default classes for interwiki links and file downloads
-        if ($mediatype == 'screen') {
-            print '@media screen {';
-            css_interwiki();
-            css_filetypes();
-            print '}';
+        // Check if there is a wrapper set for this type.
+        if ( !isset($media_files[$mediatype]) ) {
+            continue;
         }
 
+        $cssData = $media_files[$mediatype];
+
+        // Print the styles.
+        print NL;
+        if ( $cssData['encapsulate'] === true ) print $cssData['encapsulationPrefix'] . ' {';
+        print '/* START '.$cssData['mediatype'].' styles */'.NL;
+
         // load files
-        $css_content = '';
-        foreach($files[$mediatype] as $file => $location){
+        foreach($cssData['files'] as $file => $location){
             $display = str_replace(fullpath(DOKU_INC), '', fullpath($file));
-            $css_content .= "\n/* XXXXXXXXX $display XXXXXXXXX */\n";
-            $css_content .= css_loadfile($file, $location);
-        }
-        switch ($mediatype) {
-            case 'screen':
-                print NL.'@media screen { /* START screen styles */'.NL.$css_content.NL.'} /* /@media END screen styles */'.NL;
-                break;
-            case 'print':
-                print NL.'@media print { /* START print styles */'.NL.$css_content.NL.'} /* /@media END print styles */'.NL;
-                break;
-            case 'all':
-            case 'feed':
-            default:
-                print NL.'/* START rest styles */ '.NL.$css_content.NL.'/* END rest styles */'.NL;
-                break;
+            print "\n/* XXXXXXXXX $display XXXXXXXXX */\n";
+            print css_loadfile($file, $location);
         }
+
+        print NL;
+        if ( $cssData['encapsulate'] === true ) print '} /* /@media ';
+        else print '/*';
+        print ' END '.$cssData['mediatype'].' styles */'.NL;
     }
+
     // end output buffering and get contents
     $css = ob_get_contents();
     ob_end_clean();
@@ -248,92 +266,38 @@ function css_applystyle($css, $replacements) {
 }
 
 /**
- * Load style ini contents
+ * Wrapper for the files, content and mediatype for the event CSS_STYLES_INCLUDED
  *
- * Loads and merges style.ini files from template and config and prepares
- * the stylesheet modes
+ * @author Gerry Weißbach <gerry.w@gammaproduction.de>
  *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $tpl the used template
- * @param bool   $preview load preview replacements
- * @return array with keys 'stylesheets' and 'replacements'
+ * @param string $mediatype type ofthe current media files/content set
+ * @param array $files set of files that define the current mediatype
+ * @return array
  */
-function css_styleini($tpl, $preview=false) {
-    global $conf;
-
-    $stylesheets = array(); // mode, file => base
-    $replacements = array(); // placeholder => value
-
-    // load template's style.ini
-    $incbase = tpl_incdir($tpl);
-    $webbase = tpl_basedir($tpl);
-    $ini = $incbase.'style.ini';
-    if(file_exists($ini)){
-        $data = parse_ini_file($ini, true);
-
-        // stylesheets
-        if(is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){
-            $stylesheets[$mode][$incbase.$file] = $webbase;
-        }
-
-        // replacements
-        if(is_array($data['replacements'])){
-            $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'],$webbase));
-        }
-    }
-
-    // load configs's style.ini
-    $webbase = DOKU_BASE;
-    $ini = DOKU_CONF."tpl/$tpl/style.ini";
-    $incbase = dirname($ini).'/';
-    if(file_exists($ini)){
-        $data = parse_ini_file($ini, true);
-
-        // stylesheets
-        if(isset($data['stylesheets']) && is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){
-            $stylesheets[$mode][$incbase.$file] = $webbase;
-        }
-
-        // replacements
-        if(isset($data['replacements']) && is_array($data['replacements'])){
-            $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'],$webbase));
-        }
-    }
-
-    // allow replacement overwrites in preview mode
-    if($preview) {
-        $webbase = DOKU_BASE;
-        $ini     = $conf['cachedir'].'/preview.ini';
-        if(file_exists($ini)) {
-            $data = parse_ini_file($ini, true);
-            // replacements
-            if(is_array($data['replacements'])) {
-                $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'], $webbase));
-            }
-        }
-    }
-
+function css_filewrapper($mediatype, $files=array()){
     return array(
-        'stylesheets' => $stylesheets,
-        'replacements' => $replacements
-    );
+            'files'                 => $files,
+            'mediatype'             => $mediatype,
+            'encapsulate'           => $mediatype != 'all',
+            'encapsulationPrefix'   => '@media '.$mediatype
+        );
 }
 
 /**
- * Amend paths used in replacement relative urls, refer FS#2879
+ * Prints the @media encapsulated default styles of DokuWiki
  *
- * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Gerry Weißbach <gerry.w@gammaproduction.de>
  *
- * @param array $replacements with key-value pairs
- * @param string $location
- * @return array
+ * This function is being called by a CSS_STYLES_INCLUDED event
+ * The event can be distinguished by the mediatype which is:
+ *   DW_DEFAULT
  */
-function css_fixreplacementurls($replacements, $location) {
-    foreach($replacements as $key => $value) {
-        $replacements[$key] = preg_replace('#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#','\\1'.$location,$value);
-    }
-    return $replacements;
+function css_defaultstyles(){
+    // print the default classes for interwiki links and file downloads
+    print '@media screen {';
+    css_interwiki();
+    css_filetypes();
+    print '}';
 }
 
 /**
@@ -530,7 +494,7 @@ function css_datauri($match){
     if($size && $size < $conf['cssdatauri']){
         $data = base64_encode(file_get_contents($local));
     }
-    if($data){
+    if (!empty($data)){
         $url = 'data:image/'.$ext.';base64,'.$data;
     }else{
         $url = $base.$url;
diff --git a/lib/exe/js.php b/lib/exe/js.php
index ee017a41ee63d83c73791c262ee339b57012ee14..7b76efabb1154a103d002180e2bcde0189fe5417 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -47,6 +47,7 @@ function js_out(){
                 DOKU_INC.'lib/scripts/cookie.js',
                 DOKU_INC.'lib/scripts/script.js',
                 DOKU_INC.'lib/scripts/qsearch.js',
+                DOKU_INC.'lib/scripts/search.js',
                 DOKU_INC.'lib/scripts/tree.js',
                 DOKU_INC.'lib/scripts/index.js',
                 DOKU_INC.'lib/scripts/textselection.js',
@@ -99,8 +100,8 @@ function js_out(){
                  'secure' => $conf['securecookie'] && is_ssl()
             )).";";
     // FIXME: Move those to JSINFO
-    print "var DOKU_UHN    = ".((int) useHeading('navigation')).";";
-    print "var DOKU_UHC    = ".((int) useHeading('content')).";";
+    print "Object.defineProperty(window, 'DOKU_UHN', { get: function() { console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead'); return JSINFO.useHeadingNavigation; } });";
+    print "Object.defineProperty(window, 'DOKU_UHC', { get: function() { console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead'); return JSINFO.useHeadingContent; } });";
 
     // load JS specific translations
     $lang['js']['plugins'] = js_pluginstrings();
diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e9a35289c0224d77021f7a54185a3ece3d4c0c7b
--- /dev/null
+++ b/lib/exe/manifest.php
@@ -0,0 +1,14 @@
+<?php
+
+if (!defined('DOKU_INC')) {
+    define('DOKU_INC', __DIR__ . '/../../');
+}
+require_once(DOKU_INC . 'inc/init.php');
+
+if (!actionOK('manifest')) {
+    http_status(404, 'Manifest has been disabled in DokuWiki configuration.');
+    exit();
+}
+
+$manifest = new \dokuwiki\Manifest();
+$manifest->sendManifest();
diff --git a/lib/exe/opensearch.php b/lib/exe/opensearch.php
index 98f5f52d5af154158c33d22c1b45f25c3e526ff3..b00b2b7710be98ef0ce9796c81b22563e1594d67 100644
--- a/lib/exe/opensearch.php
+++ b/lib/exe/opensearch.php
@@ -28,7 +28,7 @@ if(file_exists(DOKU_INC.'favicon.ico')){
 header('Content-Type: application/opensearchdescription+xml; charset=utf-8');
 echo '<?xml version="1.0"?>'.NL;
 echo '<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">'.NL;
-echo '  <ShortName>'.htmlspecialchars($conf['title']).'</ShortName>'.NL;
+echo '  <ShortName>'.hsc($conf['title']).'</ShortName>'.NL;
 echo '  <Image width="16" height="16" type="image/x-icon">'.$ico.'</Image>'.NL;
 echo '  <Url type="text/html" template="'.DOKU_URL.DOKU_SCRIPT.'?do=search&amp;id={searchTerms}" />'.NL;
 echo '  <Url type="application/x-suggestions+json" template="'.
diff --git a/lib/images/loading.gif b/lib/images/loading.gif
deleted file mode 100644
index 35058e20f0fa29fb426d56dc31cfb36fa2af417d..0000000000000000000000000000000000000000
Binary files a/lib/images/loading.gif and /dev/null differ
diff --git a/lib/images/menu/00-default_checkbox-blank-circle-outline.svg b/lib/images/menu/00-default_checkbox-blank-circle-outline.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e8f8c07ec3961a88d9dee9f62a1ae1d98b92623b
--- /dev/null
+++ b/lib/images/menu/00-default_checkbox-blank-circle-outline.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 20a8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8 8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/01-edit_pencil.svg b/lib/images/menu/01-edit_pencil.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e3a4faa119c45adb8891af50c9c02972e709ab53
--- /dev/null
+++ b/lib/images/menu/01-edit_pencil.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/02-create_pencil.svg b/lib/images/menu/02-create_pencil.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4c30b49a74c17aed1697eb5eebc415b9e130c0b9
--- /dev/null
+++ b/lib/images/menu/02-create_pencil.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="24" width="24"><path d="M13.118 16.118h3v-3h2v3h3v2h-3v3h-2v-3h-3zM20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/03-draft_android-studio.svg b/lib/images/menu/03-draft_android-studio.svg
new file mode 100644
index 0000000000000000000000000000000000000000..589658d843a45764b8118b43f3bda98d6a2c7a98
--- /dev/null
+++ b/lib/images/menu/03-draft_android-studio.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M11 2h2v2h.5A1.5 1.5 0 0 1 15 5.5V9l-.44.44 1.64 2.84C17.31 11.19 18 9.68 18 8h2c0 2.42-1.07 4.59-2.77 6.06l3.14 5.44.13 2.22-1.87-1.22-3.07-5.33c-1.06.53-2.28.83-3.56.83-1.28 0-2.5-.3-3.56-.83L5.37 20.5 3.5 21.72l.13-2.22L9.44 9.44 9 9V5.5A1.5 1.5 0 0 1 10.5 4h.5V2M9.44 13.43c.78.37 1.65.57 2.56.57.91 0 1.78-.2 2.56-.57L13.1 10.9h-.01c-.62.6-1.56.6-2.18 0h-.01l-1.46 2.53M12 6a1 1 0 0 0-1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/04-show_file-document.svg b/lib/images/menu/04-show_file-document.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0eed2745faa6139d308a7d2179c4f2689426cadf
--- /dev/null
+++ b/lib/images/menu/04-show_file-document.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13 9h5.5L13 3.5V9M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m9 16v-2H6v2h9m3-4v-2H6v2h12z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/05-source_file-xml.svg b/lib/images/menu/05-source_file-xml.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7e0034299e318f6f22c80e4887a12ade3470fc8c
--- /dev/null
+++ b/lib/images/menu/05-source_file-xml.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13 9h5.5L13 3.5V9M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m.12 13.5l3.74 3.74 1.42-1.41-2.33-2.33 2.33-2.33-1.42-1.41-3.74 3.74m11.16 0l-3.74-3.74-1.42 1.41 2.33 2.33-2.33 2.33 1.42 1.41 3.74-3.74z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/06-revert_replay.svg b/lib/images/menu/06-revert_replay.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0911e5bf2ea6c0d1c7db2378f3638f7f61bb16c5
--- /dev/null
+++ b/lib/images/menu/06-revert_replay.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7a6 6 0 0 1 6 6 6 6 0 0 1-6 6 6 6 0 0 1-6-6H4a8 8 0 0 0 8 8 8 8 0 0 0 8-8 8 8 0 0 0-8-8z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/07-revisions_history.svg b/lib/images/menu/07-revisions_history.svg
new file mode 100644
index 0000000000000000000000000000000000000000..cedbc1b92a6445cd974751f956d3f947b3ef5188
--- /dev/null
+++ b/lib/images/menu/07-revisions_history.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M11 7v5.11l4.71 2.79.79-1.28-4-2.37V7m0-5C8.97 2 5.91 3.92 4.27 6.77L2 4.5V11h6.5L5.75 8.25C6.96 5.73 9.5 4 12.5 4a7.5 7.5 0 0 1 7.5 7.5 7.5 7.5 0 0 1-7.5 7.5c-3.27 0-6.03-2.09-7.06-5h-2.1c1.1 4.03 4.77 7 9.16 7 5.24 0 9.5-4.25 9.5-9.5A9.5 9.5 0 0 0 12.5 2z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/08-backlink_link-variant.svg b/lib/images/menu/08-backlink_link-variant.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4d639a57cadbe6dea259b6f03e968ecf77789c07
--- /dev/null
+++ b/lib/images/menu/08-backlink_link-variant.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10.59 13.41c.41.39.41 1.03 0 1.42-.39.39-1.03.39-1.42 0a5.003 5.003 0 0 1 0-7.07l3.54-3.54a5.003 5.003 0 0 1 7.07 0 5.003 5.003 0 0 1 0 7.07l-1.49 1.49c.01-.82-.12-1.64-.4-2.42l.47-.48a2.982 2.982 0 0 0 0-4.24 2.982 2.982 0 0 0-4.24 0l-3.53 3.53a2.982 2.982 0 0 0 0 4.24m2.82-4.24c.39-.39 1.03-.39 1.42 0a5.003 5.003 0 0 1 0 7.07l-3.54 3.54a5.003 5.003 0 0 1-7.07 0 5.003 5.003 0 0 1 0-7.07l1.49-1.49c-.01.82.12 1.64.4 2.43l-.47.47a2.982 2.982 0 0 0 0 4.24 2.982 2.982 0 0 0 4.24 0l3.53-3.53a2.982 2.982 0 0 0 0-4.24.973.973 0 0 1 0-1.42z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/09-subscribe_email-outline.svg b/lib/images/menu/09-subscribe_email-outline.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3b23dacd0b23966b1d435db0b25cda096cf24560
--- /dev/null
+++ b/lib/images/menu/09-subscribe_email-outline.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2m0 14H4V8l8 5 8-5v10m0-12l-8 5-8-5h16z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/10-top_arrow-up.svg b/lib/images/menu/10-top_arrow-up.svg
new file mode 100644
index 0000000000000000000000000000000000000000..61003a826611f1f670d25579b9997b55f1987d3b
--- /dev/null
+++ b/lib/images/menu/10-top_arrow-up.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/11-mediamanager_folder-image.svg b/lib/images/menu/11-mediamanager_folder-image.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4376fdfbded6cf783877cbb8a6e9d55516184a41
--- /dev/null
+++ b/lib/images/menu/11-mediamanager_folder-image.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M5 17l4.5-6 3.5 4.5 2.5-3L19 17m1-11h-8l-2-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/12-back_arrow-left.svg b/lib/images/menu/12-back_arrow-left.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d8011b10aab8168f0fd78f13aaad2cc10009db3e
--- /dev/null
+++ b/lib/images/menu/12-back_arrow-left.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/account-card-details.svg b/lib/images/menu/account-card-details.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ba742568b1e98229f751c063f99f36599209fd59
--- /dev/null
+++ b/lib/images/menu/account-card-details.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M2 3h20c1.05 0 2 .95 2 2v14c0 1.05-.95 2-2 2H2c-1.05 0-2-.95-2-2V5c0-1.05.95-2 2-2m12 3v1h8V6h-8m0 2v1h8V8h-8m0 2v1h7v-1h-7m-6 3.91C6 13.91 2 15 2 17v1h12v-1c0-2-4-3.09-6-3.09M8 6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/account-plus.svg b/lib/images/menu/account-plus.svg
new file mode 100644
index 0000000000000000000000000000000000000000..a978bf18cd6188ba3f4fcb3d96ff8b56043a32f7
--- /dev/null
+++ b/lib/images/menu/account-plus.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 14c-2.67 0-8 1.33-8 4v2h16v-2c0-2.67-5.33-4-8-4m-9-4V7H4v3H1v2h3v3h2v-3h3v-2m6 2a4 4 0 0 0 4-4 4 4 0 0 0-4-4 4 4 0 0 0-4 4 4 4 0 0 0 4 4z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/calendar-clock.svg b/lib/images/menu/calendar-clock.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b19735dbb667bbfe5218915ab32d9a093aa2cf11
--- /dev/null
+++ b/lib/images/menu/calendar-clock.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 13h1.5v2.82l2.44 1.41-.75 1.3L15 16.69V13m4-5H5v11h4.67c-.43-.91-.67-1.93-.67-3a7 7 0 0 1 7-7c1.07 0 2.09.24 3 .67V8M5 21a2 2 0 0 1-2-2V5c0-1.11.89-2 2-2h1V1h2v2h8V1h2v2h1a2 2 0 0 1 2 2v6.1c1.24 1.26 2 2.99 2 4.9a7 7 0 0 1-7 7c-1.91 0-3.64-.76-4.9-2H5m11-9.85A4.85 4.85 0 0 0 11.15 16c0 2.68 2.17 4.85 4.85 4.85A4.85 4.85 0 0 0 20.85 16c0-2.68-2.17-4.85-4.85-4.85z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/file-tree.svg b/lib/images/menu/file-tree.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0f261882f897aa41af1fb99c19c6f5d66e2aca96
--- /dev/null
+++ b/lib/images/menu/file-tree.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 3h6v4H3V3m12 7h6v4h-6v-4m0 7h6v4h-6v-4m-2-4H7v5h6v2H5V9h2v2h6v2z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/folder-multiple-image.svg b/lib/images/menu/folder-multiple-image.svg
new file mode 100644
index 0000000000000000000000000000000000000000..f66aaaddb2763f0fed938e181cf1a9d077783969
--- /dev/null
+++ b/lib/images/menu/folder-multiple-image.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 15l4.5-6 3.5 4.5 2.5-3L21 15m1-11h-8l-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2M2 6H0v14a2 2 0 0 0 2 2h18v-2H2V6z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/lock-reset.svg b/lib/images/menu/lock-reset.svg
new file mode 100644
index 0000000000000000000000000000000000000000..49693c60999aef16a39fe756006f7a42e45b1358
--- /dev/null
+++ b/lib/images/menu/lock-reset.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12.63 2c5.53 0 10.01 4.5 10.01 10s-4.48 10-10.01 10c-3.51 0-6.58-1.82-8.37-4.57l1.58-1.25C7.25 18.47 9.76 20 12.64 20a8 8 0 0 0 8-8 8 8 0 0 0-8-8C8.56 4 5.2 7.06 4.71 11h2.76l-3.74 3.73L0 11h2.69c.5-5.05 4.76-9 9.94-9m2.96 8.24c.5.01.91.41.91.92v4.61c0 .5-.41.92-.92.92h-5.53c-.51 0-.92-.42-.92-.92v-4.61c0-.51.41-.91.91-.92V9.23c0-1.53 1.25-2.77 2.77-2.77 1.53 0 2.78 1.24 2.78 2.77v1.01m-2.78-2.38c-.75 0-1.37.61-1.37 1.37v1.01h2.75V9.23c0-.76-.62-1.37-1.38-1.37z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/login.svg b/lib/images/menu/login.svg
new file mode 100644
index 0000000000000000000000000000000000000000..07a9896c0e77f08382e092d8b39956867b8fa539
--- /dev/null
+++ b/lib/images/menu/login.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 17.25V14H3v-4h7V6.75L15.25 12 10 17.25M8 2h9a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2v-4h2v4h9V4H8v4H6V4a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/logout.svg b/lib/images/menu/logout.svg
new file mode 100644
index 0000000000000000000000000000000000000000..97d3158e42164858b15b73daf3516495f0d71c43
--- /dev/null
+++ b/lib/images/menu/logout.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M17 17.25V14h-7v-4h7V6.75L22.25 12 17 17.25M13 2a2 2 0 0 1 2 2v4h-2V4H4v16h9v-4h2v4a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9z"/></svg>
\ No newline at end of file
diff --git a/lib/images/menu/settings.svg b/lib/images/menu/settings.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ced98713eb51a961d37fa3fb76769e716aa5aacc
--- /dev/null
+++ b/lib/images/menu/settings.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 15.5A3.5 3.5 0 0 1 8.5 12 3.5 3.5 0 0 1 12 8.5a3.5 3.5 0 0 1 3.5 3.5 3.5 3.5 0 0 1-3.5 3.5m7.43-2.53c.04-.32.07-.64.07-.97 0-.33-.03-.66-.07-1l2.11-1.63c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.31-.61-.22l-2.49 1c-.52-.39-1.06-.73-1.69-.98l-.37-2.65A.506.506 0 0 0 14 2h-4c-.25 0-.46.18-.5.42l-.37 2.65c-.63.25-1.17.59-1.69.98l-2.49-1c-.22-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64L4.57 11c-.04.34-.07.67-.07 1 0 .33.03.65.07.97l-2.11 1.66c-.19.15-.25.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1.01c.52.4 1.06.74 1.69.99l.37 2.65c.04.24.25.42.5.42h4c.25 0 .46-.18.5-.42l.37-2.65c.63-.26 1.17-.59 1.69-.99l2.49 1.01c.22.08.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.66z"/></svg>
\ No newline at end of file
diff --git a/lib/plugins/acl/lang/da/lang.php b/lib/plugins/acl/lang/da/lang.php
index 287356f1d453be627ace3b428dd060dee0a05e94..5209b7b10283789bc92f3059d2337e566ef4c464 100644
--- a/lib/plugins/acl/lang/da/lang.php
+++ b/lib/plugins/acl/lang/da/lang.php
@@ -11,8 +11,7 @@
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  */
 $lang['admin_acl']             = 'Rettighedsadministration';
diff --git a/lib/plugins/acl/lang/eo/lang.php b/lib/plugins/acl/lang/eo/lang.php
index f65995408e5eca94d5d3258b45dd0145bbef04a4..b59f4656e2c9ee42884a9ecb23a03385dd6a1c05 100644
--- a/lib/plugins/acl/lang/eo/lang.php
+++ b/lib/plugins/acl/lang/eo/lang.php
@@ -2,14 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Felipe Castro <fefcas@uol.com.br>
  * @author Felipo Kastro <fefcas@gmail.com>
- * @author Felipe Castro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik pedersen@shaw.ca>
- * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['admin_acl']             = 'Administrado de Alirkontrola Listo (ACL)';
 $lang['acl_group']             = 'Grupo:';
diff --git a/lib/plugins/acl/lang/eu/lang.php b/lib/plugins/acl/lang/eu/lang.php
index bb6ab964af3752ca6a95e44f220dda8dd4749ac4..722ffd13caf49d2dbf5d87548607efacd077fcd1 100644
--- a/lib/plugins/acl/lang/eu/lang.php
+++ b/lib/plugins/acl/lang/eu/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
  */
diff --git a/lib/plugins/acl/lang/fr/lang.php b/lib/plugins/acl/lang/fr/lang.php
index 483b8b5c686f7ea959ff791038cf19a442d5f874..92c07e8158da219b94df5922fcde5599e2a75521 100644
--- a/lib/plugins/acl/lang/fr/lang.php
+++ b/lib/plugins/acl/lang/fr/lang.php
@@ -18,10 +18,7 @@
  * @author Vincent Feltz <psycho@feltzv.fr>
  * @author Philippe Bajoit <philippe.bajoit@gmail.com>
  * @author Florian Gaub <floriang@floriang.net>
- * @author Samuel Dorsaz samuel.dorsaz@novelion.net
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author schplurtz@laposte.net
- * @author skimpax@gmail.com
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
diff --git a/lib/plugins/acl/lang/he/lang.php b/lib/plugins/acl/lang/he/lang.php
index 2369b80101b75a1674f2379eb2efa8c4b8700081..33ce761a97f47031a434d74df526c58745ee678b 100644
--- a/lib/plugins/acl/lang/he/lang.php
+++ b/lib/plugins/acl/lang/he/lang.php
@@ -2,9 +2,8 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author DoK <kamberd@yahoo.com>
- * @author Dotan Kamber <kamberd@yahoo.com>
  * @author Moshe Kaplan <mokplan@gmail.com>
  * @author Yaron Yogev <yaronyogev@gmail.com>
  * @author Yaron Shahrabani <sh.yaron@gmail.com>
diff --git a/lib/plugins/acl/lang/hr/lang.php b/lib/plugins/acl/lang/hr/lang.php
index 9b68c8a15800e52733d0946e851b0a8566eb3d70..d1881766f7eeaec7eb86c05fc41e0faf81f17188 100644
--- a/lib/plugins/acl/lang/hr/lang.php
+++ b/lib/plugins/acl/lang/hr/lang.php
@@ -5,7 +5,7 @@
  *
  * @author Branko Rihtman <theney@gmail.com>
  * @author Dražen Odobašić <dodobasic@gmail.com>
- * @author Dejan Igrec dejan.igrec@gmail.com
+ * @author Dejan Igrec <dejan.igrec@gmail.com>
  */
 $lang['admin_acl']             = 'Upravljanje listom kontrole pristupa';
 $lang['acl_group']             = 'Grupa:';
diff --git a/lib/plugins/acl/lang/it/lang.php b/lib/plugins/acl/lang/it/lang.php
index c44ee8822159adeb35e2f7e1603bc8e95f12884f..4aef9aa46c37a5ddbc6acf2b70d49b8acff1846f 100644
--- a/lib/plugins/acl/lang/it/lang.php
+++ b/lib/plugins/acl/lang/it/lang.php
@@ -6,15 +6,10 @@
  * @author Giorgio Vecchiocattivi <giorgio@vecchio.it>
  * @author Roberto Bolli <http://www.rbnet.it/>
  * @author Pietro Battiston toobaz@email.it
- * @author Diego Pierotto ita.translations@tiscali.it
- * @author ita.translations@tiscali.it
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
- * @author Osman Tekin osman.tekin93@hotmail.it
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
  */
 $lang['admin_acl']             = 'Gestione Lista Controllo Accessi (ACL)';
 $lang['acl_group']             = 'Gruppo:';
diff --git a/lib/plugins/acl/lang/ko/lang.php b/lib/plugins/acl/lang/ko/lang.php
index 0227584c78a54eea35ad06a36adff977ea12732c..35f06c4b4179aff1a82ccd1d66ef69714927461c 100644
--- a/lib/plugins/acl/lang/ko/lang.php
+++ b/lib/plugins/acl/lang/ko/lang.php
@@ -7,10 +7,10 @@
  * @author Anika Henke <anika@selfthinker.org>
  * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
  * @author Garam <rowain8@gmail.com>
  */
diff --git a/lib/plugins/acl/lang/lv/lang.php b/lib/plugins/acl/lang/lv/lang.php
index c0acdd7331c8d8299e5d1a25814e1e9fc45690f9..e4ca49261a8e287faf8f10bdc360cc3c7049ccbb 100644
--- a/lib/plugins/acl/lang/lv/lang.php
+++ b/lib/plugins/acl/lang/lv/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['admin_acl']             = 'Piekļuves tiesību vadība';
diff --git a/lib/plugins/acl/lang/nl/lang.php b/lib/plugins/acl/lang/nl/lang.php
index e8b3b20dc27045d1d58964e568e5b4af7fa13f03..695022d0739abd727674a44e302dbb3d3b6a9576 100644
--- a/lib/plugins/acl/lang/nl/lang.php
+++ b/lib/plugins/acl/lang/nl/lang.php
@@ -13,13 +13,10 @@
  * @author Dion Nicolaas <dion@nicolaas.net>
  * @author Danny Rotsaert <danny.rotsaert@edpnet.be>
  * @author Marijn Hofstra hofstra.m@gmail.com
- * @author Matthias Carchon webmaster@c-mattic.be
  * @author Marijn Hofstra <hofstra.m@gmail.com>
  * @author Timon Van Overveldt <timonvo@gmail.com>
- * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit <klapinklapin@gmail.com>
- * @author Gerrit Uitslag <klapinklapin@gmail.com>
  * @author Remon <no@email.local>
  */
 $lang['admin_acl']             = 'Toegangsrechten';
diff --git a/lib/plugins/acl/lang/pl/lang.php b/lib/plugins/acl/lang/pl/lang.php
index c840f449b64af4008b25b238f3bd964568e96f11..2d2f91eb99daee783b8de38695228bdf7c57971a 100644
--- a/lib/plugins/acl/lang/pl/lang.php
+++ b/lib/plugins/acl/lang/pl/lang.php
@@ -7,7 +7,7 @@
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
diff --git a/lib/plugins/acl/lang/pt-br/lang.php b/lib/plugins/acl/lang/pt-br/lang.php
index 2ef34f7b365bbc91cb647cc229f60135d9d8393a..466a2d23a802efadfc3d546451a146c2c8f9411b 100644
--- a/lib/plugins/acl/lang/pt-br/lang.php
+++ b/lib/plugins/acl/lang/pt-br/lang.php
@@ -11,12 +11,9 @@
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Frederico Guimarães <frederico@teia.bio.br>
- * @author Jair Henrique <jair.henrique@gmail.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Sergio Motta sergio@cisne.com.br
+ * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
diff --git a/lib/plugins/acl/lang/pt/lang.php b/lib/plugins/acl/lang/pt/lang.php
index aef1746125dd522e351bba38d86bc9881a2272d4..eb77cba5c81c778ed33d8d195fd3186708d17f16 100644
--- a/lib/plugins/acl/lang/pt/lang.php
+++ b/lib/plugins/acl/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author José Carlos Monteiro <jose.c.monteiro@netcabo.pt>
  * @author José Monteiro <Jose.Monteiro@DoWeDo-IT.com>
  * @author Enrico Nicoletto <liverig@gmail.com>
diff --git a/lib/plugins/acl/lang/ru/lang.php b/lib/plugins/acl/lang/ru/lang.php
index dc6744451a0126df7700851421a030256d785c7b..5dfbceda0263d5707b41f67b7d7072ed057fcc10 100644
--- a/lib/plugins/acl/lang/ru/lang.php
+++ b/lib/plugins/acl/lang/ru/lang.php
@@ -4,10 +4,9 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Denis Simakov <akinoame1@gmail.com>
- * @author Змей Этерийский evil_snake@eternion.ru
+ * @author Змей Этерийский <evil_snake@eternion.ru>
  * @author Hikaru Nakajima <jisatsu@mail.ru>
  * @author Alexei Tereschenko <alexeitlex@yahoo.com>
- * @author Irina Ponomareva irinaponomareva@webperfectionist.com
  * @author Alexander Sorkin <kibizoid@gmail.com>
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
@@ -16,7 +15,6 @@
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
- * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  */
 $lang['admin_acl']             = 'Управление списками контроля доступа';
 $lang['acl_group']             = 'Группа:';
diff --git a/lib/plugins/acl/lang/sk/lang.php b/lib/plugins/acl/lang/sk/lang.php
index 4775bfb7db5b0e97f466e067c4721456e6c39022..0434fe5e844c3bf542707d466185b0e53a9e75db 100644
--- a/lib/plugins/acl/lang/sk/lang.php
+++ b/lib/plugins/acl/lang/sk/lang.php
@@ -5,7 +5,7 @@
  *
  * @author Ondrej Vegh <ov@vsieti.sk>
  * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
+ * @author exusik <exusik@gmail.com>
  * @author Martin Michalek <michalek.dev@gmail.com>
  */
 $lang['admin_acl']             = 'Správa zoznamu prístupových práv';
diff --git a/lib/plugins/acl/lang/sl/lang.php b/lib/plugins/acl/lang/sl/lang.php
index 84c2088e88287eaa6a8d3d62278ffb2b2d57db44..9edbe0dfb8644a84ef3bdd8ba17739f77f62983a 100644
--- a/lib/plugins/acl/lang/sl/lang.php
+++ b/lib/plugins/acl/lang/sl/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Dejan Levec <webphp@gmail.com>
  * @author Boštjan Seničar <senicar@gmail.com>
  * @author Gregor Skumavc (grega.skumavc@gmail.com)
diff --git a/lib/plugins/acl/lang/sv/lang.php b/lib/plugins/acl/lang/sv/lang.php
index 34c1c6624406bc9d72383151eee4512693b1a98d..176a93786723665035f6104d9f36b0dd90d2acf3 100644
--- a/lib/plugins/acl/lang/sv/lang.php
+++ b/lib/plugins/acl/lang/sv/lang.php
@@ -2,20 +2,16 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Per Foreby <per@foreby.se>
  * @author Nicklas Henriksson <nicklas[at]nihe.se>
  * @author HÃ¥kan Sandell <hakan.sandell@home.se>
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
- * @author Tormod Johansson tormod.otter.johansson@gmail.com
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['admin_acl']             = 'Hantera behörighetslistan (ACL)';
 $lang['acl_group']             = 'Grupp:';
diff --git a/lib/plugins/acl/lang/uk/lang.php b/lib/plugins/acl/lang/uk/lang.php
index 4d8b52e1b0f77c8eb7e0e390b44a65f6e9a0d6ea..05c259601e0884361b3eee51f4782aaecbd23ad7 100644
--- a/lib/plugins/acl/lang/uk/lang.php
+++ b/lib/plugins/acl/lang/uk/lang.php
@@ -2,13 +2,10 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Oleksiy Voronin <ovoronin@gmail.com>
- * @author serg_stetsuk@ukr.net
- * @author okunia@gmail.com
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
- * @author Uko uko@uar.net
- * @author Ulrikhe Lukoie  <lukoie@gmail>.com
  */
 $lang['admin_acl']             = 'Керування списками контролю доступу';
 $lang['acl_group']             = 'Група:';
diff --git a/lib/plugins/acl/lang/zh/lang.php b/lib/plugins/acl/lang/zh/lang.php
index 5a893a37fb8cebbf171c15cd0de3b03f3c6fcd0a..3191745817da6c023ef58791f2bd34d9eda73973 100644
--- a/lib/plugins/acl/lang/zh/lang.php
+++ b/lib/plugins/acl/lang/zh/lang.php
@@ -5,15 +5,11 @@
  *
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
- * @author George Sheraton guxd@163.com
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  */
 $lang['admin_acl']             = '访问控制列表(ACL)管理器';
diff --git a/lib/plugins/authad/lang/eo/lang.php b/lib/plugins/authad/lang/eo/lang.php
index e738323da067f9c70f583c50587bdf309cc82519..94580c6cf1549796548f0d9cae4c329b5222aaab 100644
--- a/lib/plugins/authad/lang/eo/lang.php
+++ b/lib/plugins/authad/lang/eo/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['domain']                = 'Ensaluta domajno';
diff --git a/lib/plugins/authad/lang/eo/settings.php b/lib/plugins/authad/lang/eo/settings.php
index 11640ebb713a0a7f500e072ae5fdc13588c6369a..cf9cad0c28c195a67b4e8e0d51c826a6f35d2668 100644
--- a/lib/plugins/authad/lang/eo/settings.php
+++ b/lib/plugins/authad/lang/eo/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['account_suffix']        = 'Via konto-aldonaĵo, ekz. <code>@mia.domajno.lando</code>';
diff --git a/lib/plugins/authad/lang/eu/lang.php b/lib/plugins/authad/lang/eu/lang.php
index 454e3be3496d6b527bb927e46d4f1cfa446f4975..6c694bb0328c8ba9a82e3007c4f6f9c5c0db43d3 100644
--- a/lib/plugins/authad/lang/eu/lang.php
+++ b/lib/plugins/authad/lang/eu/lang.php
@@ -2,7 +2,9 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Zigor Astarbe <astarbe@gmail.com>
+ * @author Osoitz <oelkoro@gmail.com>
  */
 $lang['authpwdexpire']         = 'Zure pasahitza %d egun barru iraungiko da, laster aldatu beharko zenuke.';
+$lang['connectfail']           = 'Huts egin du Active Directory zerbitzarira konektatzean';
diff --git a/lib/plugins/authad/lang/eu/settings.php b/lib/plugins/authad/lang/eu/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6852b225805c8ca5534b29f2691df22be201dd4
--- /dev/null
+++ b/lib/plugins/authad/lang/eu/settings.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Osoitz <oelkoro@gmail.com>
+ */
+$lang['account_suffix']        = 'Zure kontuaren atzizkia. Esaterako <code>@niredomeinua.eus</code>';
+$lang['admin_password']        = 'Goiko erabiltzailearen pasahitza';
+$lang['use_ssl']               = 'SSL konexioa darabilzu? Hala bada, ez gaitu TLS behean.';
+$lang['use_tls']               = 'Erabili TLS konexioa? Erabiltzekotan, ez gaitu SSL goian.';
+$lang['expirywarn']            = 'Pasahitza iraungitzear dagoela abisatzeko aurretia egunetan. 0 desgaitzeko.';
+$lang['update_mail']           = 'Baimendu erabiltzaileei bere email helbidea eguneratzea?';
diff --git a/lib/plugins/authad/lang/he/lang.php b/lib/plugins/authad/lang/he/lang.php
index 5b193ed5f91cb6f8a9e68d5e48eeb5c28f33a8af..ac8fbcb5c44ed666733acd883c304d9d7cda3f91 100644
--- a/lib/plugins/authad/lang/he/lang.php
+++ b/lib/plugins/authad/lang/he/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author tomer <tomercarolldergicz@gmail.com>
  * @author Menashe Tomer <menashesite@gmail.com>
  */
diff --git a/lib/plugins/authad/lang/he/settings.php b/lib/plugins/authad/lang/he/settings.php
index b1436813018bfe4b8c55ef1f9a0857422cb0a8ee..d0d459cc1a0f07581934f21be161c328566cb493 100644
--- a/lib/plugins/authad/lang/he/settings.php
+++ b/lib/plugins/authad/lang/he/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Menashe Tomer <menashesite@gmail.com>
  */
 $lang['admin_password']        = 'סיסמת המשתמש המוזכן';
diff --git a/lib/plugins/authad/lang/lv/lang.php b/lib/plugins/authad/lang/lv/lang.php
index a208ac949f8391dd37c9b98147833fba0c17ca45..fd20d3410f7ea188c461151b3a1e4a046d8580ca 100644
--- a/lib/plugins/authad/lang/lv/lang.php
+++ b/lib/plugins/authad/lang/lv/lang.php
@@ -2,8 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Oskars Pakers <oskars.pakers@gmail.com>
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['domain']                = 'Iežurnālēšanās domēns';
 $lang['authpwdexpire']         = 'Tavai parolei pēc %d dienām biegsies termiņš, tā drīzumā jānomaina.';
+$lang['passchangefail']        = 'Neizdevās nomainīt paroli. Varbūt parole neatbilst noteikumiem?';
+$lang['userchangefail']        = 'Neizdevās labot lietotāju. Varbūt jūsu kontam nav nepieciešamās atļaujas?';
+$lang['connectfail']           = 'Neizdevās savienotes ar aktīvās direktorijas serveri.';
diff --git a/lib/plugins/authad/lang/lv/settings.php b/lib/plugins/authad/lang/lv/settings.php
index 5272d27d0521fc62e1a8fc9bc52b52d197c16217..72b9cf25ecb6f2a49ce0fac92f05efb9acb84422 100644
--- a/lib/plugins/authad/lang/lv/settings.php
+++ b/lib/plugins/authad/lang/lv/settings.php
@@ -2,10 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Oskars Pakers <oskars.pakers@gmail.com>
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['account_suffix']        = 'Jūsu konta sufikss. Piemēram, <code>@my.domain.org</code>';
+$lang['base_dn']               = 'Jūsu bāzes DN. Piemēram, <code>DC=my,DC=domain,DC=org</code>';
 $lang['domain_controllers']    = 'Ar komatiem atdalīts domēna kontroleru saraksts. Piemēram, <code>srv1.domain.org,srv2.domain.org</code>';
 $lang['admin_password']        = 'Minētā lietotāja parole.';
 $lang['expirywarn']            = 'Cik dienas iepriekš brīdināt lietotāju par paroles termiņa beigām. Ierakstīt 0, lai atspējotu.';
diff --git a/lib/plugins/authad/lang/pl/lang.php b/lib/plugins/authad/lang/pl/lang.php
index a83bac295908a67e2560286e4d91b89b82f546ee..8ea095a3de66a59b0337eed58d930e24cde834e0 100644
--- a/lib/plugins/authad/lang/pl/lang.php
+++ b/lib/plugins/authad/lang/pl/lang.php
@@ -3,6 +3,11 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
  * @author Aoi Karasu <aoikarasu@gmail.com>
  */
+$lang['domain']                = 'Domena logowania';
 $lang['authpwdexpire']         = 'Twoje hasło wygaśnie za %d dni. Należy je zmienić w krótkim czasie.';
+$lang['passchangefail']        = 'Nie udało się zmienić hasła. Możliwe, że zasady dotyczące haseł nie zostały spełnione.';
+$lang['userchangefail']        = 'Nie udało się zmienić atrybutów użytkownika. Możliwe, że twoje konto nie ma uprawnień do wprowadzania zmian.';
+$lang['connectfail']           = 'Nie można połączyć się z serwerem Active Directory.';
diff --git a/lib/plugins/authad/lang/pl/settings.php b/lib/plugins/authad/lang/pl/settings.php
index da0d3af00019b978f8f91860fe6c785ac1c41521..d5af79c33d59ede3809c45316712e9f89db44c74 100644
--- a/lib/plugins/authad/lang/pl/settings.php
+++ b/lib/plugins/authad/lang/pl/settings.php
@@ -3,6 +3,8 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Tomasz Bosak <bosak.tomasz@gmail.com>
  * @author Paweł Jan Czochański <czochanski@gmail.com>
  * @author Mati <mackosa@wp.pl>
@@ -17,9 +19,11 @@ Opcjonalne, ale wymagane dla niektórych akcji np. wysyłania emailowych subskry
 $lang['admin_password']        = 'Hasło dla powyższego użytkownika.';
 $lang['sso']                   = 'Czy pojedyncze logowanie powinno korzystać z Kerberos czy NTML?';
 $lang['sso_charset']           = 'Kodowanie znaków wykorzystywane do przesyłania nazwy użytkownika dla Kerberos lub NTLM. Pozostaw puste dla UTF-8 lub latin-1. Wymaga rozszerzenia iconv.';
+$lang['real_primarygroup']     = 'Czy prawdziwa grupa podstawowa powinna zostać pobrana, zamiast  przyjmowania domyślnej wartości "Domain Users" (wolniej).';
 $lang['use_ssl']               = 'Użyć połączenie SSL? Jeśli tak to nie aktywuj TLS poniżej.';
 $lang['use_tls']               = 'Użyć połączenie TLS? Jeśli tak to nie aktywuj SSL powyżej.';
 $lang['debug']                 = 'Wyświetlać dodatkowe informacje do debugowania w przypadku błędów?';
 $lang['expirywarn']            = 'Dni poprzedzających powiadomienie użytkownika o wygasającym haśle. 0 aby wyłączyć.';
+$lang['additional']            = 'Oddzielona przecinkami lista dodatkowych atrybutów AD do pobrania z danych użytkownika. Używane przez niektóre wtyczki.';
 $lang['update_name']           = 'Zezwól użytkownikom na uaktualnianie nazwy wyświetlanej w AD?';
 $lang['update_mail']           = 'Zezwól użytkownikom na uaktualnianie ich adresu email?';
diff --git a/lib/plugins/authad/lang/pt/lang.php b/lib/plugins/authad/lang/pt/lang.php
index 450e3a137603d72f6332559e1267e1d3f9c53128..4f8266b5bf45f0905df5278807f8535106b8810e 100644
--- a/lib/plugins/authad/lang/pt/lang.php
+++ b/lib/plugins/authad/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Paulo Silva <paulotsilva@yahoo.com>
  * @author André Neves <drakferion@gmail.com>
  * @author Paulo Carmino <contato@paulocarmino.com>
diff --git a/lib/plugins/authad/lang/pt/settings.php b/lib/plugins/authad/lang/pt/settings.php
index dc6741b2a65d3763c326bfaa406d67eb6c3ad54d..b734c480089f1bdc1072c967be1155d74d22af1b 100644
--- a/lib/plugins/authad/lang/pt/settings.php
+++ b/lib/plugins/authad/lang/pt/settings.php
@@ -2,11 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author André Neves <drakferion@gmail.com>
  * @author Murilo <muriloricci@hotmail.com>
  * @author Paulo Silva <paulotsilva@yahoo.com>
  * @author Guido Salatino <guidorafael23@gmail.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['account_suffix']        = 'O sufixo da sua conta. Por exemplo, <code>@my.domain.org</code>';
 $lang['base_dn']               = 'Sua base DN. Eg. <code> DC=meu, DC=dominio, DC=org </code>';
@@ -21,3 +22,4 @@ $lang['use_tls']               = 'Usar ligação TLS? Se usada, não ative SSL a
 $lang['debug']                 = 'Deve-se mostrar saída adicional de depuração de erros?';
 $lang['expirywarn']            = 'Número de dias de avanço para avisar o utilizador da expiração da senha. 0 para desativar.';
 $lang['additional']            = 'Uma lista separada por vírgula de atributos adicionais de AD para buscar a partir de dados do usuário. Usado por alguns plugins.';
+$lang['update_mail']           = 'Permitir que usuários atualizem seus endereços de e-mail?';
diff --git a/lib/plugins/authad/lang/ru/lang.php b/lib/plugins/authad/lang/ru/lang.php
index 215270901b025f92b8a9fe23b43e422bc81fb2ed..0d398f78cc0e3c4de57ad615503c07f754841f2f 100644
--- a/lib/plugins/authad/lang/ru/lang.php
+++ b/lib/plugins/authad/lang/ru/lang.php
@@ -3,12 +3,13 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
  * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Takumo <9206984@mail.ru>
  * @author dimsharav <dimsharav@gmail.com>
  */
 $lang['domain']                = 'Домен';
-$lang['authpwdexpire']         = 'Действие вашего пароля истекает через %d дней. Вы должны изменить его как можно скорее';
+$lang['authpwdexpire']         = 'Действие вашего пароля истекает через %d дней. Вы должны изменить его как можно скорее.';
 $lang['passchangefail']        = 'Не удалось изменить пароль. Возможно, он не соответствует требованиям к паролю.';
 $lang['userchangefail']        = 'Ошибка при изменении атрибутов пользователя. Возможно, у Вашей учетной записи недостаточно прав?';
-$lang['connectfail']           = 'Невозможно соединиться с сервером AD.';
+$lang['connectfail']           = 'Невозможно соединиться с сервером Active Directory.';
diff --git a/lib/plugins/authad/lang/ru/settings.php b/lib/plugins/authad/lang/ru/settings.php
index 4e95d36f931f455d727989bcfa775dd2d90551f7..d6bc8fc8a4dc8167eeb8b706e49b8573e18de2c0 100644
--- a/lib/plugins/authad/lang/ru/settings.php
+++ b/lib/plugins/authad/lang/ru/settings.php
@@ -3,28 +3,28 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
  * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author Aleksandr Selivanov <alexgearbox@gmail.com>
  * @author Artur <ncuxxx@gmail.com>
  * @author Erli Moen <evseev.jr@gmail.com>
  * @author Владимир <id37736@yandex.ru>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Type-kun <workwork-1@yandex.ru>
  * @author Vitaly Filatenko <kot@hacktest.net>
  * @author Radimir <radimir.shevchenko@gmail.com>
  */
 $lang['account_suffix']        = 'Суффикс вашего аккаунта. Например, <code>@my.domain.org</code>';
 $lang['base_dn']               = 'Ваш базовый DN. Например: <code>DC=my,DC=domain,DC=org</code>';
-$lang['domain_controllers']    = 'Список DNS-серверов, разделённых запятой. Например:<code>srv1.domain.org,srv2.domain.org</code>';
+$lang['domain_controllers']    = 'Список контроллеров домена, разделённых запятой. Например:<code>srv1.domain.org,srv2.domain.org</code>';
 $lang['admin_username']        = 'Привилегированный пользователь Active Directory с доступом ко всем остальным пользовательским данным. Необязательно, однако необходимо для определённых действий вроде отправки почтовой подписки.';
 $lang['admin_password']        = 'Пароль для указанного пользователя.';
 $lang['sso']                   = 'Использовать SSO (Single-Sign-On) через Kerberos или NTLM?';
 $lang['sso_charset']           = 'Кодировка, в которой веб-сервер передаёт имя пользователя Kerberos или NTLM. Для UTF-8 или latin-1 остаётся пустым. Требует расширение iconv.';
-$lang['real_primarygroup']     = 'Должна ли использоваться настоящая первичная группа вместо “Domain Users” (медленнее)';
+$lang['real_primarygroup']     = 'Должна ли использоваться настоящая первичная группа вместо “Domain Users” (медленнее).';
 $lang['use_ssl']               = 'Использовать SSL? Если да, то не включайте TLS.';
 $lang['use_tls']               = 'Использовать TLS? Если да, то не включайте SSL.';
 $lang['debug']                 = 'Выводить дополнительную информацию при ошибках?';
 $lang['expirywarn']            = 'За сколько дней нужно предупреждать пользователя о необходимости изменить пароль? Для отключения укажите 0 (ноль).';
 $lang['additional']            = 'Дополнительные AD-атрибуты, разделённые запятой, для выборки из данных пользователя. Используется некоторыми плагинами.';
-$lang['update_name']           = 'Разрешить пользователям редактировать свое настоящее имя?';
+$lang['update_name']           = 'Разрешить пользователям редактировать свое AD-имя?';
 $lang['update_mail']           = 'Разрешить пользователям редактировать свой электронный адрес?';
diff --git a/lib/plugins/authad/lang/sk/lang.php b/lib/plugins/authad/lang/sk/lang.php
index 7197dcbd476cffb5d5db5ca0a7d7141cfba450ae..1ff338d0835c9ad3b10bedec741581f0f0dd1882 100644
--- a/lib/plugins/authad/lang/sk/lang.php
+++ b/lib/plugins/authad/lang/sk/lang.php
@@ -4,8 +4,9 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Martin Michalek <michalek.dev@gmail.com>
- * @author Michalek <michalek.dev@gmail.com>
  */
+$lang['domain']                = 'Prihlasovacia doména';
 $lang['authpwdexpire']         = 'Platnosť hesla vyprší za %d dní, mali by ste ho zmeniť čo najskôr.';
 $lang['passchangefail']        = 'Nepodarilo sa zmeniť heslo. Možno neboli splnené podmienky';
 $lang['userchangefail']        = 'Nepodarilo sa zmeniť atribúty používateľa. Možno tvoj účet nemá oprávnenia na vykonanie týchto zmien?';
+$lang['connectfail']           = 'Nepodarilo sa pripojiť na Active Directory server.';
diff --git a/lib/plugins/authad/lang/sk/settings.php b/lib/plugins/authad/lang/sk/settings.php
index 26362e15e4b63ef18fe04a5d549e6dc3e7f2b3f7..a8aabc7170f5ca126fb9f139d91ea9cd9bd6cd39 100644
--- a/lib/plugins/authad/lang/sk/settings.php
+++ b/lib/plugins/authad/lang/sk/settings.php
@@ -18,3 +18,5 @@ $lang['use_tls']               = 'Použiť TLS pripojenie? Ak áno, nepovoľte S
 $lang['debug']                 = 'Zobraziť dodatočné ladiace informácie pri chybe?';
 $lang['expirywarn']            = 'Počet dní pred uplynutím platnosti hesla, počas ktorých používateľ dostáva upozornenie. 0 deaktivuje túto voľbu.';
 $lang['additional']            = 'Zoznam dodatočných AD atribútov oddelených čiarkou získaných z údajov používateľa. Používané niektorými pluginmi.';
+$lang['update_name']           = 'Povoliť používateľom zmenu ich zobrazovaného mena v AD?';
+$lang['update_mail']           = 'Povoliť používateľom zmenu ich emailovej adresy?';
diff --git a/lib/plugins/authad/lang/sl/lang.php b/lib/plugins/authad/lang/sl/lang.php
index dc7b3567ae4185063385632b9b162fa1af9e15d7..b4c864322598747727a3830e4c979e3476e8bc3c 100644
--- a/lib/plugins/authad/lang/sl/lang.php
+++ b/lib/plugins/authad/lang/sl/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author matej <mateju@svn.gnome.org>
  */
 $lang['authpwdexpire']         = 'Geslo bo poteklo v %d dneh. Priporočljivo ga je zamenjati.';
diff --git a/lib/plugins/authad/lang/sl/settings.php b/lib/plugins/authad/lang/sl/settings.php
index 5849ea43136770cb353a045157fe3dbff52b84e3..f166309c2415e57515c63b1e60b9dbe53a045444 100644
--- a/lib/plugins/authad/lang/sl/settings.php
+++ b/lib/plugins/authad/lang/sl/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author matej <mateju@svn.gnome.org>
  * @author Jernej Vidmar <jernej.vidmar@vidmarboehm.com>
  */
diff --git a/lib/plugins/authad/lang/sr/lang.php b/lib/plugins/authad/lang/sr/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5ac17b910161338c3b31c278f0fbd2e2eb4206a
--- /dev/null
+++ b/lib/plugins/authad/lang/sr/lang.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['domain']                = 'Домен пријаве';
+$lang['authpwdexpire']         = 'Ваша лозинка ће истећи за %d дан(а), требало би да је промените ускоро.';
+$lang['passchangefail']        = 'Нисам успео да променим лозинку. Можда нису испоштована правила за промену лозинке.';
+$lang['userchangefail']        = 'Нисам успео да променим корисничке особине. Можда ваш налог нема довољно овлашћења за прављење измена?';
+$lang['connectfail']           = 'Нисам успео да се повежем на Active Directory сервер.';
diff --git a/lib/plugins/authad/lang/sr/settings.php b/lib/plugins/authad/lang/sr/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e4409cc373a42eeba4134cf2cf1b98d367310b5
--- /dev/null
+++ b/lib/plugins/authad/lang/sr/settings.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['account_suffix']        = 'Суфикс на вашем налогу. Нпр.: <code>@moj.domen.rs</code>';
+$lang['base_dn']               = 'Ваше основно име домена. Нпр.: <code>DC=moj,DC=domen,DC=org</code>';
+$lang['domain_controllers']    = 'Списак доменских контролера, одвојених зарезима. Нпр.: <code>srv1.domen.org,srv2.domen.org</code>';
+$lang['admin_username']        = 'Повлашћени Active Directory корисник са приступом подацима свих корисника. Изборно али је потребно за одређене радње као што је слање мејлова о претплаћивању.';
+$lang['admin_password']        = 'Лозинка за корисника изнад.';
+$lang['sso']                   = 'Да ли треба да се користи Single-Sign-On преко Кербероса или NTLM-а?';
+$lang['use_ssl']               = 'Користити SSL везу? Ако се користи, не омогућујте TLS испод.';
+$lang['use_tls']               = 'Користити TLS везу? Ако се користи, не омогућујте SSL испод.';
+$lang['debug']                 = 'Приказати додатан излаз за поправљање грешака код настанка грешака?';
+$lang['expirywarn']            = 'Дана унапред за које треба упозорити корисника на истицање лозинке. 0 за искључивање.';
+$lang['update_name']           = 'Дозволити корисницима да ажурирају њихово AD приказно име?';
+$lang['update_mail']           = 'Дозволити корисницима да ажурирају њихове мејл адрсе?';
diff --git a/lib/plugins/authad/lang/sv/lang.php b/lib/plugins/authad/lang/sv/lang.php
index f253ae7fe60cf1d7b6ebcbb34fe23adc27657ebf..8c6397552688431d4b507a2d9e5e4d3773c0d95f 100644
--- a/lib/plugins/authad/lang/sv/lang.php
+++ b/lib/plugins/authad/lang/sv/lang.php
@@ -2,7 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Smorkster Andersson smorkster@gmail.com
  */
+$lang['domain']                = 'Inloggningsdomän';
 $lang['authpwdexpire']         = 'Ditt lösenord kommer att bli ogiltigt om %d dagar, du bör ändra det snart.';
+$lang['passchangefail']        = 'Kunde inte ändra lösenord. Kanske var inte lösenordspolicyn uppfylld?';
+$lang['userchangefail']        = 'Kunde inte ändra användaregenskaper. Kanske har ditt konto inte behörighet att göra ändringar?';
+$lang['connectfail']           = 'Kunde inte ansluta till Active Directory-server.';
diff --git a/lib/plugins/authad/lang/sv/settings.php b/lib/plugins/authad/lang/sv/settings.php
index 17eb523a8417838f47c198cdb8cb53558478912a..249eb33acdb7fdfad72598fdb3a58349f4b44126 100644
--- a/lib/plugins/authad/lang/sv/settings.php
+++ b/lib/plugins/authad/lang/sv/settings.php
@@ -2,11 +2,19 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['account_suffix']        = 'Ditt konto suffix. T.ex. <code>min.domän.org</code>';
+$lang['base_dn']               = 'Din bas-DN. T ex <code>DC=min,DC=domän,DC=org</code>';
+$lang['domain_controllers']    = 'En kommaseparerad lista av Domain controllers. T ex <code>srv1.domain.org,srv2.domain.org</code>';
 $lang['admin_password']        = 'Lösenord för användare ovan.';
 $lang['sso']                   = 'Ska Single-Sign-On via Kerberos eller NTLM användas?';
 $lang['use_ssl']               = 'Använda SSL anslutning? Om använd, möjliggör inte TLS nedan.';
 $lang['use_tls']               = 'Använda TLS anslutning? Om använd, möjliggör inte SSL ovan.';
+$lang['debug']                 = 'Visa utökad avlusningsinformation för fel?';
+$lang['expirywarn']            = 'Antakl dagar i förväg att varna användare om utgående lösenord. 0 för att inaktivera.';
+$lang['additional']            = 'En komma-separerad lista på extra AT-attibut att hämta från användardata. Används av vissa plugin.';
+$lang['update_name']           = 'Tillåt användare att uppdatera deras AD-visningsnamn?';
+$lang['update_mail']           = 'Tillåt användare att uppdatera deras e-postadresser?';
diff --git a/lib/plugins/authad/lang/uk/lang.php b/lib/plugins/authad/lang/uk/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..7e685a9cea58b4cf7ee547b470fad897d860d1f0
--- /dev/null
+++ b/lib/plugins/authad/lang/uk/lang.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Олексій <alexey.furashev@gmail.com>
+ * @author Vitaly <vitaly.balashov@smuzzy.com.ua>
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['domain']                = 'Домен';
+$lang['authpwdexpire']         = 'Дія вашого паролю завершится через %d днів, вам необхідно змінити його щонайвшидше.';
+$lang['passchangefail']        = 'Не вдалося змінити пароль. Можливо, політика пароля не була застосована?';
+$lang['userchangefail']        = 'Не вийшло змінити атрибути користувача. Можливо, у вашого акаунту немає дозволу на внесення змін?';
+$lang['connectfail']           = 'Не вийшло з\'єднатися с сервером Active Directory.';
diff --git a/lib/plugins/authad/lang/uk/settings.php b/lib/plugins/authad/lang/uk/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c76e7d9d1cfa03f46acf2f4eefa177aa50e46b3
--- /dev/null
+++ b/lib/plugins/authad/lang/uk/settings.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Oleksii <alexey.furashev@gmail.com>
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['account_suffix']        = 'Суфікс вашого облікового запису. Щось на шквалт: <code>@my.domain.org</code>';
+$lang['base_dn']               = 'Ваш DN. Щось на шквалт: <code>DC=my,DC=domain,DC=org</code>';
+$lang['admin_password']        = 'Пароль вказаного користувача.';
+$lang['use_ssl']               = 'Використовуєте SSL-з\'єднання? Якщо так, не вмикайте TLS нижче.';
+$lang['use_tls']               = 'Використовуєте TLS-з\'єднання? Якщо так, не вмикайте SSL нижче.';
+$lang['debug']                 = 'Показати додаткові відомості щодо помилок?';
+$lang['expirywarn']            = 'Кількість днів за яких попереджати про закінчення дії пароля користувача. 0 - не попереджати.';
+$lang['update_name']           = 'Дозволити користувачам оновлювати ім\'я AD, яке відображається?';
+$lang['update_mail']           = 'Дозволити користувачам оновлювати їх адреси електронної пошлти?';
diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php
index 9dece24279cc740805339991b9ed8d701ee841fa..52f9ba50dc073fd8185b3bc84193b364554f8de5 100644
--- a/lib/plugins/authldap/auth.php
+++ b/lib/plugins/authldap/auth.php
@@ -184,10 +184,10 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
         $info = array();
         $info['user']   = $user;
 		$this->_debug('LDAP user to find: '.htmlspecialchars($info['user']), 0, __LINE__, __FILE__);
-		
+
         $info['server'] = $this->getConf('server');
 		$this->_debug('LDAP Server: '.htmlspecialchars($info['server']), 0, __LINE__, __FILE__);
-		
+
 
         //get info for given user
         $base = $this->_makeFilter($this->getConf('usertree'), $info);
@@ -198,20 +198,20 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
         }
 
 		$this->_debug('LDAP Filter: '.htmlspecialchars($filter), 0, __LINE__, __FILE__);
-		
+
         $this->_debug('LDAP user search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
         $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
 		$sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'));
-		
+
 		$result = @ldap_get_entries($this->con, $sr);
 
         // if result is not an array
         if(!is_array($result)) {
 			// no objects found
 			$this->_debug('LDAP search returned non-array result: '.htmlspecialchars(print($result)), -1, __LINE__, __FILE__);
-            return false; 
+            return false;
         }
-		
+
 		// Don't accept more or less than one response
 		if ($result['count'] != 1)		{
 			$this->_debug('LDAP search returned '.htmlspecialchars($result['count']).' results while it should return 1!', -1, __LINE__, __FILE__);
@@ -220,10 +220,10 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
 			//}
 			return false;
 		}
-		
-		
+
+
 		$this->_debug('LDAP search found single result !', 0, __LINE__, __FILE__);
-		
+
         $user_result = $result[0];
         ldap_free_result($sr);
 
@@ -239,7 +239,9 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
             foreach($this->getConf('mapping') as $localkey => $key) {
                 if(is_array($key)) {
                     // use regexp to clean up user_result
-                    list($key, $regexp) = each($key);
+                    // $key = array($key=>$regexp), only handles the first key-value
+                    $regexp = current($key);
+                    $key = key($key);
                     if($user_result[$key]) foreach($user_result[$key] as $grpkey => $grp) {
                         if($grpkey !== 'count' && preg_match($regexp, $grp, $match)) {
                             if($localkey == 'grps') {
diff --git a/lib/plugins/authldap/lang/da/lang.php b/lib/plugins/authldap/lang/da/lang.php
index 03ae2eb351654e16429c050597cbf1734ddd0473..35249dfa014ff7e4407e115d8cd173a6bb4a4df8 100644
--- a/lib/plugins/authldap/lang/da/lang.php
+++ b/lib/plugins/authldap/lang/da/lang.php
@@ -3,6 +3,8 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Jon Theil Nielsen <jontheil@gmail.com>
  * @author Jacob Palm <mail@jacobpalm.dk>
  */
 $lang['connectfail']           = 'LDAP kan ikke forbinde: %s';
+$lang['domainfail']            = 'LDAP kan ikke finde dit bruger dn';
diff --git a/lib/plugins/authldap/lang/da/settings.php b/lib/plugins/authldap/lang/da/settings.php
index 777b5e3e9a4c5aca972484f9cf5ddd5ae00d1437..7a1384db6e0b642d3e55dd276d7fbf464808d518 100644
--- a/lib/plugins/authldap/lang/da/settings.php
+++ b/lib/plugins/authldap/lang/da/settings.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Jon Theil Nielsen <jontheil@gmail.com>
  * @author Jens Hyllegaard <jens.hyllegaard@gmail.com>
  * @author soer9648 <soer9648@eucl.dk>
  * @author Jacob Palm <mail@jacobpalm.dk>
@@ -15,6 +16,14 @@ $lang['userfilter']            = 'LDAP filter der benyttes til at søge efter br
 $lang['groupfilter']           = 'LDAP filter tder benyttes til at søge efter grupper. F.eks. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
 $lang['version']               = 'Protokol version der skal benyttes. Det er muligvis nødvendigt at sætte denne til <code>3</code>';
 $lang['starttls']              = 'Benyt TLS forbindelser?';
+$lang['binddn']                = 'DN af en valgfri <bindings-bruger, hvis ikke anonym binding er tilstrækkeligt. Fx <code>cn=admin,dc=my,dc=home</code>';
 $lang['bindpw']                = 'Kodeord til ovenstående bruger';
+$lang['userscope']             = 'Begræns søgekriterier for brugersøgning';
+$lang['groupscope']            = 'Begræns søgekriterier for gruppesøgning';
+$lang['userkey']               = 'Attribut der betegner brugernavnet; skal være i overensstemmelse med brugerfilteret.';
+$lang['groupkey']              = 'Gruppemedlemskab fra hvilken som helst brugerattribut (i stedet for standard AD-grupper), fx gruppe fra afdeling eller telefonnummer';
 $lang['modPass']               = 'Kan LDAP adgangskoden skiftes via DokuWiki?';
 $lang['debug']                 = 'Vis yderligere debug output ved fejl';
+$lang['referrals_o_-1']        = 'brug standardindstilling';
+$lang['referrals_o_0']         = 'følg ikke henvisninger';
+$lang['referrals_o_1']         = 'følg henvisninger';
diff --git a/lib/plugins/authldap/lang/de-informal/settings.php b/lib/plugins/authldap/lang/de-informal/settings.php
index a17cf356d238eee9cf6e8aece96af764fd128d47..716b92ee6175c6ff665d32e8ec23ae7ddade9f54 100644
--- a/lib/plugins/authldap/lang/de-informal/settings.php
+++ b/lib/plugins/authldap/lang/de-informal/settings.php
@@ -6,6 +6,7 @@
  * @author Matthias Schulte <dokuwiki@lupo49.de>
  * @author Volker Bödker <volker@boedker.de>
  * @author rnck <dokuwiki@rnck.de>
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
  */
 $lang['server']                = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).';
 $lang['port']                  = 'Port des LDAP-Servers, falls kein Port angegeben wurde.';
@@ -21,6 +22,7 @@ $lang['binddn']                = 'DN eines optionalen Benutzers, wenn der anonym
 $lang['bindpw']                = 'Passwort des angegebenen Benutzers.';
 $lang['userscope']             = 'Die Suchweite nach Benutzeraccounts.';
 $lang['groupscope']            = 'Die Suchweite nach Benutzergruppen.';
+$lang['userkey']               = 'Attribut, das den Benutzernamen enthält; muss konsistent zum userfilter sein.';
 $lang['groupkey']              = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).';
 $lang['modPass']               = 'Kann das LDAP Passwort via dokuwiki geändert werden?';
 $lang['debug']                 = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?';
diff --git a/lib/plugins/authldap/lang/eo/settings.php b/lib/plugins/authldap/lang/eo/settings.php
index 07b46c84a5113aca3da65791c7cd7a83a6035731..ca20f675a911aea459012fc3ad248a7849d1b6c3 100644
--- a/lib/plugins/authldap/lang/eo/settings.php
+++ b/lib/plugins/authldap/lang/eo/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Felipe Castro <fefcas@yahoo.com.br>
  */
 $lang['server']                = 'Via LDAP-servilo. AÅ­ servila nomo (<code>localhost</code>) aÅ­ plene detala URL (<code>ldap://servilo.lando:389</code>)';
diff --git a/lib/plugins/authldap/lang/es/settings.php b/lib/plugins/authldap/lang/es/settings.php
index 6ed46b0cd3ab37e9ac58227a87e0634856ebc079..ba8f41e599b9656dbe58a03a24a0e2684b343131 100644
--- a/lib/plugins/authldap/lang/es/settings.php
+++ b/lib/plugins/authldap/lang/es/settings.php
@@ -7,6 +7,7 @@
  * @author Eloy <ej.perezgomez@gmail.com>
  * @author Alejandro Nunez <nunez.alejandro@gmail.com>
  * @author Enny Rodriguez <aquilez.4@gmail.com>
+ * @author Domingo Redal <docxml@gmail.com>
  */
 $lang['server']                = 'Tu servidor LDAP. Puede ser el nombre del host  (<code>localhost</code>) o una URL completa (<code>ldap://server.tld:389</code>)';
 $lang['port']                  = 'Servidor LDAP en caso de que no se diera la URL completa anteriormente.';
@@ -18,6 +19,7 @@ $lang['version']               = 'La versión del protocolo a usar. Puede que ne
 $lang['starttls']              = 'Usar conexiones TLS?';
 $lang['referrals']             = '¿Deben ser seguidas las referencias?';
 $lang['deref']                 = '¿Cómo desreferenciar los alias?';
+$lang['binddn']                = 'DN de un usuario de enlace opcional si el enlace anónimo no es suficiente. P. ej. <code>cn=admin, dc=my, dc=home</code>';
 $lang['bindpw']                = 'Contraseña del usuario de arriba.';
 $lang['userscope']             = 'Limitar ámbito de búsqueda para búsqueda de usuarios';
 $lang['groupscope']            = 'Limitar ámbito de búsqueda para búsqueda de grupos';
diff --git a/lib/plugins/authldap/lang/eu/lang.php b/lib/plugins/authldap/lang/eu/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..f68b6d18457b2dd17ba33d9e1db0a14c609bbd0a
--- /dev/null
+++ b/lib/plugins/authldap/lang/eu/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Osoitz <oelkoro@gmail.com>
+ */
+$lang['connectfail']           = 'LDAP ezin da konektaku: %s';
diff --git a/lib/plugins/authldap/lang/eu/settings.php b/lib/plugins/authldap/lang/eu/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd3d62c8247f64077357252dfa6ab2532fed55e7
--- /dev/null
+++ b/lib/plugins/authldap/lang/eu/settings.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Osoitz <oelkoro@gmail.com>
+ */
+$lang['version']               = 'Erabiltzen duzun proitokoloaren bertsioa. <code>3</code> gisa jarri behar zenezake';
+$lang['starttls']              = 'Erabili TLS konexioak?';
+$lang['bindpw']                = 'Goiko erabiltzailearen pasahitza';
+$lang['referrals_o_-1']        = 'erabili lehenetsitakoa';
diff --git a/lib/plugins/authldap/lang/fr/settings.php b/lib/plugins/authldap/lang/fr/settings.php
index 49279f47f9b8c7db316f6a6206a0270bd8c2db41..be363670831a3eae06cff2f055667c0d12c32ccf 100644
--- a/lib/plugins/authldap/lang/fr/settings.php
+++ b/lib/plugins/authldap/lang/fr/settings.php
@@ -5,7 +5,6 @@
  *
  * @author Bruno Veilleux <bruno.vey@gmail.com>
  * @author schplurtz <Schplurtz@laposte.net>
- * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
  */
 $lang['server']                = 'Votre serveur LDAP. Soit le nom d\'hôte (<code>localhost</code>) ou l\'URL complète (<code>ldap://serveur.dom:389</code>)';
 $lang['port']                  = 'Port du serveur LDAP si l\'URL complète n\'a pas été indiquée ci-dessus';
diff --git a/lib/plugins/authldap/lang/he/settings.php b/lib/plugins/authldap/lang/he/settings.php
index 10af7010d21177312d329f9be591a16ca352a257..88864467a587d22776ab87e591cf89a948d425de 100644
--- a/lib/plugins/authldap/lang/he/settings.php
+++ b/lib/plugins/authldap/lang/he/settings.php
@@ -2,11 +2,13 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Guy Yakobovitch <guy.yakobovitch@gmail.com>
  * @author matt carroll <matt.carroll@gmail.com>
  * @author Menashe Tomer <menashesite@gmail.com>
  */
 $lang['starttls']              = 'השתמש בחיבורי TLS';
+$lang['bindpw']                = 'סיסמה של המשתמש לעיל';
 $lang['modPass']               = 'האם dokuwiki יכול ליצור סיסמאות LDAP?';
 $lang['debug']                 = 'הצג מידע נוסף על שגיאות';
 $lang['referrals_o_-1']        = 'ברירת מחדל';
diff --git a/lib/plugins/authldap/lang/lv/settings.php b/lib/plugins/authldap/lang/lv/settings.php
index 90986e4f130b6531a42e6f23b5b6ff9c4571defc..9ffb4e81ba6bc6b2b1d78cee1eb65fae4d7e79df 100644
--- a/lib/plugins/authldap/lang/lv/settings.php
+++ b/lib/plugins/authldap/lang/lv/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['starttls']              = 'Lietot TLS  savienojumus?';
diff --git a/lib/plugins/authldap/lang/pl/lang.php b/lib/plugins/authldap/lang/pl/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..a93252cd4fa4aa3b231c1a550de4a411e0f8ecdc
--- /dev/null
+++ b/lib/plugins/authldap/lang/pl/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ */
+$lang['connectfail']           = 'LDAP nie może się połączyć: %s';
+$lang['domainfail']            = 'LDAP nie może znaleźć DN użytkownika';
diff --git a/lib/plugins/authldap/lang/pl/settings.php b/lib/plugins/authldap/lang/pl/settings.php
index cc7174f6f508d4f48f4124ff81bd2dd5961ec758..7181885427255f318173969f5fbc0d59c5ad1b69 100644
--- a/lib/plugins/authldap/lang/pl/settings.php
+++ b/lib/plugins/authldap/lang/pl/settings.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
  * @author Paweł Jan Czochański <czochanski@gmail.com>
  * @author Maciej Helt <geraldziu@gmail.com>
  */
@@ -14,9 +15,20 @@ $lang['userfilter']            = 'Filtr LDAP wykorzystany przy szukaniu kont uż
 $lang['groupfilter']           = 'Filtr LDAP wykorzystany przy szukaniu grup użytkowników np. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
 $lang['version']               = 'Wykorzystywana wersja protokołu. Być może konieczne jest ustawienie tego na <code>3</code>.';
 $lang['starttls']              = 'Użyć połączeń TLS?';
+$lang['referrals']             = 'Czy należy podążać za przekierowaniami?';
+$lang['deref']                 = 'Jak rozwiązywać aliasy?';
+$lang['binddn']                = 'DN opcjonalnego użytkownika powiązanego, jeśli powiązanie anonimowe nie jest wystarczające, np. <code>cn=admin, dc=my, dc=home</code>';
 $lang['bindpw']                = 'Hasło powyższego użytkownika';
+$lang['userscope']             = 'Ogranicz zakres wyszukiwania do wyszukiwania użytkowników';
+$lang['groupscope']            = 'Ogranicz zakres wyszukiwania do wyszukiwania grup użytkowników';
+$lang['userkey']               = 'Atrybut opisujący nazwę użytkownika; musi być zgodny z filtrem użytkownika.';
+$lang['groupkey']              = 'Przynależność do grupy z dowolnego atrybutu użytkownika (zamiast standardowych grup AD), np. grupa z działu lub numer telefonu';
+$lang['modPass']               = 'Czy hasło LDAP można zmienić za pomocą dokuwiki?';
 $lang['debug']                 = 'Przy błędach wyświetl dodatkowe informacje debugujące.';
 $lang['deref_o_0']             = 'LDAP_DEREF_NEVER';
 $lang['deref_o_1']             = 'LDAP_DEREF_SEARCHING';
 $lang['deref_o_2']             = 'LDAP_DEREF_FINDING';
 $lang['deref_o_3']             = 'LDAP_DEREF_ALWAYS';
+$lang['referrals_o_-1']        = 'użyj domyślnej wartości';
+$lang['referrals_o_0']         = 'nie podążaj za przekierowaniami';
+$lang['referrals_o_1']         = 'podążaj za przekierowaniami';
diff --git a/lib/plugins/authldap/lang/pt/lang.php b/lib/plugins/authldap/lang/pt/lang.php
index cd782f4b421cdc4826d36dba561c5b65914551d7..7314d12ed370ad4bebd09c3495c38750fbea994d 100644
--- a/lib/plugins/authldap/lang/pt/lang.php
+++ b/lib/plugins/authldap/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Paulo Carmino <contato@paulocarmino.com>
  */
 $lang['connectfail']           = 'Não foi possível conectar o LDAP: %s';
diff --git a/lib/plugins/authldap/lang/pt/settings.php b/lib/plugins/authldap/lang/pt/settings.php
index 4d4ed2d85bb532f0df61324e37f8c294ff38fedc..ff308c68e5beae43fe6c775e449a63d2b62e5abb 100644
--- a/lib/plugins/authldap/lang/pt/settings.php
+++ b/lib/plugins/authldap/lang/pt/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author André Neves <drakferion@gmail.com>
  * @author Guido Salatino <guidorafael23@gmail.com>
  * @author Romulo Pereira <romuloccomp@gmail.com>
diff --git a/lib/plugins/authldap/lang/ru/settings.php b/lib/plugins/authldap/lang/ru/settings.php
index 973584e7fd9c76b0524e86afb06827e95d5e49c8..916d9a2d2ee83221e410462bdbf4f608f8b0aaa1 100644
--- a/lib/plugins/authldap/lang/ru/settings.php
+++ b/lib/plugins/authldap/lang/ru/settings.php
@@ -6,7 +6,6 @@
  * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author Aleksandr Selivanov <alexgearbox@gmail.com>
  * @author Erli Moen <evseev.jr@gmail.com>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Владимир <id37736@yandex.ru>
  * @author Vitaly Filatenko <kot@hacktest.net>
  * @author Alex P <alexander@lanos.co.uk>
diff --git a/lib/plugins/authldap/lang/sk/lang.php b/lib/plugins/authldap/lang/sk/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..1cca4697d5e90647fe44eb1d96a605327d0bd624
--- /dev/null
+++ b/lib/plugins/authldap/lang/sk/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Martin Michalek <michalek.dev@gmail.com>
+ */
+$lang['connectfail']           = 'LDAP sa nemôže pripojiť: %s';
+$lang['domainfail']            = 'LDAP nemôže nájsť vaše meno (user dn)';
diff --git a/lib/plugins/authldap/lang/sk/settings.php b/lib/plugins/authldap/lang/sk/settings.php
index e8d34658edd7a3911a7c55eeef662051e5c4baba..2d45c923eb213d5889d932e2056fdd0c6ba05141 100644
--- a/lib/plugins/authldap/lang/sk/settings.php
+++ b/lib/plugins/authldap/lang/sk/settings.php
@@ -19,7 +19,9 @@ $lang['binddn']                = 'DN prípadného priradenia používateľa, ak
 $lang['bindpw']                = 'Heslo vyššie uvedeného používateľa';
 $lang['userscope']             = 'Obmedzenie oblasti pri vyhľadávaní používateľa';
 $lang['groupscope']            = 'Obmedzenie oblasti pri vyhľadávaní skupiny';
+$lang['userkey']               = 'Atribút označujúci meno používateľa, musí byt konzistentný s používateľským filtrom.';
 $lang['groupkey']              = 'Príslušnost k skupine určená z daného atribútu používateľa (namiesto štandardnej AD skupiny) napr. skupiny podľa oddelenia alebo telefónneho čísla';
+$lang['modPass']               = 'Môže byť LDAP heslo zmenené prostredníctvom dokuwiki?';
 $lang['debug']                 = 'Zobraziť dodatočné ladiace informácie pri chybe';
 $lang['deref_o_0']             = 'LDAP_DEREF_NEVER';
 $lang['deref_o_1']             = 'LDAP_DEREF_SEARCHING';
diff --git a/lib/plugins/authldap/lang/sl/settings.php b/lib/plugins/authldap/lang/sl/settings.php
index f630703904e0a3dd28db3ed2d6efbcde04859cb6..17115200f417031a7224dc6315da66a35c0270bf 100644
--- a/lib/plugins/authldap/lang/sl/settings.php
+++ b/lib/plugins/authldap/lang/sl/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author matej <mateju@svn.gnome.org>
  * @author Jernej Vidmar <jernej.vidmar@vidmarboehm.com>
  */
diff --git a/lib/plugins/authldap/lang/sr/lang.php b/lib/plugins/authldap/lang/sr/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b78602877c22015213797a6588ddf231c483525
--- /dev/null
+++ b/lib/plugins/authldap/lang/sr/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['connectfail']           = 'LDAP - немогуће повезивање: %s';
+$lang['domainfail']            = 'LDAP - не могу наћи ваш кориснички dn';
diff --git a/lib/plugins/authldap/lang/sr/settings.php b/lib/plugins/authldap/lang/sr/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..3aec5c38a9251836bee37dcfe8eda189bd84ee72
--- /dev/null
+++ b/lib/plugins/authldap/lang/sr/settings.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['starttls']              = 'Користити TLS везе?';
+$lang['referrals']             = 'Да ли треба пратити реферале?';
+$lang['bindpw']                = 'Лозинка корисника изнад';
+$lang['userscope']             = 'Ограничи опсег претраживања за корисничке претраге';
+$lang['groupscope']            = 'Ограничи опсег претраживања за групне претраге';
+$lang['modPass']               = 'Омогућити измену LDAP лозинке преко докувикија?';
+$lang['debug']                 = 'Прикажи додатне податке за поправљање грешака приликом настанка грешака';
+$lang['referrals_o_-1']        = 'користи подразумевано';
+$lang['referrals_o_0']         = 'не прати реферале';
+$lang['referrals_o_1']         = 'прати реферале';
diff --git a/lib/plugins/authldap/lang/sv/lang.php b/lib/plugins/authldap/lang/sv/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..cdc6c338b842895cab5f2a5f9d2797a0590f4559
--- /dev/null
+++ b/lib/plugins/authldap/lang/sv/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['connectfail']           = 'LDAP kan inte ansluta: %s';
+$lang['domainfail']            = 'LDAP kan inte hitta din användar-dn';
diff --git a/lib/plugins/authldap/lang/sv/settings.php b/lib/plugins/authldap/lang/sv/settings.php
index d98400461f6a5f3506f43051eb6146ebd36279c7..07fc574269abf13ef3c55a72846ac34ab53f81d4 100644
--- a/lib/plugins/authldap/lang/sv/settings.php
+++ b/lib/plugins/authldap/lang/sv/settings.php
@@ -2,9 +2,9 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Smorkster Andersson smorkster@gmail.com
- * @author Tor Härnqvist <tor.harnqvist@gmail.com>
  */
 $lang['server']                = 'Din LDAO server. Antingen värdnamn (<code>localhost</code>) eller giltig full URL (<code>ldap://server.tld:389</code>)';
 $lang['port']                  = 'LDAP server port, om det inte angavs full URL ovan';
@@ -15,5 +15,9 @@ $lang['groupfilter']           = 'LDAP filter för att söka efter grupper. T.ex
 $lang['version']               = 'Version av protokoll att använda. Du kan behöva sätta detta till <code>3</code>';
 $lang['starttls']              = 'Använd TLS-anslutningar';
 $lang['bindpw']                = 'Lösenord för användare ovan';
+$lang['userscope']             = 'Begränsa sökomfattning för användarsökning';
+$lang['groupscope']            = 'Begränsa sökomfattning för gruppsökning';
 $lang['groupkey']              = 'Gruppmedlemskap från något användarattribut (istället för standard AD grupp) t.ex. grupp från avdelning eller telefonnummer';
+$lang['modPass']               = 'Får LDAP-lösenordet ändras via DokuWiki?';
 $lang['debug']                 = 'Visa ytterligare felsökningsinformation vid fel';
+$lang['referrals_o_-1']        = 'använd standard';
diff --git a/lib/plugins/authldap/lang/uk/lang.php b/lib/plugins/authldap/lang/uk/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..90431218f52cb99763c77c21a2c04563a4a83e69
--- /dev/null
+++ b/lib/plugins/authldap/lang/uk/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Oleksii <alexey.furashev@gmail.com>
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['connectfail']           = 'LDAP не може встановити з\'єднання: %s';
+$lang['domainfail']            = 'LDAP не знайшов Ваш dn';
diff --git a/lib/plugins/authldap/lang/uk/settings.php b/lib/plugins/authldap/lang/uk/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ae728b7664164442ade764e848baade43329fb0
--- /dev/null
+++ b/lib/plugins/authldap/lang/uk/settings.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Oleksii <alexey.furashev@gmail.com>
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['userfilter']            = 'Фільтр LDAP для відображення облікових записів. Щось на зразок <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['version']               = 'Використовувати версію протоколу. Можливо Вам доведеться вказати <code>3</code>.';
+$lang['starttls']              = 'Використовуєте TLS з\'єднання?';
+$lang['referrals']             = 'Слід підтримувати перепосилання?';
+$lang['deref']                 = 'Як скинути псевдоніми?';
+$lang['bindpw']                = 'Пароль вказаного користувача';
+$lang['userscope']             = 'Обмежити область пошуку користувачів';
+$lang['groupscope']            = 'Обмежити коло пошуку для групового запиту';
+$lang['userkey']               = 'Атрибут, який визначає ім\'я користувача, має бути узгодженим із правилами користувацьких фільтрів.';
+$lang['modPass']               = 'Можете змінити пароль в LDAP через DokuWiki?';
+$lang['debug']                 = 'Показати додаткову інформацію про помилки';
+$lang['deref_o_0']             = 'LDAP_DEREF_NEVER';
+$lang['deref_o_1']             = 'LDAP_DEREF_SEARCHING';
+$lang['deref_o_2']             = 'LDAP_DEREF_FINDING';
+$lang['referrals_o_-1']        = 'Використовувати за замовчуванням';
diff --git a/lib/plugins/authmysql/lang/da/lang.php b/lib/plugins/authmysql/lang/da/lang.php
index 286bf7e8be0f0be75e642ab0d5652f4f4fe509b6..9806e16752729b232a861da95d450845bc248e47 100644
--- a/lib/plugins/authmysql/lang/da/lang.php
+++ b/lib/plugins/authmysql/lang/da/lang.php
@@ -3,8 +3,10 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Jon Theil Nielsen <jontheil@gmail.com>
  * @author Jacob Palm <mail@jacobpalm.dk>
  */
 $lang['connectfail']           = 'Kunne ikke forbinde til databasen.';
 $lang['userexists']            = 'Beklager, en bruger med dette login findes allerede.';
 $lang['usernotexists']         = 'Beklager, brugeren eksisterer ikke.';
+$lang['writefail']             = 'Kan ikke ændre brugerdata. Informér venligst wiki-administratoren';
diff --git a/lib/plugins/authmysql/lang/eo/lang.php b/lib/plugins/authmysql/lang/eo/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..818c392b2a7880112e27cd30aef111f8dfd1bd25
--- /dev/null
+++ b/lib/plugins/authmysql/lang/eo/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
+ */
+$lang['usernotexists']         = 'Pardonu, tiu uzanto ne ekzistas.';
diff --git a/lib/plugins/authmysql/lang/eo/settings.php b/lib/plugins/authmysql/lang/eo/settings.php
index 92e97339698cdc26c041c54da270954e15f7982a..b85f81248f5a69370bd9285037ce4d52469b041e 100644
--- a/lib/plugins/authmysql/lang/eo/settings.php
+++ b/lib/plugins/authmysql/lang/eo/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  */
 $lang['server']                = 'Via MySQL-servilo';
 $lang['user']                  = 'MySQL uzantonomo';
diff --git a/lib/plugins/authmysql/lang/eu/lang.php b/lib/plugins/authmysql/lang/eu/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..64083246f99a96e5c2881411e384474c9bd5661f
--- /dev/null
+++ b/lib/plugins/authmysql/lang/eu/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Osoitz <oelkoro@gmail.com>
+ */
+$lang['connectfail']           = 'Datu-basera konektatzeak huts egin du';
+$lang['userexists']            = 'Badago izen hori duen erabiltzaile bat.';
+$lang['usernotexists']         = 'Ez dago izen hori duen erabiltzailerik.';
diff --git a/lib/plugins/authmysql/lang/eu/settings.php b/lib/plugins/authmysql/lang/eu/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..2a44a59ee87fdd01623e76725dca2d3ce7aa71c0
--- /dev/null
+++ b/lib/plugins/authmysql/lang/eu/settings.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Osoitz <oelkoro@gmail.com>
+ */
+$lang['server']                = 'Zure MYSQL zerbitzaria';
+$lang['user']                  = 'MYSQL erabiltzaile-izena';
+$lang['password']              = 'Goiko erabiltzailearen pasahitza';
+$lang['database']              = 'Erabili beharreko datu-basea';
+$lang['charset']               = 'Datu-basean erabilitako karaktere kodeketa';
+$lang['forwardClearPass']      = 'Pasatu erabiltzaileen pasahitza testu argian beheko SQL esaldiei, passcrypt aukera erabili ordez';
+$lang['debug_o_0']             = 'bat ere ez';
diff --git a/lib/plugins/authmysql/lang/he/settings.php b/lib/plugins/authmysql/lang/he/settings.php
index 3671b1bb9c86a996577ef3be6f3de642e0ec58df..22c30e52a3c73eb28976dded3aeebb881f146128 100644
--- a/lib/plugins/authmysql/lang/he/settings.php
+++ b/lib/plugins/authmysql/lang/he/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Menashe Tomer <menashesite@gmail.com>
  */
 $lang['getUserID']             = 'שאילתת SQL לקבלת מפתח ראשי של המשתמש';
diff --git a/lib/plugins/authmysql/lang/lv/settings.php b/lib/plugins/authmysql/lang/lv/settings.php
index 8550363c9a15fc78afed6ecee125ce77daba1062..008ef344a2c52ca336ac99d4a476b63ac158015f 100644
--- a/lib/plugins/authmysql/lang/lv/settings.php
+++ b/lib/plugins/authmysql/lang/lv/settings.php
@@ -2,9 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Oskars Pakers <oskars.pakers@gmail.com>
  * @author Aivars Miška <allefm@gmail.com>
  */
+$lang['server']                = 'Jūsu MySQL serveris';
 $lang['user']                  = 'MySQL lietotāja vārds';
 $lang['password']              = 'Lietotāja parole';
 $lang['delUser']               = 'SQL pieprasījums lietotāja dzēšanai';
diff --git a/lib/plugins/authmysql/lang/pl/lang.php b/lib/plugins/authmysql/lang/pl/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..14f645e672eaa7599ebf9e315553d4b46fddc6e5
--- /dev/null
+++ b/lib/plugins/authmysql/lang/pl/lang.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ */
+$lang['connectfail']           = 'Nie można połączyć się z bazą danych.';
+$lang['userexists']            = 'Niestety, użytkownik o tym loginie już istnieje.';
+$lang['usernotexists']         = 'Niestety, taki użytkownik nie istnieje.';
+$lang['writefail']             = 'Nie można zmodyfikować danych użytkownika. Proszę poinformować administratora Wiki.';
diff --git a/lib/plugins/authmysql/lang/pl/settings.php b/lib/plugins/authmysql/lang/pl/settings.php
index 075a5e8803cb4b74f9a146d81b536ba22250b217..e54372e574f5c538c81a6519baf0490522e9db5f 100644
--- a/lib/plugins/authmysql/lang/pl/settings.php
+++ b/lib/plugins/authmysql/lang/pl/settings.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
  * @author Paweł Jan Czochański <czochanski@gmail.com>
  * @author Mati <mackosa@wp.pl>
  * @author Maciej Helt <geraldziu@gmail.com>
@@ -13,6 +14,8 @@ $lang['password']              = 'Hasło dla powyższego użytkownika';
 $lang['database']              = 'Używana baza danych';
 $lang['charset']               = 'Zestaw znaków uzyty w bazie danych';
 $lang['debug']                 = 'Wyświetlaj dodatkowe informacje do debugowania.';
+$lang['forwardClearPass']      = 'Zamiast używać opcji passcrypt, przekazuj hasła użytkowników jako czysty tekst do poniższej instrukcji SQL';
+$lang['TablesToLock']          = 'Rozdzielana przecinkami lista tabel, które powinny być blokowane podczas operacji zapisu';
 $lang['checkPass']             = 'Zapytanie SQL wykorzystywane do sprawdzania haseł.';
 $lang['getUserInfo']           = 'Zapytanie SQL zwracające informacje o użytkowniku';
 $lang['getGroups']             = 'Zapytanie SQL przynależność do grup danego użytkownika';
@@ -23,4 +26,20 @@ $lang['FilterEmail']           = 'Klauzula SQL używana do filtrowania użytkown
 $lang['FilterGroup']           = 'Klauzula SQL używana do filtrowania użytkowników na podstawie ich przynależności do grup';
 $lang['SortOrder']             = 'Klauzula SQL używana do sortowania użytkowników';
 $lang['addUser']               = 'Zapytanie SQL dodające nowego użytkownika';
+$lang['addGroup']              = 'Instrukcja SQL dodajÄ…ca nowÄ… grupÄ™';
+$lang['addUserGroup']          = 'Instrukcja SQL dodająca użytkownika do istniejącej grupy';
+$lang['delGroup']              = 'Instrukcja SQL usuwajÄ…ca grupÄ™';
+$lang['getUserID']             = 'Instrukcja SQL pobierająca klucz główny użytkownika';
+$lang['delUser']               = 'Instrukcja SQL usuwająca użytkownika';
+$lang['delUserRefs']           = 'Instrukcja SQL usuwająca użytkownika ze wszystkich grup';
+$lang['updateUser']            = 'Instrukcja SQL aktualizująca profil użytkownika';
+$lang['UpdateLogin']           = 'Polecenie służące do aktualizacji loginu użytkownika';
+$lang['UpdatePass']            = 'Polecenie służące do aktualizacji hasła użytkownika';
+$lang['UpdateEmail']           = 'Polecenie służące do aktualizacji e-mailu użytkownika';
+$lang['UpdateName']            = 'Polecenie służące do aktualizacji imienia i nazwiska użytkownika';
+$lang['UpdateTarget']          = 'Instrukcja limitu do identyfikacji użytkownika podczas aktualizacji';
+$lang['delUserGroup']          = 'Instrukcja SQL usuwająca użytkownika ze wskazanej grupy';
+$lang['getGroupID']            = 'Instrukcja SQL pobierający klucz główny wskazanej grupy';
+$lang['debug_o_0']             = 'brak';
+$lang['debug_o_1']             = 'tylko w przypadku błędów';
 $lang['debug_o_2']             = 'wszystkie zapytania SQL';
diff --git a/lib/plugins/authmysql/lang/pt/lang.php b/lib/plugins/authmysql/lang/pt/lang.php
index 754a552f8dee424aab6375d16abf584ebdb78c8f..9e8bd6cd55fdb558de1ae50486827637708511bf 100644
--- a/lib/plugins/authmysql/lang/pt/lang.php
+++ b/lib/plugins/authmysql/lang/pt/lang.php
@@ -2,9 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Paulo Carmino <contato@paulocarmino.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['connectfail']           = 'Falha ao conectar com o banco de dados.';
 $lang['userexists']            = 'Desculpe, esse login já está sendo usado.';
 $lang['usernotexists']         = 'Desculpe, esse login não existe.';
+$lang['writefail']             = 'Incapaz de modificar dados do usuário. Favor informar ao Wiki-Admin.';
diff --git a/lib/plugins/authmysql/lang/pt/settings.php b/lib/plugins/authmysql/lang/pt/settings.php
index 821dcf802b9eed109aa2fa97b8d6d12afeaf0354..2488487fdb6f805f021ca672ad469ca2dfdffbbc 100644
--- a/lib/plugins/authmysql/lang/pt/settings.php
+++ b/lib/plugins/authmysql/lang/pt/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author André Neves <drakferion@gmail.com>
  * @author Guido Salatino <guidorafael23@gmail.com>
  */
diff --git a/lib/plugins/authmysql/lang/ru/settings.php b/lib/plugins/authmysql/lang/ru/settings.php
index 054580a50030facd9fc9992f01293c415dbd91a4..810937782c7d92f56af085c9e7eb841f9602eac3 100644
--- a/lib/plugins/authmysql/lang/ru/settings.php
+++ b/lib/plugins/authmysql/lang/ru/settings.php
@@ -3,10 +3,10 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
  * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author Aleksandr Selivanov <alexgearbox@gmail.com>
  * @author Type-kun <workwork-1@yandex.ru>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  */
 $lang['server']                = 'Ваш MySQL-сервер';
 $lang['user']                  = 'Имя пользователя MySQL';
@@ -14,7 +14,7 @@ $lang['password']              = 'Пароль пользователя MySQL';
 $lang['database']              = 'Имя базы данных';
 $lang['charset']               = 'Используемый набор символов в базе данных';
 $lang['debug']                 = 'Отображение дополнительной отладочной информации';
-$lang['forwardClearPass']      = 'Передача пароля пользователя открытым текстом, вместо зашифрованной формы в используемом выражении SQL';
+$lang['forwardClearPass']      = 'Передача пароля пользователя открытым текстом, вместо зашифрованной формы, в используемом выражении SQL';
 $lang['TablesToLock']          = 'Имена таблиц (через запятую), которым необходимо ограничение для записи';
 $lang['checkPass']             = 'Выражение SQL, осуществляющее проверку пароля';
 $lang['getUserInfo']           = 'Выражение SQL, осуществляющее извлечение информации о пользователе';
diff --git a/lib/plugins/authmysql/lang/sk/lang.php b/lib/plugins/authmysql/lang/sk/lang.php
index 9f7038157c2e02ebade4677843eb45f7f4380c2e..9d792b7e98b63244ad3ef912b7c5deff4ae55f3a 100644
--- a/lib/plugins/authmysql/lang/sk/lang.php
+++ b/lib/plugins/authmysql/lang/sk/lang.php
@@ -7,4 +7,5 @@
  */
 $lang['connectfail']           = 'Nepodarilo sa pripojiť k databáze.';
 $lang['userexists']            = 'Ľutujem, ale používateľ s týmto prihlasovacím menom už existuje.';
+$lang['usernotexists']         = 'Ľutujem, daný používateľ neexistuje.';
 $lang['writefail']             = 'Nie je možné zmeniť údaje používateľa, informujte prosím administrátora Wiki.';
diff --git a/lib/plugins/authmysql/lang/sl/settings.php b/lib/plugins/authmysql/lang/sl/settings.php
index 5e82816df947d1c5108d5726228df58fc7f14023..8e0b58c40cfe6fa2176e66f36458ab3702566696 100644
--- a/lib/plugins/authmysql/lang/sl/settings.php
+++ b/lib/plugins/authmysql/lang/sl/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Matej Urbančič <mateju@svn.gnome.org>
  */
 $lang['database']              = 'Podatkovna zbirka za uporabo';
diff --git a/lib/plugins/authmysql/lang/sr/lang.php b/lib/plugins/authmysql/lang/sr/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ec2fb6a58223112b6c91e0de85a450e4333091c
--- /dev/null
+++ b/lib/plugins/authmysql/lang/sr/lang.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['connectfail']           = 'Нисам успео да се повежем на базу.';
+$lang['userexists']            = 'Нажалост, корисник са таквом пријавом већ постоји.';
+$lang['usernotexists']         = 'Нажалост, тај корисник не постоји.';
+$lang['writefail']             = 'Не могу да променим корисничке податке. Обавестите админа викија';
diff --git a/lib/plugins/authmysql/lang/sr/settings.php b/lib/plugins/authmysql/lang/sr/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..eabdfbc24859aee00063b563ec0f6e54d1424acf
--- /dev/null
+++ b/lib/plugins/authmysql/lang/sr/settings.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['server']                = 'Ваш MySQL сервер';
+$lang['user']                  = 'MySQL корисничко име';
+$lang['password']              = 'Лозинка корисника изнад';
+$lang['database']              = 'База коју треба користити';
+$lang['charset']               = 'Кодни распоред коришћен у бази';
+$lang['debug']                 = 'Прикажи додатне податке за поправљање грешака';
+$lang['forwardClearPass']      = 'Пренеси корисничке лозинке као чист текст у SQL изјавама испод уместо коришћења passcrypt опције';
+$lang['TablesToLock']          = 'Списак табела одвојених размаком које треба закључати приликом уписивања';
+$lang['checkPass']             = 'SQL упит за проверу лозинки';
+$lang['getUserInfo']           = 'SQL упит за добављање података о кориснику';
+$lang['getGroups']             = 'SQL за добављање корисничких учлањења у групе';
+$lang['getUsers']              = 'SQL упит за излиставање свих корисника';
+$lang['FilterLogin']           = 'SQL услов за филтрирање корисника по имену за пријаву';
+$lang['FilterName']            = 'SQL услов за филтрирање корисника по пуном имену';
+$lang['FilterEmail']           = 'SQL услов за филтрирање корисника по мејл адреси';
+$lang['FilterGroup']           = 'SQL услов за филтрирање корисника по чланству у групама';
+$lang['SortOrder']             = 'SQL услов за сортирање корисника';
+$lang['addUser']               = 'SQL упит за додавање новог корисника';
+$lang['addGroup']              = 'SQL упит за додавање нове групе';
+$lang['addUserGroup']          = 'SQL упит за додавање корисника у постојећу групу';
+$lang['delGroup']              = 'SQL упит за уклањање групе';
+$lang['getUserID']             = 'SQL упит за добављање примарног кључа корисника';
+$lang['delUser']               = 'SQL упит за брисање корисника';
+$lang['delUserRefs']           = 'SQL упит за брисање корисника из свих група';
+$lang['updateUser']            = 'SQL упит за ажурирање корисничког профила';
+$lang['UpdateLogin']           = 'Услов за ажурирање корисничког имена за пријаву';
+$lang['UpdatePass']            = 'Услов за ажурирање корисничке лозинке';
+$lang['UpdateEmail']           = 'Услов за ажурирање корисничке мејл адресе';
+$lang['UpdateName']            = 'Услов за ажурирање корисничког пуног имена';
+$lang['UpdateTarget']          = 'Ограничи услов да би се утврдио корисник приликом ажурирања';
+$lang['delUserGroup']          = 'SQL упит за уклањање корисника из дате групе';
+$lang['getGroupID']            = 'SQL упит за добављање примарног кључа дате групе';
+$lang['debug_o_0']             = 'ништа';
+$lang['debug_o_1']             = 'само на грешкама';
+$lang['debug_o_2']             = 'сви SQL упити';
diff --git a/lib/plugins/authmysql/lang/sv/lang.php b/lib/plugins/authmysql/lang/sv/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c97bd7bb8d6bd4f547f545e0481584d0c7c545f
--- /dev/null
+++ b/lib/plugins/authmysql/lang/sv/lang.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['connectfail']           = 'Kunde inte ansluta till databas.';
+$lang['userexists']            = 'Tyvärr, en användare med denna inloggning existerar redan.';
+$lang['usernotexists']         = 'Tyvärr, den användaren existerar inte.';
+$lang['writefail']             = 'Kunde inte ändra användardata. Var god inormera Wiki-administratören.';
diff --git a/lib/plugins/authmysql/lang/sv/settings.php b/lib/plugins/authmysql/lang/sv/settings.php
index 420e443f4e50eb6b885a1033077d674d18d3bf5c..aa76b898f00e6476831c2f396536f8d65c808e81 100644
--- a/lib/plugins/authmysql/lang/sv/settings.php
+++ b/lib/plugins/authmysql/lang/sv/settings.php
@@ -2,13 +2,15 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['server']                = 'Din MySQL server';
 $lang['user']                  = 'Användarnamn för MySQL';
 $lang['password']              = 'Lösenord för användare ovan';
 $lang['database']              = 'Databas att använda';
+$lang['charset']               = 'Teckenuppsättning som används i databas';
 $lang['debug']                 = 'Visa ytterligare felsökningsinformation';
 $lang['forwardClearPass']      = 'Skicka användares lösenord i klartext till SQL sats nedan, istället för att använda passcrypt alternativet';
 $lang['checkPass']             = 'SQL sats för kontroll av lösenord';
@@ -24,3 +26,4 @@ $lang['delUserRefs']           = 'SQL sats för att ta bort en användare från
 $lang['updateUser']            = 'SQL sats för att uppdatera en användarprofil';
 $lang['delUserGroup']          = 'SQL sats för att ta bort en användare från en angiven grupp';
 $lang['debug_o_0']             = 'ingen';
+$lang['debug_o_1']             = 'enbart för fel';
diff --git a/lib/plugins/authmysql/lang/uk/lang.php b/lib/plugins/authmysql/lang/uk/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6cbaf0266ec13e34782db2b35d9b134494b0e49
--- /dev/null
+++ b/lib/plugins/authmysql/lang/uk/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['connectfail']           = 'Не вдалося з\'єднатися з базою даних.';
+$lang['userexists']            = 'Вибачте, користувач з таким логіном вже існує.';
+$lang['usernotexists']         = 'Вибачте, такого користувача не існує.';
diff --git a/lib/plugins/authpgsql/lang/eo/settings.php b/lib/plugins/authpgsql/lang/eo/settings.php
index 2f59c49141f3850819434315098ecf6e4e361d8b..3af6b40798601a6e259ddee938f6f05d7621b25c 100644
--- a/lib/plugins/authpgsql/lang/eo/settings.php
+++ b/lib/plugins/authpgsql/lang/eo/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  */
 $lang['server']                = 'Via PostgreSQL-servilo';
 $lang['port']                  = 'Via PostgreSQL-servila pordego';
diff --git a/lib/plugins/authpgsql/lang/lv/settings.php b/lib/plugins/authpgsql/lang/lv/settings.php
index 889b9566c20bc5ac4649263c84ea5588bbfaaf60..dd63544b57a7e88541a5df8454d436695407afa9 100644
--- a/lib/plugins/authpgsql/lang/lv/settings.php
+++ b/lib/plugins/authpgsql/lang/lv/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['password']              = 'Lietotāja parole';
diff --git a/lib/plugins/authpgsql/lang/pl/settings.php b/lib/plugins/authpgsql/lang/pl/settings.php
index 69422c0cfd95b6e32a6919e4ac1e3c54a62dce3b..e89fd91a2e3a9a1d7881a64a11962822e9611e05 100644
--- a/lib/plugins/authpgsql/lang/pl/settings.php
+++ b/lib/plugins/authpgsql/lang/pl/settings.php
@@ -3,7 +3,38 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Mati <mackosa@wp.pl>
  */
 $lang['server']                = 'Twój serwer PostgreSQL';
+$lang['port']                  = 'Port Twojego serwera PostgreSQL';
+$lang['user']                  = 'Nazwa użytkownika PostgreSQL';
+$lang['password']              = 'Hasła dla powyższego użytkownika';
 $lang['database']              = 'Baza danych do użycia';
+$lang['debug']                 = 'Wyświetl dodatkowe informacje debagowania';
+$lang['forwardClearPass']      = 'Przekazuj do poniższej instrukcji SQL hasła użytkowników jako czysty tekst do instrukcji SQL zamiast używać opcji passcrypt';
+$lang['checkPass']             = 'Instrukcja SQL sprawdzająca hasła';
+$lang['getUserInfo']           = 'Instrukcja SQL pobierająca dane użytkownika';
+$lang['getGroups']             = 'Instrukcja SQL pobierająca przynależność użytkownika do grup';
+$lang['getUsers']              = 'Instrukcja SQL listująca wszystkich użytkowników';
+$lang['FilterLogin']           = 'Instrukcja SQL filtrująca użytkowników po loginie';
+$lang['FilterName']            = 'Instrukcja SQL filtrująca użytkowników po imieniu i nazwisku';
+$lang['FilterEmail']           = 'Instrukcja SQL filtrująca użytkowników po emailu';
+$lang['FilterGroup']           = 'Instrukcja SQL filtrująca użytkowników po przynależności do grupy';
+$lang['SortOrder']             = 'Instrukcja SQL sortująca użytkowników';
+$lang['addUser']               = 'Instrukcja SQL dodająca nowego użytkownika';
+$lang['addGroup']              = 'Instrukcja SQL dodajÄ…ca nowÄ… grupÄ™';
+$lang['addUserGroup']          = 'Instrukcja SQL dodająca użytkownika do istniejącej grupy';
+$lang['delGroup']              = 'Instrukcja SQL usuwajÄ…ca grupÄ™';
+$lang['getUserID']             = 'Instrukcja SQL pobierająca klucz główny użytkownika';
+$lang['delUser']               = 'Instrukcja SQL usuwająca użytkownika';
+$lang['delUserRefs']           = 'Instrukcja SQL usuwająca użytkownika ze wszystkich grup';
+$lang['updateUser']            = 'Instrukcja SQL aktualizująca profil użytkownika';
+$lang['UpdateLogin']           = 'Polecenie służące do aktualizacji loginu użytkownika';
+$lang['UpdatePass']            = 'Polecenie służące do aktualizacji hasła użytkownika';
+$lang['UpdateEmail']           = 'Polecenie służące do aktualizacji e-mailu użytkownika';
+$lang['UpdateName']            = 'Polecenie służące do aktualizacji imienia i nazwiska użytkownika';
+$lang['UpdateTarget']          = 'Instrukcja limitu do identyfikacji użytkownika podczas aktualizacji';
+$lang['delUserGroup']          = 'Instrukcja SQL usuwająca użytkownika ze wskazanej grupy';
+$lang['getGroupID']            = 'Instrukcja SQL pobierająca klucz główny wskazanej grupy';
diff --git a/lib/plugins/authpgsql/lang/pt/settings.php b/lib/plugins/authpgsql/lang/pt/settings.php
index f81ec22dc7bc32b82feecb87e022a30192f18897..edc4e1a84c96494fc203c9e20860283e00dd7b1c 100644
--- a/lib/plugins/authpgsql/lang/pt/settings.php
+++ b/lib/plugins/authpgsql/lang/pt/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author André Neves <drakferion@gmail.com>
  * @author Guido Salatino <guidorafael23@gmail.com>
  */
diff --git a/lib/plugins/authpgsql/lang/ru/settings.php b/lib/plugins/authpgsql/lang/ru/settings.php
index 28efbdf1f5829f0240dd296d05a1eb32e8bc4b46..ceb5bd466b9f1c9dd13bcdcbf1f9c6611aeda097 100644
--- a/lib/plugins/authpgsql/lang/ru/settings.php
+++ b/lib/plugins/authpgsql/lang/ru/settings.php
@@ -5,7 +5,6 @@
  *
  * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author Aleksandr Selivanov <alexgearbox@gmail.com>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Vitaly Filatenko <kot@hacktest.net>
  * @author Type-kun <workwork-1@yandex.ru>
  * @author Alex P <alexander@lanos.co.uk>
diff --git a/lib/plugins/authpgsql/lang/sl/settings.php b/lib/plugins/authpgsql/lang/sl/settings.php
index 08d3cbca3eab3426f4e7bb558e744c45f500c0a3..7110a6efd7648c02bf430aae6c6d57089289d00c 100644
--- a/lib/plugins/authpgsql/lang/sl/settings.php
+++ b/lib/plugins/authpgsql/lang/sl/settings.php
@@ -2,9 +2,8 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Matej Urbančič <mateju@svn.gnome.org>
- * @author matej <mateju@svn.gnome.org>
  */
 $lang['database']              = 'Podatkovna zbirka za uporabo';
 $lang['addUserGroup']          = 'Ukaz SQL za dodajanje uporabnika v obstoječo skupino';
diff --git a/lib/plugins/authpgsql/lang/sr/settings.php b/lib/plugins/authpgsql/lang/sr/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b1cd8bfed5308a6d563bc98e7d66d655b28e03c
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/sr/settings.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['server']                = 'Ваш PostgreSQL сервер';
+$lang['port']                  = 'Порт вашег PostgreSQL сервера';
+$lang['user']                  = 'PostgreSQL корисничко име';
+$lang['password']              = 'Лозинка за корисника изнад';
+$lang['database']              = 'База коју треба користити';
+$lang['debug']                 = 'Прикажи додатне податке за поправљање грешака';
+$lang['forwardClearPass']      = 'Пренеси корисничке лозинке као чист текст ка SQL упитима испод уместо коришћења passcrypt опције';
+$lang['checkPass']             = 'SQL упит за проверу лозинки';
+$lang['getUserInfo']           = 'SQL упит за добављање корисничких података';
+$lang['getGroups']             = 'SQL упит за добављање групних учлањења корисника';
+$lang['getUsers']              = 'SQL упит за листање свих корисника';
diff --git a/lib/plugins/authpgsql/lang/sv/settings.php b/lib/plugins/authpgsql/lang/sv/settings.php
index 7da2e82c88997ac90355e70d34206576402fc949..1082583ddc157eb4a0d677fe30480d58d8b92bbe 100644
--- a/lib/plugins/authpgsql/lang/sv/settings.php
+++ b/lib/plugins/authpgsql/lang/sv/settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['server']                = 'Din PostgreSQL server';
diff --git a/lib/plugins/authpgsql/lang/uk/settings.php b/lib/plugins/authpgsql/lang/uk/settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..9a353414d2ce5c4b6a6827d7d0ef8dcd1c2a66c6
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/uk/settings.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Nina Zolotova <nina-z@i.ua>
+ */
+$lang['database']              = 'Використовувати базу даних';
diff --git a/lib/plugins/authplain/lang/da/lang.php b/lib/plugins/authplain/lang/da/lang.php
index 20b08f5cb733e796540f54f488245a288a01dce1..ff683ed387603a27e032b5fbabfede44c88f6e58 100644
--- a/lib/plugins/authplain/lang/da/lang.php
+++ b/lib/plugins/authplain/lang/da/lang.php
@@ -3,5 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kenneth Schack Banner <kescba@gmail.com>
  */
 $lang['userexists']            = 'Dette brugernavn er allerede i brug.';
+$lang['writefail']             = 'Ude af stand til at redigere bruger data. Kontakt venligst Wiki-Administratoren';
diff --git a/lib/plugins/authplain/lang/eo/lang.php b/lib/plugins/authplain/lang/eo/lang.php
index ab7655e818a5c4875b9a94c8dd398f43bca13be3..3a3f45cd50a7120c5fd00c106646bf0ab34a52fc 100644
--- a/lib/plugins/authplain/lang/eo/lang.php
+++ b/lib/plugins/authplain/lang/eo/lang.php
@@ -1,6 +1,9 @@
 <?php
+
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
  */
-$lang['userexists']     = 'Pardonu, ĉi tiu uzanto-nomo jam ekzistas.';
+$lang['userexists']            = 'Pardonu, ĉi tiu uzanto-nomo jam ekzistas.';
+$lang['usernotexists']         = 'Pardonu, tiu uzanto ne ekzistas.';
diff --git a/lib/plugins/authplain/lang/es/lang.php b/lib/plugins/authplain/lang/es/lang.php
index 68a854892463e049e6caf8effc81b09303407467..b81bbb8dd80a7554a33fc540c24af644ade3844c 100644
--- a/lib/plugins/authplain/lang/es/lang.php
+++ b/lib/plugins/authplain/lang/es/lang.php
@@ -9,4 +9,4 @@
 $lang['userexists']            = 'Lo siento, ya existe un usuario con este nombre.';
 $lang['usernotexists']         = 'Lo sentimos, no existe ese usuario.';
 $lang['writefail']             = 'No es posible modificar los datos del usuario. Por favor, informa al Administrador del Wiki';
-$lang['protected']             = 'Los datos del usuario % están protegidos y no pueden ser modificados o eliminados.';
+$lang['protected']             = 'Los datos del usuario %s están protegidos y no pueden ser modificados o eliminados.';
diff --git a/lib/plugins/authplain/lang/eu/lang.php b/lib/plugins/authplain/lang/eu/lang.php
index 09ca4d3b77ab859ec7073ddb99e9747ad155728e..2c7e8539f2f85265dd20d979e8de2f0dcc526a2e 100644
--- a/lib/plugins/authplain/lang/eu/lang.php
+++ b/lib/plugins/authplain/lang/eu/lang.php
@@ -1,6 +1,7 @@
 <?php
+
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  */
-$lang['userexists']     = 'Barkatu, izen bereko erabiltzailea existitzen da.';
+$lang['userexists']            = 'Barkatu, izen bereko erabiltzailea existitzen da.';
diff --git a/lib/plugins/authplain/lang/he/lang.php b/lib/plugins/authplain/lang/he/lang.php
index 160968edd26c10446374f8cb35a78617a3a440b2..a2e1324bb2b4980be87ce31559606b2622eb8021 100644
--- a/lib/plugins/authplain/lang/he/lang.php
+++ b/lib/plugins/authplain/lang/he/lang.php
@@ -2,6 +2,6 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  */
 $lang['userexists']            = 'משתמש בשם זה כבר נרשם, עמך הסליחה.';
diff --git a/lib/plugins/authplain/lang/lv/lang.php b/lib/plugins/authplain/lang/lv/lang.php
index 3a9d4d3e5c5b249267dd23032a73e9b3d79bf5e1..afc89e462b309d12320d54278dd27b91f439c76b 100644
--- a/lib/plugins/authplain/lang/lv/lang.php
+++ b/lib/plugins/authplain/lang/lv/lang.php
@@ -1,6 +1,7 @@
 <?php
+
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  */
-$lang['userexists']     = 'Atvaino, tāds lietotājs jau ir.';
+$lang['userexists']            = 'Atvaino, tāds lietotājs jau ir.';
diff --git a/lib/plugins/authplain/lang/pl/lang.php b/lib/plugins/authplain/lang/pl/lang.php
index c4fb1a1ab55e303a6b44703c7a1eadec9ca97fa2..95b46fe86efddd54f20a853f1699ba1027d734bb 100644
--- a/lib/plugins/authplain/lang/pl/lang.php
+++ b/lib/plugins/authplain/lang/pl/lang.php
@@ -3,5 +3,9 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Max <maxrb146@gmail.com>
  */
 $lang['userexists']            = 'Użytkownik o tej nazwie już istnieje.';
+$lang['usernotexists']         = 'Przepraszamy, użytkownik nie istnieje';
+$lang['writefail']             = 'Nie można modyfikować danych użytkownika. Proszę skontaktować się z administratorem ';
+$lang['protected']             = 'Dane użytkownika %s są chronione, nie mogą być modyfikowane oraz usuwane';
diff --git a/lib/plugins/authplain/lang/pt/lang.php b/lib/plugins/authplain/lang/pt/lang.php
index 26d4180c5bcca0ab2272ad99477199681cee5463..3334ea6670c7235643ee60b4761496926f374367 100644
--- a/lib/plugins/authplain/lang/pt/lang.php
+++ b/lib/plugins/authplain/lang/pt/lang.php
@@ -2,8 +2,10 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Paulo Carmino <contato@paulocarmino.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['userexists']            = 'Este utilizador já está inscrito. Por favor escolha outro nome de utilizador.';
 $lang['usernotexists']         = 'Desculpe, esse login não existe.';
+$lang['writefail']             = 'Incapaz de modificar dados do usuário. Favor informar ao Wiki-Admin.';
diff --git a/lib/plugins/authplain/lang/sk/lang.php b/lib/plugins/authplain/lang/sk/lang.php
index 713b321af380b5cf4616da2dc56fd84df285ace1..d1cfbfda37a70b732e6dabff12c9840c8d882241 100644
--- a/lib/plugins/authplain/lang/sk/lang.php
+++ b/lib/plugins/authplain/lang/sk/lang.php
@@ -6,4 +6,6 @@
  * @author Martin Michalek <michalek.dev@gmail.com>
  */
 $lang['userexists']            = 'Užívateľ s rovnakým menom je už zaregistrovaný.';
+$lang['usernotexists']         = 'Ľutujem, daný používateľ neexistuje.';
 $lang['writefail']             = 'Nie je možné zmeniť údaje používateľa, informujte prosím administrátora Wiki.';
+$lang['protected']             = 'Údaje používateľa %s sú chránené a nemôžu by zmenené alebo vymazané.';
diff --git a/lib/plugins/authplain/lang/sl/lang.php b/lib/plugins/authplain/lang/sl/lang.php
index d4ee30fda514aadd47e958be644251b755dfe5f3..46eb4bfead9f9db092ef3eff9b1e8c79c794a989 100644
--- a/lib/plugins/authplain/lang/sl/lang.php
+++ b/lib/plugins/authplain/lang/sl/lang.php
@@ -1,6 +1,7 @@
 <?php
+
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  */
-$lang['userexists']     = 'Uporabnik s tem imenom že obstaja.';
+$lang['userexists']            = 'Uporabnik s tem imenom že obstaja.';
diff --git a/lib/plugins/authplain/lang/sv/lang.php b/lib/plugins/authplain/lang/sv/lang.php
index fb80df956601d67ecb91d4590edf3145db660688..83c24d7692361583a8db6dd8939b3626cb961964 100644
--- a/lib/plugins/authplain/lang/sv/lang.php
+++ b/lib/plugins/authplain/lang/sv/lang.php
@@ -1,6 +1,10 @@
 <?php
+
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  */
-$lang['userexists']     = 'Det finns redan en användare med det användarnamnet.';
+$lang['userexists']            = 'Det finns redan en användare med det användarnamnet.';
+$lang['usernotexists']         = 'Tyvärr, den användaren existerar inte.';
+$lang['writefail']             = 'Kunde inte ändra användardata. Var god informera Wiki-administratören';
diff --git a/lib/plugins/authplain/lang/uk/lang.php b/lib/plugins/authplain/lang/uk/lang.php
index 8a796870facee443e46266b50ea9ccc35402c110..86ab3d1583c0ebf48d39aecafa2330fa059f22ba 100644
--- a/lib/plugins/authplain/lang/uk/lang.php
+++ b/lib/plugins/authplain/lang/uk/lang.php
@@ -2,6 +2,8 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Nina Zolotova <nina-z@i.ua>
  */
 $lang['userexists']            = 'Користувач з таким іменем вже існує.';
+$lang['usernotexists']         = 'Вибачте, такого користувача не існує.';
diff --git a/lib/plugins/cli.php b/lib/plugins/cli.php
new file mode 100644
index 0000000000000000000000000000000000000000..721f54779e5358a467172423a98e9b996d3f0e01
--- /dev/null
+++ b/lib/plugins/cli.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Base class for CLI plugins
+ *
+ * Provides DokuWiki plugin functionality on top of phpcli
+ */
+abstract class DokuWiki_CLI_Plugin extends \splitbrain\phpcli\CLI implements DokuWiki_PluginInterface {
+    use DokuWiki_PluginTrait;
+
+}
diff --git a/lib/plugins/config/admin.php b/lib/plugins/config/admin.php
index 262ff46d9b76201690f791275512481cd70b545d..76ecae24ccc86201f256be36c4153e5747d1ef3a 100644
--- a/lib/plugins/config/admin.php
+++ b/lib/plugins/config/admin.php
@@ -60,7 +60,7 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
 
         $this->_input = $INPUT->arr('config');
 
-        while (list($key) = each($this->_config->setting)) {
+        foreach ($this->_config->setting as $key => $value){
             $input = isset($this->_input[$key]) ? $this->_input[$key] : null;
             if ($this->_config->setting[$key]->update($input)) {
                 $this->_changed = true;
diff --git a/lib/plugins/config/lang/da/lang.php b/lib/plugins/config/lang/da/lang.php
index 6935049f5ada48e3857979dcc23bc5d6e9e4bb1d..7546264e93590412c24a618d2cd135bffa766840 100644
--- a/lib/plugins/config/lang/da/lang.php
+++ b/lib/plugins/config/lang/da/lang.php
@@ -3,14 +3,15 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kenneth Schack Banner <kescba@gmail.com>
+ * @author Jon Theil Nielsen <jontheil@gmail.com>
  * @author Lars Næsbye Christensen <larsnaesbye@stud.ku.dk>
  * @author Kalle Sommer Nielsen <kalle@php.net>
  * @author Esben Laursen <hyber@hyber.dk>
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  * @author Jacob Palm <mail@jacobpalm.dk>
  */
diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php
index 2b07e02d84e8bbd5490e07ad05f9b8e9aa950c96..6c31e852086b3c8317d67df90a16ca7e171b2c99 100644
--- a/lib/plugins/config/lang/de-informal/lang.php
+++ b/lib/plugins/config/lang/de-informal/lang.php
@@ -119,6 +119,7 @@ $lang['subscribe_time']        = 'Zeit nach der Zusammenfassungs- und Änderungs
 $lang['notify']                = 'Sende Änderungsbenachrichtigungen an diese E-Mail-Adresse.';
 $lang['registernotify']        = 'Sende Information bei neu registrierten Benutzern an diese E-Mail-Adresse.';
 $lang['mailfrom']              = 'Absenderadresse für automatisch erzeugte E-Mails';
+$lang['mailreturnpath']        = 'Empfänger-E-Mail-Adresse für Unzustellbarkeitsnachricht';
 $lang['mailprefix']            = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen';
 $lang['htmlmail']              = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.';
 $lang['sitemap']               = 'Erzeuge Google Sitemaps (Tage)';
diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php
index e21d1dab45e3613708efef71da04272663e7fa16..eecf550f784869bb22ab92bac82edb89e98ac20c 100644
--- a/lib/plugins/config/lang/de/lang.php
+++ b/lib/plugins/config/lang/de/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Joel Strasser <strasser999@gmail.com>
  * @author Andreas Gohr <andi@splitbrain.org>
  * @author Michael Klier <chi@chimeric.de>
  * @author Leo Moll <leo@yeasoft.com>
@@ -127,6 +128,7 @@ $lang['subscribe_time']        = 'Zeit nach der Zusammenfassungs- und Änderungs
 $lang['notify']                = 'Änderungsmitteilungen an diese E-Mail-Adresse versenden';
 $lang['registernotify']        = 'Information über neu registrierte Benutzer an diese E-Mail-Adresse senden';
 $lang['mailfrom']              = 'Absender-E-Mail-Adresse für automatische Mails';
+$lang['mailreturnpath']        = 'Empfänger-E-Mail-Adresse für Unzustellbarkeitsnachricht';
 $lang['mailprefix']            = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen (Leer lassen um den Wiki-Titel zu verwenden)';
 $lang['htmlmail']              = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.';
 $lang['sitemap']               = 'Google Sitemap erzeugen (Tage). Mit 0 deaktivieren.';
@@ -136,6 +138,9 @@ $lang['rss_content']           = 'Welche Inhalte sollen im XML-Feed dargestellt
 $lang['rss_update']            = 'XML-Feed Aktualisierungsintervall (Sekunden)';
 $lang['rss_show_summary']      = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen';
 $lang['rss_media']             = 'Welche Änderungen sollen im XML-Feed angezeigt werden?';
+$lang['rss_media_o_both']      = 'beide';
+$lang['rss_media_o_pages']     = 'Seiten';
+$lang['rss_media_o_media']     = 'Medien';
 $lang['updatecheck']           = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.';
 $lang['userewrite']            = 'Schöne Seitenadressen (URL rewriting)';
 $lang['useslash']              = 'Schrägstrich (/) als Namensraumtrenner in URLs verwenden';
diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php
index e4c81ce110eeac5582a9c249b770f983eba60c84..356db4e5e8ae39ca537901bc0efbdbdfcf73b56b 100644
--- a/lib/plugins/config/lang/en/lang.php
+++ b/lib/plugins/config/lang/en/lang.php
@@ -5,6 +5,7 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  * @author     Christopher Smith <chris@jalakai.co.uk>
  * @author     Matthias Schulte <dokuwiki@lupo49.de>
+ * @author     Schplurtz le Déboulonné <Schplurtz@laposte.net>
  */
 
 // for admin plugins, the menu prompt to be displayed in the admin menu
@@ -142,17 +143,22 @@ $lang['subscribe_time'] = 'Time after which subscription lists and digests are s
 $lang['notify']      = 'Always send change notifications to this email address';
 $lang['registernotify'] = 'Always send info on newly registered users to this email address';
 $lang['mailfrom']    = 'Sender email address to use for automatic mails';
+$lang['mailreturnpath']    = 'Recipient email address for non delivery notifications';
 $lang['mailprefix']  = 'Email subject prefix to use for automatic mails. Leave blank to use the wiki title';
 $lang['htmlmail']    = 'Send better looking, but larger in size HTML multipart emails. Disable for plain text only mails.';
 
 /* Syndication Settings */
-$lang['sitemap']     = 'Generate Google sitemap this often (in days). 0 to disable';
-$lang['rss_type']    = 'XML feed type';
-$lang['rss_linkto']  = 'XML feed links to';
-$lang['rss_content'] = 'What to display in the XML feed items?';
-$lang['rss_update']  = 'XML feed update interval (sec)';
-$lang['rss_show_summary'] = 'XML feed show summary in title';
-$lang['rss_media']   = 'What kind of changes should be listed in the XML feed?';
+$lang['sitemap']           = 'Generate Google sitemap this often (in days). 0 to disable';
+$lang['rss_type']          = 'XML feed type';
+$lang['rss_linkto']        = 'XML feed links to';
+$lang['rss_content']       = 'What to display in the XML feed items?';
+$lang['rss_update']        = 'XML feed update interval (sec)';
+$lang['rss_show_summary']  = 'XML feed show summary in title';
+$lang['rss_media']         = 'What kind of changes should be listed in the XML feed?';
+$lang['rss_media_o_both']  = 'both';
+$lang['rss_media_o_pages'] = 'pages';
+$lang['rss_media_o_media'] = 'media';
+
 
 /* Advanced Options */
 $lang['updatecheck'] = 'Check for updates and security warnings? DokuWiki needs to contact update.dokuwiki.org for this feature.';
@@ -172,6 +178,12 @@ $lang['xsendfile']   = 'Use the X-Sendfile header to let the webserver deliver s
 $lang['renderer_xhtml']   = 'Renderer to use for main (xhtml) wiki output';
 $lang['renderer__core']   = '%s (dokuwiki core)';
 $lang['renderer__plugin'] = '%s (plugin)';
+$lang['search_nslimit'] = 'Limit the search to the current X namespaces. When a search is executed from a page within a deeper namespace, the first X namespaces will be added as filter';
+$lang['search_fragment'] = 'Specify the default fragment search behavior';
+$lang['search_fragment_o_exact'] = 'exact';
+$lang['search_fragment_o_starts_with'] = 'starts with';
+$lang['search_fragment_o_ends_with'] = 'ends with';
+$lang['search_fragment_o_contains'] = 'contains';
 
 /* Network Options */
 $lang['dnslookups'] = 'DokuWiki will lookup hostnames for remote IP addresses of users editing pages. If you have a slow or non working DNS server or don\'t want this feature, disable this option';
diff --git a/lib/plugins/config/lang/eo/lang.php b/lib/plugins/config/lang/eo/lang.php
index 644ca79abee7320301ff66058a0d97b8f7d77b4a..7201b326703ebb1b972a74aa2358b1c1a0f01a79 100644
--- a/lib/plugins/config/lang/eo/lang.php
+++ b/lib/plugins/config/lang/eo/lang.php
@@ -1,15 +1,15 @@
 <?php
+
 /**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
  * Esperantolanguage file
  *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
  * @author Felipe Castro <fefcas@uol.com.br>
- * @author Felipe Castro <fefcas@gmail.com>
- * @author Felipe Castro <fefcas (cxe) gmail (punkto) com>
  * @author Felipo Kastro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik pedersen@shaw.ca>
- * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['menu']                  = 'Agordaj Difinoj';
 $lang['error']                 = 'La difinoj ne estas ĝisdatigitaj pro malvalida valoro: bonvolu revizii viajn ŝanĝojn kaj resubmeti ilin.
@@ -84,6 +84,7 @@ $lang['disableactions']        = 'Malebligi DokuWiki-ajn agojn';
 $lang['disableactions_check']  = 'Kontroli';
 $lang['disableactions_subscription'] = 'Aliĝi/Malaliĝi';
 $lang['disableactions_wikicode'] = 'Rigardi vikitekston/Eksporti fontotekston';
+$lang['disableactions_profile_delete'] = 'Forigi la propran konton';
 $lang['disableactions_other']  = 'Aliaj agoj (disigita per komoj)';
 $lang['auth_security_timeout'] = 'Sekureca tempolimo por aÅ­tentigo (sekundoj)';
 $lang['securecookie']          = 'Ĉu kuketoj difinitaj per HTTPS sendiĝu de la foliumilo nur per HTTPS? Malebligu tiun ĉi opcion kiam nur la ensaluto al via vikio estas sekurigita per SSL, sed foliumado de la vikio estas farita malsekure.';
@@ -124,6 +125,8 @@ $lang['rss_content']           = 'Kion montri en la XML-aj novaĵ-flueroj?';
 $lang['rss_update']            = 'Intertempo por ĝisdatigi XML-an novaĵ-fluon (sek.)';
 $lang['rss_show_summary']      = 'XML-a novaĵ-fluo montras resumon en la titolo';
 $lang['rss_media']             = 'Kiaj ŝangoj estu montrataj en la XML-fluo?';
+$lang['rss_media_o_both']      = 'ambaÅ­';
+$lang['rss_media_o_pages']     = 'paĝoj';
 $lang['updatecheck']           = 'Ĉu kontroli aktualigojn kaj sekurecajn avizojn? DokuWiki bezonas kontakti update.dokuwiki.org por tiu ĉi trajto.';
 $lang['userewrite']            = 'Uzi netajn URL-ojn';
 $lang['useslash']              = 'Uzi frakcistrekon kiel disigsignaĵon por nomspacoj en URL-oj';
diff --git a/lib/plugins/config/lang/es/lang.php b/lib/plugins/config/lang/es/lang.php
index 0da118e929a191cfe4db86aed80e62c1a270b1fe..f50ca1f29145318a6deca67cd374c54197c9f09f 100644
--- a/lib/plugins/config/lang/es/lang.php
+++ b/lib/plugins/config/lang/es/lang.php
@@ -158,6 +158,10 @@ $lang['renderer_xhtml']        = 'Visualizador a usar para salida (xhtml) princi
 $lang['renderer__core']        = '%s (núcleo dokuwiki)';
 $lang['renderer__plugin']      = '%s (plugin)';
 $lang['dnslookups']            = 'DokuWiki buscara los hostnames para usuarios editando las páginas con IP remota. Si usted tiene un servidor DNS bastante lento o que no funcione, favor de desactivar esta opción.';
+$lang['jquerycdn']             = '¿Deberían cargarse los ficheros de script jQuery y jQuery UI desde un CDN? Esto añade peticiones HTTP adicionales, pero los ficheros se pueden cargar más rápido y los usuarios pueden tenerlas ya almacenadas en caché.';
+$lang['jquerycdn_o_0']         = 'No CDN, sólo entrega local';
+$lang['jquerycdn_o_jquery']    = 'CDN en code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN en cdnjs.com';
 $lang['proxy____host']         = 'Nombre del servidor Proxy';
 $lang['proxy____port']         = 'Puerto del servidor Proxy';
 $lang['proxy____user']         = 'Nombre de usuario para el servidor Proxy';
diff --git a/lib/plugins/config/lang/eu/lang.php b/lib/plugins/config/lang/eu/lang.php
index 74b50799f05a604d3d90452e42cda1d70e912dd9..b48df552a81bd9ae15fe63c3f43286b3bf34af6e 100644
--- a/lib/plugins/config/lang/eu/lang.php
+++ b/lib/plugins/config/lang/eu/lang.php
@@ -1,9 +1,11 @@
 <?php
+
 /**
- * Basque language file
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
+ * @author Osoitz <oelkoro@gmail.com>
  */
 $lang['menu']                  = 'Konfigurazio Ezarpenak';
 $lang['error']                 = 'Ezarpenak ez dira eguneratu balio oker bat dela eta, mesedez errepasatu aldaketak eta berriz bidali. <br />Balio okerra(k) ertz gorriz inguratuak erakutsiko dira. ';
diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php
index 68488fa7b0af90403711588ea14ac8a298358b11..a2049dd3b8f9da68dc073128ff9ee42037564d25 100644
--- a/lib/plugins/config/lang/fr/lang.php
+++ b/lib/plugins/config/lang/fr/lang.php
@@ -3,6 +3,8 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Michael Bohn <mjbohn@gmail.com>
+ * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
  * @author Guy Brand <gb@unistra.fr>
  * @author Delassaux Julien <julien@delassaux.fr>
  * @author Maurice A. LeBlanc <leblancma@cooptel.qc.ca>
@@ -15,7 +17,6 @@
  * @author Florian Gaub <floriang@floriang.net>
  * @author Samuel Dorsaz <samuel.dorsaz@novelion.net>
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author <skimpax@gmail.com>
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
@@ -23,7 +24,6 @@
  * @author Carbain Frédéric <fcarbain@yahoo.fr>
  * @author Nicolas Friedli <nicolas@theologique.ch>
  * @author Floriang <antispam@floriang.eu>
- * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
  * @author Simon DELAGE <simon.geekitude@gmail.com>
  * @author Eric <ericstevenart@netc.fr>
  * @author Olivier Humbert <trebmuh@tuxfamily.org>
@@ -39,7 +39,7 @@ $lang['security']              = 'Avertissement de sécurité : modifier cette o
 $lang['_configuration_manager'] = 'Gestionnaire de configuration';
 $lang['_header_dokuwiki']      = 'Paramètres de DokuWiki';
 $lang['_header_plugin']        = 'Paramètres des extensions';
-$lang['_header_template']      = 'Paramètres du modèle';
+$lang['_header_template']      = 'Paramètres du thème';
 $lang['_header_undefined']     = 'Paramètres indéfinis';
 $lang['_basic']                = 'Paramètres de base';
 $lang['_display']              = 'Paramètres d\'affichage';
@@ -58,9 +58,9 @@ $lang['_msg_setting_no_default'] = 'Pas de valeur par défaut.';
 $lang['title']                 = 'Titre du wiki (nom du wiki)';
 $lang['start']                 = 'Nom de la page d\'accueil à utiliser pour toutes les catégories';
 $lang['lang']                  = 'Langue de l\'interface';
-$lang['template']              = 'Modèle (rendu visuel du wiki)';
-$lang['tagline']               = 'Descriptif du site (si le modèle supporte cette fonctionnalité)';
-$lang['sidebar']               = 'Nom du panneau latéral (si le modèle supporte cette fonctionnalité). Laisser le champ vide désactive le panneau latéral.';
+$lang['template']              = 'Thème (rendu visuel du wiki)';
+$lang['tagline']               = 'Descriptif du site (si le thème utilise cette fonctionnalité)';
+$lang['sidebar']               = 'Nom du panneau latéral (si le thème utilise cette fonctionnalité). Laisser le champ vide désactive le panneau latéral.';
 $lang['license']               = 'Sous quelle licence doit-être placé le contenu ?';
 $lang['savedir']               = 'Répertoire d\'enregistrement des données';
 $lang['basedir']               = 'Répertoire de base du serveur (par exemple : <code>/dokuwiki/</code>). Laisser vide pour une détection automatique.';
@@ -124,7 +124,7 @@ $lang['target____media']       = 'Cible pour liens média';
 $lang['target____windows']     = 'Cible pour liens vers partages Windows';
 $lang['mediarevisions']        = 'Activer les révisions (gestion de versions) des médias';
 $lang['refcheck']              = 'Vérifier si un média est toujours utilisé avant de le supprimer';
-$lang['gdlib']                 = 'Version de la librairie GD';
+$lang['gdlib']                 = 'Version de la bibliothèque GD';
 $lang['im_convert']            = 'Chemin vers l\'outil de conversion ImageMagick';
 $lang['jpg_quality']           = 'Qualité de la compression JPEG (0-100)';
 $lang['fetchsize']             = 'Taille maximale (en octets) que fetch.php peut télécharger depuis une URL tierce (par exemple pour conserver en cache et redimensionner une image tierce)';
@@ -133,6 +133,7 @@ $lang['subscribe_time']        = 'Délai après lequel les listes d\'abonnement
 $lang['notify']                = 'Notifier systématiquement les modifications à cette adresse de courriel';
 $lang['registernotify']        = 'Notifier systématiquement les nouveaux utilisateurs enregistrés à cette adresse de courriel';
 $lang['mailfrom']              = 'Adresse de courriel de l\'expéditeur des notifications par courriel du wiki';
+$lang['mailreturnpath']        = 'Adresse de courriel du destinataire pour les notifications de non-remise';
 $lang['mailprefix']            = 'Préfixe à utiliser dans les objets des courriels automatiques. Laisser vide pour utiliser le titre du wiki';
 $lang['htmlmail']              = 'Envoyer des courriel HTML multipart (visuellement plus agréable, mais plus lourd). Désactiver pour utiliser uniquement des courriel plain text';
 $lang['sitemap']               = 'Fréquence de génération du sitemap Google (jours). 0 pour désactiver';
@@ -142,6 +143,9 @@ $lang['rss_content']           = 'Quel contenu afficher dans le flux XML?';
 $lang['rss_update']            = 'Fréquence de mise à jour du flux XML (secondes)';
 $lang['rss_show_summary']      = 'Le flux XML affiche le résumé dans le titre';
 $lang['rss_media']             = 'Quels types de changements doivent être listés dans le flux XML?';
+$lang['rss_media_o_both']      = 'les deux';
+$lang['rss_media_o_pages']     = 'pages';
+$lang['rss_media_o_media']     = 'media';
 $lang['updatecheck']           = 'Vérifier les mises à jour et alertes de sécurité? DokuWiki doit pouvoir contacter update.dokuwiki.org';
 $lang['userewrite']            = 'Utiliser des URL esthétiques';
 $lang['useslash']              = 'Utiliser « / » comme séparateur de catégories dans les URL';
@@ -151,12 +155,12 @@ $lang['fnencode']              = 'Méthode pour l\'encodage des fichiers non-ASC
 $lang['autoplural']            = 'Rechercher les formes plurielles dans les liens';
 $lang['compression']           = 'Méthode de compression pour les fichiers attic';
 $lang['gzip_output']           = 'Utiliser gzip pour le Content-Encoding du XHTML';
-$lang['compress']              = 'Compresser les flux CSS et JavaScript';
+$lang['compress']              = 'Compresser les fichiers CSS et JavaScript';
 $lang['cssdatauri']            = 'Taille maximale en octets pour inclure dans les feuilles de styles CSS les images qui y sont référencées. Cette technique réduit le nombre de requêtes HTTP. Cette fonctionnalité ne fonctionne qu\'à partir de la version 8 d\'Internet Explorer! Nous recommandons une valeur entre <code>400</code> et <code>600</code>. <code>0</code> pour désactiver.';
 $lang['send404']               = 'Renvoyer « HTTP 404/Page Not Found » pour les pages inexistantes';
 $lang['broken_iua']            = 'La fonction ignore_user_abort est-elle opérationnelle sur votre système ? Ceci peut empêcher le fonctionnement de l\'index de recherche. IIS+PHP/
 CGI dysfonctionne. Voir le <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">bug 852</a> pour plus d\'informations.';
-$lang['xsendfile']             = 'Utiliser l\'en-tête X-Sendfile pour permettre au serveur web de délivrer les fichiers statiques ? Votre serveur web doit supporter cette fonctionnalité.';
+$lang['xsendfile']             = 'Utiliser l\'en-tête X-Sendfile pour permettre au serveur web de délivrer les fichiers statiques ? Votre serveur web doit prendre en charge cette technologie.';
 $lang['renderer_xhtml']        = 'Moteur de rendu du format de sortie principal (XHTML)';
 $lang['renderer__core']        = '%s (cœur de DokuWiki)';
 $lang['renderer__plugin']      = '%s (extension)';
@@ -187,7 +191,7 @@ $lang['userewrite_o_2']        = 'Interne à DokuWiki';
 $lang['deaccent_o_0']          = 'off';
 $lang['deaccent_o_1']          = 'supprimer les accents';
 $lang['deaccent_o_2']          = 'convertir en caractères latins';
-$lang['gdlib_o_0']             = 'Librairie GD non disponible';
+$lang['gdlib_o_0']             = 'Bibliothèque GD non disponible';
 $lang['gdlib_o_1']             = 'version 1.x';
 $lang['gdlib_o_2']             = 'auto-détectée';
 $lang['rss_type_o_rss']        = 'RSS 0.91';
diff --git a/lib/plugins/config/lang/he/lang.php b/lib/plugins/config/lang/he/lang.php
index dbc6a322dc5e3df05fce9949266b5b653d394e4c..8c986ae65791af5a08314f5c8c6dca038346cd4f 100644
--- a/lib/plugins/config/lang/he/lang.php
+++ b/lib/plugins/config/lang/he/lang.php
@@ -2,9 +2,9 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Guy Yakobovitch <guy.yakobovitch@gmail.com>
  * @author DoK <kamberd@yahoo.com>
- * @author Dotan Kamber <kamberd@yahoo.com>
  * @author Moshe Kaplan <mokplan@gmail.com>
  * @author Yaron Yogev <yaronyogev@gmail.com>
  * @author Yaron Shahrabani <sh.yaron@gmail.com>
diff --git a/lib/plugins/config/lang/hr/lang.php b/lib/plugins/config/lang/hr/lang.php
index f007bd789fea8353975b39bef36411f50b0770a6..8f5e7641a8d2f7dfbf155ebfc8655f53a6b238e6 100644
--- a/lib/plugins/config/lang/hr/lang.php
+++ b/lib/plugins/config/lang/hr/lang.php
@@ -112,6 +112,7 @@ $lang['subscribe_time']        = 'Vrijeme (sek.) nakon kojeg se šalju pretplatn
 $lang['notify']                = 'Uvijek šalji obavijesti o promjenama na ovu adresu epošte';
 $lang['registernotify']        = 'Uvijek šalji obavijesti o novo-kreiranim korisnicima na ovu adresu epošte';
 $lang['mailfrom']              = 'Adresa pošiljatelja epošte koja se koristi pri slanju automatskih poruka';
+$lang['mailreturnpath']        = 'Adresa e-pošte primatelja za obavijesti o ne-isporuci';
 $lang['mailprefix']            = 'Prefiks predmeta poruke kod automatskih poruka. Ostaviti prazno za korištenje naslova wikija';
 $lang['htmlmail']              = 'Šalji ljepše, ali i veće poruke u HTML obliku. Onemogući za slanje poruka kao običan tekst.';
 $lang['sitemap']               = 'Generiraj Google mapu stranica svakih (dana). 0 za onemogućivanje';
@@ -121,6 +122,9 @@ $lang['rss_content']           = 'Å to da se prikazuje u stavkama XML feed-a?';
 $lang['rss_update']            = 'Interval obnavljanja XML feed-a (sek.)';
 $lang['rss_show_summary']      = 'Prikaz sažetka u naslovu XML feed-a';
 $lang['rss_media']             = 'Koje vrste promjena trebaju biti prikazane u XML feed-u?';
+$lang['rss_media_o_both']      = 'oboje';
+$lang['rss_media_o_pages']     = 'stranice';
+$lang['rss_media_o_media']     = 'medij';
 $lang['updatecheck']           = 'Provjera za nadogradnje i sigurnosna upozorenja? DokuWiki treba imati pristup do dokuwiki.org za ovo.';
 $lang['userewrite']            = 'Koristi jednostavne URL-ove';
 $lang['useslash']              = 'Koristi kosu crtu kao separator imenskih prostora u URL-ovima';
@@ -139,6 +143,10 @@ $lang['renderer_xhtml']        = 'Mehanizam koji se koristi za slaganje osnovnog
 $lang['renderer__core']        = '%s (dokuwiki jezgra)';
 $lang['renderer__plugin']      = '%s (dodatak)';
 $lang['dnslookups']            = 'Da li da DokuWiki potraži ime računala za udaljenu IP adresu korisnik koji je izmijenio stranicu. Ako imate spor ili neispravan DNS server, nemojte koristiti ovu funkcionalnost, onemogućite ovu opciju';
+$lang['jquerycdn']             = 'Da li da se jQuery i jQuery UI script datoteke učitavaju sa CDN? To proizvodi dodatne HTTP zahtjeve, ali datoteke se mogu brže učitati i korisnici ih već mogu imati učitane u od ranije.';
+$lang['jquerycdn_o_0']         = 'Bez CDN, samo lokalna dostava';
+$lang['jquerycdn_o_jquery']    = 'CDN na code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN na cdnjs.com';
 $lang['proxy____host']         = 'Proxy poslužitelj - adresa';
 $lang['proxy____port']         = 'Proxy poslužitelj - port';
 $lang['proxy____user']         = 'Proxy poslužitelj - korisničko ime';
diff --git a/lib/plugins/config/lang/it/lang.php b/lib/plugins/config/lang/it/lang.php
index 3bb4afc5142064ce63378fa7941b6b227f0cb6e3..e07764b6a7905ffb8087d4c7b5b8be749cc970a0 100644
--- a/lib/plugins/config/lang/it/lang.php
+++ b/lib/plugins/config/lang/it/lang.php
@@ -3,19 +3,14 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Torpedo <dgtorpedo@gmail.com>
  * @author Christopher Smith <chris@jalakai.co.uk>
  * @author Silvia Sargentoni <polinnia@tin.it>
  * @author Pietro Battiston toobaz@email.it
- * @author Diego Pierotto ita.translations@tiscali.it
- * @author ita.translations@tiscali.it
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
- * @author Osman Tekin osman.tekin93@hotmail.it
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
- * @author Torpedo <dgtorpedo@gmail.com>
  * @author Riccardo <riccardofila@gmail.com>
  * @author Paolo <paolopoz12@gmail.com>
  */
@@ -126,6 +121,7 @@ $lang['subscribe_time']        = 'Tempo dopo il quale le liste di sottoscrizione
 $lang['notify']                = 'Invia notifiche sulle modifiche a questo indirizzo';
 $lang['registernotify']        = 'Invia informazioni sui nuovi utenti registrati a questo indirizzo email';
 $lang['mailfrom']              = 'Mittente per le mail automatiche';
+$lang['mailreturnpath']        = 'Indirizzo email destinatario per notifica di mancati recapiti';
 $lang['mailprefix']            = 'Prefisso da inserire nell\'oggetto delle mail automatiche';
 $lang['htmlmail']              = 'Invia email HTML multipart più gradevoli ma più ingombranti in dimensione. Disabilita per mail in puro testo.';
 $lang['sitemap']               = 'Genera una sitemap Google (giorni)';
@@ -135,6 +131,9 @@ $lang['rss_content']           = 'Cosa mostrare negli elementi dei feed XML?';
 $lang['rss_update']            = 'Intervallo di aggiornamento dei feed XML (sec)';
 $lang['rss_show_summary']      = 'I feed XML riportano un sommario nel titolo';
 $lang['rss_media']             = 'Quale tipo di cambiamento dovrebbe essere elencato nel feed XML?';
+$lang['rss_media_o_both']      = 'entrambi';
+$lang['rss_media_o_pages']     = 'pagine';
+$lang['rss_media_o_media']     = 'media';
 $lang['updatecheck']           = 'Controllare aggiornamenti e avvisi di sicurezza? DokuWiki deve contattare update.dokuwiki.org per questa funzione.';
 $lang['userewrite']            = 'Usa il rewrite delle URL';
 $lang['useslash']              = 'Usa la barra rovescia (slash) come separatore nelle URL';
diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php
index 94b1fa623c4370a838331b40df233ed0c28807ca..cfca442780004a01373f92fb984425f0d4ce1e00 100644
--- a/lib/plugins/config/lang/ko/lang.php
+++ b/lib/plugins/config/lang/ko/lang.php
@@ -3,13 +3,14 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Seungheon Song <esketch@gmail.com>
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
- * @author Erial <erial2@gmail.com>
+ * @author S.H. Lee <tuders@naver.com>
  */
 $lang['menu']                  = '환경 설정';
 $lang['error']                 = '잘못된 값 때문에 설정을 바꿀 수 없습니다, 바뀜을 검토하고 다시 제출하세요.
@@ -118,6 +119,7 @@ $lang['subscribe_time']        = '구독 목록과 요약이 보내질 경과 
 $lang['notify']                = '항상 이 이메일 주소로 바뀜 알림을 보냄';
 $lang['registernotify']        = '항상 이 이메일 주소로 새로 등록한 사용자의 정보를 보냄';
 $lang['mailfrom']              = '자동으로 보내는 메일에 사용할 보내는 사람 이메일 주소';
+$lang['mailreturnpath']        = '배달 불가 안내를 위한 수신자 메일 주소';
 $lang['mailprefix']            = '자동으로 보내는 메일에 사용할 이메일 제목 접두어. 위키 제목을 사용하려면 비워 두세요';
 $lang['htmlmail']              = '보기에는 더 좋지만 크키가 조금 더 큰 HTML 태그가 포함된 이메일을 보내기. 일반 텍스트만으로 된 메일을 보내려면 비활성화하세요.';
 $lang['sitemap']               = 'Google 사이트맵 생성 날짜 빈도 (일). 비활성화하려면 0';
@@ -127,6 +129,9 @@ $lang['rss_content']           = 'XML 피드 항목에 보여주는 내용은 
 $lang['rss_update']            = 'XML 피드 업데이트 간격 (초)';
 $lang['rss_show_summary']      = 'XML 피드의 제목에서 요악 보여주기';
 $lang['rss_media']             = '어떤 규격으로 XML 피드에 바뀜을 나열해야 합니까?';
+$lang['rss_media_o_both']      = 'ì–‘ë°©í–¥';
+$lang['rss_media_o_pages']     = '쪽';
+$lang['rss_media_o_media']     = '미디어';
 $lang['updatecheck']           = '업데이트와 보안 경고를 검사할까요? 도쿠위키는 이 기능을 위해 update.dokuwiki.org에 연결이 필요합니다.';
 $lang['userewrite']            = '멋진 URL 사용';
 $lang['useslash']              = 'URL에서 이름공간 구분자로 슬래시 사용';
@@ -145,6 +150,10 @@ $lang['renderer_xhtml']        = '주요 (xhtml) 위키 출력에 사용할 렌
 $lang['renderer__core']        = '%s (도쿠위키 코어)';
 $lang['renderer__plugin']      = '%s (플러그인)';
 $lang['dnslookups']            = '도쿠위키가 문서를 편집하는 사용자의 원격 IP 주소에 대한 호스트 이름을 조회합니다. 서버가 느리거나 DNS 서버를 작동하지 않거나 이 기능을 원하지 않으면, 이 옵션을 비활성화하세요';
+$lang['jquerycdn']             = '제이쿼리(jQuery)와 제이쿼리UI 스크립트 파일을 컨텐츠전송네트워크(CDN)에서 불러와야만 합니까? 이것은 추가적인 HTTP요청을 합니다. 하지만 파일이 빨리 불러지고 캐쉬에 저장되게 할 수 있습니다.';
+$lang['jquerycdn_o_0']         = '컨텐츠전송네트워크(CDN) 사용 안 함. 로컬 전송만 함';
+$lang['jquerycdn_o_jquery']    = '\'code.jquery.com\' 의 컨텐츠전송네트워크(CDN) 사용';
+$lang['jquerycdn_o_cdnjs']     = '\'cdnjs.com\' 의 컨텐츠전송네트워크(CDN) 사용';
 $lang['proxy____host']         = '프록시 서버 이름';
 $lang['proxy____port']         = '프록시 포트';
 $lang['proxy____user']         = '프록시 사용자 이름';
diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php
index 533b008ac479021777d7ccc906b0d2a7fc392663..8caba8ed3969f3a1ad3e4bca55a842cecf8325d8 100644
--- a/lib/plugins/config/lang/lv/lang.php
+++ b/lib/plugins/config/lang/lv/lang.php
@@ -1,7 +1,11 @@
 <?php
+
 /**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
  * Latvian, Lettish language file
  *
+ * @author Oskars Pakers <oskars.pakers@gmail.com>
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['menu']                  = 'Konfigurācijas iestatījumi.';
diff --git a/lib/plugins/config/lang/nl/lang.php b/lib/plugins/config/lang/nl/lang.php
index 5695ce1375484b07dd07ae519cd41bd1b8f3c46f..e00af3a546678662d8a2e0529471fb3ce97ea3b8 100644
--- a/lib/plugins/config/lang/nl/lang.php
+++ b/lib/plugins/config/lang/nl/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author mark prins <mprins@users.sf.net>
  * @author Pieter van der Meulen <pieter@vdmeulen.net>
  * @author Wouter Schoot <wouter@schoot.org>
  * @author John de Graaff <john@de-graaff.net>
@@ -10,14 +11,11 @@
  * @author Dion Nicolaas <dion@nicolaas.net>
  * @author Danny Rotsaert <danny.rotsaert@edpnet.be>
  * @author Marijn Hofstra hofstra.m@gmail.com
- * @author Matthias Carchon webmaster@c-mattic.be
  * @author Marijn Hofstra <hofstra.m@gmail.com>
  * @author Timon Van Overveldt <timonvo@gmail.com>
- * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit <klapinklapin@gmail.com>
  * @author Hugo Smet <hugo.smet@scarlet.be>
- * @author mark prins <mprins@users.sf.net>
  */
 $lang['menu']                  = 'Configuratie-instellingen';
 $lang['error']                 = 'De instellingen zijn niet gewijzigd wegens een incorrecte waarde, kijk je wijzigingen na en sla dan opnieuw op.<br />Je kunt de incorrecte waarde(s) herkennen aan de rode rand.';
@@ -124,6 +122,7 @@ $lang['subscribe_time']        = 'Inschrijvingsmeldingen en samenvattingen worde
 $lang['notify']                = 'Stuur altijd e-mailnotificaties naar dit adres';
 $lang['registernotify']        = 'Stuur altijd informatie over nieuw geregistreerde gebruikers naar dit e-mailadres';
 $lang['mailfrom']              = 'E-mailadres van afzender voor automatische e-mail';
+$lang['mailreturnpath']        = 'Email adres voor de ontvanger van meldingen van niet-afleverbare berichten';
 $lang['mailprefix']            = 'Te gebruiken voorvoegsel voor onderwerp automatische email. Leeglaten gebruik de wikititel.';
 $lang['htmlmail']              = 'Zend multipart HTML e-mail. Dit ziet er beter uit, maar is groter. Uitschakelen betekent e-mail in platte tekst.';
 $lang['sitemap']               = 'Genereer Google sitemap (dagen). 0 betekent uitschakelen.';
@@ -133,6 +132,9 @@ $lang['rss_content']           = 'Wat moet er in de XML feed items weergegeven w
 $lang['rss_update']            = 'XML feed verversingsinterval (sec)';
 $lang['rss_show_summary']      = 'XML feed samenvatting in titel weergeven';
 $lang['rss_media']             = 'Welk type verandering moet in de XML feed worden weergegeven?';
+$lang['rss_media_o_both']      = 'beide';
+$lang['rss_media_o_pages']     = 'pagina\'s';
+$lang['rss_media_o_media']     = 'media';
 $lang['updatecheck']           = 'Controleer op nieuwe versies en beveiligingswaarschuwingen? DokuWiki moet hiervoor contact opnemen met update.dokuwiki.org.';
 $lang['userewrite']            = 'Gebruik nette URL\'s';
 $lang['useslash']              = 'Gebruik slash (/) als scheiding tussen namepaces in URL\'s';
diff --git a/lib/plugins/config/lang/pl/lang.php b/lib/plugins/config/lang/pl/lang.php
index 55db6eba4328718bd1d245139aafef8c4f9d8e1e..0a3df552dc56b3f72e2747b6537d4662adb671e2 100644
--- a/lib/plugins/config/lang/pl/lang.php
+++ b/lib/plugins/config/lang/pl/lang.php
@@ -3,12 +3,14 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Grzegorz Żur <grzegorz.zur@gmail.com>
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
  * @author Piotr JANKOWSKI <jankowski.piotr@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
@@ -88,7 +90,9 @@ $lang['disableactions']        = 'Wyłącz akcje DokuWiki';
 $lang['disableactions_check']  = 'Sprawdzanie';
 $lang['disableactions_subscription'] = 'Subskrypcje';
 $lang['disableactions_wikicode'] = 'Pokazywanie źródeł';
+$lang['disableactions_profile_delete'] = 'Usuń własne konto ';
 $lang['disableactions_other']  = 'Inne akcje (oddzielone przecinkiem)';
+$lang['disableactions_rss']    = 'XML Syndication (RSS)';
 $lang['auth_security_timeout'] = 'Czas wygaśnięcia uwierzytelnienia (w sekundach)';
 $lang['securecookie']          = 'Czy ciasteczka wysłane do przeglądarki przez HTTPS powinny być przez nią odsyłane też tylko przez HTTPS? Odznacz tę opcję tylko wtedy, gdy logowanie użytkowników jest zabezpieczone SSL, ale przeglądanie stron odbywa się bez zabezpieczenia.';
 $lang['remote']                = 'Włącz API zdalnego dostępu. Pozwoli to innym aplikacjom na dostęp do wiki poprzez XML-RPC lub inne mechanizmy.';
@@ -119,6 +123,7 @@ $lang['subscribe_time']        = 'Czas po którym są wysyłane listy subskrypcj
 $lang['notify']                = 'Wysyłanie powiadomień na adres e-mail';
 $lang['registernotify']        = 'Prześlij informacje o nowych użytkownikach na adres e-mail';
 $lang['mailfrom']              = 'Adres e-mail tego wiki';
+$lang['mailreturnpath']        = 'Adres e-mail odbiorcy dla powiadomień o niedostarczeniu';
 $lang['mailprefix']            = 'Prefiks tematu e-mail do automatycznych wiadomości';
 $lang['htmlmail']              = 'Wysyłaj wiadomości e-mail w formacie HTML, które wyglądają lepiej, lecz ich rozmiar jest większy. Wyłącz wysyłanie wiadomości zawierających tekst niesformatowany.';
 $lang['sitemap']               = 'Okres generowania Google Sitemap (w dniach)';
@@ -128,6 +133,9 @@ $lang['rss_content']           = 'Rodzaj informacji wyświetlanych w RSS ';
 $lang['rss_update']            = 'Okres aktualizacji RSS (w sekundach)';
 $lang['rss_show_summary']      = 'Podsumowanie w tytule';
 $lang['rss_media']             = 'Rodzaj zmian wyświetlanych w RSS';
+$lang['rss_media_o_both']      = 'oba';
+$lang['rss_media_o_pages']     = 'strony';
+$lang['rss_media_o_media']     = 'media';
 $lang['updatecheck']           = 'Sprawdzanie aktualizacji i bezpieczeństwa. DokuWiki będzie kontaktować się z serwerem update.dokuwiki.org.';
 $lang['userewrite']            = 'Proste adresy URL';
 $lang['useslash']              = 'Używanie ukośnika jako separatora w adresie URL';
@@ -146,6 +154,10 @@ $lang['renderer_xhtml']        = 'Mechanizm renderowania głównej treści stron
 $lang['renderer__core']        = '%s (dokuwiki)';
 $lang['renderer__plugin']      = '%s (wtyczka)';
 $lang['dnslookups']            = 'DokiWiki wyszuka nazwy hostów dla zdalnych adresów IP użytkowników edytujących strony. Jeśli twój serwer DNS działa zbyt wolno, uległ awarii lub nie chcesz używać wyszukiwania, wyłącz tę opcję.';
+$lang['jquerycdn']             = 'Czy pliki skryptów jQuery i jQuery UI powinny być ładowane z CDN? Powoduje to dodanie dodatkowych żądań HTTP, ale pliki mogą być ładowane szybciej, a użytkownicy mogą już je mieć zbuforowane.';
+$lang['jquerycdn_o_0']         = 'Bez CDN, tylko lokalne zasoby';
+$lang['jquerycdn_o_jquery']    = 'CDN z code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN z cdnjs.com';
 $lang['proxy____host']         = 'Proxy - serwer';
 $lang['proxy____port']         = 'Proxy - port';
 $lang['proxy____user']         = 'Proxy - nazwa użytkownika';
@@ -193,6 +205,7 @@ $lang['xsendfile_o_2']         = 'Standardowy nagłówek HTTP X-Sendfile';
 $lang['xsendfile_o_3']         = 'Specyficzny nagłówek Nginx X-Accel-Redirect';
 $lang['showuseras_o_loginname'] = 'Login użytkownika';
 $lang['showuseras_o_username'] = 'Pełne nazwisko użytkownika';
+$lang['showuseras_o_username_link'] = 'Imię i nazwisko użytkownika jako połączenie między wiki';
 $lang['showuseras_o_email']    = 'E-mail użytkownika (ukrywanie według ustawień mailguard)';
 $lang['showuseras_o_email_link'] = 'Adresy e-mail użytkowników w formie linku mailto:';
 $lang['useheading_o_0']        = 'Nigdy';
diff --git a/lib/plugins/config/lang/pt-br/lang.php b/lib/plugins/config/lang/pt-br/lang.php
index 24c133af34a74b6431fb75c1357a2fb60807050e..fe532fbcb14610948c6e5d47cbd7df17d5ce8e51 100644
--- a/lib/plugins/config/lang/pt-br/lang.php
+++ b/lib/plugins/config/lang/pt-br/lang.php
@@ -9,12 +9,9 @@
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Frederico Guimarães <frederico@teia.bio.br>
- * @author Jair Henrique <jair.henrique@gmail.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Sergio Motta sergio@cisne.com.br
+ * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
@@ -128,6 +125,7 @@ $lang['subscribe_time']        = 'Tempo de espera antes do envio das listas e me
 $lang['notify']                = 'Enviar notificações de mudança para esse endereço de e-mail';
 $lang['registernotify']        = 'Enviar informações de usuários registrados para esse endereço de e-mail';
 $lang['mailfrom']              = 'Endereço de e-mail a ser utilizado para mensagens automáticas';
+$lang['mailreturnpath']        = 'Endereço de e-mail do destinatário para notificações de falha de entrega';
 $lang['mailprefix']            = 'Prefixo do assunto dos e-mails de envio automático';
 $lang['htmlmail']              = 'Enviar e-mail HTML multipartes, que têm uma aparência melhor, mas um tamanho maior. Desabilite para enviar e-mails em texto puro.';
 $lang['sitemap']               = 'Gerar Google Sitemap (dias)';
@@ -137,6 +135,9 @@ $lang['rss_content']           = 'O que deve ser exibido nos itens da fonte XML?
 $lang['rss_update']            = 'Intervalo de atualização da fonte XML (seg)';
 $lang['rss_show_summary']      = 'Resumo de exibição da fonte XML no título';
 $lang['rss_media']             = 'Que tipo de alterações devem ser listadas na fonte XML?';
+$lang['rss_media_o_both']      = 'ambos';
+$lang['rss_media_o_pages']     = 'páginas';
+$lang['rss_media_o_media']     = 'mídia';
 $lang['updatecheck']           = 'Verificar atualizações e avisos de segurança? O DokuWiki precisa contactar o "splitbrain.org" para efetuar esse recurso.';
 $lang['userewrite']            = 'Usar URLs "limpas"';
 $lang['useslash']              = 'Usar a barra como separador de espaços de nomes nas URLs';
@@ -155,6 +156,10 @@ $lang['renderer_xhtml']        = 'Renderizador a ser utilizado para a saída pri
 $lang['renderer__core']        = '%s (núcleo do DokuWiki)';
 $lang['renderer__plugin']      = '%s ("plug-in")';
 $lang['dnslookups']            = 'O DokuWiki procurará pelo nome de host dos endereços IP remotos dos usuários que estão editando as páginas. Caso você tenha um DNS lento, ele não esteja funcionando ou, ainda, você não queira esse recurso, desabilite essa opção.';
+$lang['jquerycdn']             = 'Os scripts jQuery e jQuery UI devem ser carregados a partir de uma CND? Isso adiciona requisições HTTP adicionais, mas os arquivos podem carregar mais rapidamente e os usuários podem já tê-los no cache.';
+$lang['jquerycdn_o_0']         = 'Sem CDN, somente entrega local';
+$lang['jquerycdn_o_jquery']    = 'CDN em code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN em cdnjs.com';
 $lang['proxy____host']         = 'Nome do servidor proxy';
 $lang['proxy____port']         = 'Porta do proxy';
 $lang['proxy____user']         = 'Nome de usuário do proxy';
diff --git a/lib/plugins/config/lang/pt/lang.php b/lib/plugins/config/lang/pt/lang.php
index 312f45d428eb7c0fbffbc03e70d24e842d91d3ac..ba0ab0b3c4bebc827405e5442dc65f8db3f92523 100644
--- a/lib/plugins/config/lang/pt/lang.php
+++ b/lib/plugins/config/lang/pt/lang.php
@@ -10,6 +10,7 @@
  * @author José Campos zecarlosdecampos@gmail.com
  * @author Paulo Carmino <contato@paulocarmino.com>
  * @author Alfredo Silva <alfredo.silva@sky.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['menu']                  = 'Configuração';
 $lang['error']                 = 'Parâmetros de Configuração não actualizados devido a valores inválidos. Por favor, reveja as modificações que pretende efectuar antes de re-submetê-las.<br /> Os valores incorrectos serão mostrados dentro de uma "moldura" vermelha.';
diff --git a/lib/plugins/config/lang/ru/intro.txt b/lib/plugins/config/lang/ru/intro.txt
index 01cf19063721b0744ae6aeaf62c60956bb3bc158..2b4fe3d46cba7130377af96ea51dce2f89296f02 100644
--- a/lib/plugins/config/lang/ru/intro.txt
+++ b/lib/plugins/config/lang/ru/intro.txt
@@ -1,6 +1,6 @@
 ====== Настройки вики ======
 
-Здесь вы можете изменить настройки своей «Докувики». Для справки по поводу конкретных опций смотрите [[doku>config|Конфигурирование «Докувики»]]. Дополнительные детали об этом плагине доступны здесь: [[doku>plugin:config]].
+Здесь вы можете изменить настройки своей «Докувики». Для справки по конкретным опциям смотрите [[doku>config|Конфигурирование «Докувики»]]. Дополнительные детали об этом плагине доступны здесь: [[doku>plugin:config]].
 
 Настройки, отображаемые на светло-красном фоне, защищены от изменений и не могут быть отредактированы с помощью этого плагина.  Голубым фоном отмечены настройки со значениями по умолчанию, а белым фоном — настройки, которые были локально изменены для этой конкретной «Докувики». Как голубые, так и белые настройки доступны для изменения.
 
diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php
index a3fd3bfda6964277b9906b628776f45d24448728..1089e0ba2aab037925db38a010aaf44ccf411ea6 100644
--- a/lib/plugins/config/lang/ru/lang.php
+++ b/lib/plugins/config/lang/ru/lang.php
@@ -3,12 +3,13 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
+ * @author Zhassulan <zyesmukanov@gmail.com>
  * @author Denis Simakov <akinoame1@gmail.com>
  * @author Andrew Pleshakov <beotiger@mail.ru>
- * @author Змей Этерийский evil_snake@eternion.ru
+ * @author Змей Этерийский <evil_snake@eternion.ru>
  * @author Hikaru Nakajima <jisatsu@mail.ru>
  * @author Alexei Tereschenko <alexeitlex@yahoo.com>
- * @author Irina Ponomareva irinaponomareva@webperfectionist.com
  * @author Alexander Sorkin <kibizoid@gmail.com>
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
@@ -17,9 +18,7 @@
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
- * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author RainbowSpike <1@2.ru>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author alexey <xeenych@gmail.com>
  */
 $lang['menu']                  = 'Настройки вики';
@@ -43,7 +42,7 @@ $lang['_editing']              = 'Параметры правки';
 $lang['_links']                = 'Параметры ссылок';
 $lang['_media']                = 'Параметры медиафайлов';
 $lang['_notifications']        = 'Параметры уведомлений';
-$lang['_syndication']          = 'Настройки синдикаций';
+$lang['_syndication']          = 'Параметры синдикаций (RSS)';
 $lang['_advanced']             = 'Тонкая настройка';
 $lang['_network']              = 'Параметры сети';
 $lang['_msg_setting_undefined'] = 'Не найдены метаданные настроек.';
@@ -59,7 +58,7 @@ $lang['license']               = 'На условиях какой лиценз
 $lang['savedir']               = 'Директория для данных';
 $lang['basedir']               = 'Корневая директория (например, <code>/dokuwiki/</code>). Оставьте пустым для автоопределения.';
 $lang['baseurl']               = 'Корневой адрес (URL) (например, <code>http://www.yourserver.ru</code>). Оставьте пустым для автоопределения.';
-$lang['cookiedir']             = 'Cookie директория. Оставьте пустым для автоопределения.';
+$lang['cookiedir']             = 'Директория для cookie. Оставьте пустым для автоопределения.';
 $lang['dmode']                 = 'Права для создаваемых директорий';
 $lang['fmode']                 = 'Права для создаваемых файлов';
 $lang['allowdebug']            = 'Включить отладку. <b>Отключите, если она вам не нужна!</b>';
@@ -68,7 +67,7 @@ $lang['recent_days']           = 'На сколько дней назад сох
 $lang['breadcrumbs']           = 'Вы посетили (кол-во). Поставьте 0 (ноль) для отключения.';
 $lang['youarehere']            = 'Показывать «Вы находитесь здесь»';
 $lang['fullpath']              = 'Полный путь к документу';
-$lang['typography']            = 'Типографские символы';
+$lang['typography']            = 'Выполнять замену на типографские символы';
 $lang['dformat']               = 'Формат даты и времени (см. функцию PHP <a href="http://php.net/strftime">strftime</a>)';
 $lang['signature']             = 'Шаблон подписи';
 $lang['showuseras']            = 'Что отображать при показе пользователя, редактировавшего страницу последним';
@@ -127,8 +126,9 @@ $lang['subscribe_time']        = 'Интервал рассылки подпис
 $lang['notify']                = 'Всегда отправлять сообщения об изменениях на этот электронный адрес';
 $lang['registernotify']        = 'Всегода отправлять информацию о новых зарегистрированных пользователях на этот электронный адрес';
 $lang['mailfrom']              = 'Электронный адрес вики (От:)';
+$lang['mailreturnpath']        = 'Адрес электронной почты для доставки отчета о недоставленных сообщений';
 $lang['mailprefix']            = 'Префикс, используемый для автоматического письма, станет темой сообщения. Оставьте поле пустым для использования названия вики.';
-$lang['htmlmail']              = 'Отправлять красивые, но крупные HTML-многочастные письма. Для отправки простых текстовых писем - отключить';
+$lang['htmlmail']              = 'Отправлять красивые, но более крупные HTML-письма. Отключите для отправки простых текстовых писем.';
 $lang['sitemap']               = 'Число дней, через которое нужно создавать (обновлять) карту сайта для поисковиков (Гугл, Яндекс и др.). Укажите 0 (ноль) для отключения.';
 $lang['rss_type']              = 'Тип XML-ленты';
 $lang['rss_linkto']            = 'Ссылки в XML-ленте указывают на';
@@ -136,17 +136,20 @@ $lang['rss_content']           = 'Что показывать в XML-ленте?
 $lang['rss_update']            = 'Интервал обновления XML-ленты (сек.)';
 $lang['rss_show_summary']      = 'Показывать краткую выдержку в заголовках XML-ленты';
 $lang['rss_media']             = 'Какие изменения должны быть отображены в XML-ленте?';
+$lang['rss_media_o_both']      = 'оба';
+$lang['rss_media_o_pages']     = 'страницы';
+$lang['rss_media_o_media']     = 'медиа';
 $lang['updatecheck']           = 'Проверять наличие обновлений и предупреждений о безопасности? Для этого «Докувики» потребуется связываться с update.dokuwiki.org.';
 $lang['userewrite']            = 'Удобочитаемые адреса (URL)';
-$lang['useslash']              = 'Использовать слэш в URL';
+$lang['useslash']              = 'Использовать слэш разделителем пространств имён в URL';
 $lang['sepchar']               = 'Разделитель слов в имени страницы';
 $lang['canonical']             = 'Полные канонические адреса (URL)';
 $lang['fnencode']              = 'Метод кодирования имён файлов, записанных не ASCII-символами.';
 $lang['autoplural']            = 'Проверять можественную форму имени страницы в ссылках';
 $lang['compression']           = 'Метод сжатия для архивных файлов';
-$lang['gzip_output']           = 'Использовать gzip-сжатие для xhtml';
+$lang['gzip_output']           = 'Использовать gzip-сжатие для xhtml (Content-Encoding)';
 $lang['compress']              = 'Сжимать файлы CSS и javascript';
-$lang['cssdatauri']            = 'Размер в байтах до которого изображения, указанные в CSS-файлах, должны быть встроены прямо в таблицу стилей, для уменьшения избычтоных HTTP-запросов. Этот метод не будет работать в IE версии 7 и ниже! Установка от <code>400</code> до <code>600</code> байт является хорошим показателем. Установите <code>0</code>, чтобы отключить.';
+$lang['cssdatauri']            = 'Размер в байтах, до которого изображения, указанные в CSS-файлах, должны быть встроены прямо в таблицу стилей, для уменьшения избыточных HTTP-запросов. Этот метод не будет работать в IE версии 7 и ниже! Установка от <code>400</code> до <code>600</code> байт является хорошим показателем. Установите <code>0</code>, чтобы отключить.';
 $lang['send404']               = 'Посылать «HTTP 404/Страница не найдена» для несуществующих страниц';
 $lang['broken_iua']            = 'Возможно, функция ignore_user_abort не работает в вашей системе? Это может привести к потере функциональности индексирования поиска. Эта проблема присутствует, например, в IIS+PHP/CGI. Для дополнительной информации смотрите <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">баг 852</a>.';
 $lang['xsendfile']             = 'Используете заголовок X-Sendfile для загрузки файлов на веб-сервер? Ваш веб-сервер должен поддерживать это.';
@@ -154,6 +157,7 @@ $lang['renderer_xhtml']        = 'Обработчик основного (xhtml
 $lang['renderer__core']        = '%s (ядро «Докувики»)';
 $lang['renderer__plugin']      = '%s (плагин)';
 $lang['dnslookups']            = '«Докувики» ищет DNS-имена пользователей, редактирующих страницы. Если у вас нет DNS-сервера или он работает медленно, рекомендуем отключить эту опцию.';
+$lang['jquerycdn']             = 'Требуется ли загрузка jQuery-скриптов (включая jQuery UI-скрипты) из CDN сети? Данная функция увеличивает количество HTTP запросов, но загрузка файлов будет проходить быстрее и пользователи смогут кэшировать запросы.';
 $lang['jquerycdn_o_0']         = 'Не использовать CDN. Использовать только локальную доставку';
 $lang['jquerycdn_o_jquery']    = 'Использовать CDN с code.jquery.com';
 $lang['jquerycdn_o_cdnjs']     = 'Использовать CDN с cdnjs.com';
@@ -161,7 +165,7 @@ $lang['proxy____host']         = 'proxy-адрес';
 $lang['proxy____port']         = 'proxy-порт';
 $lang['proxy____user']         = 'proxy-имя пользователя';
 $lang['proxy____pass']         = 'proxy-пароль';
-$lang['proxy____ssl']          = 'proxy-ssl';
+$lang['proxy____ssl']          = 'Использовать SSL для соединения с прокси';
 $lang['proxy____except']       = 'Регулярное выражение для адресов (URL), для которых прокси должен быть пропущен.';
 $lang['safemodehack']          = 'Включить обход safemode (хак)';
 $lang['ftp____host']           = 'ftp-адрес';
@@ -205,8 +209,8 @@ $lang['xsendfile_o_3']         = 'Проприетарный заголовок
 $lang['showuseras_o_loginname'] = 'логин';
 $lang['showuseras_o_username'] = 'полное имя пользователя';
 $lang['showuseras_o_username_link'] = 'полное имя пользователя как интервики-ссылка';
-$lang['showuseras_o_email']    = 'адрес электропочты в шифрованном виде (см. mailguard)';
-$lang['showuseras_o_email_link'] = 'адрес электропочты в виде ссылки mailto:';
+$lang['showuseras_o_email']    = 'адрес эл. почты в шифрованном виде (см. mailguard)';
+$lang['showuseras_o_email_link'] = 'адрес эл. почты в виде ссылки mailto:';
 $lang['useheading_o_0']        = 'никогда';
 $lang['useheading_o_navigation'] = 'только в навигации';
 $lang['useheading_o_content']  = 'только в содержимом вики';
diff --git a/lib/plugins/config/lang/sk/lang.php b/lib/plugins/config/lang/sk/lang.php
index dfa5ca7667ef9448f37f6f4d009d6608b220578f..79054aaea0c2fe4f7e953fc4c490b3f1f9884282 100644
--- a/lib/plugins/config/lang/sk/lang.php
+++ b/lib/plugins/config/lang/sk/lang.php
@@ -3,10 +3,9 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
- * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
  * @author Martin Michalek <michalek.dev@gmail.com>
- * @author Michalek <michalek.dev@gmail.com>
+ * @author Michal Mesko <michal.mesko@gmail.com>
+ * @author exusik <exusik@gmail.com>
  */
 $lang['menu']                  = 'Nastavenia konfigurácie';
 $lang['error']                 = 'Nastavenia neboli aktualizované kvôli neplatnej hodnote, prosím skontrolujte vaše zmeny a znovu ich pošlite. <br />Nesprávna hodnota(y) bude ohraničená červeným okrajom.';
@@ -139,6 +138,10 @@ $lang['renderer_xhtml']        = 'Používané vykresľovacie jadro pre hlavný
 $lang['renderer__core']        = '%s (dokuwiki jadro)';
 $lang['renderer__plugin']      = '%s (plugin)';
 $lang['dnslookups']            = 'DokuWiki hľadá mená vzdialených IP adries používateľov editujúcich stránky. Ak máte pomalý alebo nefunkčný DNS server alebo nechcete túto možnosť, deaktivujte túto voľbu';
+$lang['jquerycdn']             = 'Mali by byť jQuery a jQuery UI skripty načítané z CDN? Voľba zvýši počet dodatočných HTTP požiadaviek, ale súbory sa môžu načítať rýchlejšie a používatelia ich už môžu mať vo vyrovnávacej pamäti.';
+$lang['jquerycdn_o_0']         = 'Nepoužívať CDN, iba lokálne súbory';
+$lang['jquerycdn_o_jquery']    = 'CDN code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN cdnjs.com';
 $lang['proxy____host']         = 'Proxy server - názov';
 $lang['proxy____port']         = 'Proxy server - port';
 $lang['proxy____user']         = 'Proxy server - používateľské meno';
diff --git a/lib/plugins/config/lang/sl/lang.php b/lib/plugins/config/lang/sl/lang.php
index dcf8c0a5485f7070ce7145b134eef1dc49ca23b4..7db4b4b34ac4ed81bea4fc9fa720d68d431662a1 100644
--- a/lib/plugins/config/lang/sl/lang.php
+++ b/lib/plugins/config/lang/sl/lang.php
@@ -1,5 +1,8 @@
 <?php
+
 /**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
  * Slovenian language file
  *
  * @author Dejan Levec <webphp@gmail.com>
@@ -32,28 +35,29 @@ $lang['_network']              = 'Omrežne nastavitve';
 $lang['_msg_setting_undefined'] = 'Ni nastavitvenih metapodatkov.';
 $lang['_msg_setting_no_class'] = 'Ni nastavitvenega razreda.';
 $lang['_msg_setting_no_default'] = 'Ni privzete vrednosti.';
-$lang['fmode']                 = 'Način ustvarjanja datotek';
-$lang['dmode']                 = 'Način ustvarjanja map';
-$lang['lang']                  = 'Jezik vmesnika';
-$lang['basedir']               = 'Pot do strežnika (npr. /dokuwiki/). Prazno polje določa samodejno zaznavanje';
-$lang['baseurl']               = 'Naslov URL strežnika (npr. http://www.streznik.si). Prazno polje določa samodejno zaznavanje';
-$lang['savedir']               = 'Mapa za shranjevanje podatkov';
-$lang['cookiedir']             = 'Pot do piškotka. Prazno polje določa uporabo osnovnega naslova (baseurl)';
-$lang['start']                 = 'Ime začetne strani wiki';
 $lang['title']                 = 'Naslov Wiki spletišča';
+$lang['start']                 = 'Ime začetne strani wiki';
+$lang['lang']                  = 'Jezik vmesnika';
 $lang['template']              = 'Predloga';
 $lang['tagline']               = 'Označna vrstica (ob podpori predloge)';
 $lang['sidebar']               = 'Ime strani stranske vrstice (ob podpori predloge); prazno polje onemogoči stransko vrstico.';
 $lang['license']               = 'Pod pogoji katerega dovoljenja je objavljena vsebina?';
-$lang['fullpath']              = 'Pokaži polno pot strani v nogi strani';
+$lang['savedir']               = 'Mapa za shranjevanje podatkov';
+$lang['basedir']               = 'Pot do strežnika (npr. /dokuwiki/). Prazno polje določa samodejno zaznavanje';
+$lang['baseurl']               = 'Naslov URL strežnika (npr. http://www.streznik.si). Prazno polje določa samodejno zaznavanje';
+$lang['cookiedir']             = 'Pot do piškotka. Prazno polje določa uporabo osnovnega naslova (baseurl)';
+$lang['dmode']                 = 'Način ustvarjanja map';
+$lang['fmode']                 = 'Način ustvarjanja datotek';
+$lang['allowdebug']            = 'Dovoli razhroščevanje (po potrebi!)';
 $lang['recent']                = 'Nedavne spremembe';
+$lang['recent_days']           = 'Koliko nedavnih sprememb naj se ohrani (v dnevih)';
 $lang['breadcrumbs']           = 'Å tevilo drobtinic poti';
 $lang['youarehere']            = 'Hierarhične drobtinice poti';
+$lang['fullpath']              = 'Pokaži polno pot strani v nogi strani';
 $lang['typography']            = 'Omogoči tipografske zamenjave';
-$lang['htmlok']                = 'Dovoli vstavljeno kodo HTML';
-$lang['phpok']                 = 'Dovoli vstavljeno kodo PHP';
 $lang['dformat']               = 'Oblika zapisa časa (funkcija PHP <a href="http://php.net/strftime">strftime</a>)';
 $lang['signature']             = 'Podpis';
+$lang['showuseras']            = 'Kaj prikazati za prikaz uporabnika, ki je zadnji urejal stran';
 $lang['toptoclevel']           = 'Vrhnja raven kazala';
 $lang['tocminheads']           = 'Najmanjše število naslovov za izgradnjo kazala';
 $lang['maxtoclevel']           = 'Najvišja raven kazala';
@@ -61,15 +65,8 @@ $lang['maxseclevel']           = 'Največja raven urejanja odseka';
 $lang['camelcase']             = 'Uporabi EnoBesedni zapisa za povezave';
 $lang['deaccent']              = 'Počisti imena strani';
 $lang['useheading']            = 'Uporabi prvi naslov za ime strani';
-$lang['refcheck']              = 'Preverjanje sklica predstavnih datotek';
-$lang['allowdebug']            = 'Dovoli razhroščevanje (po potrebi!)';
-$lang['mediarevisions']        = 'Ali naj se omogočijo objave predstavnih vsebin?';
-$lang['usewordblock']          = 'Zaustavi neželeno besedilo glede na seznam besed';
-$lang['indexdelay']            = 'ÄŒasovni zamik pred ustvarjanjem kazala (v sekundah)';
-$lang['relnofollow']           = 'Uporabni možnost rel="nofollow" pri zunanjih povezavah';
-$lang['mailguard']             = 'Å ifriraj elektronske naslove';
-$lang['iexssprotect']          = 'Preveri poslane datoteke za zlonamerno kodo JavaScript ali HTML';
-$lang['showuseras']            = 'Kaj prikazati za prikaz uporabnika, ki je zadnji urejal stran';
+$lang['sneaky_index']          = 'Privzeto pokaže sistem DokuWiki vse imenske prostore v pogledu kazala. Z omogočanjem te možnosti bodo skriti vsi imenski prostori, v katere prijavljen uporabnik nima dovoljenj dostopa. S tem je mogoče preprečiti dostop do podrejenih strani. Možnost lahko vpliva na uporabnost nastavitev nadzora dostopa ACL.';
+$lang['hidepages']             = 'Skrij skladne strani (logični izraz)';
 $lang['useacl']                = 'Uporabi seznam nadzora dostopa (ACL)';
 $lang['autopasswd']            = 'Samodejno ustvari gesla';
 $lang['authtype']              = 'Ozadnji način overitve';
@@ -78,58 +75,64 @@ $lang['defaultgroup']          = 'Privzeta skupina';
 $lang['superuser']             = 'Skrbnik - skupina, uporabnik ali z vejico ločen seznam uporabnik1,@skupina1,uporabnik2 s polnim dostopom do vseh strani in možnosti, neodvisno od nastavitev nadzora dostopa ACL';
 $lang['manager']               = 'Upravljavec - skupina, uporabnik ali z vejico ločen seznam uporabnik1,@skupina1,uporabnik2 z dovoljenji za dostop do nekaterih možnosti upravljanja';
 $lang['profileconfirm']        = 'Potrdi spremembe profila z geslom';
+$lang['rememberme']            = 'Dovoli trajne prijavne piškotke (trajno pomnenje prijave)';
 $lang['disableactions']        = 'Onemogoči dejanja DokuWiki';
 $lang['disableactions_check']  = 'Preveri';
 $lang['disableactions_subscription'] = 'Naročanje/Preklic naročnine';
 $lang['disableactions_wikicode'] = 'Pogled izvorne kode/Surovi izvoz';
 $lang['disableactions_other']  = 'Druga dejanja (z vejico ločen seznam)';
-$lang['sneaky_index']          = 'Privzeto pokaže sistem DokuWiki vse imenske prostore v pogledu kazala. Z omogočanjem te možnosti bodo skriti vsi imenski prostori, v katere prijavljen uporabnik nima dovoljenj dostopa. S tem je mogoče preprečiti dostop do podrejenih strani. Možnost lahko vpliva na uporabnost nastavitev nadzora dostopa ACL.';
 $lang['auth_security_timeout'] = 'Varnostna časovna omejitev overitve (v sekundah)';
 $lang['securecookie']          = 'Ali naj se piškotki poslani preko varne povezave HTTPS v brskalniku pošiljajo le preko HTTPS? Onemogočanje možnosti je priporočljivo le takrat, ko je prijava varovana s protokolom  SSL, brskanje po strani pa ni posebej zavarovano.';
+$lang['usewordblock']          = 'Zaustavi neželeno besedilo glede na seznam besed';
+$lang['relnofollow']           = 'Uporabni možnost rel="nofollow" pri zunanjih povezavah';
+$lang['indexdelay']            = 'ÄŒasovni zamik pred ustvarjanjem kazala (v sekundah)';
+$lang['mailguard']             = 'Å ifriraj elektronske naslove';
+$lang['iexssprotect']          = 'Preveri poslane datoteke za zlonamerno kodo JavaScript ali HTML';
+$lang['usedraft']              = 'Samodejno shrani osnutek med urejanjem strani';
+$lang['htmlok']                = 'Dovoli vstavljeno kodo HTML';
+$lang['phpok']                 = 'Dovoli vstavljeno kodo PHP';
+$lang['locktime']              = 'Največja dovoljena starost datotek zaklepa (v sekundah)';
+$lang['cachetime']             = 'Največja dovoljena starost predpomnilnika (v sekundah)';
+$lang['target____wiki']        = 'Ciljno okno za notranje povezave';
+$lang['target____interwiki']   = 'Ciljno okno za notranje wiki povezave';
+$lang['target____extern']      = 'Ciljno okno za zunanje povezave';
+$lang['target____media']       = 'Ciljno okno za predstavne povezave';
+$lang['target____windows']     = 'Ciljno okno za povezave oken';
+$lang['mediarevisions']        = 'Ali naj se omogočijo objave predstavnih vsebin?';
+$lang['refcheck']              = 'Preverjanje sklica predstavnih datotek';
+$lang['gdlib']                 = 'Različica GD Lib';
+$lang['im_convert']            = 'Pot do orodja za pretvarjanje slik ImageMagick';
+$lang['jpg_quality']           = 'Kakovost stiskanja datotek JPG (0-100)';
+$lang['fetchsize']             = 'največja dovoljena velikost zunanjega prejemanja z datoteko fetch.php (v bajtih)';
+$lang['subscribers']           = 'Omogoči podporo naročanju na strani';
+$lang['subscribe_time']        = 'Čas po katerem so poslani povzetki sprememb (v sekundah); Vrednost mora biti krajša od časa, ki je določen z nedavno_dni.';
+$lang['notify']                = 'Pošlji obvestila o spremembah na določen elektronski naslov';
+$lang['registernotify']        = 'Pošlji obvestila o novih vpisanih uporabnikih na določen elektronski naslov';
+$lang['mailfrom']              = 'Elektronski naslov za samodejno poslana sporočila';
+$lang['mailprefix']            = 'Predpona zadeve elektronskega sporočila za samodejna sporočila.';
+$lang['sitemap']               = 'Ustvari Google kazalo strani (v dnevih)';
+$lang['rss_type']              = 'Vrsta virov XML';
+$lang['rss_linkto']            = 'XML viri so povezani z';
+$lang['rss_content']           = 'Kaj prikazati med predmeti virov XML?';
+$lang['rss_update']            = 'ÄŒasovni razmik posodobitve virov XML (v sekundah)';
+$lang['rss_show_summary']      = 'Viri XML so povzeti v naslovu';
 $lang['updatecheck']           = 'Ali naj sistem preveri za posodobitve in varnostna opozorila.';
 $lang['userewrite']            = 'Uporabi olepšan zapis naslovov URL';
 $lang['useslash']              = 'Uporabi poševnico kot ločilnik imenskih prostorov v naslovih URL';
-$lang['usedraft']              = 'Samodejno shrani osnutek med urejanjem strani';
 $lang['sepchar']               = 'Ločilnik besed imen strani';
 $lang['canonical']             = 'Uporabi polni kanonični zapis naslova URL';
 $lang['fnencode']              = 'Način kodiranja ne-ASCII imen datotek.';
 $lang['autoplural']            = 'Preveri množinske oblike povezav';
 $lang['compression']           = 'Način stiskanja za arhivirane datoteke';
-$lang['cachetime']             = 'Največja dovoljena starost predpomnilnika (v sekundah)';
-$lang['locktime']              = 'Največja dovoljena starost datotek zaklepa (v sekundah)';
-$lang['fetchsize']             = 'največja dovoljena velikost zunanjega prejemanja z datoteko fetch.php (v bajtih)';
-$lang['notify']                = 'Pošlji obvestila o spremembah na določen elektronski naslov';
-$lang['registernotify']        = 'Pošlji obvestila o novih vpisanih uporabnikih na določen elektronski naslov';
-$lang['mailfrom']              = 'Elektronski naslov za samodejno poslana sporočila';
-$lang['mailprefix']            = 'Predpona zadeve elektronskega sporočila za samodejna sporočila.';
 $lang['gzip_output']           = 'Uporabi stiskanje gzip vsebine za xhtml';
-$lang['gdlib']                 = 'Različica GD Lib';
-$lang['im_convert']            = 'Pot do orodja za pretvarjanje slik ImageMagick';
-$lang['jpg_quality']           = 'Kakovost stiskanja datotek JPG (0-100)';
-$lang['subscribers']           = 'Omogoči podporo naročanju na strani';
-$lang['subscribe_time']        = 'Čas po katerem so poslani povzetki sprememb (v sekundah); Vrednost mora biti krajša od časa, ki je določen z nedavno_dni.';
 $lang['compress']              = 'Združi odvod CSS in JavaScript v brskalniku';
 $lang['cssdatauri']            = 'Velikost sklicanih slik v bajtih, ki so navedene v datotekah CSS za zmanjšanje zahtev osveževanja strežnika HTTP. Ustrezne vrednosti so <code>400</code> do <code>600</code> bajtov. Vrednost <code>0</code> onemogoči možnost.';
-$lang['hidepages']             = 'Skrij skladne strani (logični izraz)';
 $lang['send404']               = 'Pošlji "HTTP 404/Strani ni mogoče najti" pri dostopu do neobstoječih strani';
-$lang['sitemap']               = 'Ustvari Google kazalo strani (v dnevih)';
 $lang['broken_iua']            = 'Ali je možnost ignore_user_abort okvarjena na sistemu? Napaka lahko vpliva na delovanje iskalnika. Napake so pogoste ob uporabi IIS+PHP/CGI. Več o tem si je mogoče prebrati v <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">poročilu o hrošču 852</a>.';
 $lang['xsendfile']             = 'Uporabi glavo X-Sendfile za prejemanje statičnih datotek. Spletni strežnik mora možnost podpirati.';
 $lang['renderer_xhtml']        = 'Izrisovalnik za odvod Wiki strani (xhtml)';
 $lang['renderer__core']        = '%s (jedro dokuwiki)';
 $lang['renderer__plugin']      = '%s (vstavek)';
-$lang['rememberme']            = 'Dovoli trajne prijavne piškotke (trajno pomnenje prijave)';
-$lang['rss_type']              = 'Vrsta virov XML';
-$lang['rss_linkto']            = 'XML viri so povezani z';
-$lang['rss_content']           = 'Kaj prikazati med predmeti virov XML?';
-$lang['rss_update']            = 'ÄŒasovni razmik posodobitve virov XML (v sekundah)';
-$lang['recent_days']           = 'Koliko nedavnih sprememb naj se ohrani (v dnevih)';
-$lang['rss_show_summary']      = 'Viri XML so povzeti v naslovu';
-$lang['target____wiki']        = 'Ciljno okno za notranje povezave';
-$lang['target____interwiki']   = 'Ciljno okno za notranje wiki povezave';
-$lang['target____extern']      = 'Ciljno okno za zunanje povezave';
-$lang['target____media']       = 'Ciljno okno za predstavne povezave';
-$lang['target____windows']     = 'Ciljno okno za povezave oken';
 $lang['proxy____host']         = 'Ime posredniškega strežnika';
 $lang['proxy____port']         = 'Vrata posredniškega strežnika';
 $lang['proxy____user']         = 'Uporabniško ime posredniškega strežnika';
diff --git a/lib/plugins/config/lang/sr/lang.php b/lib/plugins/config/lang/sr/lang.php
index d41cdabb376f969ffe70741b67c6426add8b140f..e8f3b8335975ce8992e7a078cb8a2d0f098f1f36 100644
--- a/lib/plugins/config/lang/sr/lang.php
+++ b/lib/plugins/config/lang/sr/lang.php
@@ -6,6 +6,7 @@
  * @author Иван Петровић petrovicivan@ubuntusrbija.org
  * @author Ivan Petrovic <petrovicivan@ubuntusrbija.org>
  * @author Miroslav Å olti <solti.miroslav@gmail.com>
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
  */
 $lang['menu']                  = 'Подешавања';
 $lang['error']                 = 'Подешавања нису прихваћена јер постоји вредност са грешком, проверите измене које сте извршили и поновите слање.<br />Вредност(и) са грешком су приказане са црвеним оквиром.';
@@ -64,7 +65,7 @@ $lang['hidepages']             = 'Сакриј подударне страниц
 $lang['useacl']                = 'Користи листу права приступа';
 $lang['autopasswd']            = 'Аутогенерисане лозинки';
 $lang['authtype']              = 'Позадински систем аутентификације';
-$lang['passcrypt']             = 'Метода енкрипције лозинки';
+$lang['passcrypt']             = 'Метода шифровања лозинки';
 $lang['defaultgroup']          = 'Подразумевана група';
 $lang['superuser']             = 'Суперкорисник - група, корисник или зарезом одвојена листа корисника корисник1,@група1,корисник2 са отвореним проступом свим страницама и функцијама без обзира на поставке Контроле приступа';
 $lang['manager']               = 'Управник - група, корисник или зарезом одвојена листа корисника корисник1,@група1,корисник2 са отвореним проступом неким функцијама за управљање';
@@ -124,6 +125,9 @@ $lang['xsendfile']             = 'Користи заглавље X-Sendfile д
 $lang['renderer_xhtml']        = 'Исцртавање користи главни (xhtml) вики испис';
 $lang['renderer__core']        = '%s (dokuwiki језгро)';
 $lang['renderer__plugin']      = '%s (додатак)';
+$lang['jquerycdn_o_0']         = 'Без CDN-a, само локална достава';
+$lang['jquerycdn_o_jquery']    = 'CDN на адреси code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN на cdnjs.com';
 $lang['proxy____host']         = 'Назив посредника (проксија)';
 $lang['proxy____port']         = 'Порт посредника (проксија)';
 $lang['proxy____user']         = 'Корисничко име на посреднику (проксију)';
@@ -171,6 +175,7 @@ $lang['xsendfile_o_2']         = 'Стандардно заглавље X-Sendfi
 $lang['xsendfile_o_3']         = 'Власничко заглавље Nginx X-Accel-Redirect';
 $lang['showuseras_o_loginname'] = 'Корисничко име';
 $lang['showuseras_o_username'] = 'Име и презиме корисника';
+$lang['showuseras_o_username_link'] = 'Пуно име корисника као корисничка веза међувикија';
 $lang['showuseras_o_email']    = 'Е-адреса (замућено по подешавањима mailguard-а)';
 $lang['showuseras_o_email_link'] = 'Корисничка Е-адреса као mailto: веза';
 $lang['useheading_o_0']        = 'Никада';
diff --git a/lib/plugins/config/lang/sv/lang.php b/lib/plugins/config/lang/sv/lang.php
index 7b7d08d68ab60f70dd337e4e5fe5d0bfdb52344e..268cc364e49f5479df11fc4852412e68bc3511e8 100644
--- a/lib/plugins/config/lang/sv/lang.php
+++ b/lib/plugins/config/lang/sv/lang.php
@@ -1,22 +1,18 @@
 <?php
+
 /**
- * swedish language file
- *
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Per Foreby <per@foreby.se>
  * @author Nicklas Henriksson <nicklas[at]nihe.se>
  * @author HÃ¥kan Sandell <hakan.sandell[at]mydata.se>
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
- * @author Tormod Johansson tormod.otter.johansson@gmail.com
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author HÃ¥kan Sandell <hakan.sandell@home.se>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['menu']                  = 'Hantera inställningar';
 $lang['error']                 = 'Inställningarna uppdaterades inte på grund av ett felaktigt värde. Titta igenom dina ändringar och försök sedan spara igen.
@@ -90,6 +86,7 @@ $lang['disableactions']        = 'Stäng av funktioner i DokuWiki';
 $lang['disableactions_check']  = 'Kontroll';
 $lang['disableactions_subscription'] = 'Prenumerera/Säg upp prenumeration';
 $lang['disableactions_wikicode'] = 'Visa källkod/Exportera råtext';
+$lang['disableactions_profile_delete'] = 'Ta bort eget konto';
 $lang['disableactions_other']  = 'Andra funktioner (kommaseparerade)';
 $lang['auth_security_timeout'] = 'Autentisieringssäkerhets timeout (sekunder)';
 $lang['securecookie']          = 'Skall cookies som sätts via HTTPS endast skickas via HTTPS från webbläsaren? Avaktivera detta alternativ endast om inloggningen till din wiki är säkrad med SSL men läsning av wikin är osäkrad.';
@@ -141,6 +138,8 @@ $lang['xsendfile']             = 'Använd X-Sendfile huvudet för att låta webs
 $lang['renderer_xhtml']        = 'Generera för användning i huvudwikipresentation (xhtml)';
 $lang['renderer__core']        = '%s (dokuwiki core)';
 $lang['renderer__plugin']      = '%s (plugin)';
+$lang['jquerycdn_o_jquery']    = 'CDN på code.jquery.com';
+$lang['jquerycdn_o_cdnjs']     = 'CDN på cdnjs.com';
 $lang['proxy____host']         = 'Proxyserver';
 $lang['proxy____port']         = 'Proxyport';
 $lang['proxy____user']         = 'Användarnamn för proxy';
@@ -188,6 +187,7 @@ $lang['xsendfile_o_2']         = 'Standard X-Sendfile-huvud';
 $lang['xsendfile_o_3']         = 'Proprietär Nginx X-Accel-Redirect header';
 $lang['showuseras_o_loginname'] = 'Användarnamn';
 $lang['showuseras_o_username'] = 'Namn';
+$lang['showuseras_o_username_link'] = 'Användarens fullständiga namn som interwiki-användarlänk';
 $lang['showuseras_o_email']    = 'Användarens e-postadress (obfuskerad enligt inställningarna i mailguard)';
 $lang['showuseras_o_email_link'] = 'Användarens e-postadress som mailto: länk';
 $lang['useheading_o_0']        = 'Aldrig';
diff --git a/lib/plugins/config/lang/uk/lang.php b/lib/plugins/config/lang/uk/lang.php
index fe700195540d6123a53c91dad7d3f30365615b6c..d8b1d5b04d38d3b3f5fbc72f0b79a77528812cb6 100644
--- a/lib/plugins/config/lang/uk/lang.php
+++ b/lib/plugins/config/lang/uk/lang.php
@@ -2,15 +2,15 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Oleksii <alexey.furashev@gmail.com>
+ * @author Vitaly <vitaly.balashov@smuzzy.com.ua>
  * @author Oleksiy Voronin <ovoronin@gmail.com>
- * @author serg_stetsuk@ukr.net
- * @author okunia@gmail.com
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
- * @author Uko uko@uar.net
- * @author Ulrikhe Lukoie  <lukoie@gmail>.com
- * @author Kate Arzamastseva pshns@ukr.net
  * @author Maksim <nikropol@yandex.ru>
+ * @author Nina Zolotova <nina-z@i.ua>
+ * @author Roman <vsmemorial@gmail.com>
  */
 $lang['menu']                  = 'Налаштування Вікі';
 $lang['error']                 = 'Параметри не збережено через помилкові значення. Будь ласка, перегляньте ваші зміни та спробуйте ще раз
diff --git a/lib/plugins/config/lang/zh/lang.php b/lib/plugins/config/lang/zh/lang.php
index 4a4eba44b05807df26555ec1b8f63e0112c0f609..6da00eeb175dd761d67033aa4a3c612678867550 100644
--- a/lib/plugins/config/lang/zh/lang.php
+++ b/lib/plugins/config/lang/zh/lang.php
@@ -3,17 +3,14 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author lempel <riverlempel@hotmail.com>
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
- * @author George Sheraton guxd@163.com
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author Garfield <garfield_550@outlook.com>
  * @author JellyChen <451453325@qq.com>
@@ -131,6 +128,7 @@ $lang['subscribe_time']        = '订阅列表和摘要发送的时间间隔(
 $lang['notify']                = '发送更改通知给这个邮件地址';
 $lang['registernotify']        = '发送新注册用户的信息给这个邮件地址';
 $lang['mailfrom']              = '自动发送邮件时使用的邮件地址';
+$lang['mailreturnpath']        = '非投递通知的收件人邮箱地址';
 $lang['mailprefix']            = '自动发送邮件时使用的邮件地址前缀';
 $lang['htmlmail']              = '发送更加美观,但体积更大的 HTML 多部分邮件。禁用则发送纯文本邮件。';
 $lang['sitemap']               = '生成 Google sitemap(天)';
@@ -140,6 +138,9 @@ $lang['rss_content']           = 'XML feed 项目中显示什么呢?';
 $lang['rss_update']            = 'XML feed 升级间隔(秒)';
 $lang['rss_show_summary']      = 'XML feed 在标题中显示摘要';
 $lang['rss_media']             = '在 XML 源中应该列出何种类型的更改?';
+$lang['rss_media_o_both']      = '两者均可';
+$lang['rss_media_o_pages']     = '页面';
+$lang['rss_media_o_media']     = '媒体';
 $lang['updatecheck']           = '自动检查更新并接收安全警告吗?开启该功能后 DokuWiki 将自动访问 splitbrain.org。';
 $lang['userewrite']            = '使用更整洁的 URL';
 $lang['useslash']              = '在 URL 中使用斜杠作为命名空间的分隔符';
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 965c2a38c6a2bcc58aa99d34babe705882421cd6..3196d7527189b8365eb5a50c2958cfcb92536e5c 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -982,6 +982,22 @@ if (!class_exists('setting_numericopt')) {
     class setting_numericopt extends setting_numeric {
         // just allow an empty config
         var $_pattern = '/^(|[-]?[0-9]+(?:[-+*][0-9]+)*)$/';
+
+
+        /**
+         * Empty string is valid for numericopt
+         *
+         * @param mixed $input
+         *
+         * @return bool
+         */
+        function update($input) {
+            if ($input === '') {
+                return true;
+            }
+
+            return parent::update($input);
+        }
     }
 }
 
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 495c44eb4b5d57ffb60c7c8218fc41ea7b690aba..acdf93ba775dec2052276c9b7f8ad3b525296ab2 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -189,6 +189,7 @@ $meta['subscribe_time'] = array('numeric');
 $meta['notify']         = array('email', '_multiple' => true);
 $meta['registernotify'] = array('email', '_multiple' => true);
 $meta['mailfrom']       = array('email', '_placeholders' => true);
+$meta['mailreturnpath']       = array('email', '_placeholders' => true);
 $meta['mailprefix']     = array('string');
 $meta['htmlmail']       = array('onoff');
 
@@ -218,6 +219,8 @@ $meta['broken_iua']  = array('onoff');
 $meta['xsendfile']   = array('multichoice','_choices' => array(0,1,2,3),'_caution' => 'warning');
 $meta['renderer_xhtml'] = array('renderer','_format' => 'xhtml','_choices' => array('xhtml'),'_caution' => 'warning');
 $meta['readdircache'] = array('numeric');
+$meta['search_nslimit'] = array('numeric', '_min' => 0);
+$meta['search_fragment'] = array('multichoice','_choices' => array('exact', 'starts_with', 'ends_with', 'contains'),);
 
 $meta['_network']    = array('fieldset');
 $meta['dnslookups']  = array('onoff');
diff --git a/lib/plugins/extension/helper/extension.php b/lib/plugins/extension/helper/extension.php
index 1f2c1af8383fb6f68abf01b4d7f1238acd24187c..e77528b97f4d0a974d97a982868f8d96a18d9a31 100644
--- a/lib/plugins/extension/helper/extension.php
+++ b/lib/plugins/extension/helper/extension.php
@@ -51,6 +51,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
      * @return bool If some (local or remote) data was found
      */
     public function setExtension($id) {
+        $id = cleanID($id);
         $this->id   = $id;
         $this->base = $id;
 
@@ -339,7 +340,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
      * @return array The names of the conflicting extensions
      */
     public function getConflicts() {
-        if (!empty($this->remoteInfo['conflicts'])) return $this->remoteInfo['dependencies'];
+        if (!empty($this->remoteInfo['conflicts'])) return $this->remoteInfo['conflicts'];
         return array();
     }
 
diff --git a/lib/plugins/extension/helper/list.php b/lib/plugins/extension/helper/list.php
index 6ca72f7cef90438a2720589fa417a09c4e1df790..656b4ea09154871f8e271d8c7a78d5eb24f03eeb 100644
--- a/lib/plugins/extension/helper/list.php
+++ b/lib/plugins/extension/helper/list.php
@@ -340,9 +340,9 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
         $link = parse_url($url);
 
         $base = $link['host'];
-        if($link['port']) $base .= $base.':'.$link['port'];
+        if(!empty($link['port'])) $base .= $base.':'.$link['port'];
         $long = $link['path'];
-        if($link['query']) $long .= $link['query'];
+        if(!empty($link['query'])) $long .= $link['query'];
 
         $name = shorten($base, $long, 55);
 
diff --git a/lib/plugins/extension/lang/de-informal/lang.php b/lib/plugins/extension/lang/de-informal/lang.php
index f0cee18858e8ccc395e397f50ece73d4532fc9d2..4daec7f6574dc62a0299b0e55518589443e89807 100644
--- a/lib/plugins/extension/lang/de-informal/lang.php
+++ b/lib/plugins/extension/lang/de-informal/lang.php
@@ -30,3 +30,66 @@ $lang['js']['display_enabled'] = 'aktiviert';
 $lang['js']['display_disabled'] = 'deaktiviert';
 $lang['js']['display_updatable'] = 'Update verfügbar';
 $lang['search_for']            = 'Suche Erweiterung:';
+$lang['search']                = 'Suche';
+$lang['extensionby']           = '<strong>%s</strong> von %s';
+$lang['screenshot']            = 'Screenshot von %s';
+$lang['popularity']            = 'Popularität: %s%%';
+$lang['homepage_link']         = 'Doku';
+$lang['bugs_features']         = 'Bugs';
+$lang['tags']                  = 'Schlagworte:';
+$lang['author_hint']           = 'Suche Erweiterungen dieses Autors';
+$lang['installed']             = 'Installiert:';
+$lang['downloadurl']           = 'URL zum Herunterladen:';
+$lang['repository']            = 'Quelle:';
+$lang['unknown']               = '<em>unbekannt</em>';
+$lang['installed_version']     = 'Installierte Version:';
+$lang['install_date']          = 'Dein letztes Update:';
+$lang['available_version']     = 'Verfügbare Version:';
+$lang['compatible']            = 'Kompatibel mit:';
+$lang['depends']               = 'Abhängig von:';
+$lang['similar']               = 'Ähnlich wie:';
+$lang['conflicts']             = 'Nicht kompatibel mit:';
+$lang['donate']                = 'Nützlich?';
+$lang['donate_action']         = 'Spendiere dem Autor einen Kaffee!';
+$lang['repo_retry']            = 'Wiederholen';
+$lang['provides']              = 'Enthält:';
+$lang['status']                = 'Status';
+$lang['status_installed']      = 'installiert';
+$lang['status_not_installed']  = 'nicht installiert';
+$lang['status_protected']      = 'geschützt';
+$lang['status_enabled']        = 'aktiviert';
+$lang['status_disabled']       = 'deaktiviert';
+$lang['status_unmodifiable']   = 'unveränderlich';
+$lang['status_plugin']         = 'Plugin';
+$lang['status_template']       = 'Template';
+$lang['status_bundled']        = 'gebündelt';
+$lang['msg_enabled']           = 'Plugin %s ist aktiviert';
+$lang['msg_disabled']          = 'Erweiterung %s ist deaktiviert';
+$lang['msg_delete_success']    = 'Erweiterung %s wurde entfernt';
+$lang['msg_delete_failed']     = 'Deinstallation der Erweiterung %s fehlgeschlagen';
+$lang['msg_template_install_success'] = 'Das Template %s wurde erfolgreich installiert';
+$lang['msg_template_update_success'] = 'Das Update des Templates %s war erfolgreich ';
+$lang['msg_plugin_install_success'] = 'Das Plugin %s wurde erfolgreich installiert';
+$lang['msg_plugin_update_success'] = 'Das Update des Plugins %s war erfolgreich';
+$lang['msg_upload_failed']     = 'Fehler beim Hochladen der Datei';
+$lang['missing_dependency']    = '<strong>Fehlende oder deaktivierte Abhängigkeit:<strong>%s';
+$lang['security_issue']        = '<strong>Sicherheitsproblem:</strong> %s';
+$lang['security_warning']      = '<strong>Sicherheitswarnung:</strong> %s';
+$lang['update_available']      = '<strong>Update:</strong> Version %s steht zum Download bereit.';
+$lang['wrong_folder']          = '<strong>Plugin wurde nicht korrekt installiert:</strong> Benenne das Plugin-Verzeichnis "%s" in "%s" um.';
+$lang['url_change']            = '<strong>URL geändert:</strong> Die Download URL wurde seit dem letzten Download geändert. Internetadresse vor Aktualisierung der Erweiterung auf Gültigkeit prüfen.<br />Neu: %s<br />Alt: %s';
+$lang['error_badurl']          = 'URLs sollten mit http oder https beginnen';
+$lang['error_dircreate']       = 'Temporärer Ordner konnte nicht erstellt werden um Download zu abzuspeichern';
+$lang['error_download']        = 'Download der Datei: %s nicht möglich.';
+$lang['error_decompress']      = 'Die heruntergeladene Datei konnte nicht entpackt werden. Dies kann die Folge eines fehlerhaften Downloads sein. In diesem Fall solltest du versuchen den Vorgang zu wiederholen. Es kann auch die Folge eines unbekannten Kompressionsformates sein, in diesem ​​Fall musst du die Datei selber herunterladen und manuell installieren.';
+$lang['error_findfolder']      = 'Das Erweiterungs-Verzeichnis konnte nicht identifiziert werden, lade die Datei herunter und installiere sie manuell.';
+$lang['error_copy']            = 'Beim Versuch Dateien in den Ordner <em>%s</em>: zu installieren trat ein Kopierfehler auf. Die Dateizugriffsberechtigungen könnten falsch sein. Dies kann an einem unvollständig installierten Plugin liegen und beeinträchtigt somit die Stabilität deiner Wiki-Installation.';
+$lang['noperms']               = 'Das Erweiterungs-Verzeichnis ist schreibgeschützt';
+$lang['notplperms']            = 'Das Template-Verzeichnis ist schreibgeschützt';
+$lang['nopluginperms']         = 'Das Plugin-Verzeichnis ist schreibgeschützt';
+$lang['git']                   = 'Diese Erweiterung wurde über git installiert und sollte daher nicht hier aktualisiert werden.';
+$lang['auth']                  = 'Dieses Auth Plugin ist in der Konfiguration nicht aktiviert, Du solltest es deaktivieren.';
+$lang['install_url']           = 'Von URL installieren:';
+$lang['install_upload']        = 'Erweiterung hochladen:';
+$lang['repo_error']            = 'Es konnte keine Verbindung zum Plugin-Verzeichnis hergestellt werden. Stelle sicher dass der Server Verbindung mit www.dokuwiki.org aufnehmen darf und überprüfe deine Proxy-Einstellungen.';
+$lang['nossl']                 = 'Deine PHP-Installation scheint SSL nicht zu unterstützen. Das Herunterladen vieler DokuWiki Erweiterungen wird scheitern.';
diff --git a/lib/plugins/extension/lang/de/intro_search.txt b/lib/plugins/extension/lang/de/intro_search.txt
index 7df8de1851ad0f29ccc5db3a4c5e95c1740f6b36..366925b9204d1cfb94d5404159d12ea04af4ba39 100644
--- a/lib/plugins/extension/lang/de/intro_search.txt
+++ b/lib/plugins/extension/lang/de/intro_search.txt
@@ -1 +1 @@
-Dieser Tab gibt Ihnen Zugriff auf alle vorhandenen Plugins und Templates für DokuWiki. Bitte bedenken sie das jede installierte Erweiterung ein Sicherheitsrisiko darstellen kann. Sie sollten vor einer Installation die [[doku>security#plugin_security|Plugin Security]] Informationen lesen.
\ No newline at end of file
+Dieser Tab gibt Ihnen Zugriff auf alle vorhandenen Plugins und Templates für DokuWiki. Bitte bedenken Sie, dass jede installierte Erweiterung ein Sicherheitsrisiko darstellen kann. Sie sollten vor einer Installation die [[doku>security#plugin_security|Plugin Security]] Informationen lesen.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/eo/lang.php b/lib/plugins/extension/lang/eo/lang.php
index e0488cb46446ea43d4c9a8e8f8cdcac6ff036d3b..bcac85d7568925e3cf1e3c24c6a28020616738f2 100644
--- a/lib/plugins/extension/lang/eo/lang.php
+++ b/lib/plugins/extension/lang/eo/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
  * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['menu']                  = 'Aldonaĵa administrado';
@@ -25,6 +26,7 @@ $lang['btn_disable']           = 'Malebligi';
 $lang['btn_install']           = 'Instali';
 $lang['btn_reinstall']         = 'Re-instali';
 $lang['js']['reallydel']       = 'Ĉu vere malinstali la aldonaĵon?';
+$lang['js']['display_updatable'] = 'ĝisdatigebla';
 $lang['search_for']            = 'Serĉi la aldonaĵon:';
 $lang['search']                = 'Serĉi';
 $lang['extensionby']           = '<strong>%s</strong> fare de %s';
diff --git a/lib/plugins/extension/lang/he/lang.php b/lib/plugins/extension/lang/he/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..ecdc19c5decd3c50ea801516673f77c31f59df9d
--- /dev/null
+++ b/lib/plugins/extension/lang/he/lang.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Guy Yakobovitch <guy.yakobovitch@gmail.com>
+ */
+$lang['menu']                  = 'מנהל הרחבות';
+$lang['tab_plugins']           = 'תוספים מותקנים';
+$lang['tab_templates']         = 'תבניות מותקנות';
+$lang['tab_install']           = 'התקנה ידנית';
+$lang['notinstalled']          = 'הרחבה זו לא מותקנת';
+$lang['status_not_installed']  = 'לא מותקן';
+$lang['status_protected']      = 'מוגן';
+$lang['status_enabled']        = 'מופעל';
+$lang['status_disabled']       = 'מושבת';
+$lang['status_unmodifiable']   = 'לא ניתן לשינוי';
+$lang['status_plugin']         = 'תוסף';
+$lang['status_template']       = 'תבנית';
+$lang['msg_enabled']           = 'תוסף %s מופעל';
+$lang['msg_disabled']          = 'תוסף %s מושבת';
+$lang['msg_delete_success']    = 'הרחבה %s הוסרה';
+$lang['msg_delete_failed']     = 'הסרת ההרחבה %s נכשלה';
+$lang['msg_template_install_success'] = 'תבנית %s הותקנה בהצלחה';
+$lang['msg_template_update_success'] = 'תבנית %s עודכנה בהצלחה';
+$lang['error_download']        = 'לא ניתן להוריד את הקובץ: %s';
diff --git a/lib/plugins/extension/lang/pl/intro_install.txt b/lib/plugins/extension/lang/pl/intro_install.txt
new file mode 100644
index 0000000000000000000000000000000000000000..338d9396f01425284b3f101425808ea72d6c49b2
--- /dev/null
+++ b/lib/plugins/extension/lang/pl/intro_install.txt
@@ -0,0 +1 @@
+Tutaj możesz ręcznie zainstalować wtyczki i szablony, przesyłając je lub podając bezpośredni adres URL do pobrania.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/pl/intro_plugins.txt b/lib/plugins/extension/lang/pl/intro_plugins.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d228485071b38b782b113d19922ca1dbf7d5ad3a
--- /dev/null
+++ b/lib/plugins/extension/lang/pl/intro_plugins.txt
@@ -0,0 +1 @@
+Są to wtyczki aktualnie zainstalowane w twoim DokuWiki. Możesz je tutaj włączyć lub wyłączyć, a nawet całkowicie odinstalować. Znajdziesz tu również informację o nowych wersjach. Przed aktualizacją koniecznie przeczytaj dokumentację wtyczki.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/pl/intro_search.txt b/lib/plugins/extension/lang/pl/intro_search.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d1773fa023deff500060d4a353c9439daca04361
--- /dev/null
+++ b/lib/plugins/extension/lang/pl/intro_search.txt
@@ -0,0 +1 @@
+W tej zakładka znajdziesz wszystkie wtyczki i szablony przygotowane dla DokuWiki przez osoby trzecie. Należy pamiętać, że instalacja kodu zewnętrznego może stwarzać ** zagrożenie bezpieczeństwa **. Koniecznie przeczytaj o [[doku>security#plugin_security|bezpieczeństwie wtyczek]].
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/pl/intro_templates.txt b/lib/plugins/extension/lang/pl/intro_templates.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ef90cbff872d3115b29ffbf1253f0fe532f92926
--- /dev/null
+++ b/lib/plugins/extension/lang/pl/intro_templates.txt
@@ -0,0 +1 @@
+Są to szablony aktualnie zainstalowane w twoim DokuWiki. [[?do=admin&page=config|Menadżer konfiguracji]] pozwala wybrać używany szablon.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/pl/lang.php b/lib/plugins/extension/lang/pl/lang.php
index ab9a818b6d5bc007651d3288eb1b61e1e12185b1..7191dcb93933eb685a7fcf8f4993334a83f1b599 100644
--- a/lib/plugins/extension/lang/pl/lang.php
+++ b/lib/plugins/extension/lang/pl/lang.php
@@ -3,37 +3,95 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Mati <mackosa@wp.pl>
  */
 $lang['menu']                  = 'Menedżer rozszerzeń';
 $lang['tab_plugins']           = 'Zainstalowane dodatki';
+$lang['tab_templates']         = 'Zainstalowane Szablony';
 $lang['tab_search']            = 'Znajdź i zainstaluj';
+$lang['tab_install']           = 'Instalacja ręczna';
+$lang['notimplemented']        = 'Ta funkcja nie została jeszcze zaimplementowana';
 $lang['notinstalled']          = 'Te rozszerzenie nie zostało zainstalowane';
 $lang['alreadyenabled']        = 'Te rozszerzenie jest już uruchomione';
+$lang['alreadydisabled']       = 'Rozszerzenie zostało wyłączone';
+$lang['pluginlistsaveerror']   = 'Wystąpił błąd podczas zapisywania listy wtyczek';
 $lang['unknownauthor']         = 'Nieznany autor';
 $lang['unknownversion']        = 'Nieznana wersja';
 $lang['btn_info']              = 'Pokaż więcej informacji';
+$lang['btn_update']            = 'Aktualizuj';
+$lang['btn_uninstall']         = 'Odinstaluj';
 $lang['btn_enable']            = 'Uruchom';
 $lang['btn_disable']           = 'Wyłącz';
+$lang['btn_install']           = 'Instaluj';
 $lang['btn_reinstall']         = 'Ponowna instalacja';
 $lang['js']['reallydel']       = 'Naprawdę odinstalować te rozszerzenie?';
+$lang['js']['display_viewoptions'] = 'Zobacz Opcje';
+$lang['js']['display_enabled'] = 'włącz';
+$lang['js']['display_disabled'] = 'wyłącz';
+$lang['js']['display_updatable'] = 'do aktualizacji';
+$lang['search_for']            = 'Szukaj rozszerzenia:';
 $lang['search']                = 'Szukaj';
+$lang['extensionby']           = '<strong>%s</strong> przez %s';
+$lang['screenshot']            = 'Zrzut ekranu z %s';
+$lang['popularity']            = 'Popularność: %s%%';
+$lang['homepage_link']         = 'Dokumenty';
 $lang['bugs_features']         = 'Błędy';
 $lang['tags']                  = 'Tagi:';
+$lang['author_hint']           = 'Szukaj rozszerzenia po autorze';
 $lang['installed']             = 'Zainstalowano:';
+$lang['downloadurl']           = 'Pobierz URL';
 $lang['repository']            = 'Repozytorium';
+$lang['unknown']               = '<em>nie znany</em>';
 $lang['installed_version']     = 'Zainstalowana wersja:';
 $lang['install_date']          = 'Twoja ostatnia aktualizacja:';
 $lang['available_version']     = 'Dostępna wersja:';
+$lang['compatible']            = 'Zgodny z:';
 $lang['depends']               = 'Zależy od:';
+$lang['similar']               = 'Podobny do:';
 $lang['conflicts']             = 'Konflikt z:';
 $lang['donate']                = 'Lubisz to?';
 $lang['donate_action']         = 'Kup autorowi kawÄ™!';
 $lang['repo_retry']            = 'Ponów';
+$lang['provides']              = 'Dostawcy:';
 $lang['status']                = 'Status:';
 $lang['status_installed']      = 'zainstalowano';
 $lang['status_not_installed']  = 'nie zainstalowano';
+$lang['status_protected']      = 'chroniony';
 $lang['status_enabled']        = 'uruchomione';
 $lang['status_disabled']       = 'wyłączone';
+$lang['status_unmodifiable']   = 'niemodyfikowalny';
 $lang['status_plugin']         = 'dodatek';
+$lang['status_template']       = 'szablon';
+$lang['status_bundled']        = 'paczka';
+$lang['msg_enabled']           = 'Dodatek %s włączony';
+$lang['msg_disabled']          = 'Dodatek %s wyłączony';
 $lang['msg_delete_success']    = 'Rozszerzenie %s odinstalowane';
+$lang['msg_delete_failed']     = 'Odinstalowywanie rozszerzenia %s nie powiodło się';
+$lang['msg_template_install_success'] = 'Szablon %s został zainstalowany';
+$lang['msg_template_update_success'] = 'Szablon %s został zaktualizowany';
+$lang['msg_plugin_install_success'] = 'Dodatek %s został zainstalowany';
+$lang['msg_plugin_update_success'] = 'Dodatek %s został zaktualizowany';
+$lang['msg_upload_failed']     = 'Ładowanie pliku nie powiodło się';
+$lang['missing_dependency']    = '<strong>Brakująca lub wyłączona zależność:</strong> %s';
+$lang['security_issue']        = '<strong>Problemy bezpieczeństwa:</strong> %s';
+$lang['security_warning']      = '<strong>Alert Bezpieczeństwa:</strong>%s';
+$lang['update_available']      = '<strong>Uaktualnij</strong> Nowa wersja %s jest dostępna.';
+$lang['wrong_folder']          = '<strong>Nieprawidłowo zainstalowana wtyczka:</strong> Zmień nazwę katalogu wtyczek z "%s" na "%s".';
+$lang['url_change']            = '<strong>URL został zmieniony:</strong>URL zmienił się od czasu ostatniego pobrania. Przed aktualizacją rozszerzenia, sprawdź czy nowy adres URL jest prawidłowy.<br />Nowy: %s<br />Stary: %s';
+$lang['error_badurl']          = 'URL powinien zaczynać się od http lub https';
+$lang['error_dircreate']       = 'Nie można utworzyć tymczasowego folderu pobierania ';
+$lang['error_download']        = 'Nie można pobrać pliku %s';
+$lang['error_decompress']      = 'Nie można rozpakować pobranego pliku. Może to być spowodowane złym pobieraniem, w takim przypadku powinieneś spróbować ponownie; lub format kompresji może być nieznany, w takim przypadku należy ręcznie pobrać i zainstalować.';
+$lang['error_findfolder']      = 'Nie można zidentyfikować katalogu z rozszerzeniami, musisz pobrać i zainstalować ręcznie';
+$lang['error_copy']            = 'Wystąpił błąd kopiowania pliku podczas próby zainstalowania plików dla katalogu <em>%s</em>: dysk może być pełny lub uprawnienia dostępu do pliku mogą być niepoprawne. Mogło to spowodować częściowo zainstalowaną wtyczkę i pozostawić twoją instalację wiki niestabilną';
+$lang['noperms']               = 'Katalog z rozszerzeniami nie posiada uprawnień zapisu';
+$lang['notplperms']            = 'Katalog z szablonami nie posiada uprawnień zapisu';
+$lang['nopluginperms']         = 'Katalog z wtyczkami nie posiada uprawnień zapisu';
+$lang['git']                   = 'To rozszerzenie zostało zainstalowane przez git, możesz nie chcieć go aktualizować tutaj.';
+$lang['auth']                  = 'Ta wtyczka autoryzacji nie jest włączona w konfiguracji, rozważ jej wyłączenie.';
+$lang['install_url']           = 'Instaluj z URL:';
+$lang['install_upload']        = 'Załaduj Rozszerzenie ';
+$lang['repo_error']            = 'Nie można skontaktować się z repozytorium wtyczek. Upewnij się, że twój serwer może skontaktować się z www.dokuwiki.org i sprawdzić ustawienia serwera proxy.';
+$lang['nossl']                 = 'Twój PHP wydaje się nie obsługiwać protokołu SSL. Pobieranie nie zadziała dla wielu rozszerzeń DokuWiki.';
diff --git a/lib/plugins/extension/lang/pt/lang.php b/lib/plugins/extension/lang/pt/lang.php
index 9713f91f3941a77df908ff8ceeb18c69fc6bdc8f..e31907c5c760ff251a4d8b80ea29df8518654e73 100644
--- a/lib/plugins/extension/lang/pt/lang.php
+++ b/lib/plugins/extension/lang/pt/lang.php
@@ -2,11 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Guido Salatino <guidorafael23@gmail.com>
  * @author Romulo Pereira <romuloccomp@gmail.com>
  * @author Paulo Carmino <contato@paulocarmino.com>
  * @author Alfredo Silva <alfredo.silva@sky.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['menu']                  = 'Gerenciador de Extensões';
 $lang['tab_plugins']           = 'Plugins Instalados';
diff --git a/lib/plugins/extension/lang/ru/intro_plugins.txt b/lib/plugins/extension/lang/ru/intro_plugins.txt
index 547ca7184f5c70f15496d2660acbb247d08987cb..96d1742baaa532e7d10c4e9101bf2c0f46cb0856 100644
--- a/lib/plugins/extension/lang/ru/intro_plugins.txt
+++ b/lib/plugins/extension/lang/ru/intro_plugins.txt
@@ -1 +1 @@
-Плагины, установленные в вашей «Докувики». Здесь вы можете их включить или выключить, или даже полностью удалить. Также здесь показываются обновления плагинов; обязательно прочтите документацию плагина перед обновлением.
\ No newline at end of file
+Плагины, установленные в вашей «Докувики». Здесь вы можете их включить/отключить или даже полностью удалить. Также здесь показываются обновления плагинов; обязательно прочтите документацию плагина перед обновлением.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/sk/lang.php b/lib/plugins/extension/lang/sk/lang.php
index 286c932529a636d0c39d7863e7ce0473654a5d1b..775e89a6b1c5848b8b73e724f5a083c79ca24ef3 100644
--- a/lib/plugins/extension/lang/sk/lang.php
+++ b/lib/plugins/extension/lang/sk/lang.php
@@ -47,6 +47,9 @@ $lang['msg_template_update_success'] = 'Šablóna %s úspešne aktualizovaná';
 $lang['msg_plugin_install_success'] = 'Plugin %s úspešne nainštalovaný';
 $lang['msg_plugin_update_success'] = 'Plugin %s úspešne aktualizovaný';
 $lang['msg_upload_failed']     = 'Nahrávanie súboru zlyhalo';
+$lang['missing_dependency']    = '<strong>Chýbajúca alebo nepovolená závislosť:</strong> %s';
+$lang['security_issue']        = '<strong>Bezpečnostný problém:</strong> %s';
+$lang['security_warning']      = '<strong>Bezpečnostné upozornenie:</strong> %s';
 $lang['update_available']      = '<strong>Aktualizácia:</strong> Nová verzia %s.';
 $lang['wrong_folder']          = '<strong>Plugin nesprávne nainštalovaný:</strong> Premenujte adresár s pluginom "%s" na "%s".';
 $lang['error_badurl']          = 'URL by mali mať na začiatku http alebo https';
diff --git a/lib/plugins/extension/lang/sr/intro_install.txt b/lib/plugins/extension/lang/sr/intro_install.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b05dc2c302dcde0844e30f250a7086e804b75f1c
--- /dev/null
+++ b/lib/plugins/extension/lang/sr/intro_install.txt
@@ -0,0 +1 @@
+Овде можете ручно инсталирати прикључке и шаблоне тако што ћете их отпремити или унети адресу за директно преузимање.
\ No newline at end of file
diff --git a/lib/plugins/extension/lang/sr/lang.php b/lib/plugins/extension/lang/sr/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..a4fc8843ce67d12a1740c13051e1075215d4eecc
--- /dev/null
+++ b/lib/plugins/extension/lang/sr/lang.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Марко М. Костић <marko.m.kostic@gmail.com>
+ */
+$lang['menu']                  = 'Управник проширења';
+$lang['tab_plugins']           = 'Инсталирани прикључци';
+$lang['tab_templates']         = 'Инсталирани шаблони';
+$lang['tab_search']            = 'Тражи и инсталирај';
+$lang['tab_install']           = 'Ручно инсталирање';
+$lang['notimplemented']        = 'Ова могућност још није израђена';
+$lang['notinstalled']          = 'Ово проширење још није инсталирано';
+$lang['alreadyenabled']        = 'Ово проширење је већ омогућено';
+$lang['alreadydisabled']       = 'Ово проширење је већ онемогућено';
+$lang['pluginlistsaveerror']   = 'Догодила се грешка приликом чувања списка прикључака';
+$lang['unknownauthor']         = 'Непознат творац';
+$lang['unknownversion']        = 'Непознато издање';
+$lang['btn_info']              = 'Прикажи још података';
+$lang['btn_update']            = 'Ажурирај';
+$lang['btn_uninstall']         = 'Деинсталирај';
+$lang['btn_enable']            = 'Омогући';
+$lang['btn_disable']           = 'Онемогући';
+$lang['btn_install']           = 'Инсталирај';
+$lang['btn_reinstall']         = 'Поново инсталирај';
+$lang['js']['reallydel']       = 'Заиста деинсталирати ово проширење?';
+$lang['js']['display_viewoptions'] = 'Опције приказа:';
+$lang['js']['display_enabled'] = 'омогућено';
+$lang['js']['display_disabled'] = 'онемогућено';
+$lang['js']['display_updatable'] = 'могуће ажурирати';
+$lang['search_for']            = 'Претражи проширење:';
+$lang['search']                = 'Претрага';
+$lang['screenshot']            = 'Снимак екрана од %s';
+$lang['popularity']            = 'Популарност: %s%%';
+$lang['homepage_link']         = 'Документа';
+$lang['bugs_features']         = 'Грешке';
+$lang['tags']                  = 'Ознаке:';
+$lang['author_hint']           = 'Претражи проширења овог творца';
+$lang['installed']             = 'Инсталирано:';
+$lang['downloadurl']           = 'Адреса за преузимање:';
+$lang['repository']            = 'Ризница:';
+$lang['unknown']               = '<em>непознато</em>';
+$lang['installed_version']     = 'Инсталирано издање:';
+$lang['install_date']          = 'Ваше последње ажурирање:';
+$lang['available_version']     = 'Доступно издање:';
+$lang['compatible']            = 'Подударно са:';
+$lang['depends']               = 'Зависи од:';
+$lang['similar']               = 'Слично као:';
+$lang['conflicts']             = 'У сукобу са:';
+$lang['donate']                = 'Свиђа вам се?';
+$lang['donate_action']         = 'Купите творцу шољицу кафе!';
+$lang['repo_retry']            = 'Поново покушај';
+$lang['provides']              = 'Пружа:';
+$lang['status']                = 'Стање:';
+$lang['status_installed']      = 'инсталирано';
+$lang['status_not_installed']  = 'није инсталирано';
+$lang['status_protected']      = 'заштићено';
+$lang['status_enabled']        = 'омогућено';
+$lang['status_disabled']       = 'онемогућено';
+$lang['status_unmodifiable']   = 'неизмењиво';
+$lang['status_plugin']         = 'прикључак';
+$lang['status_template']       = 'шаблон';
+$lang['status_bundled']        = 'упаковано';
+$lang['msg_enabled']           = 'Прикључак %s је омогућен';
+$lang['msg_disabled']          = 'Прикључак %s је онемогућен';
diff --git a/lib/plugins/extension/lang/sv/lang.php b/lib/plugins/extension/lang/sv/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..92d21f25a4f7ded0acaaca81affb20dfa0696364
--- /dev/null
+++ b/lib/plugins/extension/lang/sv/lang.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['tab_templates']         = 'Installerade templat';
+$lang['tab_search']            = 'Sök och installera';
+$lang['tab_install']           = 'Manuell installation';
+$lang['notimplemented']        = 'Denna funktion har ännu inte implementerats';
+$lang['unknownauthor']         = 'Okänd skapare';
+$lang['unknownversion']        = 'Okänd version';
+$lang['btn_info']              = 'Visa mer info';
+$lang['btn_update']            = 'Uppdatera';
+$lang['btn_uninstall']         = 'Avinstallera';
+$lang['btn_enable']            = 'Aktivera';
+$lang['btn_disable']           = 'Avaktivera';
+$lang['btn_install']           = 'Installera';
+$lang['btn_reinstall']         = 'Ominstallera';
+$lang['js']['reallydel']       = 'Vill du verkligen avinstallera detta tillägg?';
+$lang['js']['display_viewoptions'] = 'Visa alternativ:';
+$lang['js']['display_enabled'] = 'aktivera';
+$lang['js']['display_disabled'] = 'avaktivera';
+$lang['js']['display_updatable'] = 'möjlig att uppdatera';
+$lang['search']                = 'Sök';
+$lang['screenshot']            = 'Skärmdump av %s';
+$lang['popularity']            = 'Populatitet: %s%%';
+$lang['homepage_link']         = 'Dokumentation';
+$lang['bugs_features']         = 'Buggar';
+$lang['tags']                  = 'Taggar:';
+$lang['installed']             = 'Installerat:';
+$lang['downloadurl']           = 'Nedladdningslänk:';
+$lang['unknown']               = '<em>okänd</em>';
+$lang['installed_version']     = 'Installerad version:';
+$lang['install_date']          = 'Din senaste uppdatering:';
+$lang['available_version']     = 'Tillgänglig version:';
+$lang['compatible']            = 'Kompatibel med:';
+$lang['depends']               = 'Beroende av:';
+$lang['similar']               = 'Liknande som:';
+$lang['conflicts']             = 'Konflikt med:';
+$lang['donate']                = 'Som denna?';
+$lang['donate_action']         = 'Köp en kaffe till skaparen';
+$lang['repo_retry']            = 'Försök igen';
+$lang['status']                = 'Status:';
+$lang['status_installed']      = 'installerad';
+$lang['status_not_installed']  = 'inte installerad';
+$lang['status_protected']      = 'skyddad';
+$lang['status_enabled']        = 'aktiverad';
+$lang['status_disabled']       = 'avaktiverad';
+$lang['status_unmodifiable']   = 'ej modifierbar';
+$lang['msg_enabled']           = 'Tillägg %s aktiverat';
+$lang['msg_disabled']          = 'Tillägg %s avaktiverat';
+$lang['msg_template_install_success'] = 'Templat %s installerades framgångsrikt';
+$lang['msg_template_update_success'] = 'Templat %s uppdaterades framgångsrikt';
+$lang['msg_upload_failed']     = 'Uppladdning av filen misslyckades';
+$lang['security_warning']      = '<strong>Säkerhetsvarning:</strong> %s';
+$lang['update_available']      = '<strong>Uppdatering:</strong> Ny version av %s är tillgänglig.';
+$lang['url_change']            = '<strong>URL ändrad:</strong> Nedladdningslänken har ändrats sedan senaste nedladdning. Kontrollera om den nya sökvägen är giltig innan du uppdaterar tillägget.<br />Ny sökväg: %s<br />Gammal sökväg: %s';
+$lang['error_badurl']          = 'URL:er borde inledas med http eller https';
+$lang['error_dircreate']       = 'Kunde inte skapa temporär katalog för nedladdning';
+$lang['error_download']        = 'Kunde inte ladda ner filen: %s';
+$lang['notplperms']            = 'Templatkatalogen är inte skrivbar';
+$lang['nopluginperms']         = 'Tilläggskatalogen är inte skrivbar';
+$lang['install_url']           = 'Installera från URL:';
+$lang['install_upload']        = 'Ladda upp tillägg:';
+$lang['nossl']                 = 'Din PHP tycks sakna SSL-stöd. Nedladdning kommer inte att fungera för många DokuWiki-tillägg.';
diff --git a/lib/plugins/extension/lang/zh-tw/lang.php b/lib/plugins/extension/lang/zh-tw/lang.php
index c5b1e6dc58df836d0ddaa74fb4147d2c11a3d64d..8087778ba17ede1e6e1e60ec73bd6ae876dc991a 100644
--- a/lib/plugins/extension/lang/zh-tw/lang.php
+++ b/lib/plugins/extension/lang/zh-tw/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Stan <talktostan@gmail.com>
  * @author June-Hao Hou <junehao@gmail.com>
  * @author lioujheyu <lioujheyu@gmail.com>
@@ -61,7 +61,6 @@ $lang['status_template']       = '模板';
 $lang['status_bundled']        = '已綑綁內附';
 $lang['msg_enabled']           = '外掛 %s 已啟用';
 $lang['msg_disabled']          = '外掛 %s 已禁用';
-$lang['msg_delete_success']    = '附加元件已移除';
 $lang['msg_delete_failed']     = '解除安裝 %s 失敗';
 $lang['msg_template_install_success'] = '模板 %s 以成功安裝';
 $lang['msg_template_update_success'] = '模板 %s 以成功更新';
diff --git a/lib/plugins/extension/lang/zh/lang.php b/lib/plugins/extension/lang/zh/lang.php
index 0e27e89a3cfc195d855c586b60d2f10084d9c5f1..622a007b4e1e8b27d3def187a30ff14a94a32077 100644
--- a/lib/plugins/extension/lang/zh/lang.php
+++ b/lib/plugins/extension/lang/zh/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author lempel <riverlempel@hotmail.com>
  * @author Cupen <Cupenoruler@foxmail.com>
  * @author xiqingongzi <Xiqingongzi@Gmail.com>
  * @author qinghao <qingxianhao@gmail.com>
@@ -70,7 +71,7 @@ $lang['status_template']       = '模板';
 $lang['status_bundled']        = '内建';
 $lang['msg_enabled']           = '插件 %s 已启用';
 $lang['msg_disabled']          = '插件 %s 已禁用';
-$lang['msg_delete_success']    = '插件已经卸载';
+$lang['msg_delete_success']    = '%s 扩展没有安装';
 $lang['msg_delete_failed']     = '卸载扩展 %s 失败';
 $lang['msg_template_install_success'] = '模板 %s 安装成功';
 $lang['msg_template_update_success'] = '模板 %s 更新成功';
diff --git a/lib/plugins/popularity/lang/da/lang.php b/lib/plugins/popularity/lang/da/lang.php
index 6e9d7c9863bc91529a59bba2b01aec8c00139e0e..715d6ac93899360b3da2d10b6176b8e354222a25 100644
--- a/lib/plugins/popularity/lang/da/lang.php
+++ b/lib/plugins/popularity/lang/da/lang.php
@@ -8,8 +8,7 @@
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  */
 $lang['name']                  = 'Tilbagemelding om popularitet (vil måske tage en del tid at indlæse)';
diff --git a/lib/plugins/popularity/lang/eo/lang.php b/lib/plugins/popularity/lang/eo/lang.php
index 5e67e5bdb34221e762f3a1bbaaae463bf4b31d17..a0492c68c7a11a86cd5b078b79ab8a2ea9116b03 100644
--- a/lib/plugins/popularity/lang/eo/lang.php
+++ b/lib/plugins/popularity/lang/eo/lang.php
@@ -2,13 +2,10 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Felipo Kastro <fefcas@gmail.com>
- * @author Felipe Castro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik pedersen@shaw.ca>
- * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['name']                  = 'Populareca enketo (eble la ŝargo prokrastos iomete)';
 $lang['submit']                = 'Sendi datumaron';
diff --git a/lib/plugins/popularity/lang/eu/lang.php b/lib/plugins/popularity/lang/eu/lang.php
index b5b80357c6ddbdd1f46a2b216be6f76bcd0ddb4c..4f0b667dc893b54cbbf9fa1fe57b763bfd1894a8 100644
--- a/lib/plugins/popularity/lang/eu/lang.php
+++ b/lib/plugins/popularity/lang/eu/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
  */
diff --git a/lib/plugins/popularity/lang/fr/lang.php b/lib/plugins/popularity/lang/fr/lang.php
index 059bec74cbcff2316de97ccc43bc1756ce510a38..f1b9f626da4bf6fedac70e21081752077455a63d 100644
--- a/lib/plugins/popularity/lang/fr/lang.php
+++ b/lib/plugins/popularity/lang/fr/lang.php
@@ -11,10 +11,7 @@
  * @author Vincent Feltz <psycho@feltzv.fr>
  * @author Philippe Bajoit <philippe.bajoit@gmail.com>
  * @author Florian Gaub <floriang@floriang.net>
- * @author Samuel Dorsaz samuel.dorsaz@novelion.net
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author schplurtz@laposte.net
- * @author skimpax@gmail.com
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
diff --git a/lib/plugins/popularity/lang/he/lang.php b/lib/plugins/popularity/lang/he/lang.php
index 54341636bdced565913b2c22459ce6b49530b4c0..e9f75b735da30bed20d1fe59ba6c788bb479f0b5 100644
--- a/lib/plugins/popularity/lang/he/lang.php
+++ b/lib/plugins/popularity/lang/he/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Dotan Kamber <kamberd@yahoo.com>
  * @author Moshe Kaplan <mokplan@gmail.com>
  * @author Yaron Yogev <yaronyogev@gmail.com>
diff --git a/lib/plugins/popularity/lang/it/lang.php b/lib/plugins/popularity/lang/it/lang.php
index acd59a6d2d6c6ef96acc67eeff49838fb64853aa..c355254b1285d0662aab147c4f9e58d7602fc1fe 100644
--- a/lib/plugins/popularity/lang/it/lang.php
+++ b/lib/plugins/popularity/lang/it/lang.php
@@ -4,14 +4,10 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Diego Pierotto ita.translations@tiscali.it
- * @author ita.translations@tiscali.it
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
- * @author Osman Tekin osman.tekin93@hotmail.it
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
  */
 $lang['name']                  = 'Raccolta dati sul wiki (può impiegare del tempo per caricarsi)';
 $lang['submit']                = 'Invia dati';
diff --git a/lib/plugins/popularity/lang/ko/lang.php b/lib/plugins/popularity/lang/ko/lang.php
index fc8b373f60bd5ea543c301213cb1b8816285d372..fff8cac3dcc70e2443b0e410e6c4e985d4fec2c2 100644
--- a/lib/plugins/popularity/lang/ko/lang.php
+++ b/lib/plugins/popularity/lang/ko/lang.php
@@ -4,10 +4,10 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
  * @author Garam <rowain8@gmail.com>
  */
diff --git a/lib/plugins/popularity/lang/lv/lang.php b/lib/plugins/popularity/lang/lv/lang.php
index a8ef37f7a91c3bbb1860c404a429e1113eef2f75..2c9bc63e2cdaa38367d1b9b6e9eff7154e585d57 100644
--- a/lib/plugins/popularity/lang/lv/lang.php
+++ b/lib/plugins/popularity/lang/lv/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['name']                  = 'Popularitātes atsauksmes (ielāde var aizņemt kādu laiku)';
diff --git a/lib/plugins/popularity/lang/nl/lang.php b/lib/plugins/popularity/lang/nl/lang.php
index d7ec14da1f2ad4b5f8a60f56e920024aa0a7aa3c..b1b48566ba38c862a1c5512fbd8dc02c09c9b841 100644
--- a/lib/plugins/popularity/lang/nl/lang.php
+++ b/lib/plugins/popularity/lang/nl/lang.php
@@ -8,10 +8,8 @@
  * @author Dion Nicolaas <dion@nicolaas.net>
  * @author Danny Rotsaert <danny.rotsaert@edpnet.be>
  * @author Marijn Hofstra hofstra.m@gmail.com
- * @author Matthias Carchon webmaster@c-mattic.be
  * @author Marijn Hofstra <hofstra.m@gmail.com>
  * @author Timon Van Overveldt <timonvo@gmail.com>
- * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit <klapinklapin@gmail.com>
  * @author Remon <no@email.local>
diff --git a/lib/plugins/popularity/lang/pl/lang.php b/lib/plugins/popularity/lang/pl/lang.php
index 224c0eb7fa3256940c69598a135d116a23556cb6..2f198d2e52f759125bace490bc5fb344b7c0c392 100644
--- a/lib/plugins/popularity/lang/pl/lang.php
+++ b/lib/plugins/popularity/lang/pl/lang.php
@@ -7,7 +7,7 @@
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
diff --git a/lib/plugins/popularity/lang/pt-br/lang.php b/lib/plugins/popularity/lang/pt-br/lang.php
index 6b2f7a2811b4714cb58e16902806a8c8045191ae..58df300a306c92a257930f49276640f69d4a76f6 100644
--- a/lib/plugins/popularity/lang/pt-br/lang.php
+++ b/lib/plugins/popularity/lang/pt-br/lang.php
@@ -8,12 +8,9 @@
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Frederico Guimarães <frederico@teia.bio.br>
- * @author Jair Henrique <jair.henrique@gmail.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Sergio Motta sergio@cisne.com.br
+ * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
diff --git a/lib/plugins/popularity/lang/pt/lang.php b/lib/plugins/popularity/lang/pt/lang.php
index e30b9d62b2287bf03662e2861f1f32f101166592..a14d176d78e6d9a98ac25681b65056c99e2a8470 100644
--- a/lib/plugins/popularity/lang/pt/lang.php
+++ b/lib/plugins/popularity/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Fil <fil@meteopt.com>
  * @author André Neves <drakferion@gmail.com>
diff --git a/lib/plugins/popularity/lang/ru/lang.php b/lib/plugins/popularity/lang/ru/lang.php
index 9a862f194d8fd8529b1b522ce7b52d9408c164c1..2e84e061222bd11281242aa6222ea7cdb559b69f 100644
--- a/lib/plugins/popularity/lang/ru/lang.php
+++ b/lib/plugins/popularity/lang/ru/lang.php
@@ -3,10 +3,9 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
- * @author Змей Этерийский evil_snake@eternion.ru
+ * @author Змей Этерийский <evil_snake@eternion.ru>
  * @author Hikaru Nakajima <jisatsu@mail.ru>
  * @author Alexei Tereschenko <alexeitlex@yahoo.com>
- * @author Irina Ponomareva irinaponomareva@webperfectionist.com
  * @author Alexander Sorkin <kibizoid@gmail.com>
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
@@ -15,7 +14,6 @@
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
- * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  */
 $lang['name']                  = 'Сбор информации о популярности (для загрузки может потребоваться некоторое время)';
 $lang['submit']                = 'Отправить данные';
diff --git a/lib/plugins/popularity/lang/sk/lang.php b/lib/plugins/popularity/lang/sk/lang.php
index d0937c82fb91d1ceda6f7b7d2382cb2bf283a495..eb23a9a67e132bed0ab734d2b61601db11951860 100644
--- a/lib/plugins/popularity/lang/sk/lang.php
+++ b/lib/plugins/popularity/lang/sk/lang.php
@@ -4,7 +4,7 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
+ * @author exusik <exusik@gmail.com>
  * @author Martin Michalek <michalek.dev@gmail.com>
  */
 $lang['name']                  = 'Prieskum používania (môže chvíľu trvať)';
diff --git a/lib/plugins/popularity/lang/sl/lang.php b/lib/plugins/popularity/lang/sl/lang.php
index abde6555b75d6143b81b84d5fe206a6b3960a01d..3910eba4e08ba24fae4ba3556f1c28959d62db94 100644
--- a/lib/plugins/popularity/lang/sl/lang.php
+++ b/lib/plugins/popularity/lang/sl/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Matej Urbančič (mateju@svn.gnome.org)
  */
 $lang['name']                  = 'Poročilo o uporabi (nalaganje strani je lahko dolgotrajno)';
diff --git a/lib/plugins/popularity/lang/sv/lang.php b/lib/plugins/popularity/lang/sv/lang.php
index 942a708c489cd52458c567db1ef13b163bf42f9c..ffbb903f26a414709caa6a51f080886edc780dbd 100644
--- a/lib/plugins/popularity/lang/sv/lang.php
+++ b/lib/plugins/popularity/lang/sv/lang.php
@@ -2,18 +2,14 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author HÃ¥kan Sandell <hakan.sandell@home.se>
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
- * @author Tormod Johansson tormod.otter.johansson@gmail.com
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
  */
 $lang['name']                  = 'Popularitets-feedback (det kan ta en stund att ladda sidan)';
 $lang['submit']                = 'Sänd data';
diff --git a/lib/plugins/popularity/lang/uk/lang.php b/lib/plugins/popularity/lang/uk/lang.php
index 9d67c1151fb1dadd57677a54576b56794c17849b..d47a0cf5fb450d55927d2c6f85886e742093776e 100644
--- a/lib/plugins/popularity/lang/uk/lang.php
+++ b/lib/plugins/popularity/lang/uk/lang.php
@@ -2,13 +2,9 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
- * @author serg_stetsuk@ukr.net
- * @author okunia@gmail.com
+ *
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
- * @author Uko uko@uar.net
- * @author Ulrikhe Lukoie  <lukoie@gmail>.com
- * @author Kate Arzamastseva pshns@ukr.net
  */
 $lang['name']                  = 'Відгук популярності (може зайняти деякий час)';
 $lang['submit']                = 'Передати дані';
diff --git a/lib/plugins/popularity/lang/zh/lang.php b/lib/plugins/popularity/lang/zh/lang.php
index 79abe1605874b9404f98c954e7315af8e602a854..695b5c4ad0e47f57469000c1aa5dbcdd69dc9ecd 100644
--- a/lib/plugins/popularity/lang/zh/lang.php
+++ b/lib/plugins/popularity/lang/zh/lang.php
@@ -5,15 +5,11 @@
  *
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
- * @author George Sheraton guxd@163.com
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author phy25 <git@phy25.com>
  */
diff --git a/lib/plugins/revert/lang/da/lang.php b/lib/plugins/revert/lang/da/lang.php
index 782ec121f8c3fc12d4ae04c3ff12dec246d77bd3..11114bd1bfa824891b8268de99bc8737b81ffea0 100644
--- a/lib/plugins/revert/lang/da/lang.php
+++ b/lib/plugins/revert/lang/da/lang.php
@@ -8,8 +8,7 @@
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  */
 $lang['menu']                  = 'Gendannelsesstyring';
diff --git a/lib/plugins/revert/lang/de-informal/lang.php b/lib/plugins/revert/lang/de-informal/lang.php
index 7affe54f1fbb29e9a1713bb3e97e0c82986954dc..808fe6e4c1dad717f160699e1d32eec270583b3f 100644
--- a/lib/plugins/revert/lang/de-informal/lang.php
+++ b/lib/plugins/revert/lang/de-informal/lang.php
@@ -11,7 +11,6 @@
  * @author Pierre Corell <info@joomla-praxis.de>
  * @author Frank Loizzi <contact@software.bacal.de>
  * @author Volker Bödker <volker@boedker.de>
- * @author Matthias Schulte <dokuwiki@lupo49.de>
  */
 $lang['menu']                  = 'Seiten wiederherstellen';
 $lang['filter']                = 'Durchsuche als Spam markierte Seiten';
diff --git a/lib/plugins/revert/lang/eo/lang.php b/lib/plugins/revert/lang/eo/lang.php
index 2d0b0f26732ecadf83ab621aa2d9d1b11a46ad44..5e9c1717ebf8a6542624caf76c541268fc3a751a 100644
--- a/lib/plugins/revert/lang/eo/lang.php
+++ b/lib/plugins/revert/lang/eo/lang.php
@@ -2,15 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Felipe Castro <fefcas@uol.com.br>
- * @author Felipe Castro <fefcas@gmail.com>
- * @author Felipe Castro <fefcas (cxe) gmail (punkto) com>
  * @author Felipo Kastro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik pedersen@shaw.ca>
- * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
  */
 $lang['menu']                  = 'Administrado de restarigo';
 $lang['filter']                = 'Serĉi spamecajn paĝojn';
diff --git a/lib/plugins/revert/lang/eu/lang.php b/lib/plugins/revert/lang/eu/lang.php
index 40be3e38226752860a2708cb93823fa2f5fb12ad..c7495d86b058a32211f01da020e687d466d9797f 100644
--- a/lib/plugins/revert/lang/eu/lang.php
+++ b/lib/plugins/revert/lang/eu/lang.php
@@ -2,10 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
  * @author Yadav Gowda <yadav.gowda@gmail.com>
+ * @author Osoitz <oelkoro@gmail.com>
  */
 $lang['menu']                  = 'Berrezartze Kudeatzailea';
 $lang['filter']                = 'Bilatu spam duten orriak';
diff --git a/lib/plugins/revert/lang/fr/lang.php b/lib/plugins/revert/lang/fr/lang.php
index 7f604d68ac36a0a789a3fb06039f6b57e709d9bb..ed518f0cf5df4f804ac696766f07d49247d9805b 100644
--- a/lib/plugins/revert/lang/fr/lang.php
+++ b/lib/plugins/revert/lang/fr/lang.php
@@ -13,10 +13,7 @@
  * @author Vincent Feltz <psycho@feltzv.fr>
  * @author Philippe Bajoit <philippe.bajoit@gmail.com>
  * @author Florian Gaub <floriang@floriang.net>
- * @author Samuel Dorsaz samuel.dorsaz@novelion.net
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author schplurtz@laposte.net
- * @author skimpax@gmail.com
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
diff --git a/lib/plugins/revert/lang/he/lang.php b/lib/plugins/revert/lang/he/lang.php
index 2f49856f5941a4e9c802c54b33c6a5b46f015270..562bbb3d224a85ef66291b0c897b8f8b9960f490 100644
--- a/lib/plugins/revert/lang/he/lang.php
+++ b/lib/plugins/revert/lang/he/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Dotan Kamber <kamberd@yahoo.com>
  * @author Moshe Kaplan <mokplan@gmail.com>
  * @author Yaron Yogev <yaronyogev@gmail.com>
diff --git a/lib/plugins/revert/lang/it/lang.php b/lib/plugins/revert/lang/it/lang.php
index bb8a47598076b6458bd4af242c2dab2aed7d6806..dfee9965ebabe0384d0a555432cb3e29a89a287c 100644
--- a/lib/plugins/revert/lang/it/lang.php
+++ b/lib/plugins/revert/lang/it/lang.php
@@ -4,15 +4,10 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Pietro Battiston toobaz@email.it
- * @author Diego Pierotto ita.translations@tiscali.it
- * @author ita.translations@tiscali.it
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
- * @author Osman Tekin osman.tekin93@hotmail.it
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
  */
 $lang['menu']                  = 'Gestore di ripristini';
 $lang['filter']                = 'Cerca pagine con spam';
diff --git a/lib/plugins/revert/lang/ko/lang.php b/lib/plugins/revert/lang/ko/lang.php
index bf74f76c92cc7c4d5bd1e33b0a08b851c72b5765..f9e16cc0907821fb4309570e5d37f4d4c6578af3 100644
--- a/lib/plugins/revert/lang/ko/lang.php
+++ b/lib/plugins/revert/lang/ko/lang.php
@@ -3,13 +3,14 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Seungheon Song <esketch@gmail.com>
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
- * @author Erial <erial2@gmail.com>
+ * @author S.H. Lee <tuders@naver.com>
  */
 $lang['menu']                  = '되돌리기 관리자';
 $lang['filter']                = '스팸 문서 검색';
diff --git a/lib/plugins/revert/lang/lv/lang.php b/lib/plugins/revert/lang/lv/lang.php
index b873692336bfc3ad4ee0b5b992f64e127c325fa6..365171577d42c14a46f4b81e05a35835c5e54a57 100644
--- a/lib/plugins/revert/lang/lv/lang.php
+++ b/lib/plugins/revert/lang/lv/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['menu']                  = 'Piemēsloto lapu atjaunotājs';
diff --git a/lib/plugins/revert/lang/nl/lang.php b/lib/plugins/revert/lang/nl/lang.php
index a91b50fd5a20205610bb2eca08382bdf484b026e..9181f04b9dc788ca521ea64adf5c3dca682b58ae 100644
--- a/lib/plugins/revert/lang/nl/lang.php
+++ b/lib/plugins/revert/lang/nl/lang.php
@@ -9,10 +9,8 @@
  * @author Dion Nicolaas <dion@nicolaas.net>
  * @author Danny Rotsaert <danny.rotsaert@edpnet.be>
  * @author Marijn Hofstra hofstra.m@gmail.com
- * @author Matthias Carchon webmaster@c-mattic.be
  * @author Marijn Hofstra <hofstra.m@gmail.com>
  * @author Timon Van Overveldt <timonvo@gmail.com>
- * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit <klapinklapin@gmail.com>
  * @author Remon <no@email.local>
diff --git a/lib/plugins/revert/lang/pl/lang.php b/lib/plugins/revert/lang/pl/lang.php
index d9b917e46c5ff6fa9bfbb08765af36d5de152cce..27937967384267bdcf4fe14af577ed004c2d4203 100644
--- a/lib/plugins/revert/lang/pl/lang.php
+++ b/lib/plugins/revert/lang/pl/lang.php
@@ -7,7 +7,7 @@
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
diff --git a/lib/plugins/revert/lang/pt-br/lang.php b/lib/plugins/revert/lang/pt-br/lang.php
index 36ab3dc48d449b313e5fd7f8f290c6630fefa47d..93337b62fb60d608d4732384c7ab1982f3134341 100644
--- a/lib/plugins/revert/lang/pt-br/lang.php
+++ b/lib/plugins/revert/lang/pt-br/lang.php
@@ -9,12 +9,9 @@
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Frederico Guimarães <frederico@teia.bio.br>
- * @author Jair Henrique <jair.henrique@gmail.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Sergio Motta sergio@cisne.com.br
+ * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
diff --git a/lib/plugins/revert/lang/pt/lang.php b/lib/plugins/revert/lang/pt/lang.php
index f87f77db7c474d593fffa2cbb6a3d8e2755c3894..665b846bf4fe4bf50936e329613617aa00e3018e 100644
--- a/lib/plugins/revert/lang/pt/lang.php
+++ b/lib/plugins/revert/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author José Monteiro <Jose.Monteiro@DoWeDo-IT.com>
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Fil <fil@meteopt.com>
diff --git a/lib/plugins/revert/lang/ru/lang.php b/lib/plugins/revert/lang/ru/lang.php
index dd0f5219bc6c00ed6a74ef060d7d0faf09ee4ac1..5de67b470eee123904200185e0c2881185f5c45d 100644
--- a/lib/plugins/revert/lang/ru/lang.php
+++ b/lib/plugins/revert/lang/ru/lang.php
@@ -5,10 +5,9 @@
  *
  * @author Denis Simakov <akinoame1@gmail.com>
  * @author Andrew Pleshakov <beotiger@mail.ru>
- * @author Змей Этерийский evil_snake@eternion.ru
+ * @author Змей Этерийский <evil_snake@eternion.ru>
  * @author Hikaru Nakajima <jisatsu@mail.ru>
  * @author Alexei Tereschenko <alexeitlex@yahoo.com>
- * @author Irina Ponomareva irinaponomareva@webperfectionist.com
  * @author Alexander Sorkin <kibizoid@gmail.com>
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
@@ -17,7 +16,6 @@
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
- * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  */
 $lang['menu']                  = 'Менеджер откаток';
 $lang['filter']                = 'Поиск спам-страниц';
diff --git a/lib/plugins/revert/lang/sk/lang.php b/lib/plugins/revert/lang/sk/lang.php
index 97689f89db0d467f20e991f52d0b1807d02a08ad..f251aace9c1b86be00d82d6c2146b94601cb78bc 100644
--- a/lib/plugins/revert/lang/sk/lang.php
+++ b/lib/plugins/revert/lang/sk/lang.php
@@ -4,7 +4,7 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
+ * @author exusik <exusik@gmail.com>
  * @author Martin Michalek <michalek.dev@gmail.com>
  */
 $lang['menu']                  = 'Obnova dát';
diff --git a/lib/plugins/revert/lang/sl/lang.php b/lib/plugins/revert/lang/sl/lang.php
index df778fd2613ef5ff9857cc794c781747d2cea99a..9ca8f8f4b2a28c0d8cef8087f312dd65e2456bb1 100644
--- a/lib/plugins/revert/lang/sl/lang.php
+++ b/lib/plugins/revert/lang/sl/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Matej Urbančič (mateju@svn.gnome.org)
  */
 $lang['menu']                  = 'Povrnitev okvarjene vsebine';
diff --git a/lib/plugins/revert/lang/sv/lang.php b/lib/plugins/revert/lang/sv/lang.php
index 504332bae28ccc8ad9324c1507ce9a208b15399a..7cff7ffd94c9308db41181a7268a5568b5f19bfc 100644
--- a/lib/plugins/revert/lang/sv/lang.php
+++ b/lib/plugins/revert/lang/sv/lang.php
@@ -2,22 +2,18 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Per Foreby <per@foreby.se>
  * @author Nicklas Henriksson <nicklas[at]nihe.se>
  * @author HÃ¥kan Sandell <hakan.sandell@home.se>
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
- * @author Tormod Johansson tormod.otter.johansson@gmail.com
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
  * @author Henrik <henrik@idealis.se>
- * @author Tor Härnqvist <tor.harnqvist@gmail.com>
  * @author Hans Iwan Bratt <hibratt@gmail.com>
  * @author Mikael Bergström <krank23@gmail.com>
  */
diff --git a/lib/plugins/revert/lang/uk/lang.php b/lib/plugins/revert/lang/uk/lang.php
index 2c9774f0c065855616054fa1854302759b788b7a..f56c0eb047e6eba7295daf5ba33b27e37381fecf 100644
--- a/lib/plugins/revert/lang/uk/lang.php
+++ b/lib/plugins/revert/lang/uk/lang.php
@@ -2,13 +2,9 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
- * @author serg_stetsuk@ukr.net
- * @author okunia@gmail.com
+ *
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
- * @author Uko uko@uar.net
- * @author Ulrikhe Lukoie  <lukoie@gmail>.com
- * @author Kate Arzamastseva pshns@ukr.net
  */
 $lang['menu']                  = 'Менеджер відновлення';
 $lang['filter']                = 'Пошук спамних сторінок';
diff --git a/lib/plugins/revert/lang/zh/lang.php b/lib/plugins/revert/lang/zh/lang.php
index b56d830ff5694aaf22e4a34f2d5db598d17a8344..60a7ba4f0f8f5beac08b0c6735e90160e0ff4d14 100644
--- a/lib/plugins/revert/lang/zh/lang.php
+++ b/lib/plugins/revert/lang/zh/lang.php
@@ -5,15 +5,11 @@
  *
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
- * @author George Sheraton guxd@163.com
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  */
 $lang['menu']                  = '还原管理器';
diff --git a/lib/plugins/styling/admin.php b/lib/plugins/styling/admin.php
index c747c3130e1c1d4cc609f3c5d855db1eda451d7b..055ac2279a48d199b7ee2297cb027555720dc934 100644
--- a/lib/plugins/styling/admin.php
+++ b/lib/plugins/styling/admin.php
@@ -57,9 +57,9 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
     public function form() {
         global $conf;
         global $ID;
-        define('SIMPLE_TEST', 1); // hack, ideally certain functions should be moved out of css.php
-        require_once(DOKU_INC.'lib/exe/css.php');
-        $styleini     = css_styleini($conf['template'], true);
+
+        $styleUtil = new \dokuwiki\StyleUtils();
+        $styleini     = $styleUtil->cssStyleini($conf['template'], true);
         $replacements = $styleini['replacements'];
 
         if($this->ispopup) {
diff --git a/lib/plugins/styling/lang/de-informal/intro.txt b/lib/plugins/styling/lang/de-informal/intro.txt
new file mode 100644
index 0000000000000000000000000000000000000000..aa9577355efe7d602e898367b76227bd5979d774
--- /dev/null
+++ b/lib/plugins/styling/lang/de-informal/intro.txt
@@ -0,0 +1,2 @@
+Dieses Plugin ermöglicht es, bestimmte Designeinstellungen des ausgewählten Templates zu ändern.
+Alle Änderungen werden in einer lokalen Konfigurationsdatei gespeichert und sind upgrade-sicher.
\ No newline at end of file
diff --git a/lib/plugins/styling/lang/de-informal/lang.php b/lib/plugins/styling/lang/de-informal/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..60ae96b0abda100865a27ef50cc616fa7eb40bcf
--- /dev/null
+++ b/lib/plugins/styling/lang/de-informal/lang.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Felix Müller-Donath <j.felix@mueller-donath.de>
+ */
+$lang['menu']                  = 'Einstellungen fürs Template-Design';
+$lang['js']['loader']          = 'Vorschau lädt...<br />Falls diese Nachricht nicht verschwindet, könnten deine Werte fehlerhaft sein';
+$lang['js']['popup']           = 'Öffne als Popup';
+$lang['error']                 = 'Dieses Template unterstützt diese Funktion nicht.';
+$lang['btn_preview']           = 'Vorschau der Änderungen anzeigen';
+$lang['btn_save']              = 'Änderungen speichern';
+$lang['btn_reset']             = 'Aktuelle Änderungen rückgängig machen';
+$lang['btn_revert']            = 'Design auf die Voreinstellung des Templates zurücksetzen';
+$lang['__text__']              = 'Main text color';
+$lang['__background__']        = 'Haupthintergrundfarbe';
+$lang['__text_alt__']          = 'Alternative Textfarbe';
+$lang['__background_alt__']    = 'Alternative Hintergrundfarbe';
+$lang['__text_neu__']          = 'Neutrale Textfarbe';
+$lang['__background_neu__']    = 'Neutrale Hintergrundfarbe';
+$lang['__border__']            = 'Rahmenfarbe';
+$lang['__highlight__']         = 'Hervorhebungsfarbe (v.a. für Suchergebnisse)';
diff --git a/lib/plugins/styling/lang/eo/lang.php b/lib/plugins/styling/lang/eo/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..d8127e7db02c2af82e9a42004ac7a983f07a999d
--- /dev/null
+++ b/lib/plugins/styling/lang/eo/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>
+ */
+$lang['btn_preview']           = 'Antaŭaj ŝanĝoj';
+$lang['btn_save']              = 'Konservi ŝanĝojn';
diff --git a/lib/plugins/styling/lang/fr/lang.php b/lib/plugins/styling/lang/fr/lang.php
index b3f0116462974d278de3cac1811fc7d307709b5b..05725bcf62b0146c474171e29dc2755297828979 100644
--- a/lib/plugins/styling/lang/fr/lang.php
+++ b/lib/plugins/styling/lang/fr/lang.php
@@ -5,11 +5,12 @@
  *
  * @author Carbain Frédéric <fcarbain@yahoo.fr>
  * @author Nicolas Friedli <nicolas@theologique.ch>
+ * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
  */
 $lang['menu']                  = 'Paramètres de style du thème (template)';
 $lang['js']['loader']          = 'La prévisualisation est en chargement... <br />Si rien ne se passe, les données sont peut-être erronées';
 $lang['js']['popup']           = 'Ouvrir dans une nouvelle fenêtre';
-$lang['error']                 = 'Désolé, ce thème ne supporte pas cette fonctionnalité.';
+$lang['error']                 = 'Désolé, ce thème n\'utilise pas cette fonctionnalité.';
 $lang['btn_preview']           = 'Aperçu des changements';
 $lang['btn_save']              = 'sauvegarder les changements.';
 $lang['btn_reset']             = 'Remettre les changements courants à zéro';
diff --git a/lib/plugins/styling/lang/pl/intro.txt b/lib/plugins/styling/lang/pl/intro.txt
new file mode 100644
index 0000000000000000000000000000000000000000..29206a882fc91693b5562740b098959e614a514c
--- /dev/null
+++ b/lib/plugins/styling/lang/pl/intro.txt
@@ -0,0 +1 @@
+To narzędzie umożliwia zmianę niektórych ustawień stylów aktualnie wybranego szablonu. Wszystkie zmiany są przechowywane w lokalnym pliku konfiguracyjnym i są bezpieczne dla aktualizacji.
\ No newline at end of file
diff --git a/lib/plugins/styling/lang/pl/lang.php b/lib/plugins/styling/lang/pl/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..e4c84baf9e7e5af6756c22578f3d8b55387ad4ac
--- /dev/null
+++ b/lib/plugins/styling/lang/pl/lang.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
+ */
+$lang['menu']                  = 'Ustawienia Szablonu';
+$lang['js']['loader']          = 'Podgląd ładuje się ...<br />jeśli ten komunikat nie zniknie, twoje wartości mogą być błędne';
+$lang['js']['popup']           = 'Otwórz w nowym oknie';
+$lang['error']                 = 'Przepraszamy, ten szablon nie wspiera tej funkcjonalności';
+$lang['btn_preview']           = 'Pokaż zmiany ';
+$lang['btn_save']              = 'Zapisz zmiany';
+$lang['btn_reset']             = 'Cofnij zmiany ';
+$lang['btn_revert']            = 'Przywróć style do wartości domyślnych szablonu';
+$lang['__text__']              = 'Kolor tekstu ';
+$lang['__background__']        = 'Kolor tła ';
+$lang['__text_alt__']          = 'Inny kolor tekstu';
+$lang['__background_alt__']    = 'Inny kolor tła';
+$lang['__text_neu__']          = 'Kolor neutralnego tekstu';
+$lang['__background_neu__']    = 'Kolor neutralnego tła';
+$lang['__border__']            = 'kolor obramowania ';
+$lang['__highlight__']         = 'Kolor podświetlenia (głównie dla wyników wyszukiwania)';
diff --git a/lib/plugins/styling/lang/pt/lang.php b/lib/plugins/styling/lang/pt/lang.php
index 6929a40dc4487dff22efb6db95740a1f70dcd132..1c64c0430819ffe4cb79aac53f35a79c5701a07d 100644
--- a/lib/plugins/styling/lang/pt/lang.php
+++ b/lib/plugins/styling/lang/pt/lang.php
@@ -2,12 +2,18 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Alfredo Silva <alfredo.silva@sky.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
+$lang['menu']                  = 'Configurações de Estilo do Modelo';
 $lang['js']['popup']           = 'Abrir como uma janela extra';
 $lang['error']                 = 'Desculpe, este modelo não suporta esta funcionalidade.';
 $lang['btn_preview']           = 'Pré-visualizar alterações';
 $lang['btn_save']              = 'Guardar alterações';
 $lang['btn_reset']             = 'Reiniciar alterações atuais';
 $lang['__text__']              = 'Cor do texto principal';
+$lang['__background__']        = 'Cor principal do fundo';
+$lang['__text_alt__']          = 'Cor alternativa de texto';
+$lang['__background_alt__']    = 'Cor alternativa de fundo';
+$lang['__text_neu__']          = 'Cor neutra de texto';
diff --git a/lib/plugins/styling/lang/sv/lang.php b/lib/plugins/styling/lang/sv/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..00a8518b20ff0457093f9c9bccf2511305bf228a
--- /dev/null
+++ b/lib/plugins/styling/lang/sv/lang.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['btn_preview']           = 'Förhandsvisa ändringar';
+$lang['btn_save']              = 'Spara ändringar';
+$lang['btn_reset']             = 'Nollställ aktuella ändringar';
+$lang['__text__']              = 'Huvudsaklig textfärg';
+$lang['__background__']        = 'Huvudsaklig bakgrundsfärg';
+$lang['__text_alt__']          = 'Alternativ textfärg';
+$lang['__background_alt__']    = 'Alternativ bakgrundsfärg';
+$lang['__text_neu__']          = 'Neutral textfärg';
+$lang['__background_neu__']    = 'Neutral bakgrundsfärg';
+$lang['__border__']            = 'Ramfärg';
diff --git a/lib/plugins/usermanager/lang/da/lang.php b/lib/plugins/usermanager/lang/da/lang.php
index 1cb4a90381fb6ef0bbcd06c6ace9033606d8bad4..b4e3c6c2513cec78485fb0d810254a3eee885b6a 100644
--- a/lib/plugins/usermanager/lang/da/lang.php
+++ b/lib/plugins/usermanager/lang/da/lang.php
@@ -9,11 +9,9 @@
  * @author Harith <haj@berlingske.dk>
  * @author Daniel Ejsing-Duun <dokuwiki@zilvador.dk>
  * @author Erik Bjørn Pedersen <erik.pedersen@shaw.ca>
- * @author rasmus@kinnerup.com
- * @author Michael Pedersen subben@gmail.com
+ * @author rasmus <rasmus@kinnerup.com>
  * @author Mikael Lyngvig <mikael@lyngvig.org>
  * @author soer9648 <soer9648@eucl.dk>
- * @author Søren Birk <soer9648@eucl.dk>
  */
 $lang['menu']                  = 'Brugerstyring';
 $lang['noauth']                = '(Brugervalidering er ikke tilgængelig)';
diff --git a/lib/plugins/usermanager/lang/de-informal/lang.php b/lib/plugins/usermanager/lang/de-informal/lang.php
index 2523ce212a42b3fd3125a3cbc8f5a9f5fcb0cc2d..bea3bb9b2630ae87c84ca6451ea1c7d7a7943e06 100644
--- a/lib/plugins/usermanager/lang/de-informal/lang.php
+++ b/lib/plugins/usermanager/lang/de-informal/lang.php
@@ -12,6 +12,7 @@
  * @author Frank Loizzi <contact@software.bacal.de>
  * @author Volker Bödker <volker@boedker.de>
  * @author Dennis Plöger <develop@dieploegers.de>
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
  */
 $lang['menu']                  = 'Benutzerverwaltung';
 $lang['noauth']                = '(Benutzeranmeldung ist nicht verfügbar)';
@@ -59,6 +60,8 @@ $lang['add_ok']                = 'Benutzer erfolgreich hinzugefügt';
 $lang['add_fail']              = 'Hinzufügen des Benutzers fehlgeschlagen';
 $lang['notify_ok']             = 'Benachrichtigungsmail wurde versendet';
 $lang['notify_fail']           = 'Benachrichtigungsemail konnte nicht gesendet werden';
+$lang['import_userlistcsv']    = 'Benutzerliste (CSV-Datei):';
+$lang['import_header']         = 'Letzte Fehler bei Import';
 $lang['import_success_count']  = 'Benutzerimport: %d Benutzer gefunden, %d erfolgreich importiert.';
 $lang['import_failure_count']  = 'Benutzerimport: %d Benutzerimporte fehlgeschalten. Alle Fehler werden unten angezeigt.';
 $lang['import_error_fields']   = 'Falsche Anzahl Felder. Gefunden: %d. Benötigt: 4.';
@@ -69,3 +72,12 @@ $lang['import_error_upload']   = 'Import fehlgeschlagen. Die CSV-Datei konnte ni
 $lang['import_error_readfail'] = 'Import fehlgeschlagen. Konnte die hochgeladene Datei nicht lesen.';
 $lang['import_error_create']   = 'Konnte den Benutzer nicht erzeugen';
 $lang['import_notify_fail']    = 'Benachrichtigung konnte an Benutzer %s (%s) nicht geschickt werden.';
+$lang['import_downloadfailures'] = 'Fehler als CSV-Datei zur Korrektur herunterladen';
+$lang['addUser_error_missing_pass'] = 'Bitte setze entweder ein Passwort oder aktiviere die Benutzerbenachrichtigung, um die Passwortgenerierung zu ermöglichen.';
+$lang['addUser_error_pass_not_identical'] = 'Die eingegebenen Passwörter stimmen nicht überein.';
+$lang['addUser_error_modPass_disabled'] = 'Das Bearbeiten von Passwörtern ist momentan deaktiviert';
+$lang['addUser_error_name_missing'] = 'Bitte gib den Namen des neuen Benutzer ein.';
+$lang['addUser_error_modName_disabled'] = 'Das Bearbeiten von Namen ist momentan deaktiviert.';
+$lang['addUser_error_mail_missing'] = 'Bitte gib die E-Mail-Adresse des neuen Benutzer ein.';
+$lang['addUser_error_modMail_disabled'] = 'Das Bearbeiten von E-Mailadressen ist momentan deaktiviert.';
+$lang['addUser_error_create_event_failed'] = 'Ein Plug-in hat das Hinzufügen des neuen Benutzers verhindert. Für weitere Informationen sieh dir mögliche andere Meldungen an.';
diff --git a/lib/plugins/usermanager/lang/eo/lang.php b/lib/plugins/usermanager/lang/eo/lang.php
index ff7818e05b5cbea2b6925f8ebbef1ae94da3baf5..5a11e73e4f9c2cb09c6810308239918e94045ba7 100644
--- a/lib/plugins/usermanager/lang/eo/lang.php
+++ b/lib/plugins/usermanager/lang/eo/lang.php
@@ -2,16 +2,11 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Felipe Castro <fefcas@uol.com.br>
- * @author Felipe Castro <fefcas@gmail.com>
- * @author Felipe Castro <fefcas (cxe) gmail (punkto) com>
  * @author Felipo Kastro <fefcas@gmail.com>
  * @author Robert Bogenschneider <robog@gmx.de>
  * @author Erik Pedersen <erik pedersen@shaw.ca>
- * @author Erik Pedersen <erik.pedersen@shaw.ca>
- * @author Robert Bogenschneider <bogi@uea.org>
- * @author Felipe Castro <fefcas@yahoo.com.br>
  */
 $lang['menu']                  = 'Administrado de uzantoj';
 $lang['noauth']                = '(identiĝo de uzantoj ne disponeblas)';
diff --git a/lib/plugins/usermanager/lang/eu/add.txt b/lib/plugins/usermanager/lang/eu/add.txt
index 855c4321854308a45a23a873ae34c2348ab68acd..4208e518fe4db271883513069692f05f56002f06 100644
--- a/lib/plugins/usermanager/lang/eu/add.txt
+++ b/lib/plugins/usermanager/lang/eu/add.txt
@@ -1 +1 @@
-===== Erabiltzailea gehitu =====
\ No newline at end of file
+===== Gehitu erabiltzailea =====
\ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/eu/delete.txt b/lib/plugins/usermanager/lang/eu/delete.txt
index 987b98f204b2e6f9b321e427bd63ab87d5b47170..245c881c85938fe2c7db2ec2ae39625acff413f2 100644
--- a/lib/plugins/usermanager/lang/eu/delete.txt
+++ b/lib/plugins/usermanager/lang/eu/delete.txt
@@ -1 +1 @@
-===== Erabiltzailea ezabatu =====
\ No newline at end of file
+===== Ezabatu erabiltzailea =====
\ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/eu/intro.txt b/lib/plugins/usermanager/lang/eu/intro.txt
index 848b3da05c94d3f5b63d5f8b4f02554236e7d0ce..91770fdaeb3f8cceb142978dd1fe3990669cb549 100644
--- a/lib/plugins/usermanager/lang/eu/intro.txt
+++ b/lib/plugins/usermanager/lang/eu/intro.txt
@@ -1 +1 @@
-====== Erabiltzaile Kudeatzailea ======
\ No newline at end of file
+====== Erabiltzaile-kudeatzailea ======
\ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/eu/lang.php b/lib/plugins/usermanager/lang/eu/lang.php
index 1fbe1373920b2118ebc2ef896abca53036aa32db..e2f2cb8295462fc00eb7ddaddaf62a119f256bb2 100644
--- a/lib/plugins/usermanager/lang/eu/lang.php
+++ b/lib/plugins/usermanager/lang/eu/lang.php
@@ -2,11 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Inko Illarramendi <inko.i.a@gmail.com>
  * @author Zigor Astarbe <astarbe@gmail.com>
+ * @author Osoitz <oelkoro@gmail.com>
  */
-$lang['menu']                  = 'Erabiltzaile Kudeatzailea';
+$lang['menu']                  = 'Erabiltzaile-kudeatzailea';
 $lang['noauth']                = '(erabiltzaile kautotzea ez dago erabilgarri)';
 $lang['nosupport']             = '(erabiltzaile kudeaketa ez dago erabilgarri)';
 $lang['badauth']               = 'kautotze mekanismo baliogabea';
diff --git a/lib/plugins/usermanager/lang/fr/lang.php b/lib/plugins/usermanager/lang/fr/lang.php
index d1db76c2345e9c075b7dd73aa525695134250061..f2deac392a4abeb56c3ac5eb8527ed58228b6c40 100644
--- a/lib/plugins/usermanager/lang/fr/lang.php
+++ b/lib/plugins/usermanager/lang/fr/lang.php
@@ -13,9 +13,7 @@
  * @author Vincent Feltz <psycho@feltzv.fr>
  * @author Philippe Bajoit <philippe.bajoit@gmail.com>
  * @author Florian Gaub <floriang@floriang.net>
- * @author Samuel Dorsaz samuel.dorsaz@novelion.net
  * @author Johan Guilbaud <guilbaud.johan@gmail.com>
- * @author skimpax@gmail.com
  * @author Yannick Aure <yannick.aure@gmail.com>
  * @author Olivier DUVAL <zorky00@gmail.com>
  * @author Anael Mobilia <contrib@anael.eu>
@@ -28,7 +26,7 @@
  */
 $lang['menu']                  = 'Gestion des utilisateurs';
 $lang['noauth']                = '(authentification de l\'utilisateur non disponible)';
-$lang['nosupport']             = '(gestion de l\'utilisateur non supportée)';
+$lang['nosupport']             = '(gestion de l\'utilisateur non pris en charge)';
 $lang['badauth']               = 'mécanisme d\'authentification invalide';
 $lang['user_id']               = 'Identifiant ';
 $lang['user_pass']             = 'Mot de passe ';
diff --git a/lib/plugins/usermanager/lang/he/lang.php b/lib/plugins/usermanager/lang/he/lang.php
index 18202584e7e1b77a83a56aecff6f7f6b3e36cfb6..719fd901fd9b1ff0b1f20ce3a9b26f1d2107c8d0 100644
--- a/lib/plugins/usermanager/lang/he/lang.php
+++ b/lib/plugins/usermanager/lang/he/lang.php
@@ -2,9 +2,8 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author DoK <kamberd@yahoo.com>
- * @author Dotan Kamber <kamberd@yahoo.com>
  * @author Moshe Kaplan <mokplan@gmail.com>
  * @author Yaron Yogev <yaronyogev@gmail.com>
  * @author Yaron Shahrabani <sh.yaron@gmail.com>
diff --git a/lib/plugins/usermanager/lang/it/lang.php b/lib/plugins/usermanager/lang/it/lang.php
index a4834f51624e63f6bcdb2d28bed5f37fea3d95be..c1a315a01d03009a83a8427754b1c78d8d6c995e 100644
--- a/lib/plugins/usermanager/lang/it/lang.php
+++ b/lib/plugins/usermanager/lang/it/lang.php
@@ -6,15 +6,10 @@
  * @author Chris Smith <chris@jalakai.co.uk>
  * @author Silvia Sargentoni <polinnia@tin.it>
  * @author Pietro Battiston toobaz@email.it
- * @author Diego Pierotto ita.translations@tiscali.it
- * @author ita.translations@tiscali.it
  * @author Lorenzo Breda <lbreda@gmail.com>
- * @author snarchio@alice.it
  * @author robocap <robocap1@gmail.com>
- * @author Osman Tekin osman.tekin93@hotmail.it
  * @author Jacopo Corbetta <jacopo.corbetta@gmail.com>
  * @author Matteo Pasotti <matteo@xquiet.eu>
- * @author snarchio@gmail.com
  * @author Claudio Lanconelli <lancos@libero.it>
  * @author Francesco <francesco.cavalli@hotmail.com>
  * @author Fabio <fabioslurp@yahoo.it>
diff --git a/lib/plugins/usermanager/lang/ko/lang.php b/lib/plugins/usermanager/lang/ko/lang.php
index 805fda5efe7b6b013baf63a96f5c3eb9e5075981..27d07de1d3bcf9e1e5edb2ef2e716f233a9cb350 100644
--- a/lib/plugins/usermanager/lang/ko/lang.php
+++ b/lib/plugins/usermanager/lang/ko/lang.php
@@ -4,14 +4,13 @@
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
  * @author jk Lee
- * @author dongnak@gmail.com
+ * @author dongnak <dongnak@gmail.com>
  * @author Song Younghwan <purluno@gmail.com>
  * @author Seung-Chul Yoo <dryoo@live.com>
- * @author erial2@gmail.com
+ * @author erial2 <erial2@gmail.com>
  * @author Myeongjin <aranet100@gmail.com>
  * @author Gerrit Uitslag <klapinklapin@gmail.com>
  * @author Garam <rowain8@gmail.com>
- * @author Erial <erial2@gmail.com>
  */
 $lang['menu']                  = '사용자 관리자';
 $lang['noauth']                = '(사용자 인증을 사용할 수 없습니다)';
diff --git a/lib/plugins/usermanager/lang/lv/lang.php b/lib/plugins/usermanager/lang/lv/lang.php
index 4944da31ec97757039a9d5d7d8752942888f6f0b..bb110569f47b092f19dfba08c3dd0833f9331df3 100644
--- a/lib/plugins/usermanager/lang/lv/lang.php
+++ b/lib/plugins/usermanager/lang/lv/lang.php
@@ -2,9 +2,8 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Aivars Miška <allefm@gmail.lv>
- * @author Aivars Miška <allefm@gmail.com>
  */
 $lang['menu']                  = 'Lietotāju pārvaldnieks';
 $lang['noauth']                = '(lietotāju autentifikācijas nav)';
diff --git a/lib/plugins/usermanager/lang/nl/lang.php b/lib/plugins/usermanager/lang/nl/lang.php
index 8233d86633bcc40f4029d4e155c90c7cff084c46..d6afc5488279961570efc993964efa2e0aa5012f 100644
--- a/lib/plugins/usermanager/lang/nl/lang.php
+++ b/lib/plugins/usermanager/lang/nl/lang.php
@@ -9,10 +9,8 @@
  * @author Dion Nicolaas <dion@nicolaas.net>
  * @author Danny Rotsaert <danny.rotsaert@edpnet.be>
  * @author Marijn Hofstra hofstra.m@gmail.com
- * @author Matthias Carchon webmaster@c-mattic.be
  * @author Marijn Hofstra <hofstra.m@gmail.com>
  * @author Timon Van Overveldt <timonvo@gmail.com>
- * @author Jeroen
  * @author Ricardo Guijt <ricardoguijt@gmail.com>
  * @author Gerrit Uitslag <klapinklapin@gmail.com>
  * @author Rene <wllywlnt@yahoo.com>
diff --git a/lib/plugins/usermanager/lang/pl/import.txt b/lib/plugins/usermanager/lang/pl/import.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87a50e74d89b110db8313d51dbbbf703f3c143c8
--- /dev/null
+++ b/lib/plugins/usermanager/lang/pl/import.txt
@@ -0,0 +1,6 @@
+===== Hurtowy import użytkowników =====
+
+Wymaga pliku CSV z co najmniej czterema kolumnami. Kolumny muszą zawierać, w kolejności: identyfikator użytkownika, imię i nazwisko, adres e-mail i grupy.
+Pola CSV powinny być oddzielone przecinkami (,) a łańcuchy znaków objęte znakami cudzysłowu (%%""%%). Aby ominąć znak z interpretacji należy użyć odwrotnego ukośnika (\). Za przykład pliku wypróbuj powyższą funkcję "Eksportuj użytkowników". Duplikaty identyfikatorów użytkowników będą ignorowane.
+
+Hasło zostanie wygenerowane i przesłane e-mailem do każdego pomyślnie zaimportowanego użytkownika.
\ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/pl/lang.php b/lib/plugins/usermanager/lang/pl/lang.php
index fb0ddd7d66db4a9240ecbe972bfb2be51b09f097..605057c7214a1a94423697d03ce739aad88e9b89 100644
--- a/lib/plugins/usermanager/lang/pl/lang.php
+++ b/lib/plugins/usermanager/lang/pl/lang.php
@@ -3,11 +3,13 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ * @author Max <maxrb146@gmail.com>
  * @author Grzegorz Żur <grzegorz.zur@gmail.com>
  * @author Mariusz Kujawski <marinespl@gmail.com>
  * @author Maciej Kurczewski <pipijajko@gmail.com>
  * @author Sławomir Boczek <slawkens@gmail.com>
- * @author sleshek@wp.pl
+ * @author sleshek <sleshek@wp.pl>
  * @author Leszek Stachowski <shazarre@gmail.com>
  * @author maros <dobrimaros@yahoo.pl>
  * @author Grzegorz Widła <dzesdzes@gmail.com>
@@ -36,6 +38,11 @@ $lang['search']                = 'Szukaj';
 $lang['search_prompt']         = 'Rozpocznij przeszukiwanie';
 $lang['clear']                 = 'Resetuj filtr przeszukiwania';
 $lang['filter']                = 'Filtr';
+$lang['export_all']            = 'Eksportuj wszystkich użytkowników (CSV)';
+$lang['export_filtered']       = 'Eksportuj wyfiltrowaną listę użytkowników (CSV) ';
+$lang['import']                = 'Importuj nowych użytkowników';
+$lang['line']                  = 'Numer linii';
+$lang['error']                 = 'Błędna wiadomość';
 $lang['summary']               = 'Użytkownicy %1$d-%2$d z %3$d znalezionych. Całkowita ilość użytkowników %4$d.';
 $lang['nonefound']             = 'Nie znaleziono użytkowników. Całkowita ilość użytkowników %d.';
 $lang['delete_ok']             = 'Usunięto %d użytkowników.';
@@ -56,3 +63,24 @@ $lang['add_ok']                = 'Dodano użytkownika';
 $lang['add_fail']              = 'Dodawanie użytkownika nie powiodło się';
 $lang['notify_ok']             = 'Powiadomienie zostało wysłane';
 $lang['notify_fail']           = 'Wysyłanie powiadomienia nie powiodło się';
+$lang['import_userlistcsv']    = 'Plik z listą użytkowników (CSV):';
+$lang['import_header']         = 'Najnowszy import - błędy';
+$lang['import_success_count']  = 'Import użytkowników: znaleziono %d użytkowników z czego pomyślnie zaimportowano %d.';
+$lang['import_failure_count']  = 'Import użytkowników: %d błędów. Błędy wymieniono poniżej.';
+$lang['import_error_fields']   = 'Niewystarczająca ilość pól, znalezione %d, wymagane 4.';
+$lang['import_error_baduserid'] = 'Brak id użytkownika';
+$lang['import_error_badname']  = 'Błędna nazwa';
+$lang['import_error_badmail']  = 'Błędny email';
+$lang['import_error_upload']   = 'Importowanie nie powiodło się. Nie można załadować pliku CSV lub jest on pusty.';
+$lang['import_error_readfail'] = 'Ładownie przerwane. Nie można odczytać pliku. ';
+$lang['import_error_create']   = 'Nie można utworzyć użytkownika';
+$lang['import_notify_fail']    = 'Powiadomienie nie mogło być wysłane do zaimportowanego użytkownika %s o e-mailu %s.';
+$lang['import_downloadfailures'] = 'W celu korekty pobierz niepowodzenia jako plik CSV';
+$lang['addUser_error_missing_pass'] = 'Ustaw hasło albo aktywuj powiadomienia użytkowników aby móc włączyć generowanie haseł.';
+$lang['addUser_error_pass_not_identical'] = 'Wprowadzone różne hasła ';
+$lang['addUser_error_modPass_disabled'] = 'Modyfikacja haseł została wyłączona';
+$lang['addUser_error_name_missing'] = 'Wprowadź nazwę dla nowego użytkownika';
+$lang['addUser_error_modName_disabled'] = 'Modyfikacja nazw została wyłączona ';
+$lang['addUser_error_mail_missing'] = 'Wprowadź adres email dla nowego użytkownika';
+$lang['addUser_error_modMail_disabled'] = 'Modyfikacja adresów email została wyłączona ';
+$lang['addUser_error_create_event_failed'] = 'Wtyczka uniemożliwiła dodanie nowego użytkownika. Przejrzyj możliwe inne komunikaty, aby uzyskać więcej informacji.';
diff --git a/lib/plugins/usermanager/lang/pt-br/lang.php b/lib/plugins/usermanager/lang/pt-br/lang.php
index ec116e73c15ee1030e0651a917af8d9555603bc4..1305c59104adb4793a662b42f6c9cf49012fb6d2 100644
--- a/lib/plugins/usermanager/lang/pt-br/lang.php
+++ b/lib/plugins/usermanager/lang/pt-br/lang.php
@@ -9,12 +9,9 @@
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Flávio Veras <flaviove@gmail.com>
  * @author Jeferson Propheta <jeferson.propheta@gmail.com>
- * @author jair.henrique@gmail.com
+ * @author jair.henrique <jair.henrique@gmail.com>
  * @author Luis Dantas <luis@dantas.com>
- * @author Frederico Guimarães <frederico@teia.bio.br>
- * @author Jair Henrique <jair.henrique@gmail.com>
- * @author Luis Dantas <luisdantas@gmail.com>
- * @author Sergio Motta sergio@cisne.com.br
+ * @author Sergio Motta <sergio@cisne.com.br>
  * @author Isaias Masiero Filho <masiero@masiero.org>
  * @author Balaco Baco <balacobaco@imap.cc>
  * @author Victor Westmann <victor.westmann@gmail.com>
diff --git a/lib/plugins/usermanager/lang/pt/lang.php b/lib/plugins/usermanager/lang/pt/lang.php
index 86885e415e3d0a69f994874dc3acd0996d4ebb55..b12e5dc70b98911f947107a9f47c956bb08eb4e9 100644
--- a/lib/plugins/usermanager/lang/pt/lang.php
+++ b/lib/plugins/usermanager/lang/pt/lang.php
@@ -2,7 +2,7 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author José Monteiro <Jose.Monteiro@DoWeDo-IT.com>
  * @author Enrico Nicoletto <liverig@gmail.com>
  * @author Fil <fil@meteopt.com>
@@ -12,6 +12,7 @@
  * @author Romulo Pereira <romuloccomp@gmail.com>
  * @author Paulo Carmino <contato@paulocarmino.com>
  * @author Alfredo Silva <alfredo.silva@sky.com>
+ * @author Guilherme Sá <guilherme.sa@hotmail.com>
  */
 $lang['menu']                  = 'Gestor de Perfis';
 $lang['noauth']                = '(autenticação indisponível)';
diff --git a/lib/plugins/usermanager/lang/ru/import.txt b/lib/plugins/usermanager/lang/ru/import.txt
index 22372c25460364dca6a30b42ae403f35595fd78b..0f303f32cd2f85b5dcffe9f056ae3faccd5af7b4 100644
--- a/lib/plugins/usermanager/lang/ru/import.txt
+++ b/lib/plugins/usermanager/lang/ru/import.txt
@@ -1,9 +1,9 @@
 ===== Импорт нескольких пользователей =====
 
-Потребуется список пользователей в файле формата CSV, состоящий из 4 столбцов. 
+Потребуется список пользователей в файле формата CSV, состоящем из 4 столбцов. 
 Столбцы должны быть заполнены следующим образом: user-id, полное имя, эл. почта, группы. 
-Поля CSV должны быть отделены запятой (,), а строки должны быть заключены в кавычки (%%""%%). Обратный слэш (\) используется как прерывание.  
+Поля CSV должны быть отделены запятой (,), а строки должны быть заключены в кавычки (%%""%%). Обратный слэш (\) используется для экранирования.  
 В качестве примера можете взять список пользователей, экспортированный через «Экспорт пользователей».  
 Повторяющиеся идентификаторы user-id будут игнорироваться.
 
-Пароль доступа будет сгенерирован и отправлен по почте удачно импортированному пользователю. 
\ No newline at end of file
+Пароль доступа будет сгенерирован и отправлен по почте удачно импортированному пользователю.
diff --git a/lib/plugins/usermanager/lang/ru/lang.php b/lib/plugins/usermanager/lang/ru/lang.php
index 32ce109af7142229a166d6e140220e3e10d4d260..d0f98184d0e47ff1b553e36ed6b2b0c2f3969738 100644
--- a/lib/plugins/usermanager/lang/ru/lang.php
+++ b/lib/plugins/usermanager/lang/ru/lang.php
@@ -3,12 +3,12 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
  * @author Denis Simakov <akinoame1@gmail.com>
  * @author Andrew Pleshakov <beotiger@mail.ru>
- * @author Змей Этерийский evil_snake@eternion.ru
+ * @author Змей Этерийский <evil_snake@eternion.ru>
  * @author Hikaru Nakajima <jisatsu@mail.ru>
  * @author Alexei Tereschenko <alexeitlex@yahoo.com>
- * @author Irina Ponomareva irinaponomareva@webperfectionist.com
  * @author Alexander Sorkin <kibizoid@gmail.com>
  * @author Kirill Krasnov <krasnovforum@gmail.com>
  * @author Vlad Tsybenko <vlad.development@gmail.com>
@@ -17,9 +17,7 @@
  * @author Ladyko Andrey <fylh@succexy.spb.ru>
  * @author Eugene <windy.wanderer@gmail.com>
  * @author Johnny Utah <pcpa@cyberpunk.su>
- * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
  * @author Pavel <ivanovtsk@mail.ru>
- * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  * @author Igor Degraf <igordegraf@gmail.com>
  * @author Vitaly Filatenko <kot@hacktest.net>
  * @author dimsharav <dimsharav@gmail.com>
@@ -75,17 +73,17 @@ $lang['import_userlistcsv']    = 'Файл со списком пользова
 $lang['import_header']         = 'Последний импорт — список ошибок';
 $lang['import_success_count']  = 'Импорт пользователей: %d пользователей найдено, %d импортировано успешно.';
 $lang['import_failure_count']  = 'Импорт пользователей: %d не удалось. Ошибки перечислены ниже.';
-$lang['import_error_fields']   = 'Не все поля заполнены. Найдено %d, а нужно: 4.';
+$lang['import_error_fields']   = 'Не все поля заполнены. Найдено %d, а требуется 4.';
 $lang['import_error_baduserid'] = 'Отсутствует идентификатор пользователя';
-$lang['import_error_badname']  = 'Имя не годится';
-$lang['import_error_badmail']  = 'Адрес электронной почты не годится';
+$lang['import_error_badname']  = 'Неверное имя';
+$lang['import_error_badmail']  = 'Неверный адрес эл. почты';
 $lang['import_error_upload']   = 'Импорт не удался. CSV-файл не загружен или пуст.';
 $lang['import_error_readfail'] = 'Импорт не удался. Невозможно прочесть загруженный файл.';
 $lang['import_error_create']   = 'Невозможно создать пользователя';
 $lang['import_notify_fail']    = 'Оповещение не может быть отправлено импортированному пользователю %s по электронной почте %s.';
 $lang['import_downloadfailures'] = 'Скачать ошибки в формате CSV для исправления';
 $lang['addUser_error_missing_pass'] = 'Для возможности генерации пароля, пожалуйста, установите пароль или активируйте оповещения.';
-$lang['addUser_error_pass_not_identical'] = 'Введённые ппароли не совпадают.';
+$lang['addUser_error_pass_not_identical'] = 'Введённые пароли не совпадают.';
 $lang['addUser_error_modPass_disabled'] = 'Изменение пароля в настоящее время невозможно.';
 $lang['addUser_error_name_missing'] = 'Укажите имя нового пользователя.';
 $lang['addUser_error_modName_disabled'] = 'Изменение имени в настоящее время невозможно.';
diff --git a/lib/plugins/usermanager/lang/sk/lang.php b/lib/plugins/usermanager/lang/sk/lang.php
index 2c466c984ef25019c81f74275a76ab7bdfdf536e..96f8fb60e6e76cdf141a7a243f4365e46132519f 100644
--- a/lib/plugins/usermanager/lang/sk/lang.php
+++ b/lib/plugins/usermanager/lang/sk/lang.php
@@ -3,10 +3,10 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Martin Michalek <michalek.dev@gmail.com>
  * @author Ondrej Végh <ov@vsieti.sk>
  * @author Michal Mesko <michal.mesko@gmail.com>
- * @author exusik@gmail.com
- * @author Martin Michalek <michalek.dev@gmail.com>
+ * @author exusik <exusik@gmail.com>
  */
 $lang['menu']                  = 'Správa používateľov';
 $lang['noauth']                = '(autentifikácia užívateľov nie je dostupná)';
@@ -67,3 +67,8 @@ $lang['import_error_readfail'] = 'Import neúspešný. Nie je možné prečíta
 $lang['import_error_create']   = 'Nie je možné vytvoriť pouzívateľa';
 $lang['import_notify_fail']    = 'Správa nemohla byť zaslaná importovanému používatelovi, %s s emailom %s.';
 $lang['import_downloadfailures'] = 'Stiahnuť chyby vo formáte CSV za účelom opravy';
+$lang['addUser_error_modPass_disabled'] = 'Zmena hesla nie je momentálne povolená';
+$lang['addUser_error_name_missing'] = 'Prosím zadajte meno nového používateľa.';
+$lang['addUser_error_modName_disabled'] = 'Zmena mena nie je momentálne povolená.';
+$lang['addUser_error_mail_missing'] = 'Prosím zadajte emailovú adresu nového používateľa.';
+$lang['addUser_error_modMail_disabled'] = 'Zmena emailovej adresy nie je momentálne povolená.';
diff --git a/lib/plugins/usermanager/lang/sl/lang.php b/lib/plugins/usermanager/lang/sl/lang.php
index a10488e75b6598f6edbbb726113c76db1f3888e6..4a58218a8f5f137eae4ef100ab20fe5871365e84 100644
--- a/lib/plugins/usermanager/lang/sl/lang.php
+++ b/lib/plugins/usermanager/lang/sl/lang.php
@@ -2,13 +2,12 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Dejan Levec <webphp@gmail.com>
  * @author Boštjan Seničar <senicar@gmail.com>
  * @author Gregor Skumavc (grega.skumavc@gmail.com)
  * @author Matej Urbančič (mateju@svn.gnome.org)
  * @author Matej Urbančič <mateju@svn.gnome.org>
- * @author matej <mateju@svn.gnome.org>
  */
 $lang['menu']                  = 'Upravljanje uporabnikov';
 $lang['noauth']                = '(overjanje istovetnosti uporabnikov ni na voljo)';
diff --git a/lib/plugins/usermanager/lang/sv/lang.php b/lib/plugins/usermanager/lang/sv/lang.php
index 340886578c43ade6a474f5bfa8d118e15f4d9c9b..f8ff9108b55b2400e76b4ac41acd29ad120c7772 100644
--- a/lib/plugins/usermanager/lang/sv/lang.php
+++ b/lib/plugins/usermanager/lang/sv/lang.php
@@ -2,21 +2,17 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
  * @author Per Foreby <per@foreby.se>
  * @author Nicklas Henriksson <nicklas[at]nihe.se>
  * @author HÃ¥kan Sandell <hakan.sandell@home.se>
  * @author Dennis Karlsson
  * @author Tormod Otter Johansson <tormod@latast.se>
- * @author emil@sys.nu
  * @author Pontus Bergendahl <pontus.bergendahl@gmail.com>
- * @author Tormod Johansson tormod.otter.johansson@gmail.com
  * @author Emil Lind <emil@sys.nu>
  * @author Bogge Bogge <bogge@bogge.com>
  * @author Peter Åström <eaustreum@gmail.com>
- * @author mikael@mallander.net
- * @author Smorkster Andersson smorkster@gmail.com
- * @author Tor Härnqvist <tor.harnqvist@gmail.com>
  */
 $lang['menu']                  = 'Hantera användare';
 $lang['noauth']                = '(användarautentisering ej tillgänlig)';
@@ -63,6 +59,7 @@ $lang['add_ok']                = 'Användaren tillagd';
 $lang['add_fail']              = 'Användare kunde inte läggas till';
 $lang['notify_ok']             = 'E-postmeddelande skickat';
 $lang['notify_fail']           = 'E-postmeddelande kunde inte skickas';
+$lang['import_userlistcsv']    = 'Fillista över användare (CSV):';
 $lang['import_success_count']  = 'Användar-import: %d användare funna, %d importerade framgångsrikt.';
 $lang['import_failure_count']  = 'Användar-import: %d misslyckades. Misslyckandena listas nedan.';
 $lang['import_error_baduserid'] = 'Användar-id saknas';
@@ -71,3 +68,6 @@ $lang['import_error_badmail']  = 'Felaktig e-postadress';
 $lang['import_error_upload']   = 'Import misslyckades. Csv-filen kunde inte laddas upp eller är tom.';
 $lang['import_error_readfail'] = 'Import misslyckades. Den uppladdade filen gick inte att läsa.';
 $lang['import_error_create']   = 'Misslyckades att skapa användaren.';
+$lang['addUser_error_pass_not_identical'] = 'De angivna lösenorden var inte identiska.';
+$lang['addUser_error_name_missing'] = 'Var god fyll i namn på den nya användaren.';
+$lang['addUser_error_mail_missing'] = 'Var god fyll i e-postadress för den nya användaren.';
diff --git a/lib/plugins/usermanager/lang/uk/lang.php b/lib/plugins/usermanager/lang/uk/lang.php
index 3afb7b7d6f866b1e5b90726cd22a53d18a72c76a..36b6f740799c4589a8c4fa05f03e929bee72957c 100644
--- a/lib/plugins/usermanager/lang/uk/lang.php
+++ b/lib/plugins/usermanager/lang/uk/lang.php
@@ -2,13 +2,10 @@
 
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * 
+ *
  * @author Oleksiy Voronin <ovoronin@gmail.com>
- * @author serg_stetsuk@ukr.net
- * @author okunia@gmail.com
+ * @author serg_stetsuk <serg_stetsuk@ukr.net>
  * @author Oleksandr Kunytsia <okunia@gmail.com>
- * @author Uko uko@uar.net
- * @author Ulrikhe Lukoie  <lukoie@gmail>.com
  */
 $lang['menu']                  = 'Керування користувачами';
 $lang['noauth']                = '(автентифікація користувачів не	доступна)';
diff --git a/lib/plugins/usermanager/lang/zh/lang.php b/lib/plugins/usermanager/lang/zh/lang.php
index 8f7e4fe04df9a3d2eaa4e66ec72bcd2f99a24651..5e9aa77b623c5e6856bd803ebfa134e1ee234a3b 100644
--- a/lib/plugins/usermanager/lang/zh/lang.php
+++ b/lib/plugins/usermanager/lang/zh/lang.php
@@ -5,15 +5,11 @@
  *
  * @author ZDYX <zhangduyixiong@gmail.com>
  * @author http://www.chinese-tools.com/tools/converter-tradsimp.html
- * @author George Sheraton guxd@163.com
  * @author Simon zhan <simonzhan@21cn.com>
- * @author mr.jinyi@gmail.com
  * @author ben <ben@livetom.com>
  * @author lainme <lainme993@gmail.com>
  * @author caii <zhoucaiqi@gmail.com>
  * @author Hiphen Lee <jacob.b.leung@gmail.com>
- * @author caii, patent agent in China <zhoucaiqi@gmail.com>
- * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author Rachel <rzhang0802@gmail.com>
  * @author Yangyu Huang <yangyu.huang@gmail.com>
diff --git a/lib/scripts/media.js b/lib/scripts/media.js
index 89925d8c81dbdea6e7e1806f3563809a6a539503..1e9d0328f48b3e5db81dcb5729c1ef77f8c5f203 100644
--- a/lib/scripts/media.js
+++ b/lib/scripts/media.js
@@ -272,7 +272,8 @@ var dw_mediamanager = {
         cb = String.prototype.match.call(document.location, /&onselect=([^&]+)/);
         cb = cb ? cb[1].replace(/[^\w]+/, '') : 'dw_mediamanager_item_select';
 
-        opener[cb](edid, id, opts, dw_mediamanager.align);
+        // arguments here only match the dw_mediamanager_item_select function, these will need to change if you override cb with onselect GET param
+        opener[cb](edid, id, opts, dw_mediamanager.align, dw_mediamanager.keepopen);
         if (!dw_mediamanager.keepopen) {
             window.close();
         }
@@ -937,14 +938,28 @@ var dw_mediamanager = {
  * @param {string} opts
  * @param {string} align [none, left, center, right]
  */
-function dw_mediamanager_item_select(edid, mediaid, opts, align) {
+function dw_mediamanager_item_select(edid, mediaid, opts, align, keepopen) {
     var alignleft = '';
     var alignright = '';
+
+    // Get the 2 characters after the cursor to check if we're currently inside an image tag
+    var cursorInImageTag = false;
+    var textArea = jQuery('#' + edid)[0];
+    var selection = DWgetSelection(textArea);
+    selection.end = selection.end + 2;
+    var charsAfterCursor = selection.getText();
+    if (charsAfterCursor === '}}') {
+        cursorInImageTag = true;
+    }
+
     if (align !== '1') {
         alignleft = align === '2' ? '' : ' ';
         alignright = align === '4' ? '' : ' ';
     }
-
+    if (keepopen && cursorInImageTag) {
+        selection.start = selection.start + 2;
+        DWsetSelection(selection);
+    }
     insertTags(edid, '{{' + alignleft + mediaid + opts + alignright + '|', '}}', '');
 }
 
diff --git a/lib/scripts/script.js b/lib/scripts/script.js
index 5fddb0431de209770ab0ef3900065f51cf18629c..97edef0b7c64d95ad6794c74abd6f2b212de17a0 100644
--- a/lib/scripts/script.js
+++ b/lib/scripts/script.js
@@ -18,39 +18,6 @@ if (clientPC.indexOf('opera')!=-1) {
     var is_opera_seven = (window.opera && document.childNodes);
 }
 
-/**
- * Prints a animated gif to show the search is performed
- *
- * Because we need to modify the DOM here before the document is loaded
- * and parsed completely we have to rely on document.write()
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function showLoadBar(){
-
-  document.write('<img src="'+DOKU_BASE+'lib/images/loading.gif" '+
-                 'width="150" height="12" alt="..." />');
-
-  /* this does not work reliable in IE
-  obj = $(id);
-
-  if(obj){
-    obj.innerHTML = '<img src="'+DOKU_BASE+'lib/images/loading.gif" '+
-                    'width="150" height="12" alt="..." />';
-    obj.style.display="block";
-  }
-  */
-}
-
-/**
- * Disables the animated gif to show the search is done
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function hideLoadBar(id){
-  jQuery('#' + id).hide();
-}
-
 /**
  * Handler to close all open Popups
  */
diff --git a/lib/scripts/search.js b/lib/scripts/search.js
new file mode 100644
index 0000000000000000000000000000000000000000..363170825a2d3090cfdb560e28fb6f164c0e3073
--- /dev/null
+++ b/lib/scripts/search.js
@@ -0,0 +1,48 @@
+jQuery(function () {
+    'use strict';
+
+    const $searchForm = jQuery('.search-results-form');
+    if (!$searchForm.length) {
+        return;
+    }
+
+    const $toggleAssistanceButton = jQuery('<button>')
+        .addClass('toggleAssistant')
+        .attr('type', 'button')
+        .attr('aria-expanded', 'false')
+        .text(LANG.search_toggle_tools)
+        .prependTo($searchForm.find('fieldset'))
+    ;
+
+    $toggleAssistanceButton.on('click', function () {
+        jQuery('.advancedOptions').toggle(0, function () {
+            var $me = jQuery(this);
+            if ($me.attr('aria-hidden')) {
+                $me.removeAttr('aria-hidden');
+                $toggleAssistanceButton.attr('aria-expanded', 'true');
+                DokuCookie.setValue('sa', 'on');
+            } else {
+                $me.attr('aria-hidden', 'true');
+                $toggleAssistanceButton.attr('aria-expanded', 'false');
+                DokuCookie.setValue('sa', 'off');
+            }
+        });
+    });
+
+    if (DokuCookie.getValue('sa') === 'on') {
+        $toggleAssistanceButton.click();
+    }
+
+    $searchForm.find('.advancedOptions .toggle div.current').on('click', function () {
+        var $me = jQuery(this);
+        $me.parent().siblings().removeClass('open');
+        $me.parent().siblings().find('ul:first').attr('aria-expanded', 'false');
+        $me.parent().toggleClass('open');
+        if ($me.parent().hasClass('open')) {
+            $me.parent().find('ul:first').attr('aria-expanded', 'true');
+        } else {
+            $me.parent().find('ul:first').attr('aria-expanded', 'false');
+        }
+    });
+
+});
diff --git a/lib/styles/all.css b/lib/styles/all.css
index ff4bd245792a3c62b4b57cd7faa6550e1116eacc..1ae9a02c587fdbdb50acbd709368cfb7513ec512 100644
--- a/lib/styles/all.css
+++ b/lib/styles/all.css
@@ -54,6 +54,9 @@ div.no {
 .leftalign   { text-align: left;   }
 .centeralign { text-align: center; }
 .rightalign  { text-align: right;  }
+[dir=rtl] .leftalign   { text-align: left;   }
+[dir=rtl] .centeralign { text-align: center; }
+[dir=rtl] .rightalign  { text-align: right;  }
 
 /* underline */
 em.u {
diff --git a/lib/tpl/dokuwiki/css/_search.css b/lib/tpl/dokuwiki/css/_search.css
deleted file mode 100644
index a8972ae725868eea71fa4d3742b2d412b509f11a..0000000000000000000000000000000000000000
--- a/lib/tpl/dokuwiki/css/_search.css
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * This file provides styles for the search results page (?do=search)
- * and the AJAX search popup.
- */
-
-/* search results page
-********************************************************************/
-
-/* loading gif */
-#dw__loading {
-    text-align: center;
-    margin-bottom: 1.4em;
-}
-
-/*____________ matching pagenames ____________*/
-
-.dokuwiki div.search_quickresult {
-    margin-bottom: 1.4em;
-}
-.dokuwiki div.search_quickresult h3 {
-}
-.dokuwiki div.search_quickresult ul {
-    padding: 0;
-}
-.dokuwiki div.search_quickresult ul li {
-    float: left;
-    width: 12em;
-    margin: 0 1.5em;
-}
-[dir=rtl] .dokuwiki div.search_quickresult ul li {
-    float: right;
-}
-
-/*____________ search results ____________*/
-
-.dokuwiki dl.search_results {
-    margin-bottom: 1.2em;
-}
-
-/* search heading */
-.dokuwiki dl.search_results dt {
-    font-weight: normal;
-    margin-bottom: .2em;
-}
-/* search snippet */
-.dokuwiki dl.search_results dd {
-    color: @ini_text_alt;
-    background-color: inherit;
-    margin: 0 0 1.2em 0;
-}
-
-/* search hit in normal text */
-.dokuwiki .search_hit {
-    color: @ini_text;
-    background-color: __highlight__;
-}
-/* search hit in search results */
-.dokuwiki .search_results strong.search_hit {
-    font-weight: normal;
-}
-/* ellipsis separating snippets */
-.dokuwiki .search_results .search_sep {
-    color: @ini_text;
-    background-color: inherit;
-}
-
-/* "nothing found" at search + media */
-.dokuwiki div.nothing {
-    margin-bottom: 1.4em;
-}
-
-
-/* AJAX quicksearch popup
-********************************************************************/
-
-.dokuwiki form.search div.no {
-    position: relative;
-}
-
-/* .JSpopup */
-.dokuwiki form.search div.ajax_qsearch {
-    position: absolute;
-    top: 0;
-    left: -13.5em; /* -( width of #qsearch__in + padding of .ajax_qsearch + a bit more ) */
-    width: 12em;
-    padding: 0.5em;
-    font-size: .9em;
-    z-index: 20;
-    text-align: left;
-    display: none;
-}
-[dir=rtl] .dokuwiki form.search div.ajax_qsearch {
-    left: auto;
-    right: -13.5em;
-    text-align: right;
-}
-.dokuwiki form.search div.ajax_qsearch strong {
-    display: block;
-    margin-bottom: .3em;
-}
-.dokuwiki form.search div.ajax_qsearch ul {
-    margin: 0 !important;
-    padding: 0 !important;
-}
-.dokuwiki form.search div.ajax_qsearch ul li {
-    margin: 0;
-    padding: 0;
-    display: block !important;
-}
diff --git a/lib/tpl/dokuwiki/css/_search.less b/lib/tpl/dokuwiki/css/_search.less
new file mode 100644
index 0000000000000000000000000000000000000000..ad41ac58193453401f58965cacf7c007bbdc0909
--- /dev/null
+++ b/lib/tpl/dokuwiki/css/_search.less
@@ -0,0 +1,201 @@
+/**
+ * This file provides styles for the search results page (?do=search)
+ * and the AJAX search popup.
+ */
+
+/* general
+********************************************************************/
+
+/* search hit in normal text */
+.dokuwiki .search_hit {
+    color: @ini_text;
+    background-color: __highlight__;
+}
+
+/* "nothing found" at search + media */
+.dokuwiki div.nothing {
+    margin-bottom: 1.4em;
+}
+
+/* search results page
+********************************************************************/
+
+/*____________ advanced search form ____________*/
+.dokuwiki .search-results-form fieldset.search-form {
+    width: 100%;
+    margin: 1em 0;
+
+    input[name="q"] {
+        width: 50%;
+    }
+
+    button.toggleAssistant {
+        float: right;
+    }
+
+    .advancedOptions {
+        padding: 1em 0;
+
+        > div {
+            display: inline-block;
+            position: relative;
+            margin: 0 0.5em;
+        }
+
+        div.toggle {
+            // default closed toggle state
+            div.current {
+                cursor: pointer;
+                max-width: 10em;
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+
+                &::after {
+                    content: 'â–¼';
+                    font-size: smaller;
+                    color: @ini_text_alt;
+                }
+            }
+            div.changed {
+                font-weight: bold;
+            }
+            ul {
+                display: none;
+                position: absolute;
+                border: 1px solid @ini_border;
+                background-color: @ini_background;
+                padding: 0.25em 0.5em;
+                text-align: left;
+                min-width: 10em;
+                max-width: 15em;
+                max-height: 50vh;
+                overflow: auto;
+                z-index: 100;
+                li {
+                    margin: 0.25em 0;
+                    list-style: none;
+
+                    a {
+                        display: block;
+                    }
+                }
+            }
+
+            // open toggle state
+            &.open {
+                div.current::after {
+                    content: 'â–²';
+                }
+
+                ul {
+                    display: block;
+                }
+            }
+        }
+    }
+}
+
+[dir=rtl] .search-results-form fieldset.search-form .advancedOptions {
+    div.toggle ul {
+        text-align: right;
+    }
+}
+
+
+/*____________ matching pagenames ____________*/
+
+.dokuwiki div.search_quickresult {
+    margin-bottom: 1.4em;
+
+    h3 {
+    }
+    ul {
+        padding: 0;
+
+        li {
+            float: left;
+            width: 12em;
+            margin: 0 1.5em;
+        }
+    }
+}
+
+[dir=rtl] .dokuwiki div.search_quickresult ul li {
+    float: right;
+}
+
+/*____________ search results ____________*/
+
+.dokuwiki dl.search_results {
+    margin-bottom: 1.2em;
+
+    /* search heading */
+    dt {
+        font-weight: normal;
+        margin-bottom: .2em;
+    }
+
+    /* search snippet */
+    dd {
+        color: @ini_text_alt;
+        background-color: inherit;
+        margin: 0 0 1.2em 0;
+
+        /* search hit in search results */
+        strong.search_hit {
+            font-weight: normal;
+            /* color is set in general */
+        }
+
+        /* ellipsis separating snippets */
+        .search_sep {
+            color: @ini_text;
+            background-color: inherit;
+        }
+    }
+}
+
+/* AJAX quicksearch popup
+********************************************************************/
+
+.dokuwiki form.search {
+    div.no {
+        position: relative;
+    }
+
+    /* .JSpopup */
+    div.ajax_qsearch {
+        position: absolute;
+        top: 0;
+        left: -13.5em; /* -( width of #qsearch__in + padding of .ajax_qsearch + a bit more ) */
+        width: 12em;
+        padding: 0.5em;
+        font-size: .9em;
+        z-index: 20;
+        text-align: left;
+        display: none;
+
+        strong {
+            display: block;
+            margin-bottom: .3em;
+        }
+
+        ul {
+            margin: 0 !important;
+            padding: 0 !important;
+
+            li {
+                margin: 0;
+                padding: 0;
+                display: block !important;
+            }
+        }
+    }
+}
+
+[dir=rtl] .dokuwiki form.search div.ajax_qsearch {
+    left: auto;
+    right: -13.5em;
+    text-align: right;
+}
diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less
index 694f9aa92b5360e92d752b3c4296f57af67818b3..89f671b7c69568fa004cf2f272e8abd29a5d16fc 100644
--- a/lib/tpl/dokuwiki/css/design.less
+++ b/lib/tpl/dokuwiki/css/design.less
@@ -106,84 +106,10 @@
     margin-left: 0;
 }
 
-#dokuwiki__usertools a.action,
-#dokuwiki__usertools a.iw_user {
-    padding-left: 20px;
-    background: transparent url(images/usertools.png) no-repeat 0 0;
-}
-
-[dir=rtl] #dokuwiki__usertools a.action {
-    padding-left: 0;
-    padding-right: 20px;
-}
-
 #dokuwiki__header .mobileTools {
     display: none; /* hide mobile tools dropdown to only show in mobile view */
 }
 
-/*____________ user tools ____________*/
-
-#dokuwiki__usertools {
-    position: absolute;
-    top: .5em;
-    right: .5em;
-    text-align: right;
-    width: 100%;
-
-    ul {
-        margin: 0 auto;
-        padding: 0;
-        max-width: @ini_site_width;
-    }
-
-    a.action.admin {
-        background-position: left 0;
-    }
-
-    a.iw_user,
-    a.action.profile {
-        background-position: left -32px;
-    }
-
-    a.action.register {
-        background-position: left -64px;
-    }
-
-    a.action.login {
-        background-position: left -96px;
-    }
-
-    a.action.logout {
-        background-position: left -128px;
-    }
-}
-
-[dir=rtl] #dokuwiki__usertools {
-    text-align: left;
-    left: 40px;
-    right: auto;
-
-    a.action.admin {
-        background-position: right 0;
-    }
-
-    a.action.profile {
-        background-position: right -32px;
-    }
-
-    a.action.register {
-        background-position: right -64px;
-    }
-
-    a.action.login {
-        background-position: right -96px;
-    }
-
-    a.action.logout {
-        background-position: right -128px;
-    }
-}
-
 /*____________ site tools ____________*/
 
 #dokuwiki__sitetools {
diff --git a/lib/tpl/dokuwiki/css/pagetools.less b/lib/tpl/dokuwiki/css/pagetools.less
index f441a13638d7db0383c7e0bf44994fcd25941f13..2aaf0b978d94ca3787b038488931d0e67f0bfc3b 100644
--- a/lib/tpl/dokuwiki/css/pagetools.less
+++ b/lib/tpl/dokuwiki/css/pagetools.less
@@ -13,203 +13,112 @@
     /* give the same space to the left to balance it out */
     padding-left: 40px;
 }
+
 .dokuwiki div.page {
     height: 190px;
     min-height: 190px; /* 30 (= height of icons) x 6 (= maximum number of possible tools) + 2x5 */
     height: auto;
 }
-#dokuwiki__usertools {
-    /* move the tools just outside of the site */
-    right: 40px;
-}
-[dir=rtl] #dokuwiki__usertools {
-    right: auto;
-    left: 40px;
-}
-
 
 #dokuwiki__pagetools {
+    @ico-width: 28px;
+    @ico-margin: 8px;
+    @item-width: (@ico-width + @ico-margin + @ico-margin);
+    @item-height: (@ico-width + @ico-margin);
+
     position: absolute;
-    right: -40px;
+    right: (-1 * @item-width);
     /* on same vertical level as first headline, because .page has 2em padding */
     top: 2em;
-    width: 40px;
-}
-[dir=rtl] #dokuwiki__pagetools {
-    right: auto;
-    left: -40px;
-}
-
-#dokuwiki__pagetools div.tools {
-    position: fixed;
-    width: 40px;
-}
-
-#dokuwiki__pagetools ul {
-    position: absolute;
-    right: 0;
-    text-align: right;
-    margin: 0;
-    padding: 0;
-    /* add transparent border to prevent jumping when proper border is added on hover */
-    border: 1px solid transparent;
-    z-index: 10;
-}
-[dir=rtl] #dokuwiki__pagetools ul {
-    right: auto;
-    left: 0;
-    text-align: left;
-}
-
-#dokuwiki__pagetools ul li {
-    padding: 0;
-    margin: 0;
-    list-style: none;
-    font-size: 0.875em;
-}
-
-#dokuwiki__pagetools ul li a {
-    display: block;
-    min-height: 20px; /* 30 - 2x5 */
-    line-height: 20px;
-    padding: 0;
-    background-position: right 0;
-    background-repeat: no-repeat;
-    /* add transparent border to prevent jumping when proper border is added on focus */
-    border: 1px solid transparent;
-    white-space: nowrap;
-    width: 30px;
-    height: 30px;
-    overflow: hidden;
-    margin-left: auto; /* align right if the ul is larger because one item is focused */
-}
-
-#dokuwiki__pagetools ul li a:before {
-    content: url(images/pagetools-sprite.png?v=2);
-    display: inline-block;
-    font-size: 0;
-    line-height: 0;
-}
-
-[dir=rtl] #dokuwiki__pagetools ul li a {
-    background-position: left 0;
-    margin-right: auto;
-    margin-left: 0;
-}
-
-/* show all tools on hover and individual tools on focus */
-#dokuwiki__pagetools:hover ul,
-#dokuwiki__pagetools ul li a:focus,
-#dokuwiki__pagetools ul li a:active {
-    background-color: @ini_background;
-    border-color: @ini_border;
-    border-radius: 2px;
-    box-shadow: 2px 2px 2px @ini_text_alt;
-}
-
-#dokuwiki__pagetools:hover ul li a,
-#dokuwiki__pagetools ul li a:focus,
-#dokuwiki__pagetools ul li a:active {
-    width: auto;
-    height: auto;
-    overflow: visible;
-    padding: 5px 40px 5px 5px;
-    background-image: url(images/pagetools-sprite.png?v=2);
-}
-
-#dokuwiki__pagetools:hover ul li a:before,
-#dokuwiki__pagetools ul li a:focus:before {
-    content: none;
-}
-
-[dir=rtl] #dokuwiki__pagetools:hover ul,
-[dir=rtl] #dokuwiki__pagetools ul li a:focus {
-    box-shadow: -2px 2px 2px @ini_text_alt;
-}
-
-[dir=rtl] #dokuwiki__pagetools:hover li a,
-[dir=rtl] #dokuwiki__pagetools ul li a:focus,
-[dir=rtl] #dokuwiki__pagetools ul li a:active {
-    padding: 5px 5px 5px 40px;
-}
-
-#dokuwiki__pagetools ul li a:hover,
-#dokuwiki__pagetools ul li a:active,
-#dokuwiki__pagetools ul li a:focus {
-    text-decoration: none;
-}
-#dokuwiki__pagetools ul li a:hover {
-    background-color: @ini_background_alt;
-}
-
-/*____________ all available icons in sprite ____________*/
-
-@pagetools_icon_space: -90px;
-
-/**
- * page tools without highlighting
- *
- * @param string @action The action class
- * @param int @position Position in the page tools sprite
- */
-.pagetools-item(@action, @position) {
-    @position-active: (@position+0.5);
-
-    #dokuwiki__pagetools ul li a.@{action} {
-        background-position: right @pagetools_icon_space * @position;
-
-        &:before {
-            margin-top: @pagetools_icon_space * @position;
-        }
-        &:hover,
-        &:active,
-        &:focus {
-            background-position: right @pagetools_icon_space * @position-active;
+    width: @item-width;
+
+    div.tools {
+        position: fixed;
+        width: @item-width;
+
+        ul {
+            position: absolute;
+            right: 0;
+            text-align: right;
+            margin: 0;
+            padding: 0;
+            /* add transparent border to prevent jumping when proper border is added on hover */
+            border: 1px solid transparent;
+            z-index: 10;
+
+            li {
+                padding: 0;
+                margin: 0;
+                list-style: none;
+                font-size: 0.875em;
+
+                a {
+
+                    display: block;
+                    /* add transparent border to prevent jumping when proper border is added on focus */
+                    border: 1px solid transparent;
+                    white-space: nowrap;
+                    line-height: @item-height;
+                    vertical-align: middle;
+                    height: @item-height;
+
+                    span {
+                        display: none; // hide label until hover
+                        margin: 0 @ico-margin;
+                    }
+
+                    svg {
+                        width: @ico-width;
+                        height: @ico-width;
+                        margin: 0 @ico-margin;
+                        display: inline-block;
+                        vertical-align: middle;
+                        fill: @ini_border;
+                    }
+                }
+
+                // on interaction show the full item
+                a:active,
+                a:focus,
+                a:hover {
+                    background-color: @ini_background_alt;
+
+                    span {
+                        display: inline-block;
+                    }
+
+                    svg {
+                        fill: @ini_link;
+                    }
+                }
+            }
         }
     }
-    [dir=rtl] #dokuwiki__pagetools ul li a.@{action} {
-        background-position: left @pagetools_icon_space * @position;
 
-        &:hover,
-        &:active,
-        &:focus {
-            background-position: left @pagetools_icon_space * @position-active;
+    [dir=rtl] & {
+        right: auto;
+        left: (-1 * @item-width);
+
+        div.tools {
+            ul {
+                right: auto;
+                left: 0;
+                text-align: left;
+            }
         }
     }
 }
 
-/**
- * page tools with highlighting
- *
- * @param string @action The action class
- * @param int @position Position in the page tools sprite
- * @param string @mode The mode in which this tool should be highlighted
- */
-.pagetools-item(@action, @position, @mode) {
-  .pagetools-item(@action, @position);
-  @position-active: (@position+0.5);
-
-  .mode_@{mode} #dokuwiki__pagetools ul li a.@{action} {
-    background-position: right @pagetools_icon_space * @position-active;
-    &:before {
-      margin-top: @pagetools_icon_space * @position-active;
+// on hover show all items
+#dokuwiki__pagetools:hover {
+    div.tools ul {
+        background-color: @ini_background;
+        border-color: @ini_border;
+        border-radius: 2px;
+        box-shadow: 2px 2px 2px @ini_text_alt;
+
+        li a span {
+            display: inline-block;
+        }
     }
-  }
-  [dir=rtl] .mode_@{mode} #dokuwiki__pagetools ul li a.@{action} {
-    background-position: left @pagetools_icon_space * @position-active;
-  }
 }
-
-.pagetools-item(edit, 1);
-.pagetools-item(create, 2);
-.pagetools-item(show, 4);
-.pagetools-item(source, 5);
-.pagetools-item(draft, 3);
-.pagetools-item(revs, 7, revisions);
-.pagetools-item(backlink, 8, backlink);
-.pagetools-item(top, 10);
-.pagetools-item(revert, 6, revert);
-.pagetools-item(subscribe, 9, subscribe);
-.pagetools-item(mediaManager, 11);
-.pagetools-item(back, 12);
-.pagetools-item(img_backto, 12);
diff --git a/lib/tpl/dokuwiki/css/usertools.less b/lib/tpl/dokuwiki/css/usertools.less
new file mode 100644
index 0000000000000000000000000000000000000000..efdf16c0ecbae2893f4288e2b1cae7d825ea1a3c
--- /dev/null
+++ b/lib/tpl/dokuwiki/css/usertools.less
@@ -0,0 +1,50 @@
+#dokuwiki__usertools {
+    position: absolute;
+    top: .5em;
+    right: 40px; // pagetool width
+    text-align: right;
+    width: 100%;
+
+    ul {
+        margin: 0 auto;
+        padding: 0;
+        max-width: @ini_site_width;
+    }
+
+    li.action a {
+        display: inline-flex;
+        flex-direction: row-reverse;
+        flex-wrap: nowrap;
+
+        svg {
+            height: 1.4em;
+            width: 1.4em;
+            vertical-align: middle;
+            fill: @ini_border;
+            margin-right: 0.2em;
+        }
+    }
+
+    li.action a:hover,
+    li.action a:active {
+        svg {
+            fill: @ini_link;
+        }
+    }
+
+}
+
+[dir=rtl] #dokuwiki__usertools {
+    text-align: left;
+    left: 40px; // pagetool width
+    right: auto;
+
+
+    li.action a {
+
+        svg {
+            margin-right: 0;
+            margin-left: 0.2em;
+        }
+    }
+}
diff --git a/lib/tpl/dokuwiki/detail.php b/lib/tpl/dokuwiki/detail.php
index c26d81cb72b34c1af1fb0b36c02442072b3e8bd2..8e65410d71ba0036ab4414d449e5e0a17172f3b4 100644
--- a/lib/tpl/dokuwiki/detail.php
+++ b/lib/tpl/dokuwiki/detail.php
@@ -92,24 +92,7 @@ header('X-UA-Compatible: IE=edge,chrome=1');
                     <h3 class="a11y"><?php echo $lang['page_tools']; ?></h3>
                     <div class="tools">
                         <ul>
-                            <?php
-                                $data = array(
-                                    'view' => 'detail',
-                                    'items' => array(
-                                        'mediaManager' => tpl_action('mediaManager', true, 'li', true, '<span>', '</span>'),
-                                        'img_backto' =>   tpl_action('img_backto',   true, 'li', true, '<span>', '</span>'),
-                                    )
-                                );
-
-                                // the page tools can be amended through a custom plugin hook
-                                $evt = new Doku_Event('TEMPLATE_PAGETOOLS_DISPLAY', $data);
-                                if($evt->advise_before()) {
-                                    foreach($evt->data['items'] as $k => $html) echo $html;
-                                }
-                                $evt->advise_after();
-                                unset($data);
-                                unset($evt);
-                            ?>
+                            <?php echo (new \dokuwiki\Menu\DetailMenu())->getListItems(); ?>
                         </ul>
                     </div>
                 </div>
diff --git a/lib/tpl/dokuwiki/lang/de-informal/lang.php b/lib/tpl/dokuwiki/lang/de-informal/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..d8c35833aa0da998b020febf22feb56dea2e6e4c
--- /dev/null
+++ b/lib/tpl/dokuwiki/lang/de-informal/lang.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
+ */
+$lang['__background_site__']   = 'Farbe für den Seitenhintergrund (hinter dem Inhaltsbereich)';
+$lang['__link__']              = 'Allgemeine Linkfarbe';
+$lang['__existing__']          = 'Farbe für Links zu existierenden Seiten';
+$lang['__missing__']           = 'Farbe für Links zu nicht-existierenden Seiten';
+$lang['__site_width__']        = 'Breite der ganzen Seite (kann eine beliebige Längeneinheit sein: %, px, em, ...)';
+$lang['__sidebar_width__']     = 'Breite der Seitenleiste, falls vorhanden (kann eine beliebige Längeneinheit sein: %, px, em, ...)';
+$lang['__tablet_width__']      = 'Unter dieser Fensterbreite wechselt die Seite in den Tabletmodus';
+$lang['__phone_width__']       = 'Unter dieser Fensterbreite wechselt die Seite in den Handymodus';
diff --git a/lib/tpl/dokuwiki/lang/de-informal/style.txt b/lib/tpl/dokuwiki/lang/de-informal/style.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b2470034e55ea796870ee8275530798750dc6fe8
--- /dev/null
+++ b/lib/tpl/dokuwiki/lang/de-informal/style.txt
@@ -0,0 +1 @@
+Benutze einfach den Medien-Manager, um ein ''logo.png'' in den ''wiki''- oder obersten Namensraum hochzuladen, wenn du das Logo anpassen willst. Es wird dann automatisch als Logo verwendet. Alternativ kannst du dort auch ein 'favicon.ico'' hochladen. Falls du ein geschlossenes Wiki betreibst, ist es empfehlenswert, den ''wiki''- (oder Wurzel-)Namensraum für alle Nutzer in den ACL-Einstellungen als lesbar zu öffnen. Ansonsten wird das Logo nur für eingeloggte Nutzer angezeigt.
\ No newline at end of file
diff --git a/lib/tpl/dokuwiki/lang/en/lang.php b/lib/tpl/dokuwiki/lang/en/lang.php
index b7b3e7fa114604a0bb9c32749884e4a25ba0d0ed..7c890c6513a9d12cc276d4a817a19201bc915a0c 100644
--- a/lib/tpl/dokuwiki/lang/en/lang.php
+++ b/lib/tpl/dokuwiki/lang/en/lang.php
@@ -10,3 +10,4 @@ $lang['__site_width__']    = 'The width of the full site (can be any length unit
 $lang['__sidebar_width__'] = 'The width of the sidebar, if any (can be any length unit: %, px, em, ...)';
 $lang['__tablet_width__']  = 'Below screensizes of this width, the site switches to tablet mode';
 $lang['__phone_width__']   = 'Below screensizes of this width, the site switches to phone mode';
+$lang['__theme_color__']   = 'Theme color of the web app';
diff --git a/lib/tpl/dokuwiki/lang/fr/style.txt b/lib/tpl/dokuwiki/lang/fr/style.txt
index 876f116c9ac0177e81ccf8949342c8254e1933d3..9034cbc531c0a30a9f697c6d2337ecb819f56b9f 100644
--- a/lib/tpl/dokuwiki/lang/fr/style.txt
+++ b/lib/tpl/dokuwiki/lang/fr/style.txt
@@ -1 +1 @@
-Si vous souhaitez modifier le logo, utilisez simplement le gestionnaire de médias et envoyez un fichier nommé "logo.png" dans l'espace de nom "wiki" ou à la racine. Il sera automatiquement utilisé. Il en est de même pour le "favicon.ico". Si vous utilisez un wiki fermé, il est recommandé de régler les ACL de la racine ou de l'espace de nom "wiki" pour rendre ces images visibles aux utilisateurs non connectés.
\ No newline at end of file
+Si vous souhaitez modifier le logo, utilisez simplement le gestionnaire de médias et envoyez un fichier nommé "logo.png" dans la catégorie "wiki" ou à la racine. Il sera automatiquement utilisé. Il en est de même pour le "favicon.ico". Si vous utilisez un wiki fermé, il est recommandé de régler les ACL de la racine ou de la catégorie "wiki" pour rendre ces images visibles aux utilisateurs non connectés.
\ No newline at end of file
diff --git a/lib/tpl/dokuwiki/lang/pl/lang.php b/lib/tpl/dokuwiki/lang/pl/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..ffff09f58d6cccdfebc60f2f22c57d518976b270
--- /dev/null
+++ b/lib/tpl/dokuwiki/lang/pl/lang.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Wojciech Lichota <wojciech@lichota.pl>
+ */
+$lang['__background_site__']   = 'Kolor tła za polem zawartości';
+$lang['__link__']              = 'Kolor łącza';
+$lang['__existing__']          = 'Kolor łącza do istniejącej strony';
+$lang['__missing__']           = 'Kolor łącza do nieistniejącej strony';
+$lang['__site_width__']        = 'Szerokość pełnej strony (możliwa dowolna jednostka długości: %, px, em, ...)';
+$lang['__sidebar_width__']     = 'Szerokość paska bocznego, jeśli istnieje (możliwa dowolna jednostka długości: %, px, em, ...)';
+$lang['__tablet_width__']      = 'Szerokość ekrany poniżej której, strona przełączy się w tryb tabletu';
+$lang['__phone_width__']       = 'Szerokość ekrany poniżej której, strona przełączy się w tryb telefonu';
diff --git a/lib/tpl/dokuwiki/lang/pl/style.txt b/lib/tpl/dokuwiki/lang/pl/style.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7db04656284df1dbae3d1ccbf9b555d79e95b7de
--- /dev/null
+++ b/lib/tpl/dokuwiki/lang/pl/style.txt
@@ -0,0 +1 @@
+Jeśli chcesz dostosować logo, po użyj Menadżera multimediów, aby przesłać plik "logo.png" do "wiki" lub głównego katalogu a zostanie on automatycznie użyty. Możesz również załadować tam plik "favicon.ico". Jeśli używasz zamkniętej wiki, zaleca się, aby na liście ACL katalogu "wiki" (lub root)  włączyć prawo odczytu. W przeciwnym przypadku twoje logo nie będzie widoczne dla niezalogowanych użytkowników.
\ No newline at end of file
diff --git a/lib/tpl/dokuwiki/lang/ru/lang.php b/lib/tpl/dokuwiki/lang/ru/lang.php
index 813ac83a52e00b12289f7aa20800842ceb1e828a..18d24ae0eed7fc0f549b62d6e6859490d6413511 100644
--- a/lib/tpl/dokuwiki/lang/ru/lang.php
+++ b/lib/tpl/dokuwiki/lang/ru/lang.php
@@ -3,6 +3,7 @@
 /**
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  *
+ * @author Yuriy Skalko <yuriy.skalko@gmail.com>
  * @author RainbowSpike <1@2.ru>
  * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
  */
@@ -10,7 +11,7 @@ $lang['__background_site__']   = 'Цвет для дальнего фона (з
 $lang['__link__']              = 'Основной цвет ссылок';
 $lang['__existing__']          = 'Цвет ссылок на существующие страницы';
 $lang['__missing__']           = 'Цвет ссылок на несуществующие страницы';
-$lang['__site_width__']        = 'Ширина всего сайта (любые CSS-единицы)';
+$lang['__site_width__']        = 'Ширина всего сайта (любые CSS-единицы: %, px, em, ...)';
 $lang['__sidebar_width__']     = 'Ширина боковой панели, если есть (любые CSS-единицы)';
 $lang['__tablet_width__']      = 'Переключать сайт в планшетный вид ниже ширины';
 $lang['__phone_width__']       = 'Переключать сайт в мобильный вид ниже ширины';
diff --git a/lib/tpl/dokuwiki/lang/ru/style.txt b/lib/tpl/dokuwiki/lang/ru/style.txt
index 43bdcd162afbb47c03b2f1c6d3e53b8eda27b170..fe60415317f9138bca3e423c5a0eb0eb37227dc8 100644
--- a/lib/tpl/dokuwiki/lang/ru/style.txt
+++ b/lib/tpl/dokuwiki/lang/ru/style.txt
@@ -1 +1 @@
-Если вы хотите изменить логотип, просто используйте «Управление медиафайлами» для загрузки файла ''logo.png'' в корневое пространство имён или ''wiki'', и тогда он будет использоваться автоматически. Туда же вы можете загрузить ''favicon.ico''. Если у вас «закрытая» вики, рекомендуется указать права на «чтение» в списках контроля доступа для пространства имён ''wiki'' (или корневое), иначе логотип не будет показываться незалогинившимся пользователям.
\ No newline at end of file
+Если вы хотите изменить логотип, просто используйте «Управление медиафайлами» для загрузки файла ''logo.png'' в корневое пространство имён или ''wiki'', и тогда он будет использоваться автоматически. Туда же вы можете загрузить ''favicon.ico''. Если у вас закрытая вики, рекомендуется указать права на «чтение» в списках контроля доступа для пространства имён ''wiki'' (или корневое), иначе логотип не будет показываться незалогинившимся пользователям.
\ No newline at end of file
diff --git a/lib/tpl/dokuwiki/lang/sv/lang.php b/lib/tpl/dokuwiki/lang/sv/lang.php
new file mode 100644
index 0000000000000000000000000000000000000000..6fdf4238bf76ececbb97bfacac52b1cee6136cc3
--- /dev/null
+++ b/lib/tpl/dokuwiki/lang/sv/lang.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['__link__']              = 'Den generella länkfärgen';
+$lang['__existing__']          = 'Färg på länkar till existerande sidor';
+$lang['__missing__']           = 'Färg på länkar till sidor som inte finns';
+$lang['__site_width__']        = 'Bredden på hela webbsidan (kan anges i valfri längdenhet: %, px, em, ...)';
+$lang['__sidebar_width__']     = 'Bredden på sidokolumnen, om existerande (kan anges i valfri längdenhet: %, px, em, ...)';
diff --git a/lib/tpl/dokuwiki/main.php b/lib/tpl/dokuwiki/main.php
index d095ccf4f259e8a28d676a0ff2979b6c93c0349f..2d2151f9c496f4e41127d1580ce933d041dba6ad 100644
--- a/lib/tpl/dokuwiki/main.php
+++ b/lib/tpl/dokuwiki/main.php
@@ -73,28 +73,7 @@ $showSidebar = $hasSidebar && ($ACT=='show');
                 <h3 class="a11y"><?php echo $lang['page_tools']; ?></h3>
                 <div class="tools">
                     <ul>
-                        <?php
-                            $data = array(
-                                'view'  => 'main',
-                                'items' => array(
-                                    'edit'      => tpl_action('edit',      true, 'li', true, '<span>', '</span>'),
-                                    'revert'    => tpl_action('revert',    true, 'li', true, '<span>', '</span>'),
-                                    'revisions' => tpl_action('revisions', true, 'li', true, '<span>', '</span>'),
-                                    'backlink'  => tpl_action('backlink',  true, 'li', true, '<span>', '</span>'),
-                                    'subscribe' => tpl_action('subscribe', true, 'li', true, '<span>', '</span>'),
-                                    'top'       => tpl_action('top',       true, 'li', true, '<span>', '</span>')
-                                )
-                            );
-
-                            // the page tools can be amended through a custom plugin hook
-                            $evt = new Doku_Event('TEMPLATE_PAGETOOLS_DISPLAY', $data);
-                            if($evt->advise_before()){
-                                foreach($evt->data['items'] as $k => $html) echo $html;
-                            }
-                            $evt->advise_after();
-                            unset($data);
-                            unset($evt);
-                        ?>
+                        <?php echo (new \dokuwiki\Menu\PageMenu())->getListItems(); ?>
                     </ul>
                 </div>
             </div>
diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini
index b4432710b60c0e2e72d018901338f255dee42f54..723e8bc8fbcbaee30e7feb3490b4ee732c44be1a 100644
--- a/lib/tpl/dokuwiki/style.ini
+++ b/lib/tpl/dokuwiki/style.ini
@@ -25,7 +25,7 @@ css/_tabs.css             = screen
 css/_links.css            = screen
 css/_toc.css              = screen
 css/_footnotes.css        = screen
-css/_search.css           = screen
+css/_search.less          = screen
 css/_recent.css           = screen
 css/_diff.css             = screen
 css/_edit.css             = screen
@@ -34,6 +34,7 @@ css/_forms.css            = screen
 css/_admin.less           = screen
 css/structure.less        = screen
 css/design.less           = screen
+css/usertools.less        = screen
 css/pagetools.less        = screen
 css/content.less          = screen
 
@@ -67,12 +68,14 @@ __border__          = "#ccc"            ; @ini_border
 ; highlighted text (e.g. search snippets)
 __highlight__       = "#ff9"            ; @ini_highlight
 
+; default link color
+__link__            = "#2b73b7"         ; @ini_link
+
 ;--------------------------------------------------------------------------
 
 __background_site__ = "#fbfaf9"         ; @ini_background_site
 
-; these are used for links
-__link__            = "#2b73b7"         ; @ini_link
+; these are used for wiki links
 __existing__        = "#080"            ; @ini_existing
 __missing__         = "#d30"            ; @ini_missing
 
@@ -82,3 +85,5 @@ __sidebar_width__   = "16em"            ; @ini_sidebar_width
 ; cut off points for mobile devices
 __tablet_width__    = "800px"           ; @ini_tablet_width
 __phone_width__     = "480px"           ; @ini_phone_width
+
+__theme_color__     = "#008800"         ; @_ini_theme_color: theme_color of the web app
diff --git a/lib/tpl/dokuwiki/tpl_footer.php b/lib/tpl/dokuwiki/tpl_footer.php
index fa87c610b796ce4995a1a44d62c069aaba5d546d..34e8b90f664ebd34fb7f840c05d3f77ccb8ddd8b 100644
--- a/lib/tpl/dokuwiki/tpl_footer.php
+++ b/lib/tpl/dokuwiki/tpl_footer.php
@@ -16,15 +16,15 @@ if (!defined('DOKU_INC')) die();
             tpl_license('button', true, false, false); // license button, no wrapper
             $target = ($conf['target']['extern']) ? 'target="'.$conf['target']['extern'].'"' : '';
         ?>
-        <a href="http://www.dokuwiki.org/donate" title="Donate" <?php echo $target?>><img
+        <a href="https://www.dokuwiki.org/donate" title="Donate" <?php echo $target?>><img
             src="<?php echo tpl_basedir(); ?>images/button-donate.gif" width="80" height="15" alt="Donate" /></a>
-        <a href="http://php.net" title="Powered by PHP" <?php echo $target?>><img
+        <a href="https://php.net" title="Powered by PHP" <?php echo $target?>><img
             src="<?php echo tpl_basedir(); ?>images/button-php.gif" width="80" height="15" alt="Powered by PHP" /></a>
-        <a href="http://validator.w3.org/check/referer" title="Valid HTML5" <?php echo $target?>><img
+        <a href="//validator.w3.org/check/referer" title="Valid HTML5" <?php echo $target?>><img
             src="<?php echo tpl_basedir(); ?>images/button-html5.png" width="80" height="15" alt="Valid HTML5" /></a>
-        <a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS" <?php echo $target?>><img
+        <a href="//jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS" <?php echo $target?>><img
             src="<?php echo tpl_basedir(); ?>images/button-css.png" width="80" height="15" alt="Valid CSS" /></a>
-        <a href="http://dokuwiki.org/" title="Driven by DokuWiki" <?php echo $target?>><img
+        <a href="https://dokuwiki.org/" title="Driven by DokuWiki" <?php echo $target?>><img
             src="<?php echo tpl_basedir(); ?>images/button-dw.png" width="80" height="15" alt="Driven by DokuWiki" /></a>
     </div>
 </div></div><!-- /footer -->
diff --git a/lib/tpl/dokuwiki/tpl_header.php b/lib/tpl/dokuwiki/tpl_header.php
index 5b092c5644819d164223f08289379f4e7f7779e0..bb8732bdc994a5ba418ce0ebd4a4a19b111e8b8d 100644
--- a/lib/tpl/dokuwiki/tpl_header.php
+++ b/lib/tpl/dokuwiki/tpl_header.php
@@ -46,12 +46,7 @@ if (!defined('DOKU_INC')) die();
                             tpl_userinfo(); /* 'Logged in as ...' */
                             echo '</li>';
                         }
-                        tpl_toolsevent('usertools', array(
-                            tpl_action('admin', true, 'li', true),
-                            tpl_action('profile', true, 'li', true),
-                            tpl_action('register', true, 'li', true),
-                            tpl_action('login', true, 'li', true)
-                        ));
+                        echo (new \dokuwiki\Menu\UserMenu())->getListItems('action ');
                     ?>
                 </ul>
             </div>
@@ -62,16 +57,10 @@ if (!defined('DOKU_INC')) die();
             <h3 class="a11y"><?php echo $lang['site_tools']; ?></h3>
             <?php tpl_searchform(); ?>
             <div class="mobileTools">
-                <?php tpl_actiondropdown($lang['tools']); ?>
+                <?php echo (new \dokuwiki\Menu\MobileMenu())->getDropdown($lang['tools']); ?>
             </div>
             <ul>
-                <?php
-                    tpl_toolsevent('sitetools', array(
-                        tpl_action('recent', true, 'li', true),
-                        tpl_action('media', true, 'li', true),
-                        tpl_action('index', true, 'li', true)
-                    ));
-                ?>
+                <?php echo (new \dokuwiki\Menu\SiteMenu())->getListItems('action ', false); ?>
             </ul>
         </div>
 
diff --git a/lib/tpl/index.php b/lib/tpl/index.php
index 558f262a7ad4fa090234db761ab67d2048764022..fb368840e6ceee26e5b7499954301b108138f16c 100644
--- a/lib/tpl/index.php
+++ b/lib/tpl/index.php
@@ -50,11 +50,11 @@ $ini = css_styleini($conf['template']);
 
 if ($ini) {
     echo '<table>';
-    echo "<caption>".htmlspecialchars($conf['template'])."'s style.ini</caption>";
+    echo "<caption>".hsc($conf['template'])."'s style.ini</caption>";
     foreach($ini['replacements'] as $key => $val){
         echo '<tr>';
-        echo '<td>'.htmlspecialchars($key).'</td>';
-        echo '<td>'.htmlspecialchars($val).'</td>';
+        echo '<td>'.hsc($key).'</td>';
+        echo '<td>'.hsc($val).'</td>';
         echo '<td>';
         if(preg_match('/^#[0-f]{3,6}$/i',$val)){
             echo '<div class="color" style="background-color:'.$val.';">&#160;</div>';
@@ -64,7 +64,7 @@ if ($ini) {
     }
     echo '</table>';
 } else {
-    echo "<p>Non-existent or invalid template or style.ini: <strong>".htmlspecialchars($conf['template'])."</strong></p>";
+    echo "<p>Non-existent or invalid template or style.ini: <strong>".hsc($conf['template'])."</strong></p>";
 }
 ?>
 </body>
diff --git a/vendor/.htaccess b/vendor/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..5f279f180699c2f115c326319a8afc645c5a7245
--- /dev/null
+++ b/vendor/.htaccess
@@ -0,0 +1,7 @@
+<IfModule mod_authz_host>
+    Require all denied
+</IfModule>
+<IfModule !mod_authz_host>
+    Order allow,deny
+    Deny from all
+</IfModule>
diff --git a/vendor/aziraphale/email-address-validator/.gitignore b/vendor/aziraphale/email-address-validator/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..57872d0f1e5f46731396e93c4e22b149809798f8
--- /dev/null
+++ b/vendor/aziraphale/email-address-validator/.gitignore
@@ -0,0 +1 @@
+/vendor/
diff --git a/inc/EmailAddressValidator.php b/vendor/aziraphale/email-address-validator/EmailAddressValidator.php
similarity index 52%
rename from inc/EmailAddressValidator.php
rename to vendor/aziraphale/email-address-validator/EmailAddressValidator.php
index fd6f3275babd7d144a13ecfcc21a6e00b535221d..21285bc058c98a422a9f04143b47c79859f84d18 100644
--- a/inc/EmailAddressValidator.php
+++ b/vendor/aziraphale/email-address-validator/EmailAddressValidator.php
@@ -1,110 +1,106 @@
 <?php
+
 /**
- * EmailAddressValidator Class
+ * Class EmailAddressValidator
  *
- * @author  Dave Child <dave@addedbytes.com>
- * @link    http://code.google.com/p/php-email-address-validation/
- * @license http://www.opensource.org/licenses/bsd-license.php
- * @version SVN r10 + Issue 15 fix + Issue 12 fix
+ * @link https://github.com/aziraphale/email-address-validator
+ * @link http://code.google.com/p/php-email-address-validation/
+ * @license New BSD license http://www.opensource.org/licenses/bsd-license.php
+ * @example if (EmailAddressValidator::checkEmailAddress('test@example.org')) {
+ * @example     // Email address is technically valid
+ * @example }
  */
-class EmailAddressValidator {
-    /**
-     * Set true to allow addresses like me@localhost
-     */
-    public $allowLocalAddresses = false;
-
+class EmailAddressValidator
+{
     /**
      * Check email address validity
-     * @param  string $strEmailAddress     Email address to be checked
-     * @return bool True if email is valid, false if not
+     * @param string $emailAddress Email address to be checked
+     * @param bool $allowLocal allow local domains
+     * @return bool Whether email is valid
      */
-    public function check_email_address($strEmailAddress) {
-
+    public static function checkEmailAddress($emailAddress, $allowLocal = false)
+    {
         // If magic quotes is "on", email addresses with quote marks will
         // fail validation because of added escape characters. Uncommenting
         // the next three lines will allow for this issue.
         //if (get_magic_quotes_gpc()) {
-        //    $strEmailAddress = stripslashes($strEmailAddress);
+        //    $emailAddress = stripslashes($emailAddress);
         //}
 
         // Control characters are not allowed
-        if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
+        if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $emailAddress)) {
             return false;
         }
 
         // Check email length - min 3 (a@a), max 256
-        if (!$this->check_text_length($strEmailAddress, 3, 256)) {
+        if (!self::checkTextLength($emailAddress, 3, 256)) {
             return false;
         }
 
         // Split it into sections using last instance of "@"
-        $intAtSymbol = strrpos($strEmailAddress, '@');
-        if ($intAtSymbol === false) {
+        $atSymbol = strrpos($emailAddress, '@');
+        if ($atSymbol === false) {
             // No "@" symbol in email.
             return false;
         }
-        $arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
-        $arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);
+        $emailAddressParts[0] = substr($emailAddress, 0, $atSymbol);
+        $emailAddressParts[1] = substr($emailAddress, $atSymbol + 1);
 
         // Count the "@" symbols. Only one is allowed, except where
         // contained in quote marks in the local part. Quickest way to
         // check this is to remove anything in quotes. We also remove
         // characters escaped with backslash, and the backslash
         // character.
-        $arrTempAddress[0] = preg_replace('/\./'
-                                         ,''
-                                         ,$arrEmailAddress[0]);
-        $arrTempAddress[0] = preg_replace('/"[^"]+"/'
-                                         ,''
-                                         ,$arrTempAddress[0]);
-        $arrTempAddress[1] = $arrEmailAddress[1];
-        $strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
+        $tempAddressParts[0] = preg_replace('/\./', '', $emailAddressParts[0]);
+        $tempAddressParts[0] = preg_replace('/"[^"]+"/', '', $tempAddressParts[0]);
+        $tempAddressParts[1] = $emailAddressParts[1];
+        $tempAddress = $tempAddressParts[0] . $tempAddressParts[1];
         // Then check - should be no "@" symbols.
-        if (strrpos($strTempAddress, '@') !== false) {
+        if (strrpos($tempAddress, '@') !== false) {
             // "@" symbol found
             return false;
         }
 
         // Check local portion
-        if (!$this->check_local_portion($arrEmailAddress[0])) {
+        if (!self::checkLocalPortion($emailAddressParts[0])) {
             return false;
         }
 
         // Check domain portion
-        if (!$this->check_domain_portion($arrEmailAddress[1])) {
+        if (!self::checkDomainPortion($emailAddressParts[1], $allowLocal)) {
             return false;
         }
 
         // If we're still here, all checks above passed. Email is valid.
         return true;
-
     }
 
     /**
      * Checks email section before "@" symbol for validity
-     * @param string  $strLocalPortion     Text to be checked
-     * @return bool True if local portion is valid, false if not
+     * @param string $localPortion Text to be checked
+     * @return bool Whether local portion is valid
      */
-    protected function check_local_portion($strLocalPortion) {
+    public static function checkLocalPortion($localPortion)
+    {
         // Local portion can only be from 1 to 64 characters, inclusive.
         // Please note that servers are encouraged to accept longer local
         // parts than 64 characters.
-        if (!$this->check_text_length($strLocalPortion, 1, 64)) {
+        if (!self::checkTextLength($localPortion, 1, 64)) {
             return false;
         }
         // Local portion must be:
         // 1) a dot-atom (strings separated by periods)
         // 2) a quoted string
         // 3) an obsolete format string (combination of the above)
-        $arrLocalPortion = explode('.', $strLocalPortion);
-        for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
+        $localPortionParts = explode('.', $localPortion);
+        for ($i = 0, $max = sizeof($localPortionParts); $i < $max; $i++) {
              if (!preg_match('.^('
                             .    '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
                             .    '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
                             .'|'
                             .    '("[^\\\"]{0,62}")'
                             .')$.'
-                            ,$arrLocalPortion[$i])) {
+                            ,$localPortionParts[$i])) {
                 return false;
             }
         }
@@ -113,12 +109,14 @@ class EmailAddressValidator {
 
     /**
      * Checks email section after "@" symbol for validity
-     * @param  string $strDomainPortion     Text to be checked
-     * @return bool True if domain portion is valid, false if not
+     * @param string $domainPortion Text to be checked
+     * @param bool $allowLocal allow local domains?
+     * @return bool Whether domain portion is valid
      */
-    protected function check_domain_portion($strDomainPortion) {
+    public static function checkDomainPortion($domainPortion, $allowLocal = false)
+    {
         // Total domain can only be from 1 to 255 characters, inclusive
-        if (!$this->check_text_length($strDomainPortion, 1, 255)) {
+        if (!self::checkTextLength($domainPortion, 1, 255)) {
             return false;
         }
 
@@ -130,7 +128,7 @@ class EmailAddressValidator {
         $IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet";
         $ls32 = "(?:$h16:$h16|$IPv4Address)";
         $IPv6Address =
-            "(?:(?:{$IPv4Address})|(?:".
+            "(?:(?:{$IPv4Address})|(?:" .
             "(?:$h16:){6}$ls32" .
             "|::(?:$h16:){5}$ls32" .
             "|(?:$h16)?::(?:$h16:){4}$ls32" .
@@ -142,26 +140,25 @@ class EmailAddressValidator {
             "|(?:(?:$h16:){0,6}$h16)?::" .
             ")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)";
 
-        // Check if domain is IP, possibly enclosed in square brackets.
-        if (preg_match("/^($IPv4Address|\[$IPv4Address\]|\[$IPv6Address\])$/",
-                        $strDomainPortion)){
+        if (preg_match("/^($IPv4Address|\\[$IPv4Address\\]|\\[$IPv6Address\\])$/",
+                            $domainPortion)){
             return true;
         } else {
-            $arrDomainPortion = explode('.', $strDomainPortion);
-            if (!$this->allowLocalAddresses && sizeof($arrDomainPortion) < 2) {
+            $domainPortionParts = explode('.', $domainPortion);
+            if (!$allowLocal && sizeof($domainPortionParts) < 2) {
                 return false; // Not enough parts to domain
             }
-            for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
+            for ($i = 0, $max = sizeof($domainPortionParts); $i < $max; $i++) {
                 // Each portion must be between 1 and 63 characters, inclusive
-                if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
+                if (!self::checkTextLength($domainPortionParts[$i], 1, 63)) {
                     return false;
                 }
                 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
-                   .'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
+                   .'([A-Za-z0-9]+))$/', $domainPortionParts[$i])) {
                     return false;
                 }
                 if ($i == $max - 1) { // TLD cannot be only numbers
-                    if (strlen(preg_replace('/[0-9]/', '', $arrDomainPortion[$i])) <= 0) {
+                    if (strlen(preg_replace('/[0-9]/', '', $domainPortionParts[$i])) <= 0) {
                         return false;
                     }
                 }
@@ -172,20 +169,15 @@ class EmailAddressValidator {
 
     /**
      * Check given text length is between defined bounds
-     * @param   string $strText     Text to be checked
-     * @param   int $intMinimum  Minimum acceptable length
-     * @param   int $intMaximum  Maximum acceptable length
-     * @return bool True if string is within bounds (inclusive), false if not
+     * @param string $text Text to be checked
+     * @param int $minimum Minimum acceptable length
+     * @param int $maximum Maximum acceptable length
+     * @return bool Whether string is within bounds (inclusive)
      */
-    protected function check_text_length($strText, $intMinimum, $intMaximum) {
+    protected static function checkTextLength($text, $minimum, $maximum)
+    {
         // Minimum and maximum are both inclusive
-        $intTextLength = strlen($strText);
-        if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
-            return false;
-        } else {
-            return true;
-        }
+        $textLength = strlen($text);
+        return ($textLength >= $minimum && $textLength <= $maximum);
     }
-
 }
-
diff --git a/vendor/aziraphale/email-address-validator/README.md b/vendor/aziraphale/email-address-validator/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..60bff60938d0dab69e0b75ce8e30b8bd47384ed7
--- /dev/null
+++ b/vendor/aziraphale/email-address-validator/README.md
@@ -0,0 +1,59 @@
+Email-Address-Validator
+=======================
+
+This is a fork of [AddedBytes' EmailAddressValidator class](https://code.google.com/p/php-email-address-validation/).
+
+## Changes ##
+Changes include:
+
+- [Composer](https://getcomposer.org/) support
+- Refactored the class to be purely static
+- Opened up methods for checking the "local part" (the bit before the `@`) and the "domain part" (after the `@`) 
+to be public methods
+- Additional code style and docblock fixing to properly follow the [PHP-FIG PSR-1](http://www.php-fig.org/psr/psr-1/) 
+and [PSR-2](http://www.php-fig.org/psr/psr-2/) documents
+
+Note that this class is still **un-namespaced** - i.e. it's still declared in the global namespace. The `composer.json` 
+file is still set up to correctly load it when required, so this shouldn't be a problem in practice - it's just perhaps
+not best-practice.
+
+## Installation ##
+Use [Composer](https://getcomposer.org/):
+```
+php composer.phar require aziraphale/email-address-validator:^2
+```
+
+If you don't want to use Composer (why not?!), just download the `EmailAddressValidator.php` file, save it with your project, and `require` it where needed.
+
+Note that this updated version is **version 2.0.0**. I have kept the original class tagged as **version 1.0.10** (it was the 10th commit to the Google Code svn repository). If you want to use Composer to install the **old** class, simply specify `^1` as the version constraint (which will allow for backwards-compatible changes to be installed, if any get made, while never jumping to my modified class without your direct action):
+```
+php composer.phar require aziraphale/email-address-validator:^1
+```
+
+## Usage ##
+Due to the aforementioned changes, the way of using this class has completely changed. However it has such a small and simple interface that these changes shouldn't be problematic.
+
+As a recap, the **old usage** was like this:
+```php
+$validator = new EmailAddressValidator;
+if ($validator->check_email_address('test@example.org')) {
+    // Email address is technically valid
+}
+```
+
+The **new syntax** is as follows (ensure you have already included Composer's `autoload.php` file!):
+```php
+if (EmailAddressValidator::checkEmailAddress("test@example.org")) {
+    // Email address is technically valid
+}
+```
+
+with a couple of additional methods in case they're helpful:
+```php
+if (EmailAddressValidator::checkLocalPortion("test")) {
+    // "test" is technically a valid string to have before the "@" in an email address
+}
+if (EmailAddressValidator::checkDomainPotion("example.org")) {
+    // "example.org" is technically a valid email address host
+}
+```
diff --git a/vendor/aziraphale/email-address-validator/composer.json b/vendor/aziraphale/email-address-validator/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..6c72ddb744011dc4a6cb448f566c167fa2b06e8d
--- /dev/null
+++ b/vendor/aziraphale/email-address-validator/composer.json
@@ -0,0 +1,26 @@
+{
+    "name": "aziraphale/email-address-validator",
+    "version": "2.0.1",
+    "description": "Fork of AddedBytes' PHP EmailAddressValidator script, now with Composer support!",
+    "homepage": "https://github.com/aziraphale/email-address-validator",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Dave Child",
+            "email": "dave@addedbytes.com"
+        },
+        {
+            "name": "Andrew Gillard",
+            "email": "andrew@lorddeath.net"
+        }
+    ],
+    "require": {},
+    "autoload": {
+        "psr-0": {
+            "EmailAddressValidator": ""
+        }
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^5.7"
+    }
+}
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
index 2baad22d947444b741b34ac99ce74fe9566d3297..538036724cf34215e03a61c1074b299b3371b678 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -27,4 +27,9 @@ return array(
     'RSSCreator10' => $vendorDir . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator10.php',
     'RSSCreator20' => $vendorDir . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator20.php',
     'UniversalFeedCreator' => $vendorDir . '/openpsa/universalfeedcreator/lib/UniversalFeedCreator.php',
+    'lessc' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php',
+    'lessc_formatter_classic' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php',
+    'lessc_formatter_compressed' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php',
+    'lessc_formatter_lessjs' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php',
+    'lessc_parser' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php',
 );
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
index 86667b9500dd63f3f75a7c4c959ae62d52b4d7dc..6a43fa58f37d49a085be26b0d87919775b4604ee 100644
--- a/vendor/composer/autoload_namespaces.php
+++ b/vendor/composer/autoload_namespaces.php
@@ -7,4 +7,5 @@ $baseDir = dirname($vendorDir);
 
 return array(
     'SimplePie' => array($vendorDir . '/simplepie/simplepie/library'),
+    'EmailAddressValidator' => array($vendorDir . '/aziraphale/email-address-validator'),
 );
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index 3488312df1eeac4437fca8c5283f883492f75b13..3a072f73917956c0fc3a6627f8bba305874f3a8c 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'splitbrain\\phpcli\\' => array($vendorDir . '/splitbrain/php-cli/src'),
     'splitbrain\\PHPArchive\\' => array($vendorDir . '/splitbrain/php-archive/src'),
     'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
 );
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index 46be7ebe188c393d99388940b88b7c3e4f94304e..ee9e282754381388861ccf780c46165e7b05e72b 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -14,6 +14,7 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b
     public static $prefixLengthsPsr4 = array (
         's' => 
         array (
+            'splitbrain\\phpcli\\' => 18,
             'splitbrain\\PHPArchive\\' => 22,
         ),
         'p' => 
@@ -23,6 +24,10 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b
     );
 
     public static $prefixDirsPsr4 = array (
+        'splitbrain\\phpcli\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/splitbrain/php-cli/src',
+        ),
         'splitbrain\\PHPArchive\\' => 
         array (
             0 => __DIR__ . '/..' . '/splitbrain/php-archive/src',
@@ -41,6 +46,13 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b
                 0 => __DIR__ . '/..' . '/simplepie/simplepie/library',
             ),
         ),
+        'E' => 
+        array (
+            'EmailAddressValidator' => 
+            array (
+                0 => __DIR__ . '/..' . '/aziraphale/email-address-validator',
+            ),
+        ),
     );
 
     public static $classMap = array (
@@ -65,6 +77,11 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b
         'RSSCreator10' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator10.php',
         'RSSCreator20' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator20.php',
         'UniversalFeedCreator' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/UniversalFeedCreator.php',
+        'lessc' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php',
+        'lessc_formatter_classic' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php',
+        'lessc_formatter_compressed' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php',
+        'lessc_formatter_lessjs' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php',
+        'lessc_parser' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php',
     );
 
     public static function getInitializer(ClassLoader $loader)
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index a9d312261e3c77b1a50550e1d8242edda95c5d43..9c444bb55e3fe8ec8b61b9b255706433286ec384 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1,17 +1,259 @@
 [
+    {
+        "name": "geshi/geshi",
+        "version": "v1.0.9.0",
+        "version_normalized": "1.0.9.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/GeSHi/geshi-1.0.git",
+            "reference": "5a7b461338d322d941986a656d4d1651452e73dd"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/5a7b461338d322d941986a656d4d1651452e73dd",
+            "reference": "5a7b461338d322d941986a656d4d1651452e73dd",
+            "shasum": ""
+        },
+        "require-dev": {
+            "phpunit/phpunit": "^5.7"
+        },
+        "time": "2017-05-05T05:51:25+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "classmap": [
+                "src/geshi/",
+                "src/geshi.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "GPL-2.0+"
+        ],
+        "authors": [
+            {
+                "name": "Benny Baumann",
+                "email": "BenBE@geshi.org",
+                "homepage": "http://blog.benny-baumann.de/",
+                "role": "Developer"
+            }
+        ],
+        "description": "Generic Syntax Highlighter",
+        "homepage": "http://qbnz.com/highlighter/"
+    },
+    {
+        "name": "openpsa/universalfeedcreator",
+        "version": "v1.8.3",
+        "version_normalized": "1.8.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/flack/UniversalFeedCreator.git",
+            "reference": "6261e130446d8f787bbfd229a602fb11e6816a4e"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/flack/UniversalFeedCreator/zipball/6261e130446d8f787bbfd229a602fb11e6816a4e",
+            "reference": "6261e130446d8f787bbfd229a602fb11e6816a4e",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "*"
+        },
+        "time": "2017-05-18T08:28:48+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "classmap": [
+                "lib"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "LGPL"
+        ],
+        "authors": [
+            {
+                "name": "Andreas Flack",
+                "email": "flack@contentcontrol-berlin.de",
+                "homepage": "http://www.contentcontrol-berlin.de/"
+            }
+        ],
+        "description": "RSS and Atom feed generator by Kai Blankenhorn",
+        "keywords": [
+            "atom",
+            "georss",
+            "gpx",
+            "opml",
+            "pie",
+            "rss"
+        ]
+    },
+    {
+        "name": "aziraphale/email-address-validator",
+        "version": "2.0.1",
+        "version_normalized": "2.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/aziraphale/email-address-validator.git",
+            "reference": "fa25bc22c1c0b6491657c91473fae3e40719a650"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/aziraphale/email-address-validator/zipball/fa25bc22c1c0b6491657c91473fae3e40719a650",
+            "reference": "fa25bc22c1c0b6491657c91473fae3e40719a650",
+            "shasum": ""
+        },
+        "require-dev": {
+            "phpunit/phpunit": "^5.7"
+        },
+        "time": "2017-05-22T14:05:57+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "EmailAddressValidator": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Dave Child",
+                "email": "dave@addedbytes.com"
+            },
+            {
+                "name": "Andrew Gillard",
+                "email": "andrew@lorddeath.net"
+            }
+        ],
+        "description": "Fork of AddedBytes' PHP EmailAddressValidator script, now with Composer support!",
+        "homepage": "https://github.com/aziraphale/email-address-validator"
+    },
+    {
+        "name": "marcusschwarz/lesserphp",
+        "version": "v0.5.1",
+        "version_normalized": "0.5.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/MarcusSchwarz/lesserphp.git",
+            "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/MarcusSchwarz/lesserphp/zipball/e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
+            "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
+            "shasum": ""
+        },
+        "require-dev": {
+            "phpunit/phpunit": "~4.3"
+        },
+        "time": "2016-09-30T11:13:18+00:00",
+        "bin": [
+            "plessc"
+        ],
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "0.5.1-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "classmap": [
+                "lessc.inc.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT",
+            "GPL-3.0"
+        ],
+        "authors": [
+            {
+                "name": "Leaf Corcoran",
+                "email": "leafot@gmail.com",
+                "homepage": "http://leafo.net"
+            },
+            {
+                "name": "Marcus Schwarz",
+                "email": "github@maswaba.de",
+                "homepage": "https://www.maswaba.de"
+            }
+        ],
+        "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.",
+        "homepage": "http://leafo.net/lessphp/"
+    },
+    {
+        "name": "splitbrain/php-archive",
+        "version": "1.0.9",
+        "version_normalized": "1.0.9.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/splitbrain/php-archive.git",
+            "reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/splitbrain/php-archive/zipball/2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
+            "reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "4.5.*"
+        },
+        "suggest": {
+            "ext-iconv": "Used for proper filename encode handling",
+            "ext-mbstring": "Can be used alternatively for handling filename encoding"
+        },
+        "time": "2017-06-11T06:11:38+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "splitbrain\\PHPArchive\\": "src"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Andreas Gohr",
+                "email": "andi@splitbrain.org"
+            }
+        ],
+        "description": "Pure-PHP implementation to read and write TAR and ZIP archives",
+        "keywords": [
+            "archive",
+            "extract",
+            "tar",
+            "unpack",
+            "unzip",
+            "zip"
+        ]
+    },
     {
         "name": "phpseclib/phpseclib",
-        "version": "2.0.4",
-        "version_normalized": "2.0.4.0",
+        "version": "2.0.10",
+        "version_normalized": "2.0.10.0",
         "source": {
             "type": "git",
             "url": "https://github.com/phpseclib/phpseclib.git",
-            "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf"
+            "reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
-            "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
+            "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d305b780829ea4252ed9400b3f5937c2c99b51d4",
+            "reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4",
             "shasum": ""
         },
         "require": {
@@ -19,7 +261,7 @@
         },
         "require-dev": {
             "phing/phing": "~2.7",
-            "phpunit/phpunit": "~4.0",
+            "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
             "sami/sami": "~2.0",
             "squizlabs/php_codesniffer": "~2.0"
         },
@@ -29,7 +271,7 @@
             "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
             "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
         },
-        "time": "2016-10-04T00:57:04+00:00",
+        "time": "2018-02-19T04:29:13+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
@@ -93,81 +335,19 @@
             "x509"
         ]
     },
-    {
-        "name": "simplepie/simplepie",
-        "version": "1.4.3",
-        "version_normalized": "1.4.3.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/simplepie/simplepie.git",
-            "reference": "2a24b6e74aa9bf33243020f52895fe77efe94ccf"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/simplepie/simplepie/zipball/2a24b6e74aa9bf33243020f52895fe77efe94ccf",
-            "reference": "2a24b6e74aa9bf33243020f52895fe77efe94ccf",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.3.0"
-        },
-        "require-dev": {
-            "phpunit/phpunit": "~4 || ~5"
-        },
-        "suggest": {
-            "mf2/mf2": "Microformat module that allows for parsing HTML for microformats"
-        },
-        "time": "2016-11-27T01:39:18+00:00",
-        "type": "library",
-        "installation-source": "dist",
-        "autoload": {
-            "psr-0": {
-                "SimplePie": "library"
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "BSD-3-Clause"
-        ],
-        "authors": [
-            {
-                "name": "Ryan Parman",
-                "homepage": "http://ryanparman.com/",
-                "role": "Creator, alumnus developer"
-            },
-            {
-                "name": "Geoffrey Sneddon",
-                "homepage": "http://gsnedders.com/",
-                "role": "Alumnus developer"
-            },
-            {
-                "name": "Ryan McCue",
-                "email": "me@ryanmccue.info",
-                "homepage": "http://ryanmccue.info/",
-                "role": "Developer"
-            }
-        ],
-        "description": "A simple Atom/RSS parsing library for PHP",
-        "homepage": "http://simplepie.org/",
-        "keywords": [
-            "atom",
-            "feeds",
-            "rss"
-        ]
-    },
     {
         "name": "paragonie/random_compat",
-        "version": "v2.0.10",
-        "version_normalized": "2.0.10.0",
+        "version": "v2.0.12",
+        "version_normalized": "2.0.12.0",
         "source": {
             "type": "git",
             "url": "https://github.com/paragonie/random_compat.git",
-            "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
+            "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
-            "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
+            "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
+            "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
             "shasum": ""
         },
         "require": {
@@ -179,7 +359,7 @@
         "suggest": {
             "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
         },
-        "time": "2017-03-13T16:27:32+00:00",
+        "time": "2018-04-04T21:24:14+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
@@ -206,148 +386,118 @@
         ]
     },
     {
-        "name": "splitbrain/php-archive",
-        "version": "1.0.8",
-        "version_normalized": "1.0.8.0",
+        "name": "simplepie/simplepie",
+        "version": "1.5.1",
+        "version_normalized": "1.5.1.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/splitbrain/php-archive.git",
-            "reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c"
+            "url": "https://github.com/simplepie/simplepie.git",
+            "reference": "db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/splitbrain/php-archive/zipball/6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
-            "reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
+            "url": "https://api.github.com/repos/simplepie/simplepie/zipball/db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e",
+            "reference": "db9fff27b6d49eed3d4047cd3211ec8dba2f5d6e",
             "shasum": ""
         },
         "require": {
             "php": ">=5.3.0"
         },
         "require-dev": {
-            "phpunit/phpunit": "4.5.*"
+            "phpunit/phpunit": "~4 || ~5"
         },
         "suggest": {
-            "ext-iconv": "Used for proper filename encode handling",
-            "ext-mbstring": "Can be used alternatively for handling filename encoding"
+            "mf2/mf2": "Microformat module that allows for parsing HTML for microformats"
         },
-        "time": "2017-03-19T09:10:53+00:00",
+        "time": "2017-11-12T02:03:34+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
-            "psr-4": {
-                "splitbrain\\PHPArchive\\": "src"
+            "psr-0": {
+                "SimplePie": "library"
             }
         },
         "notification-url": "https://packagist.org/downloads/",
         "license": [
-            "MIT"
+            "BSD-3-Clause"
         ],
         "authors": [
             {
-                "name": "Andreas Gohr",
-                "email": "andi@splitbrain.org"
-            }
-        ],
-        "description": "Pure-PHP implementation to read and write TAR and ZIP archives",
-        "keywords": [
-            "archive",
-            "extract",
-            "tar",
-            "unpack",
-            "unzip",
-            "zip"
-        ]
-    },
-    {
-        "name": "geshi/geshi",
-        "version": "v1.0.9.0",
-        "version_normalized": "1.0.9.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/GeSHi/geshi-1.0.git",
-            "reference": "5a7b461338d322d941986a656d4d1651452e73dd"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/5a7b461338d322d941986a656d4d1651452e73dd",
-            "reference": "5a7b461338d322d941986a656d4d1651452e73dd",
-            "shasum": ""
-        },
-        "require-dev": {
-            "phpunit/phpunit": "^5.7"
-        },
-        "time": "2017-05-05T05:51:25+00:00",
-        "type": "library",
-        "installation-source": "dist",
-        "autoload": {
-            "classmap": [
-                "src/geshi/",
-                "src/geshi.php"
-            ]
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "GPL-2.0+"
-        ],
-        "authors": [
+                "name": "Ryan Parman",
+                "homepage": "http://ryanparman.com/",
+                "role": "Creator, alumnus developer"
+            },
             {
-                "name": "Benny Baumann",
-                "email": "BenBE@geshi.org",
-                "homepage": "http://blog.benny-baumann.de/",
+                "name": "Geoffrey Sneddon",
+                "homepage": "http://gsnedders.com/",
+                "role": "Alumnus developer"
+            },
+            {
+                "name": "Ryan McCue",
+                "email": "me@ryanmccue.info",
+                "homepage": "http://ryanmccue.info/",
                 "role": "Developer"
             }
         ],
-        "description": "Generic Syntax Highlighter",
-        "homepage": "http://qbnz.com/highlighter/"
+        "description": "A simple Atom/RSS parsing library for PHP",
+        "homepage": "http://simplepie.org/",
+        "keywords": [
+            "atom",
+            "feeds",
+            "rss"
+        ]
     },
     {
-        "name": "openpsa/universalfeedcreator",
-        "version": "v1.8.3",
-        "version_normalized": "1.8.3.0",
+        "name": "splitbrain/php-cli",
+        "version": "1.1.2",
+        "version_normalized": "1.1.2.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/flack/UniversalFeedCreator.git",
-            "reference": "6261e130446d8f787bbfd229a602fb11e6816a4e"
+            "url": "https://github.com/splitbrain/php-cli.git",
+            "reference": "1d6f0bf9eccbfd79d1f4d185ef27573601185c23"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/flack/UniversalFeedCreator/zipball/6261e130446d8f787bbfd229a602fb11e6816a4e",
-            "reference": "6261e130446d8f787bbfd229a602fb11e6816a4e",
+            "url": "https://api.github.com/repos/splitbrain/php-cli/zipball/1d6f0bf9eccbfd79d1f4d185ef27573601185c23",
+            "reference": "1d6f0bf9eccbfd79d1f4d185ef27573601185c23",
             "shasum": ""
         },
         "require": {
-            "php": ">=5.0"
+            "php": ">=5.3.0"
         },
         "require-dev": {
-            "phpunit/phpunit": "*"
+            "phpunit/phpunit": "4.5.*"
         },
-        "time": "2017-05-18T08:28:48+00:00",
+        "suggest": {
+            "psr/log": "Allows you to make the CLI available as PSR-3 logger"
+        },
+        "time": "2018-02-02T08:46:12+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
-            "classmap": [
-                "lib"
-            ]
+            "psr-4": {
+                "splitbrain\\phpcli\\": "src"
+            }
         },
         "notification-url": "https://packagist.org/downloads/",
         "license": [
-            "LGPL"
+            "MIT"
         ],
         "authors": [
             {
-                "name": "Andreas Flack",
-                "email": "flack@contentcontrol-berlin.de",
-                "homepage": "http://www.contentcontrol-berlin.de/"
+                "name": "Andreas Gohr",
+                "email": "andi@splitbrain.org"
             }
         ],
-        "description": "RSS and Atom feed generator by Kai Blankenhorn",
+        "description": "Easy command line scripts for PHP with opt parsing and color output. No dependencies",
         "keywords": [
-            "atom",
-            "georss",
-            "gpx",
-            "opml",
-            "pie",
-            "rss"
+            "argparse",
+            "cli",
+            "command line",
+            "console",
+            "getopt",
+            "optparse",
+            "terminal"
         ]
     }
 ]
diff --git a/vendor/marcusschwarz/lesserphp/.gitignore b/vendor/marcusschwarz/lesserphp/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..7e33d9cbf9e47d9f5758da60e36ccbb6db1cc44e
--- /dev/null
+++ b/vendor/marcusschwarz/lesserphp/.gitignore
@@ -0,0 +1,10 @@
+*.swp
+*~
+/*.less
+/*.css
+tests/bootstrap
+tests/tmp
+vendor
+composer.lock
+
+.idea/
diff --git a/vendor/marcusschwarz/lesserphp/HISTORY.md b/vendor/marcusschwarz/lesserphp/HISTORY.md
new file mode 100644
index 0000000000000000000000000000000000000000..19ec7dc83f17071e2043d2951074cd98a388359a
--- /dev/null
+++ b/vendor/marcusschwarz/lesserphp/HISTORY.md
@@ -0,0 +1,29 @@
+# lesserphp v0.5.1
+
+Originally written by Leaf Corcoran, obviously abandoned circa 2014
+https://github.com/leafo/lessphp
+
+Last version provided by Leaf was 0.5.0
+
+### v.0.5.1
+* 2016-09-30: renaming it to lesserphp for easier distinction
+* 2016-09-30: applying some pull requests of the origin repository
+  * https://github.com/leafo/lessphp/pull/584
+  * https://github.com/leafo/lessphp/pull/607
+  * https://github.com/leafo/lessphp/pull/619
+* 2016-09-29: applying some pull requests of the origin repository
+  * https://github.com/leafo/lessphp/pull/590
+  * https://github.com/leafo/lessphp/pull/523
+  * https://github.com/leafo/lessphp/pull/540
+  * https://github.com/leafo/lessphp/pull/564
+  * https://github.com/leafo/lessphp/pull/566
+* 2016-09-26: applying some pull requests of the origin repository
+  * https://github.com/leafo/lessphp/pull/592
+  * https://github.com/leafo/lessphp/pull/601
+  * https://github.com/leafo/lessphp/pull/603
+  * https://github.com/leafo/lessphp/pull/604
+  * https://github.com/leafo/lessphp/pull/605
+  * https://github.com/leafo/lessphp/pull/610
+  * https://github.com/leafo/lessphp/pull/616
+* 2016-09-26: making it compatible with php7.x
+* 2016-09-26: Forking master from https://github.com/leafo/lessphp
diff --git a/vendor/marcusschwarz/lesserphp/LICENSE b/vendor/marcusschwarz/lesserphp/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..5290202668d7cdc6972cc7b09e824d7ae36d8ea0
--- /dev/null
+++ b/vendor/marcusschwarz/lesserphp/LICENSE
@@ -0,0 +1,661 @@
+For ease of distribution, lessphp 0.5.1 is under a dual license.
+You are free to pick which one suits your needs.
+
+
+
+
+MIT LICENSE
+
+
+
+
+Copyright (c) 2013 - 2015 Leaf Corcoran, http://leafo.net/lessphp
+Copyright (c) 2016 -  Marcus Schwarz, https://www.maswaba.de
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
+GPL VERSION 3
+
+
+
+
+					GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
diff --git a/vendor/marcusschwarz/lesserphp/README.md b/vendor/marcusschwarz/lesserphp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b30e07eace7dde846a56700b14b16ee05908bbd6
--- /dev/null
+++ b/vendor/marcusschwarz/lesserphp/README.md
@@ -0,0 +1,97 @@
+[![Build Status](https://travis-ci.org/MarcusSchwarz/lessphp.svg?branch=0.5.1)](https://travis-ci.org/MarcusSchwarz/lessphp)
+
+# lesserphp v0.5.1
+### <http://github.com/MarcusSchwarz/lesserphp>
+
+`lesserphp` is a compiler for LESS written in PHP. It is based on lessphp bei leafo.
+The documentation is great,
+so check it out: <http://leafo.net/lessphp/docs/>.
+
+Here's a quick tutorial:
+
+### How to use in your PHP project
+
+The only file required is `lessc.inc.php`, so copy that to your include directory.
+
+The typical flow of **lesserphp** is to create a new instance of `lessc`,
+configure it how you like, then tell it to compile something using one built in
+compile methods.
+
+The `compile` method compiles a string of LESS code to CSS.
+
+```php
+<?php
+require "lessc.inc.php";
+
+$less = new lessc;
+echo $less->compile(".block { padding: 3 + 4px }");
+```
+
+The `compileFile` method reads and compiles a file. It will either return the
+result or write it to the path specified by an optional second argument.
+
+```php
+<?php
+echo $less->compileFile("input.less");
+```
+
+The `checkedCompile` method is like `compileFile`, but it only compiles if the output
+file doesn't exist or it's older than the input file:
+
+```php
+<?php
+$less->checkedCompile("input.less", "output.css");
+```
+
+If there any problem compiling your code, an exception is thrown with a helpful message:
+
+```php
+<?php
+try {
+  $less->compile("invalid LESS } {");
+} catch (\Exception $e) {
+  echo "fatal error: " . $e->getMessage();
+}
+```
+
+The `lessc` object can be configured through an assortment of instance methods.
+Some possible configuration options include [changing the output format][1],
+[setting variables from PHP][2], and [controlling the preservation of
+comments][3], writing [custom functions][4] and much more. It's all described
+in [the documentation][0].
+
+
+ [0]: http://leafo.net/lessphp/docs/
+ [1]: http://leafo.net/lessphp/docs/#output_formatting
+ [2]: http://leafo.net/lessphp/docs/#setting_variables_from_php
+ [3]: http://leafo.net/lessphp/docs/#preserving_comments
+ [4]: http://leafo.net/lessphp/docs/#custom_functions
+
+
+### How to use from the command line
+
+An additional script has been included to use the compiler from the command
+line. In the simplest invocation, you specify an input file and the compiled
+css is written to standard out:
+
+    $ plessc input.less > output.css
+
+Using the -r flag, you can specify LESS code directly as an argument or, if
+the argument is left off, from standard in:
+
+    $ plessc -r "my less code here"
+
+Finally, by using the -w flag you can watch a specified input file and have it
+compile as needed to the output file:
+
+    $ plessc -w input-file output-file
+
+Errors from watch mode are written to standard out.
+
+The -f flag sets the [output formatter][1]. For example, to compress the
+output run this:
+
+    $ plessc -f=compressed myfile.less
+
+For more help, run `plessc --help`
+
diff --git a/vendor/marcusschwarz/lesserphp/composer.json b/vendor/marcusschwarz/lesserphp/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..d32a5d4afdc3200f0669ceb0ff998b494e7587c3
--- /dev/null
+++ b/vendor/marcusschwarz/lesserphp/composer.json
@@ -0,0 +1,38 @@
+{
+    "name": "marcusschwarz/lesserphp",
+    "type": "library",
+    "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.",
+    "homepage": "http://leafo.net/lessphp/",
+    "license": [
+        "MIT",
+        "GPL-3.0"
+    ],
+    "authors": [
+        {
+            "name": "Leaf Corcoran",
+            "email": "leafot@gmail.com",
+            "homepage": "http://leafo.net"
+        },
+        {
+            "name": "Marcus Schwarz",
+            "email": "github@maswaba.de",
+            "homepage": "https://www.maswaba.de"
+        }
+
+    ],
+    "bin": ["plessc"],
+    "autoload": {
+        "classmap": ["lessc.inc.php"]
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "0.5.1-dev"
+        }
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~4.3"
+    },
+    "scripts": {
+        "test": "phpunit"
+    }
+}
diff --git a/inc/lessc.inc.php b/vendor/marcusschwarz/lesserphp/lessc.inc.php
similarity index 83%
rename from inc/lessc.inc.php
rename to vendor/marcusschwarz/lesserphp/lessc.inc.php
index 53b390c089511186b1b827e9db1268f4f1d0f700..b9e80ccc88563ce4e05c61243418af6396465b75 100644
--- a/inc/lessc.inc.php
+++ b/vendor/marcusschwarz/lesserphp/lessc.inc.php
@@ -1,18 +1,19 @@
 <?php
 
 /**
- * lessphp v0.4.0
+ * lessphp v0.5.1
  * http://leafo.net/lessphp
  *
- * LESS css compiler, adapted from http://lesscss.org
+ * LESS CSS compiler, adapted from http://lesscss.org
  *
- * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
+ * Copyright 2013, Leaf Corcoran <leafot@gmail.com>
+ * Copyright 2016, Marcus Schwarz <github@maswaba.de>
  * Licensed under MIT or GPLv3, see LICENSE
  */
 
 
 /**
- * The less compiler and parser.
+ * The LESS compiler and parser.
  *
  * Converting LESS to CSS is a three stage process. The incoming file is parsed
  * by `lessc_parser` into a syntax tree, then it is compiled into another tree
@@ -27,7 +28,7 @@
  *
  * In summary:
  *
- * The `lessc` class creates an intstance of the parser, feeds it LESS code,
+ * The `lessc` class creates an instance of the parser, feeds it LESS code,
  * then transforms the resulting tree to a CSS tree. This class also holds the
  * evaluation context, such as all available mixins and variables at any given
  * time.
@@ -38,9 +39,10 @@
  * handling things like indentation.
  */
 class lessc {
-	static public $VERSION = "v0.4.0";
-	static protected $TRUE = array("keyword", "true");
-	static protected $FALSE = array("keyword", "false");
+	static public $VERSION = "v0.5.1";
+
+	static public $TRUE = array("keyword", "true");
+	static public $FALSE = array("keyword", "false");
 
 	protected $libFunctions = array();
 	protected $registeredVars = array();
@@ -50,9 +52,13 @@ class lessc {
 	public $mPrefix = '$'; // prefix of abstract blocks
 	public $parentSelector = '&';
 
+	static public $lengths = array( "px", "m", "cm", "mm", "in", "pt", "pc" );
+	static public $times = array( "s", "ms" );
+	static public $angles = array( "rad", "deg", "grad", "turn" );
+
+	static public $lengths_to_base = array( 1, 3779.52755906, 37.79527559, 3.77952756, 96, 1.33333333, 16  );
 	public $importDisabled = false;
-    /** @var  string|string[] */
-	public $importDir;
+	public $importDir = array();
 
 	protected $numberPrecision = null;
 
@@ -63,8 +69,6 @@ class lessc {
 	protected $sourceParser = null;
 	protected $sourceLoc = null;
 
-	static public $defaultValue = array("keyword", "");
-
 	static protected $nextImportId = 0; // uniquely identify imports
 
 	// attempts to find the path of an import url, returns null for css files
@@ -167,28 +171,27 @@ class lessc {
 		$this->sourceParser = $oldSourceParser;
 	}
 
-    /**
-     * Recursively compiles a block.
-     *
-     * A block is analogous to a CSS block in most cases. A single LESS document
-     * is encapsulated in a block when parsed, but it does not have parent tags
-     * so all of it's children appear on the root level when compiled.
-     *
-     * Blocks are made up of props and children.
-     *
-     * Props are property instructions, array tuples which describe an action
-     * to be taken, eg. write a property, set a variable, mixin a block.
-     *
-     * The children of a block are just all the blocks that are defined within.
-     * This is used to look up mixins when performing a mixin.
-     *
-     * Compiling the block involves pushing a fresh environment on the stack,
-     * and iterating through the props, compiling each one.
-     *
-     * See lessc::compileProp()
-     *
-     * @param stdClass $block
-     */
+	/**
+	 * Recursively compiles a block.
+	 *
+	 * A block is analogous to a CSS block in most cases. A single LESS document
+	 * is encapsulated in a block when parsed, but it does not have parent tags
+	 * so all of it's children appear on the root level when compiled.
+	 *
+	 * Blocks are made up of props and children.
+	 *
+	 * Props are property instructions, array tuples which describe an action
+	 * to be taken, eg. write a property, set a variable, mixin a block.
+	 *
+	 * The children of a block are just all the blocks that are defined within.
+	 * This is used to look up mixins when performing a mixin.
+	 *
+	 * Compiling the block involves pushing a fresh environment on the stack,
+	 * and iterating through the props, compiling each one.
+	 *
+	 * See lessc::compileProp()
+	 *
+	 */
 	protected function compileBlock($block) {
 		switch ($block->type) {
 		case "root":
@@ -209,7 +212,7 @@ class lessc {
 			$this->compileNestedBlock($block, array($name));
 			break;
 		default:
-			$this->throwError("unknown block type: $block->type\n");
+            $block->parser->throwError("unknown block type: $block->type\n", $block->count);
 		}
 	}
 
@@ -285,39 +288,73 @@ class lessc {
 		foreach ($this->sortProps($block->props) as $prop) {
 			$this->compileProp($prop, $block, $out);
 		}
+		$out->lines = $this->deduplicate($out->lines);
+	}
 
-		$out->lines = array_values(array_unique($out->lines));
+	/**
+	 * Deduplicate lines in a block. Comments are not deduplicated. If a
+	 * duplicate rule is detected, the comments immediately preceding each
+	 * occurence are consolidated.
+	 */
+	protected function deduplicate($lines) {
+		$unique = array();
+		$comments = array();
+
+		foreach($lines as $line) {
+			if (strpos($line, '/*') === 0) {
+				$comments[] = $line;
+				continue;
+			}
+			if (!in_array($line, $unique)) {
+				$unique[] = $line;
+			}
+			array_splice($unique, array_search($line, $unique), 0, $comments);
+			$comments = array();
+		}
+		return array_merge($unique, $comments);
 	}
 
 	protected function sortProps($props, $split = false) {
 		$vars = array();
 		$imports = array();
 		$other = array();
+		$stack = array();
 
 		foreach ($props as $prop) {
 			switch ($prop[0]) {
+			case "comment":
+				$stack[] = $prop;
+				break;
 			case "assign":
+				$stack[] = $prop;
 				if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
-					$vars[] = $prop;
+					$vars = array_merge($vars, $stack);
 				} else {
-					$other[] = $prop;
+					$other = array_merge($other, $stack);
 				}
+				$stack = array();
 				break;
 			case "import":
 				$id = self::$nextImportId++;
 				$prop[] = $id;
-				$imports[] = $prop;
+				$stack[] = $prop;
+				$imports = array_merge($imports, $stack);
 				$other[] = array("import_mixin", $id);
+				$stack = array();
 				break;
 			default:
-				$other[] = $prop;
+				$stack[] = $prop;
+				$other = array_merge($other, $stack);
+				$stack = array();
+				break;
 			}
 		}
+		$other = array_merge($other, $stack);
 
 		if ($split) {
-			return array(array_merge($vars, $imports), $other);
+			return array(array_merge($imports, $vars), $other);
 		} else {
-			return array_merge($vars, $imports, $other);
+			return array_merge($imports, $vars, $other);
 		}
 	}
 
@@ -539,7 +576,7 @@ class lessc {
 			return true; // not having enough is handled above
 		} else {
 			$numMatched = $i + 1;
-			// greater than becuase default values always match
+			// greater than because default values always match
 			return $numMatched >= count($orderedArgs);
 		}
 	}
@@ -659,6 +696,7 @@ class lessc {
 			list(, $child) = $prop;
 			$this->compileBlock($child);
 			break;
+		case 'ruleset':
 		case 'mixin':
 			list(, $path, $args, $suffix) = $prop;
 
@@ -686,8 +724,12 @@ class lessc {
 			$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
 
 			if ($mixins === null) {
-				// fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
-				break; // throw error here??
+                $block->parser->throwError("{$prop[1][0]} is undefined", $block->count);
+			}
+
+			if(strpos($prop[1][0], "$") === 0) {
+				//Use Ruleset Logic - Only last element
+				$mixins = array(array_pop($mixins));
 			}
 
 			foreach ($mixins as $mixin) {
@@ -710,7 +752,7 @@ class lessc {
 				}
 
 				$oldParent = $mixin->parent;
-				if ($mixin !== $block) $mixin->parent = $block;
+				if ($mixin != $block) $mixin->parent = $block;
 
 				foreach ($this->sortProps($mixin->props) as $subProp) {
 					if ($suffix !== null &&
@@ -773,27 +815,23 @@ class lessc {
 
 			break;
 		default:
-			$this->throwError("unknown op: {$prop[0]}\n");
+            $block->parser->throwError("unknown op: {$prop[0]}\n", $block->count);
 		}
 	}
 
 
-    /**
-     * Compiles a primitive value into a CSS property value.
-     *
-     * Values in lessphp are typed by being wrapped in arrays, their format is
-     * typically:
-     *
-     *     array(type, contents [, additional_contents]*)
-     *
-     * The input is expected to be reduced. This function will not work on
-     * things like expressions and variables.
-     *
-     * @param array $value
-     *
-     * @return string
-     */
-	protected function compileValue($value) {
+	/**
+	 * Compiles a primitive value into a CSS property value.
+	 *
+	 * Values in lessphp are typed by being wrapped in arrays, their format is
+	 * typically:
+	 *
+	 *     array(type, contents [, additional_contents]*)
+	 *
+	 * The input is expected to be reduced. This function will not work on
+	 * things like expressions and variables.
+	 */
+	public function compileValue($value) {
 		switch ($value[0]) {
 		case 'list':
 			// [1] - delimiter
@@ -859,7 +897,7 @@ class lessc {
 
 	protected function lib_pow($args) {
 		list($base, $exp) = $this->assertArgs($args, 2, "pow");
-		return pow($this->assertNumber($base), $this->assertNumber($exp));
+        return array( "number", pow($this->assertNumber($base), $this->assertNumber($exp)), $args[2][0][2] );
 	}
 
 	protected function lib_pi() {
@@ -868,8 +906,66 @@ class lessc {
 
 	protected function lib_mod($args) {
 		list($a, $b) = $this->assertArgs($args, 2, "mod");
-		return $this->assertNumber($a) % $this->assertNumber($b);
-	}
+        return array( "number", $this->assertNumber($a) % $this->assertNumber($b), $args[2][0][2] );
+ 	}
+
+	protected function lib_convert($args) {
+        list($value, $to) = $this->assertArgs($args, 2, "convert");
+
+        // If it's a keyword, grab the string version instead
+        if( is_array( $to ) && $to[0] == "keyword" )
+                $to = $to[1];
+
+ 		return $this->convert( $value, $to );
+ 	}
+
+	protected function lib_abs($num) {
+        return array( "number", abs($this->assertNumber($num)), $num[2] );
+ 	}
+
+	protected function lib_min($args) {
+        $values = $this->assertMinArgs($args, 1, "min");
+
+        $first_format = $values[0][2];
+
+        $min_index = 0;
+        $min_value = $values[0][1];
+
+        for( $a = 0; $a < sizeof( $values ); $a++ )
+        {
+            $converted = $this->convert( $values[$a], $first_format );
+
+            if( $converted[1] < $min_value )
+            {
+                $min_index = $a;
+                $min_value = $values[$a][1];
+            }
+ 		}
+
+ 		return $values[ $min_index ];
+ 	}
+
+	protected function lib_max($args) {
+        $values = $this->assertMinArgs($args, 1, "max");
+
+        $first_format = $values[0][2];
+
+        $max_index = 0;
+        $max_value = $values[0][1];
+
+        for( $a = 0; $a < sizeof( $values ); $a++ )
+        {
+            $converted = $this->convert( $values[$a], $first_format );
+
+            if( $converted[1] > $max_value )
+            {
+                $max_index = $a;
+                $max_value = $values[$a][1];
+            }
+ 		}
+
+ 		return $values[ $max_index ];
+    }
 
 	protected function lib_tan($num) {
 		return tan($this->assertNumber($num));
@@ -957,6 +1053,39 @@ class lessc {
 		return $this->lib_rgbahex($color);
 	}
 
+	/**
+	 * Given an url, decide whether to output a regular link or the base64-encoded contents of the file
+	 *
+	 * @param  array  $value either an argument list (two strings) or a single string
+	 * @return string        formatted url(), either as a link or base64-encoded
+	 */
+	protected function lib_data_uri($value) {
+		$mime = ($value[0] === 'list') ? $value[2][0][2] : null;
+		$url = ($value[0] === 'list') ? $value[2][1][2][0] : $value[2][0];
+
+		$fullpath = $this->findImport($url);
+
+		if($fullpath && ($fsize = filesize($fullpath)) !== false) {
+			// IE8 can't handle data uris larger than 32KB
+			if($fsize/1024 < 32) {
+				if(is_null($mime)) {
+					if(class_exists('finfo')) { // php 5.3+
+						$finfo = new finfo(FILEINFO_MIME);
+						$mime = explode('; ', $finfo->file($fullpath));
+						$mime = $mime[0];
+					} elseif(function_exists('mime_content_type')) { // PHP 5.2
+						$mime = mime_content_type($fullpath);
+					}
+				}
+
+				if(!is_null($mime)) // fallback if the mime type is still unknown
+					$url = sprintf('data:%s;base64,%s', $mime, base64_encode(file_get_contents($fullpath)));
+			}
+		}
+
+		return 'url("'.$url.'")';
+	}
+
 	// utility func to unquote a string
 	protected function lib_e($arg) {
 		switch ($arg[0]) {
@@ -965,7 +1094,7 @@ class lessc {
 				if (isset($items[0])) {
 					return $this->lib_e($items[0]);
 				}
-				return self::$defaultValue;
+				$this->throwError("unrecognised input");
 			case "string":
 				$arg[1] = "";
 				return $arg;
@@ -1015,8 +1144,14 @@ class lessc {
 	}
 
 	protected function lib_round($arg) {
-		$value = $this->assertNumber($arg);
-		return array("number", round($value), $arg[2]);
+		if($arg[0] != "list") {
+			$value = $this->assertNumber($arg);
+			return array("number", round($value), $arg[2]);
+		} else {
+			$value = $this->assertNumber($arg[2][0]);
+			$precision = $this->assertNumber($arg[2][1]);
+			return array("number", round($value, $precision), $arg[2][0][2]);
+		}
 	}
 
 	protected function lib_unit($arg) {
@@ -1029,15 +1164,11 @@ class lessc {
 		}
 	}
 
-    /**
-     * Helper function to get arguments for color manipulation functions.
-     * takes a list that contains a color like thing and a percentage
-     *
-     * @param array $args
-     *
-     * @return array
-     */
-	protected function colorArgs($args) {
+	/**
+	 * Helper function to get arguments for color manipulation functions.
+	 * takes a list that contains a color like thing and a percentage
+	 */
+	public function colorArgs($args) {
 		if ($args[0] != 'list' || count($args[2]) < 2) {
 			return array(array('color', 0, 0, 0), 0);
 		}
@@ -1178,36 +1309,62 @@ class lessc {
 	}
 
 	protected function lib_contrast($args) {
-		if ($args[0] != 'list' || count($args[2]) < 3) {
-			return array(array('color', 0, 0, 0), 0);
-		}
-
-		list($inputColor, $darkColor, $lightColor) = $args[2];
-
-		$inputColor = $this->assertColor($inputColor);
-		$darkColor = $this->assertColor($darkColor);
-		$lightColor = $this->assertColor($lightColor);
-		$hsl = $this->toHSL($inputColor);
-
-		if ($hsl[3] > 50) {
-			return $darkColor;
-		}
-
-		return $lightColor;
-	}
-
-	protected function assertColor($value, $error = "expected color value") {
+	    $darkColor  = array('color', 0, 0, 0);
+	    $lightColor = array('color', 255, 255, 255);
+	    $threshold  = 0.43;
+
+	    if ( $args[0] == 'list' ) {
+	        $inputColor = ( isset($args[2][0]) ) ? $this->assertColor($args[2][0])  : $lightColor;
+	        $darkColor  = ( isset($args[2][1]) ) ? $this->assertColor($args[2][1])  : $darkColor;
+	        $lightColor = ( isset($args[2][2]) ) ? $this->assertColor($args[2][2])  : $lightColor;
+            if( isset($args[2][3]) ) {
+                if( isset($args[2][3][2]) && $args[2][3][2] == '%' ) {
+                    $args[2][3][1] /= 100;
+                    unset($args[2][3][2]);
+ 	        	}
+ 		        $threshold = $this->assertNumber($args[2][3]);
+ 	        }
+	    }
+	    else {
+	        $inputColor  = $this->assertColor($args);
+	    }
+
+	    $inputColor = $this->coerceColor($inputColor);
+	    $darkColor  = $this->coerceColor($darkColor);
+	    $lightColor = $this->coerceColor($lightColor);
+
+	    //Figure out which is actually light and dark!
+	    if ( $this->lib_luma($darkColor) > $this->lib_luma($lightColor) ) {
+	        $t  = $lightColor;
+	        $lightColor = $darkColor;
+	        $darkColor  = $t;
+	    }
+
+	    $inputColor_alpha = $this->lib_alpha($inputColor);
+	    if ( ( $this->lib_luma($inputColor) * $inputColor_alpha) < $threshold) {
+	        return $lightColor;
+	    }
+	    return $darkColor;
+	}
+
+	protected function lib_luma($color) {
+	    $color = $this->coerceColor($color);
+	    return (0.2126 * $color[0] / 255) + (0.7152 * $color[1] / 255) + (0.0722 * $color[2] / 255);
+	}
+
+
+	public function assertColor($value, $error = "expected color value") {
 		$color = $this->coerceColor($value);
 		if (is_null($color)) $this->throwError($error);
 		return $color;
 	}
 
-	protected function assertNumber($value, $error = "expecting number") {
+	public function assertNumber($value, $error = "expecting number") {
 		if ($value[0] == "number") return $value[1];
 		$this->throwError($error);
 	}
 
-	protected function assertArgs($value, $expectedArgs, $name="") {
+	public function assertArgs($value, $expectedArgs, $name="") {
 		if ($expectedArgs == 1) {
 			return $value;
 		} else {
@@ -1226,6 +1383,21 @@ class lessc {
 		}
 	}
 
+	public function assertMinArgs($value, $expectedMinArgs, $name="") {
+    	if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
+ 		$values = $value[2];
+ 		$numValues = count($values);
+ 		if ($expectedMinArgs > $numValues) {
+        	if ($name) {
+            	$name = $name . ": ";
+        	}
+
+ 			$this->throwError("${name}expecting at least $expectedMinArgs arguments, got $numValues");
+ 		}
+
+ 		return $values;
+}
+
 	protected function toHSL($color) {
 		if ($color[0] == 'hsl') return $color;
 
@@ -1272,14 +1444,10 @@ class lessc {
 		return $temp1;
 	}
 
-    /**
-     * Converts a hsl array into a color value in rgb.
-     * Expects H to be in range of 0 to 360, S and L in 0 to 100
-     *
-     * @param array $color
-     *
-     * @return array
-     */
+	/**
+	 * Converts a hsl array into a color value in rgb.
+	 * Expects H to be in range of 0 to 360, S and L in 0 to 100
+	 */
 	protected function toRGB($color) {
 		if ($color[0] == 'color') return $color;
 
@@ -1311,14 +1479,10 @@ class lessc {
 		return min($max, max($min, $v));
 	}
 
-    /**
-     * Convert the rgb, rgba, hsl color literals of function type
-     * as returned by the parser into values of color type.
-     *
-     * @param array $func
-     *
-     * @return bool|mixed
-     */
+	/**
+	 * Convert the rgb, rgba, hsl color literals of function type
+	 * as returned by the parser into values of color type.
+	 */
 	protected function funcToColor($func) {
 		$fname = $func[1];
 		if ($func[2][0] != 'list') return false; // need a list of arguments
@@ -1399,7 +1563,7 @@ class lessc {
 			}
 
 			$seen[$key] = true;
-			$out = $this->reduce($this->get($key, self::$defaultValue));
+			$out = $this->reduce($this->get($key));
 			$seen[$key] = false;
 			return $out;
 		case "list":
@@ -1427,8 +1591,9 @@ class lessc {
 
 			list(, $name, $args) = $value;
 			if ($name == "%") $name = "_sprintf";
+
 			$f = isset($this->libFunctions[$name]) ?
-				$this->libFunctions[$name] : array($this, 'lib_'.$name);
+				$this->libFunctions[$name] : array($this, 'lib_'.str_replace('-', '_', $name));
 
 			if (is_callable($f)) {
 				if ($args[0] == 'list')
@@ -1535,7 +1700,7 @@ class lessc {
 		return $value;
 	}
 
-	protected function toBool($a) {
+	public function toBool($a) {
 		if ($a) return self::$TRUE;
 		else return self::$FALSE;
 	}
@@ -1601,6 +1766,78 @@ class lessc {
 		}
 	}
 
+    protected function convert( $number, $to )
+    {
+        $value = $this->assertNumber( $number );
+        $from = $number[2];
+
+        // easy out
+        if( $from == $to )
+            return $number;
+
+        // check if the from value is a length
+        if( ( $from_index = array_search( $from, self::$lengths ) ) !== false ) {
+            // make sure to value is too
+            if( in_array( $to, self::$lengths ) ) {
+                // do the actual conversion
+                $to_index = array_search( $to, self::$lengths );
+                $px = $value * self::$lengths_to_base[ $from_index ];
+                $result = $px * ( 1 / self::$lengths_to_base[ $to_index ] );
+
+                $result = round( $result, 8 );
+                return array( "number", $result, $to );
+            }
+        }
+
+        // do the same check for times
+        if( in_array( $from, self::$times ) ) {
+            if( in_array( $to, self::$times ) ) {
+                // currently only ms and s are valid
+                if( $to == "ms" )
+                    $result = $value * 1000;
+                else
+                    $result = $value / 1000;
+
+                $result = round( $result, 8 );
+                return array( "number", $result, $to );
+            }
+        }
+
+        // lastly check for an angle
+        if( in_array( $from, self::$angles ) ) {
+            // convert whatever angle it is into degrees
+            if( $from == "rad" )
+                $deg = rad2deg( $value );
+
+            else if( $from == "turn" )
+                $deg = $value * 360;
+
+            else if( $from == "grad" )
+                $deg = $value / (400 / 360);
+
+            else
+                $deg = $value;
+
+            // Then convert it from degrees into desired unit
+            if( $to == "deg" )
+                $result = $deg;
+
+            if( $to == "rad" )
+                $result = deg2rad( $deg );
+
+            if( $to == "turn" )
+                $result = $value / 360;
+
+            if( $to == "grad" )
+                $result = $value * (400 / 360);
+
+            $result = round( $result, 8 );
+            return array( "number", $result, $to );
+        }
+
+        // we don't know how to convert these
+        $this->throwError( "Cannot convert {$from} to {$to}" );
+    }
 
 	// make sure a color's components don't go out of bounds
 	protected function fixColor($c) {
@@ -1758,10 +1995,13 @@ class lessc {
 
 
 	// get the highest occurrence entry for a name
-	protected function get($name, $default=null) {
+	protected function get($name) {
 		$current = $this->env;
 
-		$isArguments = $name == $this->vPrefix . 'arguments';
+        // track scope to evaluate
+        $scope_secondary = array();
+
+        $isArguments = $name == $this->vPrefix . 'arguments';
 		while ($current) {
 			if ($isArguments && isset($current->arguments)) {
 				return array('list', ' ', $current->arguments);
@@ -1769,13 +2009,42 @@ class lessc {
 
 			if (isset($current->store[$name]))
 				return $current->store[$name];
-			else {
-				$current = isset($current->storeParent) ?
-					$current->storeParent : $current->parent;
-			}
+			// has secondary scope?
+			if (isset($current->storeParent))
+				$scope_secondary[] = $current->storeParent;
+
+			if (isset($current->parent))
+				$current = $current->parent;
+			else
+				$current = null;
 		}
 
-		return $default;
+		while (count($scope_secondary)) {
+            // pop one off
+            $current = array_shift($scope_secondary);
+            while ($current) {
+                if ($isArguments && isset($current->arguments)) {
+                    return array('list', ' ', $current->arguments);
+                }
+
+                if (isset($current->store[$name])) {
+                    return $current->store[$name];
+                }
+
+                // has secondary scope?
+                if (isset($current->storeParent)) {
+                    $scope_secondary[] = $current->storeParent;
+                }
+
+                if (isset($current->parent)) {
+                    $current = $current->parent;
+                } else {
+                    $current = null;
+                }
+            }
+        }
+
+		$this->throwError("variable $name is undefined");
 	}
 
 	// inject array of unparsed strings into environment as variables
@@ -1787,19 +2056,17 @@ class lessc {
 			$parser->count = 0;
 			$parser->buffer = (string)$strValue;
 			if (!$parser->propertyValue($value)) {
-				throw new Exception("failed to parse passed in variable $name: $strValue");
+				throw new \Exception("failed to parse passed in variable $name: $strValue");
 			}
 
 			$this->set($name, $value);
 		}
 	}
 
-    /**
-     * Initialize any static state, can initialize parser for a file
-     * $opts isn't used yet
-     *
-     * @param null|string $fname
-     */
+	/**
+	 * Initialize any static state, can initialize parser for a file
+	 * $opts isn't used yet
+	 */
 	public function __construct($fname = null) {
 		if ($fname !== null) {
 			// used for deprecated parse method
@@ -1816,6 +2083,7 @@ class lessc {
 
 		$this->env = null;
 		$this->scope = null;
+        $this->allParsedFiles = array();
 
 		$this->formatter = $this->newFormatter();
 
@@ -1835,7 +2103,7 @@ class lessc {
 
 	public function compileFile($fname, $outFname = null) {
 		if (!is_readable($fname)) {
-			throw new Exception('load error: failed to find '.$fname);
+			throw new \Exception('load error: failed to find '.$fname);
 		}
 
 		$pi = pathinfo($fname);
@@ -1858,6 +2126,43 @@ class lessc {
 		return $out;
 	}
 
+    /**
+     * Based on explicit input/output files does a full change check on cache before compiling.
+     *
+     * @param string $in
+     * @param string $out
+     * @param boolean $force
+     * @return string Compiled CSS results
+     * @throws Exception
+     */
+    public function checkedCachedCompile($in, $out, $force = false) {
+        if (!is_file($in) || !is_readable($in)) {
+            throw new Exception('Invalid or unreadable input file specified.');
+        }
+        if (is_dir($out) || !is_writable(file_exists($out) ? $out : dirname($out))) {
+            throw new Exception('Invalid or unwritable output file specified.');
+        }
+
+        $outMeta = $out . '.meta';
+        $metadata = null;
+        if (!$force && is_file($outMeta)) {
+            $metadata = unserialize(file_get_contents($outMeta));
+        }
+
+        $output = $this->cachedCompile($metadata ? $metadata : $in);
+
+        if (!$metadata || $metadata['updated'] != $output['updated']) {
+            $css = $output['compiled'];
+            unset($output['compiled']);
+            file_put_contents($out, $css);
+            file_put_contents($outMeta, serialize($output));
+        } else {
+            $css = file_get_contents($out);
+        }
+
+        return $css;
+    }
+
 	// compile only if changed input has changed or output doesn't exist
 	public function checkedCompile($in, $out) {
 		if (!is_file($out) || filemtime($in) > filemtime($out)) {
@@ -1946,7 +2251,7 @@ class lessc {
 
 		if ($str == null) {
 			if (empty($this->_parseFile)) {
-				throw new exception("nothing to parse");
+				throw new \Exception("nothing to parse");
 			}
 
 			$out = $this->compileFile($this->_parseFile);
@@ -2013,22 +2318,18 @@ class lessc {
 		return $this->allParsedFiles;
 	}
 
-	protected function addParsedFile($file) {
+	public function addParsedFile($file) {
 		$this->allParsedFiles[realpath($file)] = filemtime($file);
 	}
 
-    /**
-     * Uses the current value of $this->count to show line and line number
-     *
-     * @param null|string $msg
-     *
-     * @throws exception
-     */
-	protected function throwError($msg = null) {
+	/**
+	 * Uses the current value of $this->count to show line and line number
+	 */
+	public function throwError($msg = null) {
 		if ($this->sourceLoc >= 0) {
 			$this->sourceParser->throwError($msg, $this->sourceLoc);
 		}
-		throw new exception($msg);
+		throw new \Exception($msg);
 	}
 
 	// compile file $in to file $out if $in is newer than $out
@@ -2290,15 +2591,14 @@ class lessc_parser {
 		$this->whitespace();
 
 		// parse the entire file
-		$lastCount = $this->count;
 		while (false !== $this->parseChunk());
 
 		if ($this->count != strlen($this->buffer))
 			$this->throwError();
 
 		// TODO report where the block was opened
-		if (!is_null($this->env->parent))
-			throw new exception('parse error: unclosed block');
+		if ( !property_exists($this->env, 'parent') || !is_null($this->env->parent) )
+			throw new \Exception('parse error: unclosed block');
 
 		return $this->env;
 	}
@@ -2343,6 +2643,10 @@ class lessc_parser {
 		if (empty($this->buffer)) return false;
 		$s = $this->seek();
 
+		if ($this->whitespace()) {
+			return true;
+		}
+
 		// setting a property
 		if ($this->keyword($key) && $this->assign() &&
 			$this->propertyValue($value, $key) && $this->end())
@@ -2387,6 +2691,16 @@ class lessc_parser {
 						$this->append(array("directive", $dirName, $dirValue));
 						return true;
 					}
+				} elseif ($this->literal(":", true)) {
+					//Ruleset Definition
+					if (($this->openString("{", $dirValue, null, array(";")) || true) &&
+							$this->literal("{"))
+					{
+						$dir = $this->pushBlock($this->fixTags(array("@".$dirName)));
+						$dir->name = $dirName;
+						if (isset($dirValue)) $dir->value = $dirValue;
+						return true;
+					}
 				}
 			}
 
@@ -2423,7 +2737,7 @@ class lessc_parser {
 		}
 
 		// opening a simple block
-		if ($this->tags($tags) && $this->literal('{')) {
+		if ($this->tags($tags) && $this->literal('{', false)) {
 			$tags = $this->fixTags($tags);
 			$this->pushBlock($tags);
 			return true;
@@ -2435,7 +2749,7 @@ class lessc_parser {
 		if ($this->literal('}', false)) {
 			try {
 				$block = $this->pop();
-			} catch (exception $e) {
+			} catch (\Exception $e) {
 				$this->seek($s);
 				$this->throwError($e->getMessage());
 			}
@@ -2519,15 +2833,10 @@ class lessc_parser {
 		return true;
 	}
 
-    /**
-     * Attempt to consume an expression.
-     *
-     * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
-     *
-     * @param array $out
-     *
-     * @return bool
-     */
+	/**
+	 * Attempt to consume an expression.
+	 * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
+	 */
 	protected function expression(&$out) {
 		if ($this->value($lhs)) {
 			$out = $this->expHelper($lhs, 0);
@@ -2549,14 +2858,9 @@ class lessc_parser {
 		return false;
 	}
 
-    /**
-     * recursively parse infix equation with $lhs at precedence $minP
-     *
-     * @param array $lhs
-     * @param mixed $minP
-     *
-     * @return array
-     */
+	/**
+	 * recursively parse infix equation with $lhs at precedence $minP
+	 */
 	protected function expHelper($lhs, $minP) {
 		$this->inExp = true;
 		$ss = $this->seek();
@@ -2674,7 +2978,7 @@ class lessc_parser {
 		if ($this->unit($value)) return true;
 		if ($this->color($value)) return true;
 		if ($this->func($value)) return true;
-		if ($this->string($value)) return true;
+		if ($this->stringValue($value)) return true;
 
 		if ($this->keyword($word)) {
 			$value = array('keyword', $word);
@@ -2688,7 +2992,7 @@ class lessc_parser {
 		}
 
 		// unquote string (should this work on any type?
-		if ($this->literal("~") && $this->string($str)) {
+		if ($this->literal("~") && $this->stringValue($str)) {
 			$value = array("escape", $str);
 			return true;
 		} else {
@@ -2708,7 +3012,6 @@ class lessc_parser {
 
 	// an import statement
 	protected function import(&$out) {
-		$s = $this->seek();
 		if (!$this->literal('@import')) return false;
 
 		// @import "something.css" media;
@@ -2819,7 +3122,7 @@ class lessc_parser {
 				}
 			}
 
-			if (($tok == "'" || $tok == '"') && $this->string($str)) {
+			if (($tok == "'" || $tok == '"') && $this->stringValue($str)) {
 				$content[] = $str;
 				continue;
 			}
@@ -2850,7 +3153,7 @@ class lessc_parser {
 		return true;
 	}
 
-	protected function string(&$out) {
+	protected function stringValue(&$out) {
 		$s = $this->seek();
 		if ($this->literal('"', false)) {
 			$delim = '"';
@@ -3068,7 +3371,6 @@ class lessc_parser {
 	// list of tags of specifying mixin path
 	// optionally separated by > (lazy, accepts extra >)
 	protected function mixinTags(&$tags) {
-		$s = $this->seek();
 		$tags = array();
 		while ($this->tag($tt, true)) {
 			$tags[] = $tt;
@@ -3104,7 +3406,7 @@ class lessc_parser {
 					$attrParts[] = " ";
 					continue;
 				}
-				if ($this->string($str)) {
+				if ($this->stringValue($str)) {
 					// escape parent selector, (yuck)
 					foreach ($str[2] as &$chunk) {
 						$chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
@@ -3276,14 +3578,10 @@ class lessc_parser {
 		return false;
 	}
 
-    /**
-     * Consume an assignment operator
-     * Can optionally take a name that will be set to the current property name
-     *
-     * @param null|string $name
-     *
-     * @return bool
-     */
+	/**
+	 * Consume an assignment operator
+	 * Can optionally take a name that will be set to the current property name
+	 */
 	protected function assign($name = null) {
 		if ($name) $this->currentProperty = $name;
 		return $this->literal(':') || $this->literal('=');
@@ -3300,7 +3598,7 @@ class lessc_parser {
 
 	// consume an end of statement delimiter
 	protected function end() {
-		if ($this->literal(';')) {
+		if ($this->literal(';', false)) {
 			return true;
 		} elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
 			// if there is end of file or a closing block next then we don't need a ;
@@ -3449,9 +3747,9 @@ class lessc_parser {
 		if ($this->writeComments) {
 			$gotWhite = false;
 			while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
-				if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
+				if (isset($m[1]) && empty($this->seenComments[$this->count])) {
 					$this->append(array("comment", $m[1]));
-					$this->commentsSeen[$this->count] = true;
+					$this->seenComments[$this->count] = true;
 				}
 				$this->count += strlen($m[0]);
 				$gotWhite = true;
@@ -3495,14 +3793,14 @@ class lessc_parser {
 
 		// TODO this depends on $this->count
 		if ($this->peek("(.*?)(\n|$)", $m, $count)) {
-			throw new exception("$msg: failed at `$m[1]` $loc");
+			throw new \Exception("$msg: failed at `$m[1]` $loc");
 		} else {
-			throw new exception("$msg: $loc");
+			throw new \Exception("$msg: $loc");
 		}
 	}
 
 	protected function pushBlock($selectors=null, $type=null) {
-		$b = new stdclass;
+		$b = new \stdClass();
 		$b->parent = $this->env;
 
 		$b->type = $type;
@@ -3514,6 +3812,14 @@ class lessc_parser {
 		$b->props = array();
 		$b->children = array();
 
+        // add a reference to the parser so
+        // we can access the parser to throw errors
+        // or retrieve the sourceName of this block.
+        $b->parser = $this;
+
+        // so we know the position of this block
+        $b->count = $this->count;
+
 		$this->env = $b;
 		return $b;
 	}
diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php
index be7388dfd3b801d8e2ac16c5c495e43cd37fabf9..9a4fab99197125859b0c08484c1fe0abb284ad9d 100644
--- a/vendor/paragonie/random_compat/lib/cast_to_int.php
+++ b/vendor/paragonie/random_compat/lib/cast_to_int.php
@@ -38,9 +38,10 @@ if (!is_callable('RandomCompat_intval')) {
      * through.
      * 
      * @param int|float $number    The number we want to convert to an int
-     * @param boolean   $fail_open Set to true to not throw an exception
+     * @param bool      $fail_open Set to true to not throw an exception
      * 
      * @return float|int
+     * @psalm-suppress InvalidReturnType
      *
      * @throws TypeError
      */
diff --git a/vendor/paragonie/random_compat/lib/random.php b/vendor/paragonie/random_compat/lib/random.php
index df74c8a4b624fa410ec45c5e8f1678cdc73f33a0..080b87c199d47a85a41bb4fb1da09689d4116883 100644
--- a/vendor/paragonie/random_compat/lib/random.php
+++ b/vendor/paragonie/random_compat/lib/random.php
@@ -203,8 +203,9 @@ if (!is_callable('random_bytes')) {
          * and hope the developer won't let it fail silently.
          *
          * @param mixed $length
-         * @return void
+         * @psalm-suppress MissingReturnType
          * @throws Exception
+         * @return string
          */
         function random_bytes($length)
         {
@@ -212,6 +213,7 @@ if (!is_callable('random_bytes')) {
             throw new Exception(
                 'There is no suitable CSPRNG installed on your system'
             );
+            return '';
         }
     }
 }
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php
index 02160b91924efb19868fa2f7fc6af64b91ee7565..705af5262bde0e092ca26aff660ae38b8a6e3e87 100644
--- a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php
+++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php
@@ -70,10 +70,10 @@ if (!is_callable('random_bytes')) {
                 $n = ($bytes - $i) > 1073741824
                     ? 1073741824
                     : $bytes - $i;
-                $buf .= Sodium::randombytes_buf($n);
+                $buf .= Sodium::randombytes_buf((int) $n);
             }
         } else {
-            $buf .= Sodium::randombytes_buf($bytes);
+            $buf .= Sodium::randombytes_buf((int) $bytes);
         }
 
         if (is_string($buf)) {
diff --git a/vendor/paragonie/random_compat/lib/random_int.php b/vendor/paragonie/random_compat/lib/random_int.php
index b2ea02d17c5f820ecde415875a16904d5c8007c2..5b2143a16297a5ee79ba48f997ef2f39e5d97696 100644
--- a/vendor/paragonie/random_compat/lib/random_int.php
+++ b/vendor/paragonie/random_compat/lib/random_int.php
@@ -78,7 +78,7 @@ if (!is_callable('random_int')) {
         }
 
         if ($max === $min) {
-            return $min;
+            return (int) $min;
         }
 
         /**
@@ -185,6 +185,6 @@ if (!is_callable('random_int')) {
              */
         } while (!is_int($val) || $val > $max || $val < $min);
 
-        return (int)$val;
+        return (int) $val;
     }
 }
diff --git a/vendor/paragonie/random_compat/psalm.xml b/vendor/paragonie/random_compat/psalm.xml
index f501315602d6bb52f047c217eed74efb8e3bd113..ee072a972adf83d77da058b68d5bfea1a3bcd860 100644
--- a/vendor/paragonie/random_compat/psalm.xml
+++ b/vendor/paragonie/random_compat/psalm.xml
@@ -8,6 +8,9 @@
         <directory name="lib" />
     </projectFiles>
     <issueHandlers>
+        <RedundantConditionGivenDocblockType errorLevel="info" />
+        <UnresolvableInclude errorLevel="info" />
+        <DuplicateClass errorLevel="info" />
         <InvalidOperand errorLevel="info" />
         <UndefinedConstant errorLevel="info" />
         <MissingReturnType errorLevel="info" />
diff --git a/vendor/phpseclib/phpseclib/README.md b/vendor/phpseclib/phpseclib/README.md
index a6bde111ce104ec109bd803d3065e6b716268b03..94402bee0dc48b41bd6149a5c89a50d52c7b15d3 100644
--- a/vendor/phpseclib/phpseclib/README.md
+++ b/vendor/phpseclib/phpseclib/README.md
@@ -6,17 +6,37 @@ MIT-licensed pure-PHP implementations of an arbitrary-precision integer
 arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael,
 AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
 
-* [Download (1.0.4)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.4.zip/download)
 * [Browse Git](https://github.com/phpseclib/phpseclib)
-* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/2.0/latest/)
-
-<img src="http://phpseclib.sourceforge.net/pear-icon.png" alt="PEAR Channel" width="16" height="16">
-PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm)
+* [Code Coverage Report](https://coverage.phpseclib.org/2.0/latest/)
 
 ## Documentation
 
 * [Documentation / Manual](http://phpseclib.sourceforge.net/)
-* [API Documentation](http://phpseclib.bantux.org/api/2.0/) (generated by Sami)
+* [API Documentation](https://api.phpseclib.org/2.0/) (generated by Sami)
+
+## Branches
+
+### master
+
+* Development Branch
+* Unstable API
+* Do not use in production
+
+### 2.0
+
+* Modernized version of 1.0
+* Minimum PHP version: 5.3.3
+* PSR-4 autoloading with namespace rooted at `\phpseclib`
+* Install via Composer: `composer require phpseclib/phpseclib ~2.0`
+
+### 1.0
+
+* Long term support (LTS) release
+* PHP4 compatible
+* Composer compatible (PSR-0 autoloading)
+* Install using Composer: `composer require phpseclib/phpseclib ~1.0`
+* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm)
+* [Download 1.0.10 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.10.zip/download)
 
 ## Support
 
@@ -26,40 +46,29 @@ Need Support?
 * [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new)
 * [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use)
 
-## Installing Development Dependencies
-
-Dependencies are managed via Composer.
+## Contributing
 
-1. Download the [`composer.phar`](https://getcomposer.org/composer.phar) executable as per the
-   [Composer Download Instructions](https://getcomposer.org/download/), e.g. by running
+1. Fork the Project
 
-    ``` sh
-    curl -sS https://getcomposer.org/installer | php
-    ```
+2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/))
 
-2. Install Dependencies
+3. Install Development Dependencies
 
     ``` sh
-    php composer.phar install
+    composer install
     ```
 
-## Contributing
-
-1. Fork the Project
-
-2. Install Development Dependencies
-
-3. Create a Feature Branch
+4. Create a Feature Branch
 
-4. (Recommended) Run the Test Suite
+5. (Recommended) Run the Test Suite
 
     ``` sh
     vendor/bin/phpunit
     ```
-5. (Recommended) Check whether your code conforms to our Coding Standards by running
+6. (Recommended) Check whether your code conforms to our Coding Standards by running
 
     ``` sh
     vendor/bin/phing -f build/build.xml sniff
     ```
 
-6. Send us a Pull Request
+7. Send us a Pull Request
diff --git a/vendor/phpseclib/phpseclib/composer.json b/vendor/phpseclib/phpseclib/composer.json
index 4b84b110e66afe7c206c51c2a1e286a2de384a66..b4e8a1c9c9213efd79ec15cfcc7f8d8150e5a7ac 100644
--- a/vendor/phpseclib/phpseclib/composer.json
+++ b/vendor/phpseclib/phpseclib/composer.json
@@ -55,7 +55,7 @@
     },
     "require-dev": {
         "phing/phing": "~2.7",
-        "phpunit/phpunit": "~4.0",
+        "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
         "sami/sami": "~2.0",
         "squizlabs/php_codesniffer": "~2.0"
     },
diff --git a/vendor/phpseclib/phpseclib/composer.lock b/vendor/phpseclib/phpseclib/composer.lock
deleted file mode 100644
index beda2d64016f1a21c24dcb0b6f2a0acc8026fb00..0000000000000000000000000000000000000000
--- a/vendor/phpseclib/phpseclib/composer.lock
+++ /dev/null
@@ -1,1819 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
-        "This file is @generated automatically"
-    ],
-    "hash": "8599992bf6058a9da82372eb8bcae2c2",
-    "content-hash": "fde47c84178c55c06de858a2128e3d07",
-    "packages": [],
-    "packages-dev": [
-        {
-            "name": "doctrine/instantiator",
-            "version": "1.0.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3,<8.0-DEV"
-            },
-            "require-dev": {
-                "athletic/athletic": "~0.1.8",
-                "ext-pdo": "*",
-                "ext-phar": "*",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "homepage": "http://ocramius.github.com/"
-                }
-            ],
-            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
-            "homepage": "https://github.com/doctrine/instantiator",
-            "keywords": [
-                "constructor",
-                "instantiate"
-            ],
-            "time": "2015-06-14 21:17:01"
-        },
-        {
-            "name": "michelf/php-markdown",
-            "version": "1.6.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/michelf/php-markdown.git",
-                "reference": "156e56ee036505ec637d761ee62dc425d807183c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/michelf/php-markdown/zipball/156e56ee036505ec637d761ee62dc425d807183c",
-                "reference": "156e56ee036505ec637d761ee62dc425d807183c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-lib": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Michelf": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Michel Fortin",
-                    "email": "michel.fortin@michelf.ca",
-                    "homepage": "https://michelf.ca/",
-                    "role": "Developer"
-                },
-                {
-                    "name": "John Gruber",
-                    "homepage": "https://daringfireball.net/"
-                }
-            ],
-            "description": "PHP Markdown",
-            "homepage": "https://michelf.ca/projects/php-markdown/",
-            "keywords": [
-                "markdown"
-            ],
-            "time": "2015-12-24 01:37:31"
-        },
-        {
-            "name": "nikic/php-parser",
-            "version": "v0.9.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb",
-                "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": ">=5.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "0.9-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "PHPParser": "lib/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Nikita Popov"
-                }
-            ],
-            "description": "A PHP parser written in PHP",
-            "keywords": [
-                "parser",
-                "php"
-            ],
-            "time": "2014-07-23 18:24:17"
-        },
-        {
-            "name": "phing/phing",
-            "version": "2.14.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phingofficial/phing.git",
-                "reference": "7dd73c83c377623def54b58121f46b4dcb35dd61"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phingofficial/phing/zipball/7dd73c83c377623def54b58121f46b4dcb35dd61",
-                "reference": "7dd73c83c377623def54b58121f46b4dcb35dd61",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.2.0"
-            },
-            "require-dev": {
-                "ext-pdo_sqlite": "*",
-                "lastcraft/simpletest": "@dev",
-                "mikey179/vfsstream": "^1.6",
-                "pdepend/pdepend": "2.x",
-                "pear/archive_tar": "1.4.x",
-                "pear/http_request2": "dev-trunk",
-                "pear/net_growl": "dev-trunk",
-                "pear/pear-core-minimal": "1.10.1",
-                "pear/versioncontrol_git": "@dev",
-                "pear/versioncontrol_svn": "~0.5",
-                "phpdocumentor/phpdocumentor": "2.x",
-                "phploc/phploc": "~2.0.6",
-                "phpmd/phpmd": "~2.2",
-                "phpunit/phpunit": ">=3.7",
-                "sebastian/git": "~1.0",
-                "sebastian/phpcpd": "2.x",
-                "squizlabs/php_codesniffer": "~2.2",
-                "symfony/yaml": "~2.7"
-            },
-            "suggest": {
-                "pdepend/pdepend": "PHP version of JDepend",
-                "pear/archive_tar": "Tar file management class",
-                "pear/versioncontrol_git": "A library that provides OO interface to handle Git repository",
-                "pear/versioncontrol_svn": "A simple OO-style interface for Subversion, the free/open-source version control system",
-                "phpdocumentor/phpdocumentor": "Documentation Generator for PHP",
-                "phploc/phploc": "A tool for quickly measuring the size of a PHP project",
-                "phpmd/phpmd": "PHP version of PMD tool",
-                "phpunit/php-code-coverage": "Library that provides collection, processing, and rendering functionality for PHP code coverage information",
-                "phpunit/phpunit": "The PHP Unit Testing Framework",
-                "sebastian/phpcpd": "Copy/Paste Detector (CPD) for PHP code",
-                "tedivm/jshrink": "Javascript Minifier built in PHP"
-            },
-            "bin": [
-                "bin/phing"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.14.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "classes/phing/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "include-path": [
-                "classes"
-            ],
-            "license": [
-                "LGPL-3.0"
-            ],
-            "authors": [
-                {
-                    "name": "Michiel Rook",
-                    "email": "mrook@php.net"
-                },
-                {
-                    "name": "Phing Community",
-                    "homepage": "https://www.phing.info/trac/wiki/Development/Contributors"
-                }
-            ],
-            "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.",
-            "homepage": "https://www.phing.info/",
-            "keywords": [
-                "build",
-                "phing",
-                "task",
-                "tool"
-            ],
-            "time": "2016-03-10 21:39:23"
-        },
-        {
-            "name": "phpdocumentor/reflection-common",
-            "version": "1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
-                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
-                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jaap van Otterdijk",
-                    "email": "opensource@ijaap.nl"
-                }
-            ],
-            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
-            "homepage": "http://www.phpdoc.org",
-            "keywords": [
-                "FQSEN",
-                "phpDocumentor",
-                "phpdoc",
-                "reflection",
-                "static analysis"
-            ],
-            "time": "2015-12-27 11:43:31"
-        },
-        {
-            "name": "phpdocumentor/reflection-docblock",
-            "version": "3.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
-                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5",
-                "phpdocumentor/reflection-common": "^1.0@dev",
-                "phpdocumentor/type-resolver": "^0.2.0",
-                "webmozart/assert": "^1.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^4.4"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2016-06-10 09:48:41"
-        },
-        {
-            "name": "phpdocumentor/type-resolver",
-            "version": "0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
-                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5",
-                "phpdocumentor/reflection-common": "^1.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^5.2||^4.8.24"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "time": "2016-06-10 07:14:17"
-        },
-        {
-            "name": "phpspec/prophecy",
-            "version": "v1.6.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
-                "reference": "58a8137754bc24b25740d4281399a4a3596058e0",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": "^5.3|^7.0",
-                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
-                "sebastian/comparator": "^1.1",
-                "sebastian/recursion-context": "^1.0"
-            },
-            "require-dev": {
-                "phpspec/phpspec": "^2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Prophecy\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Konstantin Kudryashov",
-                    "email": "ever.zet@gmail.com",
-                    "homepage": "http://everzet.com"
-                },
-                {
-                    "name": "Marcello Duarte",
-                    "email": "marcello.duarte@gmail.com"
-                }
-            ],
-            "description": "Highly opinionated mocking framework for PHP 5.3+",
-            "homepage": "https://github.com/phpspec/prophecy",
-            "keywords": [
-                "Double",
-                "Dummy",
-                "fake",
-                "mock",
-                "spy",
-                "stub"
-            ],
-            "time": "2016-06-07 08:13:47"
-        },
-        {
-            "name": "phpunit/php-code-coverage",
-            "version": "2.2.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "phpunit/php-file-iterator": "~1.3",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-token-stream": "~1.3",
-                "sebastian/environment": "^1.3.2",
-                "sebastian/version": "~1.0"
-            },
-            "require-dev": {
-                "ext-xdebug": ">=2.1.4",
-                "phpunit/phpunit": "~4"
-            },
-            "suggest": {
-                "ext-dom": "*",
-                "ext-xdebug": ">=2.2.1",
-                "ext-xmlwriter": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
-            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
-            "keywords": [
-                "coverage",
-                "testing",
-                "xunit"
-            ],
-            "time": "2015-10-06 15:47:00"
-        },
-        {
-            "name": "phpunit/php-file-iterator",
-            "version": "1.4.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
-                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
-            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
-            "keywords": [
-                "filesystem",
-                "iterator"
-            ],
-            "time": "2015-06-21 13:08:43"
-        },
-        {
-            "name": "phpunit/php-text-template",
-            "version": "1.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Simple template engine.",
-            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
-            "keywords": [
-                "template"
-            ],
-            "time": "2015-06-21 13:50:34"
-        },
-        {
-            "name": "phpunit/php-timer",
-            "version": "1.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
-            },
-            "dist": {
-                "type": "zip",
-                "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": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Utility class for timing",
-            "homepage": "https://github.com/sebastianbergmann/php-timer/",
-            "keywords": [
-                "timer"
-            ],
-            "time": "2016-05-12 18:03:57"
-        },
-        {
-            "name": "phpunit/php-token-stream",
-            "version": "1.4.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
-                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Wrapper around PHP's tokenizer extension.",
-            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
-            "keywords": [
-                "tokenizer"
-            ],
-            "time": "2015-09-15 10:49:45"
-        },
-        {
-            "name": "phpunit/phpunit",
-            "version": "4.8.26",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
-                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-json": "*",
-                "ext-pcre": "*",
-                "ext-reflection": "*",
-                "ext-spl": "*",
-                "php": ">=5.3.3",
-                "phpspec/prophecy": "^1.3.1",
-                "phpunit/php-code-coverage": "~2.1",
-                "phpunit/php-file-iterator": "~1.4",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-timer": "^1.0.6",
-                "phpunit/phpunit-mock-objects": "~2.3",
-                "sebastian/comparator": "~1.1",
-                "sebastian/diff": "~1.2",
-                "sebastian/environment": "~1.3",
-                "sebastian/exporter": "~1.2",
-                "sebastian/global-state": "~1.0",
-                "sebastian/version": "~1.0",
-                "symfony/yaml": "~2.1|~3.0"
-            },
-            "suggest": {
-                "phpunit/php-invoker": "~1.1"
-            },
-            "bin": [
-                "phpunit"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.8.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "The PHP Unit Testing framework.",
-            "homepage": "https://phpunit.de/",
-            "keywords": [
-                "phpunit",
-                "testing",
-                "xunit"
-            ],
-            "time": "2016-05-17 03:09:28"
-        },
-        {
-            "name": "phpunit/phpunit-mock-objects",
-            "version": "2.3.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": ">=5.3.3",
-                "phpunit/php-text-template": "~1.2",
-                "sebastian/exporter": "~1.2"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "suggest": {
-                "ext-soap": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Mock Object library for PHPUnit",
-            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
-            "keywords": [
-                "mock",
-                "xunit"
-            ],
-            "time": "2015-10-02 06:51:40"
-        },
-        {
-            "name": "pimple/pimple",
-            "version": "v2.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/silexphp/Pimple.git",
-                "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/silexphp/Pimple/zipball/ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
-                "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Pimple": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                }
-            ],
-            "description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
-            "homepage": "http://pimple.sensiolabs.org",
-            "keywords": [
-                "container",
-                "dependency injection"
-            ],
-            "time": "2014-07-24 07:10:08"
-        },
-        {
-            "name": "sami/sami",
-            "version": "v2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/FriendsOfPHP/Sami.git",
-                "reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/Sami/zipball/fa58b324f41aa2aefe21dac4f22d8c98965fc012",
-                "reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012",
-                "shasum": ""
-            },
-            "require": {
-                "michelf/php-markdown": "~1.3",
-                "nikic/php-parser": "0.9.*",
-                "php": ">=5.3.0",
-                "pimple/pimple": "2.*",
-                "symfony/console": "~2.1",
-                "symfony/filesystem": "~2.1",
-                "symfony/finder": "~2.1",
-                "symfony/process": "~2.1",
-                "symfony/yaml": "~2.1",
-                "twig/twig": "1.*"
-            },
-            "bin": [
-                "sami.php"
-            ],
-            "type": "application",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Sami": "."
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                }
-            ],
-            "description": "Sami, an API documentation generator",
-            "homepage": "http://sami.sensiolabs.org",
-            "keywords": [
-                "phpdoc"
-            ],
-            "time": "2014-06-25 12:05:18"
-        },
-        {
-            "name": "sebastian/comparator",
-            "version": "1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
-                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "sebastian/diff": "~1.2",
-                "sebastian/exporter": "~1.2"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides the functionality to compare PHP values for equality",
-            "homepage": "http://www.github.com/sebastianbergmann/comparator",
-            "keywords": [
-                "comparator",
-                "compare",
-                "equality"
-            ],
-            "time": "2015-07-26 15:48:44"
-        },
-        {
-            "name": "sebastian/diff",
-            "version": "1.4.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
-                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.8"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Kore Nordmann",
-                    "email": "mail@kore-nordmann.de"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Diff implementation",
-            "homepage": "https://github.com/sebastianbergmann/diff",
-            "keywords": [
-                "diff"
-            ],
-            "time": "2015-12-08 07:14:41"
-        },
-        {
-            "name": "sebastian/environment",
-            "version": "1.3.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
-                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
-            "keywords": [
-                "Xdebug",
-                "environment",
-                "hhvm"
-            ],
-            "time": "2016-05-17 03:18:57"
-        },
-        {
-            "name": "sebastian/exporter",
-            "version": "1.2.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "sebastian/recursion-context": "~1.0"
-            },
-            "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides the functionality to export PHP variables for visualization",
-            "homepage": "http://www.github.com/sebastianbergmann/exporter",
-            "keywords": [
-                "export",
-                "exporter"
-            ],
-            "time": "2016-06-17 09:04:28"
-        },
-        {
-            "name": "sebastian/global-state",
-            "version": "1.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.2"
-            },
-            "suggest": {
-                "ext-uopz": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
-            "keywords": [
-                "global state"
-            ],
-            "time": "2015-10-12 03:26:01"
-        },
-        {
-            "name": "sebastian/recursion-context",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides functionality to recursively process PHP variables",
-            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2015-11-11 19:50:13"
-        },
-        {
-            "name": "sebastian/version",
-            "version": "1.0.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "shasum": ""
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
-            "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21 13:59:46"
-        },
-        {
-            "name": "squizlabs/php_codesniffer",
-            "version": "2.6.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
-                "reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
-                "reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
-                "shasum": ""
-            },
-            "require": {
-                "ext-simplexml": "*",
-                "ext-tokenizer": "*",
-                "ext-xmlwriter": "*",
-                "php": ">=5.1.2"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "bin": [
-                "scripts/phpcs",
-                "scripts/phpcbf"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "CodeSniffer.php",
-                    "CodeSniffer/CLI.php",
-                    "CodeSniffer/Exception.php",
-                    "CodeSniffer/File.php",
-                    "CodeSniffer/Fixer.php",
-                    "CodeSniffer/Report.php",
-                    "CodeSniffer/Reporting.php",
-                    "CodeSniffer/Sniff.php",
-                    "CodeSniffer/Tokens.php",
-                    "CodeSniffer/Reports/",
-                    "CodeSniffer/Tokenizers/",
-                    "CodeSniffer/DocGenerators/",
-                    "CodeSniffer/Standards/AbstractPatternSniff.php",
-                    "CodeSniffer/Standards/AbstractScopeSniff.php",
-                    "CodeSniffer/Standards/AbstractVariableSniff.php",
-                    "CodeSniffer/Standards/IncorrectPatternException.php",
-                    "CodeSniffer/Standards/Generic/Sniffs/",
-                    "CodeSniffer/Standards/MySource/Sniffs/",
-                    "CodeSniffer/Standards/PEAR/Sniffs/",
-                    "CodeSniffer/Standards/PSR1/Sniffs/",
-                    "CodeSniffer/Standards/PSR2/Sniffs/",
-                    "CodeSniffer/Standards/Squiz/Sniffs/",
-                    "CodeSniffer/Standards/Zend/Sniffs/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Greg Sherwood",
-                    "role": "lead"
-                }
-            ],
-            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
-            "homepage": "http://www.squizlabs.com/php-codesniffer",
-            "keywords": [
-                "phpcs",
-                "standards"
-            ],
-            "time": "2016-05-30 22:24:32"
-        },
-        {
-            "name": "symfony/console",
-            "version": "v2.8.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/console.git",
-                "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
-                "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/event-dispatcher": "~2.1|~3.0.0",
-                "symfony/process": "~2.1|~3.0.0"
-            },
-            "suggest": {
-                "psr/log": "For using the console logger",
-                "symfony/event-dispatcher": "",
-                "symfony/process": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Console\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Console Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-06-06 15:06:25"
-        },
-        {
-            "name": "symfony/filesystem",
-            "version": "v2.8.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/filesystem.git",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Filesystem\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Filesystem Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-04-12 18:01:21"
-        },
-        {
-            "name": "symfony/finder",
-            "version": "v2.8.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/finder.git",
-                "reference": "3ec095fab1800222732ca522a95dce8fa124007b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b",
-                "reference": "3ec095fab1800222732ca522a95dce8fa124007b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Finder\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Finder Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
-        },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "dff51f72b0706335131b00a7f49606168c582594"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
-                "reference": "dff51f72b0706335131b00a7f49606168c582594",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2016-05-18 14:26:46"
-        },
-        {
-            "name": "symfony/process",
-            "version": "v2.8.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/process.git",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Process\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Process Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
-        },
-        {
-            "name": "symfony/yaml",
-            "version": "v2.8.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
-        },
-        {
-            "name": "twig/twig",
-            "version": "v1.24.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/twigphp/Twig.git",
-                "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512",
-                "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.2.7"
-            },
-            "require-dev": {
-                "symfony/debug": "~2.7",
-                "symfony/phpunit-bridge": "~2.7"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.24-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Twig_": "lib/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com",
-                    "homepage": "http://fabien.potencier.org",
-                    "role": "Lead Developer"
-                },
-                {
-                    "name": "Armin Ronacher",
-                    "email": "armin.ronacher@active-4.com",
-                    "role": "Project Founder"
-                },
-                {
-                    "name": "Twig Team",
-                    "homepage": "http://twig.sensiolabs.org/contributors",
-                    "role": "Contributors"
-                }
-            ],
-            "description": "Twig, the flexible, fast, and secure template language for PHP",
-            "homepage": "http://twig.sensiolabs.org",
-            "keywords": [
-                "templating"
-            ],
-            "time": "2016-05-30 09:11:59"
-        },
-        {
-            "name": "webmozart/assert",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/webmozart/assert.git",
-                "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
-                "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Webmozart\\Assert\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@gmail.com"
-                }
-            ],
-            "description": "Assertions to validate method input/output with nice error messages.",
-            "keywords": [
-                "assert",
-                "check",
-                "validate"
-            ],
-            "time": "2015-08-24 13:29:44"
-        }
-    ],
-    "aliases": [],
-    "minimum-stability": "stable",
-    "stability-flags": [],
-    "prefer-stable": false,
-    "prefer-lowest": false,
-    "platform": {
-        "php": ">=5.3.3"
-    },
-    "platform-dev": []
-}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
index fd99c44f322b35c8b407886f290ed6f3ec3b91ff..54a8997ed8efd6e8455d7f3edd618ccd22803c8f 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
@@ -492,8 +492,8 @@ abstract class Base
         $this->_setEngine();
 
         // Determining whether inline crypting can be used by the cipher
-        if ($this->use_inline_crypt !== false && function_exists('create_function')) {
-            $this->use_inline_crypt = true;
+        if ($this->use_inline_crypt !== false) {
+            $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
         }
     }
 
@@ -2492,6 +2492,11 @@ abstract class Base
         }
 
         // Create the $inline function and return its name as string. Ready to run!
+        if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+            eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
+            return $func;
+        }
+
         return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
     }
 
@@ -2550,4 +2555,44 @@ abstract class Base
                 return $result . pack('H*', sha1($hash));
         }
     }
+
+    /**
+     * Convert float to int
+     *
+     * On ARM CPUs converting floats to ints doesn't always work
+     *
+     * @access private
+     * @param string $x
+     * @return int
+     */
+    function safe_intval($x)
+    {
+        switch (true) {
+            case is_int($x):
+            // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
+            case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
+                return $x;
+        }
+        return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
+            ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
+    }
+
+    /**
+     * eval()'able string for in-line float to int
+     *
+     * @access private
+     * @return string
+     */
+    function safe_intval_inline()
+    {
+        switch (true) {
+            case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
+            case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
+                return '%s';
+                break;
+            default:
+                $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
+                return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
+        }
+    }
 }
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
index 3949e8123f881864e4e300ee7f585fd7d3fd0319..74cc49de8abac9a0c3c87065db73addd9bb47352 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
@@ -294,7 +294,7 @@ class Blowfish extends Base
     function setKeyLength($length)
     {
         if ($length < 32) {
-            $this->key_length = 7;
+            $this->key_length = 4;
         } elseif ($length > 448) {
             $this->key_length = 56;
         } else {
@@ -317,7 +317,10 @@ class Blowfish extends Base
     function isValidEngine($engine)
     {
         if ($engine == self::ENGINE_OPENSSL) {
-            if ($this->key_length != 16) {
+            if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
+                return false;
+            }
+            if ($this->key_length < 16) {
                 return false;
             }
             $this->cipher_name_openssl_ecb = 'bf-ecb';
@@ -405,16 +408,14 @@ class Blowfish extends Base
 
         for ($i = 0; $i < 16; $i+= 2) {
             $l^= $p[$i];
-            $r^= ($sb_0[$l >> 24 & 0xff]  +
-                  $sb_1[$l >> 16 & 0xff]  ^
+            $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff]  + $sb_1[$l >> 16 & 0xff]) ^
                   $sb_2[$l >>  8 & 0xff]) +
-                  $sb_3[$l       & 0xff];
+                  $sb_3[$l       & 0xff]);
 
             $r^= $p[$i + 1];
-            $l^= ($sb_0[$r >> 24 & 0xff]  +
-                  $sb_1[$r >> 16 & 0xff]  ^
+            $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff]  + $sb_1[$r >> 16 & 0xff]) ^
                   $sb_2[$r >>  8 & 0xff]) +
-                  $sb_3[$r       & 0xff];
+                  $sb_3[$r       & 0xff]);
         }
         return pack("N*", $r ^ $p[17], $l ^ $p[16]);
     }
@@ -440,16 +441,14 @@ class Blowfish extends Base
 
         for ($i = 17; $i > 2; $i-= 2) {
             $l^= $p[$i];
-            $r^= ($sb_0[$l >> 24 & 0xff]  +
-                  $sb_1[$l >> 16 & 0xff]  ^
+            $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
                   $sb_2[$l >>  8 & 0xff]) +
-                  $sb_3[$l       & 0xff];
+                  $sb_3[$l       & 0xff]);
 
             $r^= $p[$i - 1];
-            $l^= ($sb_0[$r >> 24 & 0xff]  +
-                  $sb_1[$r >> 16 & 0xff]  ^
+            $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
                   $sb_2[$r >>  8 & 0xff]) +
-                  $sb_3[$r       & 0xff];
+                  $sb_3[$r       & 0xff]);
         }
         return pack("N*", $r ^ $p[0], $l ^ $p[1]);
     }
@@ -475,6 +474,8 @@ class Blowfish extends Base
             $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
         }
 
+        $safeint = $this->safe_intval_inline();
+
         if (!isset($lambda_functions[$code_hash])) {
             switch (true) {
                 case $gen_hi_opt_code:
@@ -510,16 +511,14 @@ class Blowfish extends Base
             for ($i = 0; $i < 16; $i+= 2) {
                 $encrypt_block.= '
                     $l^= ' . $p[$i] . ';
-                    $r^= ($sb_0[$l >> 24 & 0xff]  +
-                          $sb_1[$l >> 16 & 0xff]  ^
+                    $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
                           $sb_2[$l >>  8 & 0xff]) +
-                          $sb_3[$l       & 0xff];
+                          $sb_3[$l       & 0xff]') . ';
 
                     $r^= ' . $p[$i + 1] . ';
-                    $l^= ($sb_0[$r >> 24 & 0xff]  +
-                          $sb_1[$r >> 16 & 0xff]  ^
+                    $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . '  ^
                           $sb_2[$r >>  8 & 0xff]) +
-                          $sb_3[$r       & 0xff];
+                          $sb_3[$r       & 0xff]') . ';
                 ';
             }
             $encrypt_block.= '
@@ -539,16 +538,14 @@ class Blowfish extends Base
             for ($i = 17; $i > 2; $i-= 2) {
                 $decrypt_block.= '
                     $l^= ' . $p[$i] . ';
-                    $r^= ($sb_0[$l >> 24 & 0xff]  +
-                          $sb_1[$l >> 16 & 0xff]  ^
+                    $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
                           $sb_2[$l >>  8 & 0xff]) +
-                          $sb_3[$l       & 0xff];
+                          $sb_3[$l       & 0xff]') . ';
 
                     $r^= ' . $p[$i - 1] . ';
-                    $l^= ($sb_0[$r >> 24 & 0xff]  +
-                          $sb_1[$r >> 16 & 0xff]  ^
+                    $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
                           $sb_2[$r >>  8 & 0xff]) +
-                          $sb_3[$r       & 0xff];
+                          $sb_3[$r       & 0xff]') . ';
                 ';
             }
 
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
index 512204691a0f35065ff8a0b94b20180fd915b943..9a8225fb5d243721a5332da431fdabda63fbafff 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
@@ -1357,8 +1357,8 @@ class DES extends Base
                         $k[self::ENCRYPT][$i] = '$ke[' . $i . ']';
                         $k[self::DECRYPT][$i] = '$kd[' . $i . ']';
                     }
-                    $init_encrypt = '$ke = $self->keys[self::ENCRYPT];';
-                    $init_decrypt = '$kd = $self->keys[self::DECRYPT];';
+                    $init_encrypt = '$ke = $self->keys[$self::ENCRYPT];';
+                    $init_decrypt = '$kd = $self->keys[$self::DECRYPT];';
                     break;
             }
 
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php
index 07665a1658538350efebc29fe5dd25f48e98f137..6ae01329e2e1781e670cac5de88d9c227f883225 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php
@@ -802,7 +802,12 @@ class Hash
             $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
         }
 
-        return fmod($result, $mod);
+        if ((php_uname('m') & "\xDF\xDF\xDF") != 'ARM') {
+            return fmod($result, $mod);
+        }
+
+        return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
+            ((fmod(floor($result / 0x80000000), 2) & 1) << 31);
     }
 
     /**
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
index e9cfa3f834e447b78324cba68b3d5a324923f1cf..b2b9d48eaa15ca8123065a6f3ae08f4d618399aa 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
@@ -296,7 +296,7 @@ class RC2 extends Base
     function setKeyLength($length)
     {
         if ($length < 8) {
-            $this->default_key_length = 8;
+            $this->default_key_length = 1;
         } elseif ($length > 1024) {
             $this->default_key_length = 128;
         } else {
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php
index 1e768d7d96549e704f1621dd2c6180ae9e000687..25e4ff854d55bfc7251e459ffaba1e5d8d799a25 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php
@@ -107,7 +107,7 @@ class RC4 extends Base
      * @var string
      * @access private
      */
-    var $key = "\0";
+    var $key;
 
     /**
      * The Key Stream for decryption and encryption
@@ -144,8 +144,10 @@ class RC4 extends Base
      */
     function isValidEngine($engine)
     {
-        switch ($engine) {
-            case Base::ENGINE_OPENSSL:
+        if ($engine == Base::ENGINE_OPENSSL) {
+            if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
+                $this->cipher_name_openssl = 'rc4-40';
+            } else {
                 switch (strlen($this->key)) {
                     case 5:
                         $this->cipher_name_openssl = 'rc4-40';
@@ -159,6 +161,7 @@ class RC4 extends Base
                     default:
                         return false;
                 }
+            }
         }
 
         return parent::isValidEngine($engine);
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
index ef508a433272e92d6a2e5384904ac0df09166cf4..cd116b56da8da9a1d2ef060accd5a0903e633fdd 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
@@ -1572,6 +1572,15 @@ class RSA
         }
 
         if ($components === false) {
+            $this->comment = null;
+            $this->modulus = null;
+            $this->k = null;
+            $this->exponent = null;
+            $this->primes = null;
+            $this->exponents = null;
+            $this->coefficients = null;
+            $this->publicExponent = null;
+
             return false;
         }
 
@@ -2414,7 +2423,7 @@ class RSA
         $db = $maskedDB ^ $dbMask;
         $lHash2 = substr($db, 0, $this->hLen);
         $m = substr($db, $this->hLen);
-        if ($lHash != $lHash2) {
+        if (!$this->_equals($lHash, $lHash2)) {
             user_error('Decryption error');
             return false;
         }
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php
index 170d1c3775f551335ab4b0d5f0393fb7039c4828..01e34cc367dddefe8502a4c2decb0182e165bdca 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php
@@ -45,6 +45,10 @@ class Random
      */
     static function string($length)
     {
+        if (!$length) {
+            return '';
+        }
+
         if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
             try {
                 return \random_bytes($length);
@@ -62,7 +66,7 @@ class Random
             // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
             // ie. class_alias is a function that was introduced in PHP 5.3
             if (extension_loaded('mcrypt') && function_exists('class_alias')) {
-                return mcrypt_create_iv($length);
+                return @mcrypt_create_iv($length);
             }
             // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
             // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
@@ -101,7 +105,7 @@ class Random
             // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
             // restrictions or some such
             if (extension_loaded('mcrypt')) {
-                return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
+                return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
             }
         }
         // at this point we have no choice but to use a pure-PHP CSPRNG
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php
index 3dd4ea1d31f96af892c20c467edfa0a5ea9f5c2d..70980a2ff1bff2ae67eefc81b6f4f7411963057a 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php
@@ -432,8 +432,10 @@ class Twofish extends Base
                          $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
                          $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
                     $B = ($B << 8) | ($B >> 24 & 0xff);
-                    $K[] = $A+= $B;
-                    $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = $A;
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                 }
                 for ($i = 0; $i < 256; ++$i) {
                     $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
@@ -456,8 +458,10 @@ class Twofish extends Base
                          $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
                          $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
                     $B = ($B << 8) | ($B >> 24 & 0xff);
-                    $K[] = $A+= $B;
-                    $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = $A;
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                 }
                 for ($i = 0; $i < 256; ++$i) {
                     $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
@@ -481,8 +485,10 @@ class Twofish extends Base
                          $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
                          $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
                     $B = ($B << 8) | ($B >> 24 & 0xff);
-                    $K[] = $A+= $B;
-                    $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = $A;
+                    $A = $this->safe_intval($A + $B);
+                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                 }
                 for ($i = 0; $i < 256; ++$i) {
                     $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
@@ -578,9 +584,9 @@ class Twofish extends Base
                   $S1[ $R1        & 0xff] ^
                   $S2[($R1 >>  8) & 0xff] ^
                   $S3[($R1 >> 16) & 0xff];
-            $R2^= $t0 + $t1 + $K[++$ki];
+            $R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
             $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
-            $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
+            $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
 
             $t0 = $S0[ $R2        & 0xff] ^
                   $S1[($R2 >>  8) & 0xff] ^
@@ -590,9 +596,9 @@ class Twofish extends Base
                   $S1[ $R3        & 0xff] ^
                   $S2[($R3 >>  8) & 0xff] ^
                   $S3[($R3 >> 16) & 0xff];
-            $R0^= ($t0 + $t1 + $K[++$ki]);
+            $R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
             $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
-            $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
+            $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
         }
 
         // @codingStandardsIgnoreStart
@@ -634,9 +640,9 @@ class Twofish extends Base
                   $S1[$R1       & 0xff] ^
                   $S2[$R1 >>  8 & 0xff] ^
                   $S3[$R1 >> 16 & 0xff];
-            $R3^= $t0 + ($t1 << 1) + $K[--$ki];
+            $R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
             $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
-            $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
+            $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
 
             $t0 = $S0[$R2       & 0xff] ^
                   $S1[$R2 >>  8 & 0xff] ^
@@ -646,9 +652,9 @@ class Twofish extends Base
                   $S1[$R3       & 0xff] ^
                   $S2[$R3 >>  8 & 0xff] ^
                   $S3[$R3 >> 16 & 0xff];
-            $R1^= $t0 + ($t1 << 1) + $K[--$ki];
+            $R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
             $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
-            $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
+            $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
         }
 
         // @codingStandardsIgnoreStart
@@ -679,6 +685,8 @@ class Twofish extends Base
             $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
         }
 
+        $safeint = $this->safe_intval_inline();
+
         if (!isset($lambda_functions[$code_hash])) {
             switch (true) {
                 case $gen_hi_opt_code:
@@ -727,9 +735,9 @@ class Twofish extends Base
                           $S1[ $R1        & 0xff] ^
                           $S2[($R1 >>  8) & 0xff] ^
                           $S3[($R1 >> 16) & 0xff];
-                    $R2^= ($t0 + $t1 + '.$K[++$ki].');
+                    $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
                     $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
-                    $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
+                    $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
 
                     $t0 = $S0[ $R2        & 0xff] ^
                           $S1[($R2 >>  8) & 0xff] ^
@@ -739,16 +747,16 @@ class Twofish extends Base
                           $S1[ $R3        & 0xff] ^
                           $S2[($R3 >>  8) & 0xff] ^
                           $S3[($R3 >> 16) & 0xff];
-                    $R0^= ($t0 + $t1 + '.$K[++$ki].');
+                    $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
                     $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
-                    $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
+                    $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
                 ';
             }
             $encrypt_block.= '
-                $in = pack("V4", '.$K[4].' ^ $R2,
-                                 '.$K[5].' ^ $R3,
-                                 '.$K[6].' ^ $R0,
-                                 '.$K[7].' ^ $R1);
+                $in = pack("V4", ' . $K[4] . ' ^ $R2,
+                                 ' . $K[5] . ' ^ $R3,
+                                 ' . $K[6] . ' ^ $R0,
+                                 ' . $K[7] . ' ^ $R1);
             ';
 
             // Generating decrypt code:
@@ -769,9 +777,9 @@ class Twofish extends Base
                           $S1[$R1       & 0xff] ^
                           $S2[$R1 >>  8 & 0xff] ^
                           $S3[$R1 >> 16 & 0xff];
-                    $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
+                    $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                     $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
-                    $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
+                    $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
 
                     $t0 = $S0[$R2       & 0xff] ^
                           $S1[$R2 >>  8 & 0xff] ^
@@ -781,16 +789,16 @@ class Twofish extends Base
                           $S1[$R3       & 0xff] ^
                           $S2[$R3 >>  8 & 0xff] ^
                           $S3[$R3 >> 16 & 0xff];
-                    $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
+                    $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                     $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
-                    $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
+                    $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
                 ';
             }
             $decrypt_block.= '
-                $in = pack("V4", '.$K[0].' ^ $R2,
-                                 '.$K[1].' ^ $R3,
-                                 '.$K[2].' ^ $R0,
-                                 '.$K[3].' ^ $R1);
+                $in = pack("V4", ' . $K[0] . ' ^ $R2,
+                                 ' . $K[1] . ' ^ $R3,
+                                 ' . $K[2] . ' ^ $R0,
+                                 ' . $K[3] . ' ^ $R1);
             ';
 
             $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php b/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php
index 1f3eecb30a1b44a8df89ad29251523a4b8ab196a..5ff1f2ea1ab98a735724e42e9aa499aafaa79552 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php
@@ -305,6 +305,9 @@ class ANSI
                             case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
                                 $this->old_x = $this->x;
                                 $this->x-= $match[1];
+                                if ($this->x < 0) {
+                                    $this->x = 0;
+                                }
                                 break;
                             case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
                                 break;
@@ -416,7 +419,7 @@ class ANSI
 
                     if ($this->x > $this->max_x) {
                         $this->x = 0;
-                        $this->y++;
+                        $this->_newLine();
                     } else {
                         $this->x++;
                     }
diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php
index 8308645b40f388af026e85145804bbd044e3af67..1da046e826dcea740ee4bab299c9a202666137b5 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php
@@ -25,6 +25,8 @@ namespace phpseclib\File;
 
 use phpseclib\File\ASN1\Element;
 use phpseclib\Math\BigInteger;
+use DateTime;
+use DateTimeZone;
 
 /**
  * Pure-PHP ASN.1 Parser
@@ -707,7 +709,7 @@ class ASN1
                 if (isset($mapping['implicit'])) {
                     $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
                 }
-                return @date($this->format, $decoded['content']);
+                return $decoded['content'] ? $decoded['content']->format($this->format) : false;
             case self::TYPE_BIT_STRING:
                 if (isset($mapping['mapping'])) {
                     $offset = ord($decoded['content'][0]);
@@ -956,7 +958,8 @@ class ASN1
             case self::TYPE_GENERALIZED_TIME:
                 $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
                 $format.= 'mdHis';
-                $value = @gmdate($format, strtotime($source)) . 'Z';
+                $date = new DateTime($source, new DateTimeZone('GMT'));
+                $value = $date->format($format) . 'Z';
                 break;
             case self::TYPE_BIT_STRING:
                 if (isset($mapping['mapping'])) {
@@ -1137,33 +1140,32 @@ class ASN1
            http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
            http://www.obj-sys.com/asn1tutorial/node14.html */
 
-        $pattern = $tag == self::TYPE_UTC_TIME ?
-            '#(..)(..)(..)(..)(..)(..)(.*)#' :
-            '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
-
-        preg_match($pattern, $content, $matches);
-
-        list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
+        $format = 'YmdHis';
 
         if ($tag == self::TYPE_UTC_TIME) {
-            $year = $year >= 50 ? "19$year" : "20$year";
+            // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
+            // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
+            // browsers parse it phpseclib ought to too
+            if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
+                $content = $matches[1] . '00' . $matches[2];
+            }
+            $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
+            $content = $prefix . $content;
+        } elseif (strpos($content, '.') !== false) {
+            $format.= '.u';
         }
 
-        if ($timezone == 'Z') {
-            $mktime = 'gmmktime';
-            $timezone = 0;
-        } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
-            $mktime = 'gmmktime';
-            $timezone = 60 * $matches[3] + 3600 * $matches[2];
-            if ($matches[1] == '-') {
-                $timezone = -$timezone;
-            }
-        } else {
-            $mktime = 'mktime';
-            $timezone = 0;
+        if ($content[strlen($content) - 1] == 'Z') {
+            $content = substr($content, 0, -1) . '+0000';
+        }
+
+        if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
+            $format.= 'O';
         }
 
-        return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
+        // error supression isn't necessary as of PHP 7.0:
+        // http://php.net/manual/en/migration70.other-changes.php
+        return @DateTime::createFromFormat($format, $content);
     }
 
     /**
diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/X509.php b/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
index 863d9e991ab19e31da7b1fb2bf4f420c11108313..67317db23d22c057a784cacaa761336300202105 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
@@ -31,6 +31,8 @@ use phpseclib\Crypt\Random;
 use phpseclib\Crypt\RSA;
 use phpseclib\File\ASN1\Element;
 use phpseclib\Math\BigInteger;
+use DateTime;
+use DateTimeZone;
 
 /**
  * Pure-PHP X.509 Parser
@@ -1907,6 +1909,9 @@ class X509
             // "SET Secure Electronic Transaction Specification"
             // http://www.maithean.com/docs/set_bk3.pdf
             case '2.23.42.7.0': // id-set-hashedRootKey
+            // "Certificate Transparency"
+            // https://tools.ietf.org/html/rfc6962
+            case '1.3.6.1.4.1.11129.2.4.2':
                 return true;
 
             // CSR attributes
@@ -2027,30 +2032,32 @@ class X509
         }
 
         if ($names = $this->getExtension('id-ce-subjectAltName')) {
-            foreach ($names as $key => $value) {
-                $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
-                switch ($key) {
-                    case 'dNSName':
-                        /* From RFC2818 "HTTP over TLS":
-
-                           If a subjectAltName extension of type dNSName is present, that MUST
-                           be used as the identity. Otherwise, the (most specific) Common Name
-                           field in the Subject field of the certificate MUST be used. Although
-                           the use of the Common Name is existing practice, it is deprecated and
-                           Certification Authorities are encouraged to use the dNSName instead. */
-                        if (preg_match('#^' . $value . '$#', $components['host'])) {
-                            return true;
-                        }
-                        break;
-                    case 'iPAddress':
-                        /* From RFC2818 "HTTP over TLS":
-
-                           In some cases, the URI is specified as an IP address rather than a
-                           hostname. In this case, the iPAddress subjectAltName must be present
-                           in the certificate and must exactly match the IP in the URI. */
-                        if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
-                            return true;
-                        }
+            foreach ($names as $name) {
+                foreach ($name as $key => $value) {
+                    $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
+                    switch ($key) {
+                        case 'dNSName':
+                            /* From RFC2818 "HTTP over TLS":
+
+                               If a subjectAltName extension of type dNSName is present, that MUST
+                               be used as the identity. Otherwise, the (most specific) Common Name
+                               field in the Subject field of the certificate MUST be used. Although
+                               the use of the Common Name is existing practice, it is deprecated and
+                               Certification Authorities are encouraged to use the dNSName instead. */
+                            if (preg_match('#^' . $value . '$#', $components['host'])) {
+                                return true;
+                            }
+                            break;
+                        case 'iPAddress':
+                            /* From RFC2818 "HTTP over TLS":
+
+                               In some cases, the URI is specified as an IP address rather than a
+                               hostname. In this case, the iPAddress subjectAltName must be present
+                               in the certificate and must exactly match the IP in the URI. */
+                            if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
+                                return true;
+                            }
+                    }
                 }
             }
             return false;
@@ -2079,7 +2086,7 @@ class X509
         }
 
         if (!isset($date)) {
-            $date = time();
+            $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
         }
 
         $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
@@ -2089,8 +2096,8 @@ class X509
         $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
 
         switch (true) {
-            case $date < @strtotime($notBefore):
-            case $date > @strtotime($notAfter):
+            case $date < new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get())):
+            case $date > new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get())):
                 return false;
         }
 
@@ -2134,7 +2141,8 @@ class X509
                         $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
                         switch (true) {
                             case !is_array($authorityKey):
-                            case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+                            case !$subjectKeyID:
+                            case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
                                 $signingCert = $this->currentCert; // working cert
                         }
                 }
@@ -2151,7 +2159,11 @@ class X509
                                 $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
                                 switch (true) {
                                     case !is_array($authorityKey):
-                                    case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+                                    case !$subjectKeyID:
+                                    case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+                                        if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
+                                            break 2; // serial mismatch - check other ca
+                                        }
                                         $signingCert = $ca; // working cert
                                         break 3;
                                 }
@@ -2197,7 +2209,11 @@ class X509
                                 $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
                                 switch (true) {
                                     case !is_array($authorityKey):
-                                    case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+                                    case !$subjectKeyID:
+                                    case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+                                        if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
+                                            break 2; // serial mismatch - check other ca
+                                        }
                                         $signingCert = $ca; // working cert
                                         break 3;
                                 }
@@ -2469,6 +2485,10 @@ class X509
         }
 
         $dn = array_values($dn);
+        // fix for https://bugs.php.net/75433 affecting PHP 7.2
+        if (!isset($dn[0])) {
+            $dn = array_splice($dn, 0, 0);
+        }
     }
 
     /**
@@ -2712,7 +2732,9 @@ class X509
                     $value = array_pop($value); // Always strip data type.
                 }
             } elseif (is_object($value) && $value instanceof Element) {
-                $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
+                $callback = function ($x) {
+                    return "\x" . bin2hex($x[0]);
+                };
                 $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
             }
             $output.= $desc . '=' . $value;
@@ -3335,7 +3357,11 @@ class X509
      */
     function _timeField($date)
     {
-        $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
+        if ($date instanceof Element) {
+            return $date;
+        }
+        $dateObj = new DateTime($date, new DateTimeZone('GMT'));
+        $year = $dateObj->format('Y'); // the same way ASN1.php parses this
         if ($year < 2050) {
             return array('utcTime' => $date);
         } else {
@@ -3400,8 +3426,12 @@ class X509
                 return false;
             }
 
-            $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
-            $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
+            $startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
+            $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
+
+            $endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
+            $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
+
             /* "The serial number MUST be a positive integer"
                "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
                 -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
@@ -3463,8 +3493,8 @@ class X509
 
         $altName = array();
 
-        if (isset($subject->domains) && count($subject->domains) > 1) {
-            $altName = array_map(array('X509', '_dnsName'), $subject->domains);
+        if (isset($subject->domains) && count($subject->domains)) {
+            $altName = array_map(array('\phpseclib\File\X509', '_dnsName'), $subject->domains);
         }
 
         if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
@@ -3669,7 +3699,9 @@ class X509
 
         $currentCert = isset($this->currentCert) ? $this->currentCert : null;
         $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
-        $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
+
+        $thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
+        $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
 
         if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
             $this->currentCert = $crl->currentCert;
@@ -3820,7 +3852,11 @@ class X509
      */
     function setStartDate($date)
     {
-        $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
+        if (!is_object($date) || !is_a($date, 'DateTime')) {
+            $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
+        }
+
+        $this->startDate = $date->format('D, d M Y H:i:s O');
     }
 
     /**
@@ -3844,7 +3880,11 @@ class X509
             $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
             $this->endDate = new Element($temp);
         } else {
-            $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
+            if (!is_object($date) || !is_a($date, 'DateTime')) {
+                $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
+            }
+
+            $this->endDate = $date->format('D, d M Y H:i:s O');
         }
     }
 
@@ -4054,6 +4094,10 @@ class X509
         }
 
         $extensions = array_values($extensions);
+        // fix for https://bugs.php.net/75433 affecting PHP 7.2
+        if (!isset($extensions[0])) {
+            $extensions = array_splice($extensions, 0, 0);
+        }
         return $result;
     }
 
@@ -4574,8 +4618,9 @@ class X509
         }
 
         $i = count($rclist);
+        $revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
         $rclist[] = array('userCertificate' => $serial,
-                          'revocationDate'  => $this->_timeField(@date('D, d M Y H:i:s O')));
+                          'revocationDate'  => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
         return $i;
     }
 
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
index 4b13d7c64e5d9c67384149ad650c60cce72f4763..2aa39a50acd8d8061a1bdb8c1495e0e9d5b1c422 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
@@ -360,8 +360,12 @@ class BigInteger
             case 256:
                 switch (MATH_BIGINTEGER_MODE) {
                     case self::MODE_GMP:
-                        $sign = $this->is_negative ? '-' : '';
-                        $this->value = gmp_init($sign . '0x' . bin2hex($x));
+                        $this->value = function_exists('gmp_import') ?
+                            gmp_import($x) :
+                            gmp_init('0x' . bin2hex($x));
+                        if ($this->is_negative) {
+                            $this->value = gmp_neg($this->value);
+                        }
                         break;
                     case self::MODE_BCMATH:
                         // round $len to the nearest 4 (thanks, DavidMJ!)
@@ -548,9 +552,13 @@ class BigInteger
                     return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                 }
 
-                $temp = gmp_strval(gmp_abs($this->value), 16);
-                $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
-                $temp = pack('H*', $temp);
+                if (function_exists('gmp_export')) {
+                    $temp = gmp_export($this->value);
+                } else {
+                    $temp = gmp_strval(gmp_abs($this->value), 16);
+                    $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
+                    $temp = pack('H*', $temp);
+                }
 
                 return $this->precision > 0 ?
                     substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
@@ -2860,8 +2868,7 @@ class BigInteger
         switch (MATH_BIGINTEGER_MODE) {
             case self::MODE_GMP:
                 $temp = new static();
-                $temp->value = gmp_xor($this->value, $x->value);
-
+                $temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
                 return $this->_normalize($temp);
             case self::MODE_BCMATH:
                 $left = $this->toBytes();
@@ -2877,6 +2884,7 @@ class BigInteger
 
         $length = max(count($this->value), count($x->value));
         $result = $this->copy();
+        $result->is_negative = false;
         $result->value = array_pad($result->value, $length, 0);
         $x->value = array_pad($x->value, $length, 0);
 
@@ -2900,7 +2908,7 @@ class BigInteger
         // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
         $temp = $this->toBytes();
         if ($temp == '') {
-            return '';
+            return $this->_normalize(new static());
         }
         $pre_msb = decbin(ord($temp[0]));
         $temp = ~$temp;
@@ -3435,7 +3443,7 @@ class BigInteger
                     break;
                 }
             }
-            $s = 26 * $i + $j - 1;
+            $s = 26 * $i + $j;
             $r->_rshift($s);
         }
 
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
index 8784b543a923210c5ac11811444ef2ba4bcc25ce..f95bce6df760ebe26d63a16d8bc8a14af0b322dc 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
@@ -99,7 +99,7 @@ class SCP
      *
      * Connects to an SSH server
      *
-     * @param \phpseclib\Net\SSH1|\phpseclin\Net\SSH2 $ssh
+     * @param \phpseclib\Net\SSH1|\phpseclib\Net\SSH2 $ssh
      * @return \phpseclib\Net\SCP
      * @access public
      */
@@ -299,6 +299,9 @@ class SCP
                     $response = $this->ssh->_get_binary_packet();
                     switch ($response[SSH1::RESPONSE_TYPE]) {
                         case NET_SSH1_SMSG_STDOUT_DATA:
+                            if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
+                                return false;
+                            }
                             extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
                             return $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
                         case NET_SSH1_SMSG_STDERR_DATA:
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
index 053ad3b776bb31606a2d13bd642da42d0e9da7f1..8825f30cfaf2a4193b25745bfe0fd0341738e7d0 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
@@ -158,7 +158,7 @@ class SFTP extends SSH2
      * Current working directory
      *
      * @var string
-     * @see self::_realpath()
+     * @see self::realpath()
      * @see self::chdir()
      * @access private
      */
@@ -187,7 +187,7 @@ class SFTP extends SSH2
      *
      * @see self::getSFTPErrors()
      * @see self::getLastSFTPError()
-     * @var string
+     * @var array
      * @access private
      */
     var $sftp_errors = array();
@@ -236,6 +236,20 @@ class SFTP extends SSH2
      */
     var $sortOptions = array();
 
+    /**
+     * Canonicalization Flag
+     *
+     * Determines whether or not paths should be canonicalized before being
+     * passed on to the remote server.
+     *
+     * @see self::enablePathCanonicalization()
+     * @see self::disablePathCanonicalization()
+     * @see self::realpath()
+     * @var bool
+     * @access private
+     */
+    var $canonicalize_paths = true;
+
     /**
      * Default Constructor.
      *
@@ -335,7 +349,7 @@ class SFTP extends SSH2
             // yields inconsistent behavior depending on how php is compiled.  so we left shift -1 (which, in
             // two's compliment, consists of all 1 bits) by 31.  on 64-bit systems this'll yield 0xFFFFFFFF80000000.
             // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
-              -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
+            (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
         );
         // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
         // the flag definitions change somewhat in SFTPv5+.  if SFTPv5+ support is added to this library, maybe name
@@ -372,7 +386,7 @@ class SFTP extends SSH2
         );
 
         if (!defined('NET_SFTP_QUEUE_SIZE')) {
-            define('NET_SFTP_QUEUE_SIZE', 50);
+            define('NET_SFTP_QUEUE_SIZE', 32);
         }
     }
 
@@ -409,7 +423,7 @@ class SFTP extends SSH2
 
         $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
 
-        $response = $this->_get_channel_packet(self::CHANNEL);
+        $response = $this->_get_channel_packet(self::CHANNEL, true);
         if ($response === false) {
             return false;
         }
@@ -430,7 +444,7 @@ class SFTP extends SSH2
 
         $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
 
-        $response = $this->_get_channel_packet(self::CHANNEL);
+        $response = $this->_get_channel_packet(self::CHANNEL, true);
         if ($response === false) {
             // from PuTTY's psftp.exe
             $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
@@ -454,7 +468,7 @@ class SFTP extends SSH2
 
             $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
 
-            $response = $this->_get_channel_packet(self::CHANNEL);
+            $response = $this->_get_channel_packet(self::CHANNEL, true);
             if ($response === false) {
                 return false;
             }
@@ -472,11 +486,20 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nversion', $this->_string_shift($response, 4)));
         $this->version = $version;
         while (!empty($response)) {
+            if (strlen($response) < 4) {
+                return false;
+            }
             extract(unpack('Nlength', $this->_string_shift($response, 4)));
             $key = $this->_string_shift($response, $length);
+            if (strlen($response) < 4) {
+                return false;
+            }
             extract(unpack('Nlength', $this->_string_shift($response, 4)));
             $value = $this->_string_shift($response, $length);
             $this->extensions[$key] = $value;
@@ -566,6 +589,26 @@ class SFTP extends SSH2
         $this->stat_cache = array();
     }
 
+    /**
+     * Enable path canonicalization
+     *
+     * @access public
+     */
+    function enablePathCanonicalization()
+    {
+        $this->canonicalize_paths = true;
+    }
+
+    /**
+     * Enable path canonicalization
+     *
+     * @access public
+     */
+    function disablePathCanonicalization()
+    {
+        $this->canonicalize_paths = false;
+    }
+
     /**
      * Returns the current directory name
      *
@@ -587,12 +630,15 @@ class SFTP extends SSH2
     function _logError($response, $status = -1)
     {
         if ($status == -1) {
+            if (strlen($response) < 4) {
+                return;
+            }
             extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         }
 
         $error = $this->status_codes[$status];
 
-        if ($this->version > 2) {
+        if ($this->version > 2 || strlen($response) < 4) {
             extract(unpack('Nlength', $this->_string_shift($response, 4)));
             $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
         } else {
@@ -621,13 +667,20 @@ class SFTP extends SSH2
      * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it.  Returns
      * the absolute (canonicalized) path.
      *
+     * If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
+     *
      * @see self::chdir()
+     * @see self::disablePathCanonicalization()
      * @param string $path
      * @return mixed
      * @access private
      */
     function _realpath($path)
     {
+        if (!$this->canonicalize_paths) {
+            return $path;
+        }
+
         if ($this->pwd === false) {
             // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
             if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
@@ -641,6 +694,9 @@ class SFTP extends SSH2
                     // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
                     // at is the first part and that part is defined the same in SFTP versions 3 through 6.
                     $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
+                    if (strlen($response) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nlength', $this->_string_shift($response, 4)));
                     return $this->_string_shift($response, $length);
                 case NET_SFTP_STATUS:
@@ -875,10 +931,19 @@ class SFTP extends SSH2
             $response = $this->_get_sftp_packet();
             switch ($this->packet_type) {
                 case NET_SFTP_NAME:
+                    if (strlen($response) < 4) {
+                        return false;
+                    }
                     extract(unpack('Ncount', $this->_string_shift($response, 4)));
                     for ($i = 0; $i < $count; $i++) {
+                        if (strlen($response) < 4) {
+                            return false;
+                        }
                         extract(unpack('Nlength', $this->_string_shift($response, 4)));
                         $shortname = $this->_string_shift($response, $length);
+                        if (strlen($response) < 4) {
+                            return false;
+                        }
                         extract(unpack('Nlength', $this->_string_shift($response, 4)));
                         $longname = $this->_string_shift($response, $length);
                         $attributes = $this->_parseAttributes($response);
@@ -905,6 +970,9 @@ class SFTP extends SSH2
                     }
                     break;
                 case NET_SFTP_STATUS:
+                    if (strlen($response) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nstatus', $this->_string_shift($response, 4)));
                     if ($status != NET_SFTP_STATUS_EOF) {
                         $this->_logError($response, $status);
@@ -1079,7 +1147,7 @@ class SFTP extends SSH2
                 $temp[$dir] = array();
             }
             if ($i === $max) {
-                if (is_object($temp[$dir])) {
+                if (is_object($temp[$dir]) && is_object($value)) {
                     if (!isset($value->stat) && isset($temp[$dir]->stat)) {
                         $value->stat = $temp[$dir]->stat;
                     }
@@ -1267,7 +1335,7 @@ class SFTP extends SSH2
     /**
      * Returns general information about a file or symbolic link
      *
-     * Determines information without calling \phpseclib\Net\SFTP::_realpath().
+     * Determines information without calling \phpseclib\Net\SFTP::realpath().
      * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
      *
      * @param string $filename
@@ -1428,7 +1496,7 @@ class SFTP extends SSH2
             return true;
         }
 
-        $filename = $this->_realPath($filename);
+        $filename = $this->realpath($filename);
         // rather than return what the permissions *should* be, we'll return what they actually are.  this will also
         // tell us if the file actually exists.
         // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
@@ -1499,6 +1567,9 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -1611,12 +1682,18 @@ class SFTP extends SSH2
                 return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Ncount', $this->_string_shift($response, 4)));
         // the file isn't a symlink
         if (!$count) {
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nlength', $this->_string_shift($response, 4)));
         return $this->_string_shift($response, $length);
     }
@@ -1651,6 +1728,9 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -1714,6 +1794,9 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -1751,6 +1834,9 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
@@ -1871,7 +1957,14 @@ class SFTP extends SSH2
                 break;
             case is_resource($data):
                 $mode = $mode & ~self::SOURCE_LOCAL_FILE;
-                $fp = $data;
+                $info = stream_get_meta_data($data);
+                if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
+                    $fp = fopen('php://memory', 'w+');
+                    stream_copy_to_stream($data, $fp);
+                    rewind($fp);
+                } else {
+                    $fp = $data;
+                }
                 break;
             case $mode & self::SOURCE_LOCAL_FILE:
                 if (!is_file($data)) {
@@ -1886,7 +1979,7 @@ class SFTP extends SSH2
 
         if (isset($fp)) {
             $stat = fstat($fp);
-            $size = $stat['size'];
+            $size = !empty($stat) ? $stat['size'] : 0;
 
             if ($local_start >= 0) {
                 fseek($fp, $local_start);
@@ -1976,6 +2069,9 @@ class SFTP extends SSH2
                 return false;
             }
 
+            if (strlen($response) < 4) {
+                return false;
+            }
             extract(unpack('Nstatus', $this->_string_shift($response, 4)));
             if ($status != NET_SFTP_STATUS_OK) {
                 $this->_logError($response, $status);
@@ -2007,6 +2103,9 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -2180,6 +2279,15 @@ class SFTP extends SSH2
             return false;
         }
 
+        if (is_object($path)) {
+            // It's an object. Cast it as string before we check anything else.
+            $path = (string) $path;
+        }
+
+        if (!is_string($path) || $path == '') {
+            return false;
+        }
+
         $path = $this->_realpath($path);
         if ($path === false) {
             return false;
@@ -2197,6 +2305,9 @@ class SFTP extends SSH2
         }
 
         // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -2622,6 +2733,9 @@ class SFTP extends SSH2
         }
 
         // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
+        if (strlen($response) < 4) {
+            return false;
+        }
         extract(unpack('Nstatus', $this->_string_shift($response, 4)));
         if ($status != NET_SFTP_STATUS_OK) {
             $this->_logError($response, $status);
@@ -2649,6 +2763,10 @@ class SFTP extends SSH2
     function _parseAttributes(&$response)
     {
         $attr = array();
+        if (strlen($response) < 4) {
+            user_error('Malformed file attributes');
+            return array();
+        }
         extract(unpack('Nflags', $this->_string_shift($response, 4)));
         // SFTPv4+ have a type field (a byte) that follows the above flag field
         foreach ($this->attributes as $key => $value) {
@@ -2663,9 +2781,17 @@ class SFTP extends SSH2
                     $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
                     break;
                 case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
+                    if (strlen($response) < 8) {
+                        user_error('Malformed file attributes');
+                        return $attr;
+                    }
                     $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
                     break;
                 case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
+                    if (strlen($response) < 4) {
+                        user_error('Malformed file attributes');
+                        return $attr;
+                    }
                     $attr+= unpack('Npermissions', $this->_string_shift($response, 4));
                     // mode == permissions; permissions was the original array key and is retained for bc purposes.
                     // mode was added because that's the more industry standard terminology
@@ -2676,13 +2802,29 @@ class SFTP extends SSH2
                     }
                     break;
                 case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
+                    if (strlen($response) < 8) {
+                        user_error('Malformed file attributes');
+                        return $attr;
+                    }
                     $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
                     break;
                 case NET_SFTP_ATTR_EXTENDED: // 0x80000000
+                    if (strlen($response) < 4) {
+                        user_error('Malformed file attributes');
+                        return $attr;
+                    }
                     extract(unpack('Ncount', $this->_string_shift($response, 4)));
                     for ($i = 0; $i < $count; $i++) {
+                        if (strlen($response) < 4) {
+                            user_error('Malformed file attributes');
+                            return $attr;
+                        }
                         extract(unpack('Nlength', $this->_string_shift($response, 4)));
                         $key = $this->_string_shift($response, $length);
+                        if (strlen($response) < 4) {
+                            user_error('Malformed file attributes');
+                            return $attr;
+                        }
                         extract(unpack('Nlength', $this->_string_shift($response, 4)));
                         $attr[$key] = $this->_string_shift($response, $length);
                     }
@@ -2792,13 +2934,13 @@ class SFTP extends SSH2
         if (defined('NET_SFTP_LOGGING')) {
             $packet_type = '-> ' . $this->packet_types[$type] .
                            ' (' . round($stop - $start, 4) . 's)';
-            if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
+            if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
                 echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
                 flush();
                 ob_flush();
             } else {
                 $this->packet_type_log[] = $packet_type;
-                if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
+                if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
                     $this->packet_log[] = $data;
                 }
             }
@@ -2828,7 +2970,7 @@ class SFTP extends SSH2
 
         // SFTP packet length
         while (strlen($this->packet_buffer) < 4) {
-            $temp = $this->_get_channel_packet(self::CHANNEL);
+            $temp = $this->_get_channel_packet(self::CHANNEL, true);
             if (is_bool($temp)) {
                 $this->packet_type = false;
                 $this->packet_buffer = '';
@@ -2836,13 +2978,16 @@ class SFTP extends SSH2
             }
             $this->packet_buffer.= $temp;
         }
+        if (strlen($this->packet_buffer) < 4) {
+            return false;
+        }
         extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
         $tempLength = $length;
         $tempLength-= strlen($this->packet_buffer);
 
         // SFTP packet type and data payload
         while ($tempLength > 0) {
-            $temp = $this->_get_channel_packet(self::CHANNEL);
+            $temp = $this->_get_channel_packet(self::CHANNEL, true);
             if (is_bool($temp)) {
                 $this->packet_type = false;
                 $this->packet_buffer = '';
@@ -2868,13 +3013,13 @@ class SFTP extends SSH2
         if (defined('NET_SFTP_LOGGING')) {
             $packet_type = '<- ' . $this->packet_types[$this->packet_type] .
                            ' (' . round($stop - $start, 4) . 's)';
-            if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
+            if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
                 echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
                 flush();
                 ob_flush();
             } else {
                 $this->packet_type_log[] = $packet_type;
-                if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
+                if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
                     $this->packet_log[] = $packet;
                 }
             }
@@ -2898,10 +3043,10 @@ class SFTP extends SSH2
         }
 
         switch (NET_SFTP_LOGGING) {
-            case NET_SFTP_LOG_COMPLEX:
+            case self::LOG_COMPLEX:
                 return $this->_format_log($this->packet_log, $this->packet_type_log);
                 break;
-            //case NET_SFTP_LOG_SIMPLE:
+            //case self::LOG_SIMPLE:
             default:
                 return $this->packet_type_log;
         }
@@ -2910,7 +3055,7 @@ class SFTP extends SSH2
     /**
      * Returns all errors
      *
-     * @return string
+     * @return array
      * @access public
      */
     function getSFTPErrors()
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
index 08d726ca84266f91bd939bbbb917d69710421c2a..d2c4425deae3a0859a89725041ba4a706838028a 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
@@ -179,7 +179,7 @@ class Stream
 
         if ($host[0] == '$') {
             $host = substr($host, 1);
-            global $$host;
+            global ${$host};
             if (($$host instanceof SFTP) === false) {
                 return false;
             }
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
index cc108a94f9866f409402bd1f0ee1e13160bbcd5e..514b20a2d97c2c1ab0590f4433a4e4fe60c4efde 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
@@ -575,28 +575,46 @@ class SSH1
 
         $this->_string_shift($response[self::RESPONSE_DATA], 4);
 
+        if (strlen($response[self::RESPONSE_DATA]) < 2) {
+            return false;
+        }
         $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
         $server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
         $this->server_key_public_exponent = $server_key_public_exponent;
 
+        if (strlen($response[self::RESPONSE_DATA]) < 2) {
+            return false;
+        }
         $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
         $server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
+
         $this->server_key_public_modulus = $server_key_public_modulus;
 
         $this->_string_shift($response[self::RESPONSE_DATA], 4);
 
+        if (strlen($response[self::RESPONSE_DATA]) < 2) {
+            return false;
+        }
         $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
         $host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
         $this->host_key_public_exponent = $host_key_public_exponent;
 
+        if (strlen($response[self::RESPONSE_DATA]) < 2) {
+            return false;
+        }
         $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
         $host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
+
         $this->host_key_public_modulus = $host_key_public_modulus;
 
         $this->_string_shift($response[self::RESPONSE_DATA], 4);
 
         // get a list of the supported ciphers
+        if (strlen($response[self::RESPONSE_DATA]) < 4) {
+            return false;
+        }
         extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
+
         foreach ($this->supported_ciphers as $mask => $name) {
             if (($supported_ciphers_mask & (1 << $mask)) == 0) {
                 unset($this->supported_ciphers[$mask]);
@@ -604,6 +622,9 @@ class SSH1
         }
 
         // get a list of the supported authentications
+        if (strlen($response[self::RESPONSE_DATA]) < 4) {
+            return false;
+        }
         extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
         foreach ($this->supported_authentications as $mask => $name) {
             if (($supported_authentications_mask & (1 << $mask)) == 0) {
@@ -895,7 +916,7 @@ class SSH1
     /**
      * Returns the output of an interactive shell when there's a match for $expect
      *
-     * $expect can take the form of a string literal or, if $mode == self::READ__REGEX,
+     * $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
      * a regular expression.
      *
      * @see self::write()
@@ -904,7 +925,7 @@ class SSH1
      * @return bool
      * @access public
      */
-    function read($expect, $mode = self::READ__SIMPLE)
+    function read($expect, $mode = self::READ_SIMPLE)
     {
         if (!($this->bitmap & self::MASK_LOGIN)) {
             user_error('Operation disallowed prior to login()');
@@ -918,7 +939,7 @@ class SSH1
 
         $match = $expect;
         while (true) {
-            if ($mode == self::READ__REGEX) {
+            if ($mode == self::READ_REGEX) {
                 preg_match($expect, $this->interactiveBuffer, $matches);
                 $match = isset($matches[0]) ? $matches[0] : '';
             }
@@ -1091,7 +1112,11 @@ class SSH1
         }
 
         $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
-        $temp = unpack('Nlength', fread($this->fsock, 4));
+        $data = fread($this->fsock, 4);
+        if (strlen($data) < 4) {
+            return false;
+        }
+        $temp = unpack('Nlength', $data);
 
         $padding_length = 8 - ($temp['length'] & 7);
         $length = $temp['length'] + $padding_length;
@@ -1112,6 +1137,9 @@ class SSH1
         $type = $raw[$padding_length];
         $data = substr($raw, $padding_length + 1, -4);
 
+        if (strlen($raw) < 4) {
+            return false;
+        }
         $temp = unpack('Ncrc', substr($raw, -4));
 
         //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
index 1158075501fdef0ab01f39e1c0e0f3767eaf098c..cdb7cb39e327080798d050aed9ef81f3273717f3 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
@@ -100,10 +100,10 @@ class SSH2
      * @see \phpseclib\Net\SSH2::_get_channel_packet()
      * @access private
     */
-    const CHANNEL_EXEC          = 0; // PuTTy uses 0x100
-    const CHANNEL_SHELL         = 1;
-    const CHANNEL_SUBSYSTEM     = 2;
-    const CHANNEL_AGENT_FORWARD = 3;
+    const CHANNEL_EXEC          = 1; // PuTTy uses 0x100
+    const CHANNEL_SHELL         = 2;
+    const CHANNEL_SUBSYSTEM     = 3;
+    const CHANNEL_AGENT_FORWARD = 4;
     /**#@-*/
 
     /**#@+
@@ -126,6 +126,10 @@ class SSH2
      * Dumps the content real-time to a file
      */
     const LOG_REALTIME_FILE = 4;
+    /**
+     * Make sure that the log never gets larger than this
+     */
+    const LOG_MAX_SIZE = 1048576; // 1024 * 1024
     /**#@-*/
 
     /**#@+
@@ -141,9 +145,9 @@ class SSH2
      */
     const READ_REGEX = 2;
     /**
-     * Make sure that the log never gets larger than this
+     * Returns when a string matching the regular expression $expect is found
      */
-    const LOG_MAX_SIZE = 1048576; // 1024 * 1024
+    const READ_NEXT = 3;
     /**#@-*/
 
     /**
@@ -866,6 +870,54 @@ class SSH2
      */
     var $agent;
 
+    /**
+     * Send the identification string first?
+     *
+     * @var bool
+     * @access private
+     */
+    var $send_id_string_first = true;
+
+    /**
+     * Send the key exchange initiation packet first?
+     *
+     * @var bool
+     * @access private
+     */
+    var $send_kex_first = true;
+
+    /**
+     * Some versions of OpenSSH incorrectly calculate the key size
+     *
+     * @var bool
+     * @access private
+     */
+    var $bad_key_size_fix = false;
+
+    /**
+     * The selected decryption algorithm
+     *
+     * @var string
+     * @access private
+     */
+    var $decrypt_algorithm = '';
+
+    /**
+     * Should we try to re-connect to re-establish keys?
+     *
+     * @var bool
+     * @access private
+     */
+    var $retry_connect = false;
+
+    /**
+     * Binary Packet Buffer
+     *
+     * @var string|false
+     * @access private
+     */
+    var $binary_packet_buffer = false;
+
     /**
      * Default Constructor.
      *
@@ -978,13 +1030,69 @@ class SSH2
      * CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT
      *
      * @param int $engine
-     * @access private
+     * @access public
      */
     function setCryptoEngine($engine)
     {
         $this->crypto_engine = $engine;
     }
 
+    /**
+     * Send Identification String First
+     *
+     * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
+     * both sides MUST send an identification string". It does not say which side sends it first. In
+     * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+     *
+     * @access public
+     */
+    function sendIdentificationStringFirst()
+    {
+        $this->send_id_string_first = true;
+    }
+
+    /**
+     * Send Identification String Last
+     *
+     * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
+     * both sides MUST send an identification string". It does not say which side sends it first. In
+     * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+     *
+     * @access public
+     */
+    function sendIdentificationStringLast()
+    {
+        $this->send_id_string_first = false;
+    }
+
+    /**
+     * Send SSH_MSG_KEXINIT First
+     *
+     * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
+     * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
+     * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+     *
+     * @access public
+     */
+    function sendKEXINITFirst()
+    {
+        $this->send_kex_first = true;
+    }
+
+    /**
+     * Send SSH_MSG_KEXINIT Last
+     *
+     * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
+     * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
+     * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+     *
+     * @access public
+     */
+    function sendKEXINITLast()
+    {
+        $this->send_kex_first = false;
+    }
+
     /**
      * Connect to an SSHv2 server
      *
@@ -1005,7 +1113,10 @@ class SSH2
 
         if (!is_resource($this->fsock)) {
             $start = microtime(true);
-            $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
+            // with stream_select a timeout of 0 means that no timeout takes place;
+            // with fsockopen a timeout of 0 means that you instantly timeout
+            // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
+            $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
             if (!$this->fsock) {
                 $host = $this->host . ':' . $this->port;
                 user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
@@ -1021,6 +1132,12 @@ class SSH2
             }
         }
 
+        $this->identifier = $this->_generate_identifier();
+
+        if ($this->send_id_string_first) {
+            fputs($this->fsock, $this->identifier . "\r\n");
+        }
+
         /* According to the SSH2 specs,
 
           "The server MAY send other lines of data before sending the version
@@ -1082,8 +1199,6 @@ class SSH2
 
         $extra = $matches[1];
 
-        $this->identifier = $this->_generate_identifier();
-
         if (defined('NET_SSH2_LOGGING')) {
             $this->_append_log('<-', $matches[0]);
             $this->_append_log('->', $this->identifier . "\r\n");
@@ -1094,25 +1209,33 @@ class SSH2
             $this->errors[] = utf8_decode($data);
         }
 
-        if ($matches[3] != '1.99' && $matches[3] != '2.0') {
+        if (version_compare($matches[3], '1.99', '<')) {
             user_error("Cannot connect to SSH $matches[3] servers");
             return false;
         }
 
-        fputs($this->fsock, $this->identifier . "\r\n");
-
-        $response = $this->_get_binary_packet();
-        if ($response === false) {
-            user_error('Connection closed by server');
-            return false;
+        if (!$this->send_id_string_first) {
+            fputs($this->fsock, $this->identifier . "\r\n");
         }
 
-        if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
-            user_error('Expected SSH_MSG_KEXINIT');
-            return false;
+        if (!$this->send_kex_first) {
+            $response = $this->_get_binary_packet();
+            if ($response === false) {
+                user_error('Connection closed by server');
+                return false;
+            }
+
+            if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
+                user_error('Expected SSH_MSG_KEXINIT');
+                return false;
+            }
+
+            if (!$this->_key_exchange($response)) {
+                return false;
+            }
         }
 
-        if (!$this->_key_exchange($response)) {
+        if ($this->send_kex_first && !$this->_key_exchange()) {
             return false;
         }
 
@@ -1134,7 +1257,7 @@ class SSH2
         $identifier = 'SSH-2.0-phpseclib_2.0';
 
         $ext = array();
-        if (extension_loaded('libsodium')) {
+        if (function_exists('\\Sodium\\library_version_major')) {
             $ext[] = 'libsodium';
         }
 
@@ -1160,10 +1283,10 @@ class SSH2
     /**
      * Key Exchange
      *
-     * @param string $kexinit_payload_server
+     * @param string $kexinit_payload_server optional
      * @access private
      */
-    function _key_exchange($kexinit_payload_server)
+    function _key_exchange($kexinit_payload_server = false)
     {
         $kex_algorithms = array(
             // Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
@@ -1284,8 +1407,9 @@ class SSH2
         );
 
         // some SSH servers have buggy implementations of some of the above algorithms
-        switch ($this->server_identifier) {
-            case 'SSH-2.0-SSHD':
+        switch (true) {
+            case $this->server_identifier == 'SSH-2.0-SSHD':
+            case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
                 $mac_algorithms = array_values(array_diff(
                     $mac_algorithms,
                     array('hmac-sha1-96', 'hmac-md5-96')
@@ -1300,76 +1424,124 @@ class SSH2
 
         $client_cookie = Random::string(16);
 
+        $kexinit_payload_client = pack(
+            'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
+            NET_SSH2_MSG_KEXINIT,
+            $client_cookie,
+            strlen($str_kex_algorithms),
+            $str_kex_algorithms,
+            strlen($str_server_host_key_algorithms),
+            $str_server_host_key_algorithms,
+            strlen($encryption_algorithms_client_to_server),
+            $encryption_algorithms_client_to_server,
+            strlen($encryption_algorithms_server_to_client),
+            $encryption_algorithms_server_to_client,
+            strlen($mac_algorithms_client_to_server),
+            $mac_algorithms_client_to_server,
+            strlen($mac_algorithms_server_to_client),
+            $mac_algorithms_server_to_client,
+            strlen($compression_algorithms_client_to_server),
+            $compression_algorithms_client_to_server,
+            strlen($compression_algorithms_server_to_client),
+            $compression_algorithms_server_to_client,
+            0,
+            '',
+            0,
+            '',
+            0,
+            0
+        );
+
+        if ($this->send_kex_first) {
+            if (!$this->_send_binary_packet($kexinit_payload_client)) {
+                return false;
+            }
+
+            $kexinit_payload_server = $this->_get_binary_packet();
+            if ($kexinit_payload_server === false) {
+                user_error('Connection closed by server');
+                return false;
+            }
+
+            if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
+                user_error('Expected SSH_MSG_KEXINIT');
+                return false;
+            }
+        }
+
         $response = $kexinit_payload_server;
         $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
         $server_cookie = $this->_string_shift($response, 16);
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
         $first_kex_packet_follows = $first_kex_packet_follows != 0;
 
-        // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
-        $kexinit_payload_client = pack(
-            'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
-            NET_SSH2_MSG_KEXINIT,
-            $client_cookie,
-            strlen($str_kex_algorithms),
-            $str_kex_algorithms,
-            strlen($str_server_host_key_algorithms),
-            $str_server_host_key_algorithms,
-            strlen($encryption_algorithms_client_to_server),
-            $encryption_algorithms_client_to_server,
-            strlen($encryption_algorithms_server_to_client),
-            $encryption_algorithms_server_to_client,
-            strlen($mac_algorithms_client_to_server),
-            $mac_algorithms_client_to_server,
-            strlen($mac_algorithms_server_to_client),
-            $mac_algorithms_server_to_client,
-            strlen($compression_algorithms_client_to_server),
-            $compression_algorithms_client_to_server,
-            strlen($compression_algorithms_server_to_client),
-            $compression_algorithms_server_to_client,
-            0,
-            '',
-            0,
-            '',
-            0,
-            0
-        );
-
-        if (!$this->_send_binary_packet($kexinit_payload_client)) {
+        if (!$this->send_kex_first && !$this->_send_binary_packet($kexinit_payload_client)) {
             return false;
         }
-        // here ends the second place.
 
         // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
         // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
@@ -1432,10 +1604,16 @@ class SSH2
                     return false;
                 }
 
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
                 $primeBytes = $this->_string_shift($response, $primeLength);
                 $prime = new BigInteger($primeBytes, -256);
 
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('NgLength', $this->_string_shift($response, 4)));
                 $gBytes = $this->_string_shift($response, $gLength);
                 $g = new BigInteger($gBytes, -256);
@@ -1518,6 +1696,9 @@ class SSH2
             user_error('Connection closed by server');
             return false;
         }
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         if ($type != $serverKexReplyMessage) {
@@ -1525,18 +1706,33 @@ class SSH2
             return false;
         }
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
 
+        if (strlen($server_public_host_key) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
         $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $fBytes = $this->_string_shift($response, $temp['length']);
 
+        if (strlen($response) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($response, 4));
         $this->signature = $this->_string_shift($response, $temp['length']);
 
+        if (strlen($this->signature) < 4) {
+            return false;
+        }
         $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
         $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
 
@@ -1607,6 +1803,9 @@ class SSH2
             return false;
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         if ($type != NET_SSH2_MSG_NEWKEYS) {
@@ -1614,6 +1813,8 @@ class SSH2
             return false;
         }
 
+        $this->decrypt_algorithm = $decrypt;
+
         $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
 
         $this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
@@ -1780,6 +1981,10 @@ class SSH2
      */
     function _encryption_algorithm_to_key_size($algorithm)
     {
+        if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
+            return 16;
+        }
+
         switch ($algorithm) {
             case 'none':
                 return 0;
@@ -1854,6 +2059,27 @@ class SSH2
         return null;
     }
 
+    /*
+     * Tests whether or not proposed algorithm has a potential for issues
+     *
+     * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
+     * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
+     * @param string $algorithm Name of the encryption algorithm
+     * @return bool
+     * @access private
+     */
+    function _bad_algorithm_candidate($algorithm)
+    {
+        switch ($algorithm) {
+            case 'arcfour256':
+            case 'aes192-ctr':
+            case 'aes256-ctr':
+                return true;
+        }
+
+        return false;
+    }
+
     /**
      * Login
      *
@@ -1933,10 +2159,20 @@ class SSH2
 
             $response = $this->_get_binary_packet();
             if ($response === false) {
+                if ($this->retry_connect) {
+                    $this->retry_connect = false;
+                    if (!$this->_connect()) {
+                        return false;
+                    }
+                    return $this->_login_helper($username, $password);
+                }
                 user_error('Connection closed by server');
                 return false;
             }
 
+            if (strlen($response) < 4) {
+                return false;
+            }
             extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
             if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
@@ -1986,6 +2222,9 @@ class SSH2
                 return false;
             }
 
+            if (!strlen($response)) {
+                return false;
+            }
             extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
             switch ($type) {
@@ -2041,6 +2280,9 @@ class SSH2
             return false;
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         switch ($type) {
@@ -2048,14 +2290,23 @@ class SSH2
                 if (defined('NET_SSH2_LOGGING')) {
                     $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
                 }
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
                 return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
             case NET_SSH2_MSG_USERAUTH_FAILURE:
                 // can we use keyboard-interactive authentication?  if not then either the login is bad or the server employees
                 // multi-factor authentication
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $auth_methods = explode(',', $this->_string_shift($response, $length));
+                if (!strlen($response)) {
+                    return false;
+                }
                 extract(unpack('Cpartial_success', $this->_string_shift($response, 1)));
                 $partial_success = $partial_success != 0;
 
@@ -2130,16 +2381,31 @@ class SSH2
             }
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         switch ($type) {
             case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $this->_string_shift($response, $length); // name; may be empty
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $this->_string_shift($response, $length); // instruction; may be empty
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $this->_string_shift($response, $length); // language tag; may be empty
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));
 
                 for ($i = 0; $i < count($responses); $i++) {
@@ -2154,6 +2420,9 @@ class SSH2
 
                 if (isset($this->keyboard_requests_responses)) {
                     for ($i = 0; $i < $num_prompts; $i++) {
+                        if (strlen($response) < 4) {
+                            return false;
+                        }
                         extract(unpack('Nlength', $this->_string_shift($response, 4)));
                         // prompt - ie. "Password: "; must not be empty
                         $prompt = $this->_string_shift($response, $length);
@@ -2299,10 +2568,16 @@ class SSH2
             return false;
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         switch ($type) {
             case NET_SSH2_MSG_USERAUTH_FAILURE:
+                if (strlen($response) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
                 $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
                 return false;
@@ -2334,6 +2609,9 @@ class SSH2
             return false;
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
         switch ($type) {
@@ -2389,7 +2667,12 @@ class SSH2
         $this->is_timeout = false;
         $this->stdErrorLog = '';
 
-        if (!($this->bitmap & self::MASK_LOGIN)) {
+        if (!$this->isAuthenticated()) {
+            return false;
+        }
+
+        if ($this->in_request_pty_exec) {
+            user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
             return false;
         }
 
@@ -2452,6 +2735,9 @@ class SSH2
                 return false;
             }
 
+            if (!strlen($response)) {
+                return false;
+            }
             list(, $type) = unpack('C', $this->_string_shift($response, 1));
 
             switch ($type) {
@@ -2588,6 +2874,9 @@ class SSH2
             return false;
         }
 
+        if (!strlen($response)) {
+            return false;
+        }
         list(, $type) = unpack('C', $this->_string_shift($response, 1));
 
         switch ($type) {
@@ -2681,7 +2970,7 @@ class SSH2
         $this->curTimeout = $this->timeout;
         $this->is_timeout = false;
 
-        if (!($this->bitmap & self::MASK_LOGIN)) {
+        if (!$this->isAuthenticated()) {
             user_error('Operation disallowed prior to login()');
             return false;
         }
@@ -2693,6 +2982,10 @@ class SSH2
 
         $channel = $this->_get_interactive_channel();
 
+        if ($mode == self::READ_NEXT) {
+            return $this->_get_channel_packet($channel);
+        }
+
         $match = $expect;
         while (true) {
             if ($mode == self::READ_REGEX) {
@@ -2723,7 +3016,7 @@ class SSH2
      */
     function write($cmd)
     {
-        if (!($this->bitmap & self::MASK_LOGIN)) {
+        if (!$this->isAuthenticated()) {
             user_error('Operation disallowed prior to login()');
             return false;
         }
@@ -2891,6 +3184,24 @@ class SSH2
         return (bool) ($this->bitmap & self::MASK_LOGIN);
     }
 
+    /**
+     * Resets a connection for re-use
+     *
+     * @param int $reason
+     * @access private
+     */
+    function _reset_connection($reason)
+    {
+        $this->_disconnect($reason);
+        $this->decrypt = $this->encrypt = false;
+        $this->decrypt_block_size = $this->encrypt_block_size = 8;
+        $this->hmac_check = $this->hmac_create = false;
+        $this->hmac_size = false;
+        $this->session_id = false;
+        $this->retry_connect = true;
+        $this->get_seq_no = $this->send_seq_no = 0;
+    }
+
     /**
      * Gets Binary Packets
      *
@@ -2900,7 +3211,7 @@ class SSH2
      * @return string
      * @access private
      */
-    function _get_binary_packet()
+    function _get_binary_packet($skip_channel_filter = false)
     {
         if (!is_resource($this->fsock) || feof($this->fsock)) {
             user_error('Connection closed prematurely');
@@ -2923,6 +3234,9 @@ class SSH2
             return false;
         }
 
+        if (strlen($raw) < 5) {
+            return false;
+        }
         extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
 
         $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
@@ -2931,6 +3245,11 @@ class SSH2
         // "implementations SHOULD check that the packet length is reasonable"
         // PuTTY uses 0x9000 as the actual max packet size and so to shall we
         if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
+            if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt_algorithm) && !($this->bitmap & SSH2::MASK_LOGIN)) {
+                $this->bad_key_size_fix = true;
+                $this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+                return false;
+            }
             user_error('Invalid size');
             return false;
         }
@@ -2946,6 +3265,7 @@ class SSH2
             $buffer.= $temp;
             $remaining_length-= strlen($temp);
         }
+
         $stop = microtime(true);
         if (strlen($buffer)) {
             $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
@@ -2981,7 +3301,7 @@ class SSH2
             $this->last_packet = $current;
         }
 
-        return $this->_filter($payload);
+        return $this->_filter($payload, $skip_channel_filter);
     }
 
     /**
@@ -2993,48 +3313,72 @@ class SSH2
      * @return string
      * @access private
      */
-    function _filter($payload)
+    function _filter($payload, $skip_channel_filter)
     {
         switch (ord($payload[0])) {
             case NET_SSH2_MSG_DISCONNECT:
                 $this->_string_shift($payload, 1);
+                if (strlen($payload) < 8) {
+                    return false;
+                }
                 extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
                 $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
                 $this->bitmap = 0;
                 return false;
             case NET_SSH2_MSG_IGNORE:
-                $payload = $this->_get_binary_packet();
+                $payload = $this->_get_binary_packet($skip_channel_filter);
                 break;
             case NET_SSH2_MSG_DEBUG:
                 $this->_string_shift($payload, 2);
+                if (strlen($payload) < 4) {
+                    return false;
+                }
                 extract(unpack('Nlength', $this->_string_shift($payload, 4)));
                 $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
-                $payload = $this->_get_binary_packet();
+                $payload = $this->_get_binary_packet($skip_channel_filter);
                 break;
             case NET_SSH2_MSG_UNIMPLEMENTED:
                 return false;
             case NET_SSH2_MSG_KEXINIT:
                 if ($this->session_id !== false) {
+                    $this->send_kex_first = false;
                     if (!$this->_key_exchange($payload)) {
                         $this->bitmap = 0;
                         return false;
                     }
-                    $payload = $this->_get_binary_packet();
+                    $payload = $this->_get_binary_packet($skip_channel_filter);
                 }
         }
 
         // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
-        if (($this->bitmap & self::MASK_CONNECTED) && !($this->bitmap & self::MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
+        if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
             $this->_string_shift($payload, 1);
+            if (strlen($payload) < 4) {
+                return false;
+            }
             extract(unpack('Nlength', $this->_string_shift($payload, 4)));
             $this->banner_message = utf8_decode($this->_string_shift($payload, $length));
             $payload = $this->_get_binary_packet();
         }
 
         // only called when we've already logged in
-        if (($this->bitmap & self::MASK_CONNECTED) && ($this->bitmap & self::MASK_LOGIN)) {
+        if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
             switch (ord($payload[0])) {
+                case NET_SSH2_MSG_CHANNEL_DATA:
+                case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
+                case NET_SSH2_MSG_CHANNEL_REQUEST:
+                case NET_SSH2_MSG_CHANNEL_CLOSE:
+                case NET_SSH2_MSG_CHANNEL_EOF:
+                    if (!$skip_channel_filter && !empty($this->server_channels)) {
+                        $this->binary_packet_buffer = $payload;
+                        $this->_get_channel_packet(true);
+                        $payload = $this->_get_binary_packet();
+                    }
+                    break;
                 case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
+                    if (strlen($payload) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nlength', $this->_string_shift($payload, 4)));
                     $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);
 
@@ -3042,12 +3386,18 @@ class SSH2
                         return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
                     }
 
-                    $payload = $this->_get_binary_packet();
+                    $payload = $this->_get_binary_packet($skip_channel_filter);
                     break;
                 case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
                     $this->_string_shift($payload, 1);
+                    if (strlen($payload) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nlength', $this->_string_shift($payload, 4)));
                     $data = $this->_string_shift($payload, $length);
+                    if (strlen($payload) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
                     switch ($data) {
                         case 'auth-agent':
@@ -3055,6 +3405,9 @@ class SSH2
                             if (isset($this->agent)) {
                                 $new_channel = self::CHANNEL_AGENT_FORWARD;
 
+                                if (strlen($payload) < 8) {
+                                    return false;
+                                }
                                 extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
                                 extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));
 
@@ -3096,15 +3449,18 @@ class SSH2
                                 return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
                             }
                     }
-                    $payload = $this->_get_binary_packet();
+                    $payload = $this->_get_binary_packet($skip_channel_filter);
                     break;
                 case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
                     $this->_string_shift($payload, 1);
+                    if (strlen($payload) < 8) {
+                        return false;
+                    }
                     extract(unpack('Nchannel', $this->_string_shift($payload, 4)));
                     extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
                     $this->window_size_client_to_server[$channel]+= $window_size;
 
-                    $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet();
+                    $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
             }
         }
 
@@ -3165,6 +3521,10 @@ class SSH2
      */
     function disablePTY()
     {
+        if ($this->in_request_pty_exec) {
+            $this->_close_channel(self::CHANNEL_EXEC);
+            $this->in_request_pty_exec = false;
+        }
         $this->request_pty = false;
     }
 
@@ -3197,32 +3557,38 @@ class SSH2
         }
 
         while (true) {
-            if ($this->curTimeout) {
-                if ($this->curTimeout < 0) {
-                    $this->is_timeout = true;
-                    return true;
-                }
+            if ($this->binary_packet_buffer !== false) {
+                $response = $this->binary_packet_buffer;
+                $this->binary_packet_buffer = false;
+            } else {
+                if ($this->curTimeout) {
+                    if ($this->curTimeout < 0) {
+                        $this->is_timeout = true;
+                        return true;
+                    }
 
-                $read = array($this->fsock);
-                $write = $except = null;
+                    $read = array($this->fsock);
+                    $write = $except = null;
 
-                $start = microtime(true);
-                $sec = floor($this->curTimeout);
-                $usec = 1000000 * ($this->curTimeout - $sec);
-                // on windows this returns a "Warning: Invalid CRT parameters detected" error
-                if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
-                    $this->is_timeout = true;
-                    return true;
+                    $start = microtime(true);
+                    $sec = floor($this->curTimeout);
+                    $usec = 1000000 * ($this->curTimeout - $sec);
+                    // on windows this returns a "Warning: Invalid CRT parameters detected" error
+                    if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
+                        $this->is_timeout = true;
+                        return true;
+                    }
+                    $elapsed = microtime(true) - $start;
+                    $this->curTimeout-= $elapsed;
                 }
-                $elapsed = microtime(true) - $start;
-                $this->curTimeout-= $elapsed;
-            }
 
-            $response = $this->_get_binary_packet();
-            if ($response === false) {
-                user_error('Connection closed by server');
-                return false;
+                $response = $this->_get_binary_packet(true);
+                if ($response === false) {
+                    user_error('Connection closed by server');
+                    return false;
+                }
             }
+
             if ($client_channel == -1 && $response === true) {
                 return true;
             }
@@ -3230,8 +3596,14 @@ class SSH2
                 return '';
             }
 
+            if (!strlen($response)) {
+                return false;
+            }
             extract(unpack('Ctype', $this->_string_shift($response, 1)));
 
+            if (strlen($response) < 4) {
+                return false;
+            }
             if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
                 extract(unpack('Nlength', $this->_string_shift($response, 4)));
             } else {
@@ -3251,18 +3623,103 @@ class SSH2
                     $this->window_size_server_to_client[$channel]+= $this->window_size;
                 }
 
+                switch ($type) {
+                    case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
+                        /*
+                        if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
+                            $this->_send_channel_packet($client_channel, chr(0));
+                        }
+                        */
+                        // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
+                        if (strlen($response) < 8) {
+                            return false;
+                        }
+                        extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
+                        $data = $this->_string_shift($response, $length);
+                        $this->stdErrorLog.= $data;
+                        if ($skip_extended || $this->quiet_mode) {
+                            continue 2;
+                        }
+                        if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
+                            return $data;
+                        }
+                        if (!isset($this->channel_buffers[$channel])) {
+                            $this->channel_buffers[$channel] = array();
+                        }
+                        $this->channel_buffers[$channel][] = $data;
+
+                        continue 2;
+                    case NET_SSH2_MSG_CHANNEL_REQUEST:
+                        if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
+                            continue 2;
+                        }
+                        if (strlen($response) < 4) {
+                            return false;
+                        }
+                        extract(unpack('Nlength', $this->_string_shift($response, 4)));
+                        $value = $this->_string_shift($response, $length);
+                        switch ($value) {
+                            case 'exit-signal':
+                                $this->_string_shift($response, 1);
+                                if (strlen($response) < 4) {
+                                    return false;
+                                }
+                                extract(unpack('Nlength', $this->_string_shift($response, 4)));
+                                $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
+                                $this->_string_shift($response, 1);
+                                if (strlen($response) < 4) {
+                                    return false;
+                                }
+                                extract(unpack('Nlength', $this->_string_shift($response, 4)));
+                                if ($length) {
+                                    $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
+                                }
+
+                                $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
+                                $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
+
+                                $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
+
+                                continue 3;
+                            case 'exit-status':
+                                if (strlen($response) < 5) {
+                                    return false;
+                                }
+                                extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
+                                $this->exit_status = $exit_status;
+
+                                // "The client MAY ignore these messages."
+                                // -- http://tools.ietf.org/html/rfc4254#section-6.10
+
+                                continue 3;
+                            default:
+                                // "Some systems may not implement signals, in which case they SHOULD ignore this message."
+                                //  -- http://tools.ietf.org/html/rfc4254#section-6.9
+                                continue 3;
+                        }
+                }
+
                 switch ($this->channel_status[$channel]) {
                     case NET_SSH2_MSG_CHANNEL_OPEN:
                         switch ($type) {
                             case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
+                                if (strlen($response) < 4) {
+                                    return false;
+                                }
                                 extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
                                 $this->server_channels[$channel] = $server_channel;
+                                if (strlen($response) < 4) {
+                                    return false;
+                                }
                                 extract(unpack('Nwindow_size', $this->_string_shift($response, 4)));
                                 if ($window_size < 0) {
                                     $window_size&= 0x7FFFFFFF;
                                     $window_size+= 0x80000000;
                                 }
                                 $this->window_size_client_to_server[$channel] = $window_size;
+                                if (strlen($response) < 4) {
+                                     return false;
+                                }
                                 $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
                                 $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
                                 $result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
@@ -3302,6 +3759,9 @@ class SSH2
                         $this->_send_channel_packet($channel, chr(0));
                     }
                     */
+                    if (strlen($response) < 4) {
+                        return false;
+                    }
                     extract(unpack('Nlength', $this->_string_shift($response, 4)));
                     $data = $this->_string_shift($response, $length);
 
@@ -3321,61 +3781,6 @@ class SSH2
                     }
                     $this->channel_buffers[$channel][] = $data;
                     break;
-                case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
-                    /*
-                    if ($client_channel == self::CHANNEL_EXEC) {
-                        $this->_send_channel_packet($client_channel, chr(0));
-                    }
-                    */
-                    // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
-                    extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
-                    $data = $this->_string_shift($response, $length);
-                    $this->stdErrorLog.= $data;
-                    if ($skip_extended || $this->quiet_mode) {
-                        break;
-                    }
-                    if ($client_channel == $channel) {
-                        return $data;
-                    }
-                    if (!isset($this->channel_buffers[$channel])) {
-                        $this->channel_buffers[$channel] = array();
-                    }
-                    $this->channel_buffers[$channel][] = $data;
-                    break;
-                case NET_SSH2_MSG_CHANNEL_REQUEST:
-                    extract(unpack('Nlength', $this->_string_shift($response, 4)));
-                    $value = $this->_string_shift($response, $length);
-                    switch ($value) {
-                        case 'exit-signal':
-                            $this->_string_shift($response, 1);
-                            extract(unpack('Nlength', $this->_string_shift($response, 4)));
-                            $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
-                            $this->_string_shift($response, 1);
-                            extract(unpack('Nlength', $this->_string_shift($response, 4)));
-                            if ($length) {
-                                $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
-                            }
-
-                            $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
-                            $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
-
-                            $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
-
-                            break;
-                        case 'exit-status':
-                            extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
-                            $this->exit_status = $exit_status;
-
-                            // "The client MAY ignore these messages."
-                            // -- http://tools.ietf.org/html/rfc4254#section-6.10
-
-                            break;
-                        default:
-                            // "Some systems may not implement signals, in which case they SHOULD ignore this message."
-                            //  -- http://tools.ietf.org/html/rfc4254#section-6.9
-                            break;
-                    }
-                    break;
                 case NET_SSH2_MSG_CHANNEL_CLOSE:
                     $this->curTimeout = 0;
 
@@ -3696,10 +4101,9 @@ class SSH2
         switch (NET_SSH2_LOGGING) {
             case self::LOG_SIMPLE:
                 return $this->message_number_log;
-                break;
             case self::LOG_COMPLEX:
-                return $this->_format_log($this->message_log, $this->message_number_log);
-                break;
+                $log = $this->_format_log($this->message_log, $this->message_number_log);
+                return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>';
             default:
                 return false;
         }
@@ -3991,6 +4395,9 @@ class SSH2
         $signature = $this->signature;
         $server_public_host_key = $this->server_public_host_key;
 
+        if (strlen($server_public_host_key) < 4) {
+            return false;
+        }
         extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
         $this->_string_shift($server_public_host_key, $length);
 
@@ -4006,15 +4413,27 @@ class SSH2
             case 'ssh-dss':
                 $zero = new BigInteger();
 
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $p = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
 
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $q = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
 
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $g = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
 
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $y = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
 
@@ -4061,15 +4480,24 @@ class SSH2
 
                 break;
             case 'ssh-rsa':
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $e = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
 
+                if (strlen($server_public_host_key) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                 $rawN = $this->_string_shift($server_public_host_key, $temp['length']);
                 $n = new BigInteger($rawN, -256);
                 $nLength = strlen(ltrim($rawN, "\0"));
 
                 /*
+                if (strlen($signature) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($signature, 4));
                 $signature = $this->_string_shift($signature, $temp['length']);
 
@@ -4082,6 +4510,9 @@ class SSH2
                 }
                 */
 
+                if (strlen($signature) < 4) {
+                    return false;
+                }
                 $temp = unpack('Nlength', $this->_string_shift($signature, 4));
                 $s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);
 
diff --git a/vendor/simplepie/simplepie/library/SimplePie.php b/vendor/simplepie/simplepie/library/SimplePie.php
index 63ab10b5ff95760dea630faf11cfadbe583770e2..34b6ca0c9fe0e173a3a26d31ea0b7b1258fae3dc 100755
--- a/vendor/simplepie/simplepie/library/SimplePie.php
+++ b/vendor/simplepie/simplepie/library/SimplePie.php
@@ -5,7 +5,7 @@
  * A PHP-Based RSS and Atom Feed Framework.
  * Takes the hard work out of managing a complete RSS/Atom solution.
  *
- * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2017, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.4.3
- * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @version 1.5.1
+ * @copyright 2004-2017 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -50,7 +50,7 @@ define('SIMPLEPIE_NAME', 'SimplePie');
 /**
  * SimplePie Version
  */
-define('SIMPLEPIE_VERSION', '1.4.3');
+define('SIMPLEPIE_VERSION', '1.5.1');
 
 /**
  * SimplePie Build
@@ -643,6 +643,12 @@ class SimplePie
 	 */
 	public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
 
+	/**
+	 * @var bool Should we throw exceptions, or use the old-style error property?
+	 * @access private
+	 */
+	public $enable_exceptions = false;
+	
 	/**
 	 * The SimplePie class contains feed level data and options
 	 *
@@ -804,7 +810,7 @@ class SimplePie
 	}
 
 	/**
-	 * Set the the default timeout for fetching remote feeds
+	 * Set the default timeout for fetching remote feeds
 	 *
 	 * This allows you to change the maximum time the feed's server to respond
 	 * and send the feed back.
@@ -1314,6 +1320,11 @@ class SimplePie
 			}
 		}
 
+		// The default sanitize class gets set in the constructor, check if it has
+		// changed.
+		if ($this->registry->get_class('Sanitize') !== 'SimplePie_Sanitize') {
+			$this->sanitize = $this->registry->create('Sanitize');
+		}
 		if (method_exists($this->sanitize, 'set_registry'))
 		{
 			$this->sanitize->set_registry($this->registry);
@@ -1638,33 +1649,18 @@ class SimplePie
 				try
 				{
 					$microformats = false;
-					if (function_exists('Mf2\parse')) {
+					if (class_exists('DOMXpath') && function_exists('Mf2\parse')) {
+						$doc = new DOMDocument();
+						@$doc->loadHTML($file->body);
+						$xpath = new DOMXpath($doc);
 						// Check for both h-feed and h-entry, as both a feed with no entries
 						// and a list of entries without an h-feed wrapper are both valid.
-						$position = 0;
-						while ($position = strpos($file->body, 'h-feed', $position))
-						{
-							$start = $position < 200 ? 0 : $position - 200;
-							$check = substr($file->body, $start, 400);
-							if ($microformats = preg_match('/class="[^"]*h-feed/', $check))
-							{
-								break;
-							}
-							$position += 7;
-						}
-						$position = 0;
-						while ($position = strpos($file->body, 'h-entry', $position))
-						{
-							$start = $position < 200 ? 0 : $position - 200;
-							$check = substr($file->body, $start, 400);
-							if ($microformats = preg_match('/class="[^"]*h-entry/', $check))
-							{
-								break;
-							}
-							$position += 7;
-						}
+						$query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '.
+							'contains(concat(" ", @class, " "), " h-entry ")]';
+						$result = $xpath->query($query);
+						$microformats = $result->length !== 0;
 					}
-					// Now also do feed discovery, but if an h-entry was found don't
+					// Now also do feed discovery, but if microformats were found don't
 					// overwrite the current value of file.
 					$discovered = $locate->find($this->autodiscovery,
 					                            $this->all_discovered_feeds);
@@ -2600,15 +2596,15 @@ class SimplePie
 			}
 		}
 
-		if (isset($this->data['links'][$rel]))
+		if (isset($this->data['headers']['link']) &&
+		    preg_match('/<([^>]+)>; rel='.preg_quote($rel).'/',
+		               $this->data['headers']['link'], $match))
 		{
-			return $this->data['links'][$rel];
+			return array($match[1]);
 		}
-		else if (isset($this->data['headers']['link']) &&
-		         preg_match('/<([^>]+)>; rel='.preg_quote($rel).'/',
-		                    $this->data['headers']['link'], $match))
+		else if (isset($this->data['links'][$rel]))
 		{
-			return array($match[1]);
+			return $this->data['links'][$rel];
 		}
 		else
 		{
@@ -3149,7 +3145,7 @@ class SimplePie
 
 		if (($url = $this->get_link()) !== null)
 		{
-			return 'http://g.etfv.co/' . urlencode($url);
+			return 'https://www.google.com/s2/favicons?domain=' . urlencode($url);
 		}
 
 		return false;
diff --git a/vendor/simplepie/simplepie/library/SimplePie/Category.php b/vendor/simplepie/simplepie/library/SimplePie/Category.php
index 92d511e1ae64c8e9e69abbe95861a5b43d9842b4..df0f13f9a1807ca85c90c864f39aa294022e8636 100644
--- a/vendor/simplepie/simplepie/library/SimplePie/Category.php
+++ b/vendor/simplepie/simplepie/library/SimplePie/Category.php
@@ -56,7 +56,7 @@ class SimplePie_Category
 	/**
 	 * Category identifier
 	 *
-	 * @var string
+	 * @var string|null
 	 * @see get_term
 	 */
 	var $term;
@@ -64,7 +64,7 @@ class SimplePie_Category
 	/**
 	 * Categorization scheme identifier
 	 *
-	 * @var string
+	 * @var string|null
 	 * @see get_scheme()
 	 */
 	var $scheme;
@@ -72,23 +72,36 @@ class SimplePie_Category
 	/**
 	 * Human readable label
 	 *
-	 * @var string
+	 * @var string|null
 	 * @see get_label()
 	 */
 	var $label;
 
+	/**
+	 * Category type
+	 * 
+	 * category for <category>
+	 * subject for <dc:subject>
+	 *
+	 * @var string|null
+	 * @see get_type()
+	 */
+	var $type;
+
 	/**
 	 * Constructor, used to input the data
 	 *
-	 * @param string $term
-	 * @param string $scheme
-	 * @param string $label
+	 * @param string|null $term
+	 * @param string|null $scheme
+	 * @param string|null $label
+	 * @param string|null $type
 	 */
-	public function __construct($term = null, $scheme = null, $label = null)
+	public function __construct($term = null, $scheme = null, $label = null, $type = null)
 	{
 		$this->term = $term;
 		$this->scheme = $scheme;
 		$this->label = $label;
+		$this->type = $type;
 	}
 
 	/**
@@ -109,14 +122,7 @@ class SimplePie_Category
 	 */
 	public function get_term()
 	{
-		if ($this->term !== null)
-		{
-			return $this->term;
-		}
-		else
-		{
-			return null;
-		}
+		return $this->term;
 	}
 
 	/**
@@ -126,31 +132,32 @@ class SimplePie_Category
 	 */
 	public function get_scheme()
 	{
-		if ($this->scheme !== null)
-		{
-			return $this->scheme;
-		}
-		else
-		{
-			return null;
-		}
+		return $this->scheme;
 	}
 
 	/**
 	 * Get the human readable label
 	 *
+	 * @param bool $strict
 	 * @return string|null
 	 */
-	public function get_label()
+	public function get_label($strict = false)
 	{
-		if ($this->label !== null)
-		{
-			return $this->label;
-		}
-		else
+		if ($this->label === null && $strict !== true)
 		{
 			return $this->get_term();
 		}
+		return $this->label;
+	}
+
+	/**
+	 * Get the category type
+	 *
+	 * @return string|null
+	 */
+	public function get_type()
+	{
+		return $this->type;
 	}
 }
 
diff --git a/vendor/simplepie/simplepie/library/SimplePie/File.php b/vendor/simplepie/simplepie/library/SimplePie/File.php
index e670e05a0115dbf0585d2431e0c5a2aef05943a4..2bb0a3b441a0dd0b2dd794ec87cb9b7315b32389 100644
--- a/vendor/simplepie/simplepie/library/SimplePie/File.php
+++ b/vendor/simplepie/simplepie/library/SimplePie/File.php
@@ -136,8 +136,7 @@ class SimplePie_File
 						$this->url = $info['url'];
 					}
 					curl_close($fp);
-					$this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
-					$this->headers = array_pop($this->headers);
+					$this->headers = SimplePie_HTTP_Parser::prepareHeaders($this->headers, $info['redirect_count'] + 1);
 					$parser = new SimplePie_HTTP_Parser($this->headers);
 					if ($parser->parse())
 					{
diff --git a/vendor/simplepie/simplepie/library/SimplePie/HTTP/Parser.php b/vendor/simplepie/simplepie/library/SimplePie/HTTP/Parser.php
index 63ae1e03d21eddad314d019d473057f816afc520..e982c206f9aefcb47c5f5a555a98180f9725f08e 100644
--- a/vendor/simplepie/simplepie/library/SimplePie/HTTP/Parser.php
+++ b/vendor/simplepie/simplepie/library/SimplePie/HTTP/Parser.php
@@ -496,4 +496,25 @@ class SimplePie_HTTP_Parser
 			}
 		}
 	}
+
+	/**
+	 * Prepare headers (take care of proxies headers)
+	 *
+	 * @param string  $headers Raw headers
+	 * @param integer $count   Redirection count. Default to 1.
+	 *
+	 * @return string
+	 */
+	static public function prepareHeaders($headers, $count = 1)
+	{
+		$data = explode("\r\n\r\n", $headers, $count);
+		$data = array_pop($data);
+		if (false !== stripos($data, "HTTP/1.0 200 Connection established\r\n\r\n")) {
+			$data = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $data);
+		}
+		if (false !== stripos($data, "HTTP/1.1 200 Connection established\r\n\r\n")) {
+			$data = str_ireplace("HTTP/1.1 200 Connection established\r\n\r\n", '', $data);
+		}
+		return $data;
+	}
 }
diff --git a/vendor/simplepie/simplepie/library/SimplePie/Item.php b/vendor/simplepie/simplepie/library/SimplePie/Item.php
index 3979b8f1b1d2627da671df7d58ddfdf160a72fbb..2083e7a9202a64f0b092c23bbc3aa19f57c086d3 100644
--- a/vendor/simplepie/simplepie/library/SimplePie/Item.php
+++ b/vendor/simplepie/simplepie/library/SimplePie/Item.php
@@ -206,9 +206,10 @@ class SimplePie_Item
 	 *
 	 * @since Beta 2
 	 * @param boolean $hash Should we force using a hash instead of the supplied ID?
-	 * @return string
+	 * @param string|false $fn User-supplied function to generate an hash
+	 * @return string|null
 	 */
-	public function get_id($hash = false, $fn = '')
+	public function get_id($hash = false, $fn = 'md5')
 	{
 		if (!$hash)
 		{
@@ -237,7 +238,15 @@ class SimplePie_Item
 				return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 		}
-		if ($fn === '' || !is_callable($fn)) $fn = 'md5';
+		if ($fn === false)
+		{
+			return null;
+		}
+		elseif (!is_callable($fn))
+		{
+			trigger_error('User-supplied function $fn must be callable', E_USER_WARNING);
+			$fn = 'md5';
+		}
 		return call_user_func($fn,
 		       $this->get_permalink().$this->get_title().$this->get_content());
 	}
@@ -460,47 +469,50 @@ class SimplePie_Item
 	{
 		$categories = array();
 
-		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+		$type = 'category';
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, $type) as $category)
 		{
 			$term = null;
 			$scheme = null;
 			$label = null;
 			if (isset($category['attribs']['']['term']))
 			{
-				$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_HTML);
+				$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if (isset($category['attribs']['']['scheme']))
 			{
-				$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_HTML);
+				$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if (isset($category['attribs']['']['label']))
 			{
-				$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_HTML);
+				$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
-			$categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+			$categories[] = $this->registry->create('Category', array($term, $scheme, $label, $type));
 		}
-		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, $type) as $category)
 		{
 			// This is really the label, but keep this as the term also for BC.
 			// Label will also work on retrieving because that falls back to term.
-			$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML);
+			$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
 			if (isset($category['attribs']['']['domain']))
 			{
-				$scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_HTML);
+				$scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			else
 			{
 				$scheme = null;
 			}
-			$categories[] = $this->registry->create('Category', array($term, $scheme, null));
+			$categories[] = $this->registry->create('Category', array($term, $scheme, null, $type));
 		}
-		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+
+		$type = 'subject';
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, $type) as $category)
 		{
-			$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
+			$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null, $type));
 		}
-		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, $type) as $category)
 		{
-			$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
+			$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null, $type));
 		}
 
 		if (!empty($categories))
@@ -637,7 +649,7 @@ class SimplePie_Item
 			$email = null;
 			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
 			{
-				$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
+				$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
 			{
@@ -645,7 +657,7 @@ class SimplePie_Item
 			}
 			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
 			{
-				$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
+				$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if ($name !== null || $email !== null || $uri !== null)
 			{
@@ -659,7 +671,7 @@ class SimplePie_Item
 			$email = null;
 			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
 			{
-				$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
+				$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
 			{
@@ -667,7 +679,7 @@ class SimplePie_Item
 			}
 			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
 			{
-				$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
+				$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
 			}
 			if ($name !== null || $email !== null || $url !== null)
 			{
@@ -676,19 +688,19 @@ class SimplePie_Item
 		}
 		if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
 		{
-			$authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_HTML)));
+			$authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
 		}
 		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
 		{
-			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
+			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
 		}
 		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
 		{
-			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
+			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
 		}
 		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
 		{
-			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
+			$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
 		}
 
 		if (!empty($authors))
@@ -2814,9 +2826,17 @@ class SimplePie_Item
 					{
 						$length = ceil($link['attribs']['']['length']);
 					}
+					if (isset($link['attribs']['']['title']))
+					{
+						$title = $this->sanitize($link['attribs']['']['title'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$title = $title_parent;
+					}
 
 					// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
-					$this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
+					$this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title, $width));
 				}
 			}
 
diff --git a/vendor/simplepie/simplepie/library/SimplePie/Parser.php b/vendor/simplepie/simplepie/library/SimplePie/Parser.php
index 17139abe95a2af5ed3f1eeccd0da788764733244..df12340231f2f7ef8b9d28c5f8c275cdc0a780a7 100644
--- a/vendor/simplepie/simplepie/library/SimplePie/Parser.php
+++ b/vendor/simplepie/simplepie/library/SimplePie/Parser.php
@@ -76,26 +76,17 @@ class SimplePie_Parser
 
 	public function parse(&$data, $encoding, $url = '')
 	{
-		if (function_exists('Mf2\parse')) {
+		if (class_exists('DOMXpath') && function_exists('Mf2\parse')) {
+			$doc = new DOMDocument();
+			@$doc->loadHTML($data);
+			$xpath = new DOMXpath($doc);
 			// Check for both h-feed and h-entry, as both a feed with no entries
 			// and a list of entries without an h-feed wrapper are both valid.
-			$position = 0;
-			while ($position = strpos($data, 'h-feed', $position)) {
-				$start = $position < 200 ? 0 : $position - 200;
-				$check = substr($data, $start, 400);
-				if (preg_match('/class="[^"]*h-feed/', $check)) {
-					return $this->parse_microformats($data, $url);
-				}
-				$position += 7;
-			}
-			$position = 0;
-			while ($position = strpos($data, 'h-entry', $position)) {
-				$start = $position < 200 ? 0 : $position - 200;
-				$check = substr($data, $start, 400);
-				if (preg_match('/class="[^"]*h-entry/', $check)) {
-					return $this->parse_microformats($data, $url);
-				}
-				$position += 7;
+			$query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '.
+				'contains(concat(" ", @class, " "), " h-entry ")]';
+			$result = $xpath->query($query);
+			if ($result->length !== 0) {
+				return $this->parse_microformats($data, $url);
 			}
 		}
 
@@ -465,7 +456,7 @@ class SimplePie_Parser
 				$h_feed = $mf_item;
 				break;
 			}
-			// Also look for an h-feed in the children of each top level item.
+			// Also look for h-feed or h-entry in the children of each top level item.
 			if (!isset($mf_item['children'][0]['type'])) continue;
 			if (in_array('h-feed', $mf_item['children'][0]['type'])) {
 				$h_feed = $mf_item['children'][0];
@@ -474,6 +465,13 @@ class SimplePie_Parser
 				if (in_array('h-card', $mf_item['type'])) $feed_author = $mf_item;
 				break;
 			}
+			else if (in_array('h-entry', $mf_item['children'][0]['type'])) {
+				$entries = $mf_item['children'];
+				// In this case the parent of the h-entry list may be an h-card, so use
+				// it as the feed_author.
+				if (in_array('h-card', $mf_item['type'])) $feed_author = $mf_item;
+				break;
+			}
 		}
 		if (isset($h_feed['children'])) {
 			$entries = $h_feed['children'];
@@ -485,7 +483,7 @@ class SimplePie_Parser
 				$feed_author = $mf['items'][0]['properties']['author'][0];
 			}
 		}
-		else {
+		else if (count($entries) === 0) {
 			$entries = $mf['items'];
 		}
 		for ($i = 0; $i < count($entries); $i++) {
@@ -554,18 +552,21 @@ class SimplePie_Parser
 					$photo_list = array();
 					for ($j = 0; $j < count($entry['properties']['photo']); $j++) {
 						$photo = $entry['properties']['photo'][$j];
-						if (strpos($content, $photo) === false) {
+						if (!empty($photo) && strpos($content, $photo) === false) {
 							$photo_list[] = $photo;
 						}
 					}
 					// When there's more than one photo show the first and use a lightbox.
+					// Need a permanent, unique name for the image set, but don't have
+					// anything unique except for the content itself, so use that.
 					$count = count($photo_list);
 					if ($count > 1) {
+						$image_set_id = preg_replace('/[[:^alnum:]]/', '', $photo_list[0]);
 						$description = '<p>';
 						for ($j = 0; $j < $count; $j++) {
 							$hidden = $j === 0 ? '' : 'class="hidden" ';
 							$description .= '<a href="'.$photo_list[$j].'" '.$hidden.
-								'data-lightbox="image-set-'.$i.'">'.
+								'data-lightbox="image-set-'.$image_set_id.'">'.
 								'<img src="'.$photo_list[$j].'"></a>';
 						}
 						$description .= '<br><b>'.$count.' photos</b></p>';
@@ -583,10 +584,18 @@ class SimplePie_Parser
 						$item['title'] = array(array('data' => $title));
 					}
 					$description .= $entry['properties']['content'][0]['html'];
-					if (isset($entry['properties']['in-reply-to'][0]['value'])) {
-						$in_reply_to = $entry['properties']['in-reply-to'][0]['value'];
-						$description .= '<p><span class="in-reply-to"></span> '.
-							'<a href="'.$in_reply_to.'">'.$in_reply_to.'</a><p>';
+					if (isset($entry['properties']['in-reply-to'][0])) {
+						$in_reply_to = '';
+						if (is_string($entry['properties']['in-reply-to'][0])) {
+							$in_reply_to = $entry['properties']['in-reply-to'][0];
+						}
+						else if (isset($entry['properties']['in-reply-to'][0]['value'])) {
+							$in_reply_to = $entry['properties']['in-reply-to'][0]['value'];
+						}
+						if ($in_reply_to !== '') {
+							$description .= '<p><span class="in-reply-to"></span> '.
+								'<a href="'.$in_reply_to.'">'.$in_reply_to.'</a><p>';
+						}
 					}
 					$item['description'] = array(array('data' => $description));
 				}
@@ -627,7 +636,7 @@ class SimplePie_Parser
 			$image = array(array('child' => array('' => array('url' =>
 				array(array('data' => $feed_author['properties']['photo'][0]))))));
 		}
-		// Use the a name given for the h-feed, or get the title from the html.
+		// Use the name given for the h-feed, or get the title from the html.
 		if ($feed_title !== '') {
 			$feed_title = array(array('data' => htmlspecialchars($feed_title)));
 		}
diff --git a/vendor/splitbrain/php-archive/.gitignore b/vendor/splitbrain/php-archive/.gitignore
index c6277c187bf8f14922e7322bcf90fa753e201db3..e11729e196077a9f41f8028764e6ee65a3960849 100644
--- a/vendor/splitbrain/php-archive/.gitignore
+++ b/vendor/splitbrain/php-archive/.gitignore
@@ -5,4 +5,4 @@ vendor/
 composer.lock
 apigen.phar
 docs/
-
+nbproject/
\ No newline at end of file
diff --git a/vendor/splitbrain/php-archive/src/Tar.php b/vendor/splitbrain/php-archive/src/Tar.php
index f9d7bfbc094a4c5e78ab15028f40bde918107a08..b25575854115ddbed0c8b7bfe215c97179069945 100644
--- a/vendor/splitbrain/php-archive/src/Tar.php
+++ b/vendor/splitbrain/php-archive/src/Tar.php
@@ -356,7 +356,7 @@ class Tar extends Archive
         }
 
         if ($this->comptype === Archive::COMPRESS_GZIP) {
-            return gzcompress($this->memory, $this->complevel);
+            return gzencode($this->memory, $this->complevel);
         }
         if ($this->comptype === Archive::COMPRESS_BZIP) {
             return bzcompress($this->memory);
diff --git a/vendor/splitbrain/php-cli/.gitignore b/vendor/splitbrain/php-cli/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c6277c187bf8f14922e7322bcf90fa753e201db3
--- /dev/null
+++ b/vendor/splitbrain/php-cli/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+.idea/
+composer.phar
+vendor/
+composer.lock
+apigen.phar
+docs/
+
diff --git a/vendor/splitbrain/php-cli/LICENSE b/vendor/splitbrain/php-cli/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4a8abc3eba582d23b3fb9b0cda35b35fb0b023f4
--- /dev/null
+++ b/vendor/splitbrain/php-cli/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Andreas Gohr
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/splitbrain/php-cli/README.md b/vendor/splitbrain/php-cli/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7cc52ed81a819357695da053fa6f5604cbe9f3b6
--- /dev/null
+++ b/vendor/splitbrain/php-cli/README.md
@@ -0,0 +1,158 @@
+# PHP-CLI
+
+PHP-CLI is a simple library that helps with creating nice looking command line scripts.
+
+It takes care of
+
+- **option parsing**
+- **help page generation**
+- **automatic width adjustment**
+- **colored output**
+- **optional PSR3 compatibility**
+
+It is lightweight and has **no 3rd party dependencies**.
+
+[![Build Status](https://travis-ci.org/splitbrain/php-cli.svg)](https://travis-ci.org/splitbrain/php-cli)
+
+## Installation
+
+Use composer:
+
+```php composer.phar require splitbrain/php-cli```
+
+## Usage and Examples
+
+Minimal example:
+
+```php
+#!/usr/bin/php
+<?php
+require __DIR__ . '/../vendor/autoload.php';
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+class Minimal extends CLI
+{
+    // register options and arguments
+    protected function setup(Options $options)
+    {
+        $options->setHelp('A very minimal example that does nothing but print a version');
+        $options->registerOption('version', 'print version', 'v');
+    }
+
+    // implement your code
+    protected function main(Options $options)
+    {
+        if ($options->getOpt('version')) {
+            $this->info('1.0.0');
+        } else {
+            echo $options->help();
+        }
+    }
+}
+// execute it
+$cli = new Minimal();
+$cli->run();
+```
+
+![Screenshot](screenshot.png)
+
+
+The basic usage is simple:
+
+- create a class and ``extend splitbrain\phpcli\CLI``
+- implement the ```setup($options)``` method and register options, arguments, commands and set help texts
+    - ``$options->setHelp()`` adds a general description
+    - ``$options->registerOption()`` adds an option
+    - ``$options->registerArgument()`` adds an argument
+    - ``$options->registerCommand()`` adds a sub command
+- implement the ```main($options)``` method and do your business logic there
+    - ``$options->getOpts`` lets you access set options
+    - ``$options->getArgs()`` returns the remaining arguments after removing the options
+    - ``$options->getCmd()`` returns the sub command the user used
+- instantiate your class and call ```run()``` on it
+
+More examples can be found in the examples directory. Please refer to the [API docs](https://splitbrain.github.io/php-cli/)
+for further info.
+
+## Exceptions
+
+By default the CLI class registers an exception handler and will print the exception's message to the end user and
+exit the programm with a non-zero exit code. You can disable this behaviour and catch all exceptions yourself by
+passing false to the constructor.
+
+You can use the provided ``splitbrain\phpcli\Exception`` to signal any problems within your main code yourself. The
+exceptions's code will be used as the exit code then.
+
+Stacktraces will be printed on log level `debug`. 
+
+## Colored output
+
+Colored output is handled through the ``Colors`` class. It tries to detect if a color terminal is available and only
+then uses terminal colors. You can always suppress colored output by passing ``--no-colors`` to your scripts.
+Disabling colors will also disable the emoticon prefixes.
+
+Simple colored log messages can be printed by you using the convinence methods ``success()`` (green), ``info()`` (cyan),
+``error()`` (red) or ``fatal()`` (red). The latter will also exit the programm with a non-zero exit code.
+
+For more complex coloring you can access the color class through ``$this->colors`` in your script. The ``wrap()`` method
+is probably what you want to use.
+
+The table formatter allows coloring full columns. To use that mechanism pass an array of colors as third parameter to
+its ``format()`` method. Please note that you can not pass colored texts in the second parameters (text length calculation
+and wrapping will fail, breaking your texts).
+
+## Table Formatter
+
+The ``TableFormatter`` class allows you to align texts in multiple columns. It tries to figure out the available
+terminal width on its own. It can be overwritten by setting a ``COLUMNS`` environment variable.
+
+The formatter is used through the ``format()`` method which expects at least two arrays: The first defines the column
+widths, the second contains the texts to fill into the columns. Between each column a border is printed (a single space
+by default).
+
+See the ``example/table.php`` for sample usage.
+
+Columns width can be given in three forms:
+
+- fixed width in characters by providing an integer (eg. ``15``)
+- precentages by provifing an integer and a percent sign (eg. ``25%``)
+- a single fluid "rest" column marked with an asterisk (eg. ``*``)
+
+When mixing fixed and percentage widths, percentages refer to the remaining space after all fixed columns have been
+assigned.
+
+Space for borders is automatically calculated. It is recommended to always have some relative (percentage) or a fluid
+column to adjust for different terminal widths.
+
+The table formatter is used for the automatic help screen accessible when calling your script with ``-h`` or ``--help``.
+
+## PSR-3 Logging
+
+The CLI class is a fully PSR-3 compatible logger (printing colored log data to STDOUT and STDERR). This is useful when
+you call backend code from your CLI that expects a Logger instance to produce any sensible status output while running.
+ 
+To use this ability simply inherit from `splitbrain\phpcli\PSR3CLI` instead of `splitbrain\phpcli\CLI`, then pass `$this`
+as the logger instance. Be sure you have the suggested `psr/log` composer package installed.
+
+![Screenshot](screenshot2.png)
+
+You can adjust the verbosity of your CLI tool using the `--loglevel` parameter. Supported loglevels are the PSR-3
+loglevels and our own `success` level:
+
+* debug
+* info
+* notice      
+* success
+* warning
+* error
+* critical
+* alert
+* emergency
+
+Convenience methods for all log levels are available. Placeholder interpolation as described in PSR-3 is available, too.
+Messages from `warning` level onwards are printed to `STDERR` all below are printed to `STDOUT`. 
+
+The default log level of your script can be set by overwriting the `$logdefault` member.
+
+See `example/logging.php` for an example.
\ No newline at end of file
diff --git a/vendor/splitbrain/php-cli/composer.json b/vendor/splitbrain/php-cli/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..79e2502c427c059b7265aa40504792d2dde1e34c
--- /dev/null
+++ b/vendor/splitbrain/php-cli/composer.json
@@ -0,0 +1,34 @@
+{
+  "name": "splitbrain/php-cli",
+  "description": "Easy command line scripts for PHP with opt parsing and color output. No dependencies",
+  "keywords": [
+    "cli",
+    "console",
+    "terminal",
+    "command line",
+    "getopt",
+    "optparse",
+    "argparse"
+  ],
+  "license": "MIT",
+  "authors": [
+    {
+      "name": "Andreas Gohr",
+      "email": "andi@splitbrain.org"
+    }
+  ],
+  "require": {
+    "php": ">=5.3.0"
+  },
+  "suggest": {
+    "psr/log": "Allows you to make the CLI available as PSR-3 logger"
+  },
+  "require-dev": {
+    "phpunit/phpunit": "4.5.*"
+  },
+  "autoload": {
+    "psr-4": {
+      "splitbrain\\phpcli\\": "src"
+    }
+  }
+}
diff --git a/vendor/splitbrain/php-cli/src/CLI.php b/vendor/splitbrain/php-cli/src/CLI.php
new file mode 100644
index 0000000000000000000000000000000000000000..569ec6756cbc766e4d667f633f75d4634cdf89b6
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/CLI.php
@@ -0,0 +1,318 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+/**
+ * Class CLI
+ *
+ * Your commandline script should inherit from this class and implement the abstract methods.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ */
+abstract class CLI
+{
+    /** @var string the executed script itself */
+    protected $bin;
+    /** @var  Options the option parser */
+    protected $options;
+    /** @var  Colors */
+    public $colors;
+
+    /** @var array PSR-3 compatible loglevels and their prefix, color, output channel */
+    protected $loglevel = array(
+        'debug' => array('', Colors::C_LIGHTGRAY, STDOUT),
+        'info' => array('ℹ ', Colors::C_CYAN, STDOUT),
+        'notice' => array('☛ ', Colors::C_CYAN, STDOUT),
+        'success' => array('✓ ', Colors::C_GREEN, STDOUT),
+        'warning' => array('âš  ', Colors::C_BROWN, STDERR),
+        'error' => array('✗ ', Colors::C_RED, STDERR),
+        'critical' => array('☠ ', Colors::C_LIGHTRED, STDERR),
+        'alert' => array('✖ ', Colors::C_LIGHTRED, STDERR),
+        'emergency' => array('✘ ', Colors::C_LIGHTRED, STDERR),
+    );
+
+    protected $logdefault = 'info';
+
+    /**
+     * constructor
+     *
+     * Initialize the arguments, set up helper classes and set up the CLI environment
+     *
+     * @param bool $autocatch should exceptions be catched and handled automatically?
+     */
+    public function __construct($autocatch = true)
+    {
+        if ($autocatch) {
+            set_exception_handler(array($this, 'fatal'));
+        }
+
+        $this->colors = new Colors();
+        $this->options = new Options($this->colors);
+    }
+
+    /**
+     * Register options and arguments on the given $options object
+     *
+     * @param Options $options
+     * @return void
+     *
+     * @throws Exception
+     */
+    abstract protected function setup(Options $options);
+
+    /**
+     * Your main program
+     *
+     * Arguments and options have been parsed when this is run
+     *
+     * @param Options $options
+     * @return void
+     *
+     * @throws Exception
+     */
+    abstract protected function main(Options $options);
+
+    /**
+     * Execute the CLI program
+     *
+     * Executes the setup() routine, adds default options, initiate the options parsing and argument checking
+     * and finally executes main()
+     *
+     * @throws Exception
+     */
+    public function run()
+    {
+        if ('cli' != php_sapi_name()) {
+            throw new Exception('This has to be run from the command line');
+        }
+
+        // setup
+        $this->setup($this->options);
+        $this->options->registerOption(
+            'help',
+            'Display this help screen and exit immeadiately.',
+            'h'
+        );
+        $this->options->registerOption(
+            'no-colors',
+            'Do not use any colors in output. Useful when piping output to other tools or files.'
+        );
+        $this->options->registerOption(
+            'loglevel',
+            'Minimum level of messages to display. Default is ' . $this->colors->wrap($this->logdefault, Colors::C_CYAN) . '. ' .
+            'Valid levels are: debug, info, notice, success, warning, error, critical, alert, emergency.',
+            null,
+            'level'
+        );
+
+        // parse
+        $this->options->parseOptions();
+
+        // handle defaults
+        if ($this->options->getOpt('no-colors')) {
+            $this->colors->disable();
+        }
+        if ($this->options->getOpt('help')) {
+            echo $this->options->help();
+            exit(0);
+        }
+        $level = $this->options->getOpt('loglevel', $this->logdefault);
+        if (!isset($this->loglevel[$level])) $this->fatal('Unknown log level');
+        foreach (array_keys($this->loglevel) as $l) {
+            if ($l == $level) break;
+            unset($this->loglevel[$l]);
+        }
+
+        // check arguments
+        $this->options->checkArguments();
+
+        // execute
+        $this->main($this->options);
+
+        exit(0);
+    }
+
+    // region logging
+
+    /**
+     * Exits the program on a fatal error
+     *
+     * @param \Exception|string $error either an exception or an error message
+     * @param array $context
+     */
+    public function fatal($error, array $context = array())
+    {
+        $code = 0;
+        if (is_object($error) && is_a($error, 'Exception')) {
+            /** @var Exception $error */
+            $this->debug(get_class($error) . ' caught in ' . $error->getFile() . ':' . $error->getLine());
+            $this->debug($error->getTraceAsString());
+            $code = $error->getCode();
+            $error = $error->getMessage();
+
+        }
+        if (!$code) {
+            $code = Exception::E_ANY;
+        }
+
+        $this->critical($error, $context);
+        exit($code);
+    }
+
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array $context
+     *
+     * @return void
+     */
+    public function emergency($message, array $context = array())
+    {
+        $this->log('emergency', $message, $context);
+    }
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function alert($message, array $context = array())
+    {
+        $this->log('alert', $message, $context);
+    }
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function critical($message, array $context = array())
+    {
+        $this->log('critical', $message, $context);
+    }
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function error($message, array $context = array())
+    {
+        $this->log('error', $message, $context);
+    }
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function warning($message, array $context = array())
+    {
+        $this->log('warning', $message, $context);
+    }
+
+    /**
+     * Normal, positive outcome
+     *
+     * @param string $string
+     * @param array $context
+     */
+    public function success($string, array $context = array())
+    {
+        $this->log('success', $string, $context);
+    }
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function notice($message, array $context = array())
+    {
+        $this->log('notice', $message, $context);
+    }
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function info($message, array $context = array())
+    {
+        $this->log('info', $message, $context);
+    }
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array $context
+     */
+    public function debug($message, array $context = array())
+    {
+        $this->log('debug', $message, $context);
+    }
+
+    /**
+     * @param string $level
+     * @param string $message
+     * @param array $context
+     */
+    public function log($level, $message, array $context = array())
+    {
+        // is this log level wanted?
+        if (!isset($this->loglevel[$level])) return;
+
+        /** @var string $prefix */
+        /** @var string $color */
+        /** @var resource $channel */
+        list($prefix, $color, $channel) = $this->loglevel[$level];
+        if(!$this->colors->isEnabled()) $prefix = '';
+
+        $message = $this->interpolate($message, $context);
+        $this->colors->ptln($prefix . $message, $color, $channel);
+    }
+
+    /**
+     * Interpolates context values into the message placeholders.
+     *
+     * @param $message
+     * @param array $context
+     * @return string
+     */
+    function interpolate($message, array $context = array())
+    {
+        // build a replacement array with braces around the context keys
+        $replace = array();
+        foreach ($context as $key => $val) {
+            // check that the value can be casted to string
+            if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
+                $replace['{' . $key . '}'] = $val;
+            }
+        }
+
+        // interpolate replacement values into the message and return
+        return strtr($message, $replace);
+    }
+
+    // endregion
+}
diff --git a/vendor/splitbrain/php-cli/src/Colors.php b/vendor/splitbrain/php-cli/src/Colors.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae252566e41174fb8eb407d7135aa3a7da144c40
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/Colors.php
@@ -0,0 +1,170 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+/**
+ * Class Colors
+ *
+ * Handles color output on (Linux) terminals
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ */
+class Colors
+{
+    // these constants make IDE autocompletion easier, but color names can also be passed as strings
+    const C_RESET = 'reset';
+    const C_BLACK = 'black';
+    const C_DARKGRAY = 'darkgray';
+    const C_BLUE = 'blue';
+    const C_LIGHTBLUE = 'lightblue';
+    const C_GREEN = 'green';
+    const C_LIGHTGREEN = 'lightgreen';
+    const C_CYAN = 'cyan';
+    const C_LIGHTCYAN = 'lightcyan';
+    const C_RED = 'red';
+    const C_LIGHTRED = 'lightred';
+    const C_PURPLE = 'purple';
+    const C_LIGHTPURPLE = 'lightpurple';
+    const C_BROWN = 'brown';
+    const C_YELLOW = 'yellow';
+    const C_LIGHTGRAY = 'lightgray';
+    const C_WHITE = 'white';
+
+    /** @var array known color names */
+    protected $colors = array(
+        self::C_RESET => "\33[0m",
+        self::C_BLACK => "\33[0;30m",
+        self::C_DARKGRAY => "\33[1;30m",
+        self::C_BLUE => "\33[0;34m",
+        self::C_LIGHTBLUE => "\33[1;34m",
+        self::C_GREEN => "\33[0;32m",
+        self::C_LIGHTGREEN => "\33[1;32m",
+        self::C_CYAN => "\33[0;36m",
+        self::C_LIGHTCYAN => "\33[1;36m",
+        self::C_RED => "\33[0;31m",
+        self::C_LIGHTRED => "\33[1;31m",
+        self::C_PURPLE => "\33[0;35m",
+        self::C_LIGHTPURPLE => "\33[1;35m",
+        self::C_BROWN => "\33[0;33m",
+        self::C_YELLOW => "\33[1;33m",
+        self::C_LIGHTGRAY => "\33[0;37m",
+        self::C_WHITE => "\33[1;37m",
+    );
+
+    /** @var bool should colors be used? */
+    protected $enabled = true;
+
+    /**
+     * Constructor
+     *
+     * Tries to disable colors for non-terminals
+     */
+    public function __construct()
+    {
+        if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) {
+            $this->enabled = false;
+            return;
+        }
+        if (!getenv('TERM')) {
+            $this->enabled = false;
+            return;
+        }
+    }
+
+    /**
+     * enable color output
+     */
+    public function enable()
+    {
+        $this->enabled = true;
+    }
+
+    /**
+     * disable color output
+     */
+    public function disable()
+    {
+        $this->enabled = false;
+    }
+
+    /**
+     * @return bool is color support enabled?
+     */
+    public function isEnabled()
+    {
+        return $this->enabled;
+    }
+
+    /**
+     * Convenience function to print a line in a given color
+     *
+     * @param string   $line    the line to print, a new line is added automatically
+     * @param string   $color   one of the available color names
+     * @param resource $channel file descriptor to write to
+     *
+     * @throws Exception
+     */
+    public function ptln($line, $color, $channel = STDOUT)
+    {
+        $this->set($color);
+        fwrite($channel, rtrim($line) . "\n");
+        $this->reset();
+    }
+
+    /**
+     * Returns the given text wrapped in the appropriate color and reset code
+     *
+     * @param string $text string to wrap
+     * @param string $color one of the available color names
+     * @return string the wrapped string
+     * @throws Exception
+     */
+    public function wrap($text, $color)
+    {
+        return $this->getColorCode($color) . $text . $this->getColorCode('reset');
+    }
+
+    /**
+     * Gets the appropriate terminal code for the given color
+     *
+     * @param string $color one of the available color names
+     * @return string color code
+     * @throws Exception
+     */
+    public function getColorCode($color)
+    {
+        if (!$this->enabled) {
+            return '';
+        }
+        if (!isset($this->colors[$color])) {
+            throw new Exception("No such color $color");
+        }
+
+        return $this->colors[$color];
+    }
+
+    /**
+     * Set the given color for consecutive output
+     *
+     * @param string $color one of the supported color names
+     * @param resource $channel file descriptor to write to
+     * @throws Exception
+     */
+    public function set($color, $channel = STDOUT)
+    {
+        fwrite($channel, $this->getColorCode($color));
+    }
+
+    /**
+     * reset the terminal color
+     *
+     * @param resource $channel file descriptor to write to
+     *
+     * @throws Exception
+     */
+    public function reset($channel = STDOUT)
+    {
+        $this->set('reset', $channel);
+    }
+}
diff --git a/vendor/splitbrain/php-cli/src/Exception.php b/vendor/splitbrain/php-cli/src/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2aa98115e7bd1f29acb92210d3450e8a5596237
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/Exception.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+/**
+ * Class Exception
+ *
+ * The code is used as exit code for the CLI tool. This should probably be extended. Many cases just fall back to the
+ * E_ANY code.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ */
+class Exception extends \Exception
+{
+    const E_ANY = -1; // no error code specified
+    const E_UNKNOWN_OPT = 1; //Unrecognized option
+    const E_OPT_ARG_REQUIRED = 2; //Option requires argument
+    const E_OPT_ARG_DENIED = 3; //Option not allowed argument
+    const E_OPT_ABIGUOUS = 4; //Option abiguous
+    const E_ARG_READ = 5; //Could not read argv
+
+    /**
+     * @param string $message The Exception message to throw.
+     * @param int $code The Exception code
+     * @param \Exception $previous The previous exception used for the exception chaining.
+     */
+    public function __construct($message = "", $code = 0, \Exception $previous = null)
+    {
+        if (!$code) {
+            $code = self::E_ANY;
+        }
+        parent::__construct($message, $code, $previous);
+    }
+}
diff --git a/vendor/splitbrain/php-cli/src/Options.php b/vendor/splitbrain/php-cli/src/Options.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d8b44debe8449801e3cfa4420456a5943448391
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/Options.php
@@ -0,0 +1,470 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+/**
+ * Class Options
+ *
+ * Parses command line options passed to the CLI script. Allows CLI scripts to easily register all accepted options and
+ * commands and even generates a help text from this setup.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ */
+class Options
+{
+    /** @var  array keeps the list of options to parse */
+    protected $setup;
+
+    /** @var  array store parsed options */
+    protected $options = array();
+
+    /** @var string current parsed command if any */
+    protected $command = '';
+
+    /** @var  array passed non-option arguments */
+    protected $args = array();
+
+    /** @var  string the executed script */
+    protected $bin;
+
+    /** @var  Colors for colored help output */
+    protected $colors;
+
+    /**
+     * Constructor
+     *
+     * @param Colors $colors optional configured color object
+     * @throws Exception when arguments can't be read
+     */
+    public function __construct(Colors $colors = null)
+    {
+        if (!is_null($colors)) {
+            $this->colors = $colors;
+        } else {
+            $this->colors = new Colors();
+        }
+
+        $this->setup = array(
+            '' => array(
+                'opts' => array(),
+                'args' => array(),
+                'help' => ''
+            )
+        ); // default command
+
+        $this->args = $this->readPHPArgv();
+        $this->bin = basename(array_shift($this->args));
+
+        $this->options = array();
+    }
+
+    /**
+     * Sets the help text for the tool itself
+     *
+     * @param string $help
+     */
+    public function setHelp($help)
+    {
+        $this->setup['']['help'] = $help;
+    }
+
+    /**
+     * Register the names of arguments for help generation and number checking
+     *
+     * This has to be called in the order arguments are expected
+     *
+     * @param string $arg argument name (just for help)
+     * @param string $help help text
+     * @param bool $required is this a required argument
+     * @param string $command if theses apply to a sub command only
+     * @throws Exception
+     */
+    public function registerArgument($arg, $help, $required = true, $command = '')
+    {
+        if (!isset($this->setup[$command])) {
+            throw new Exception("Command $command not registered");
+        }
+
+        $this->setup[$command]['args'][] = array(
+            'name' => $arg,
+            'help' => $help,
+            'required' => $required
+        );
+    }
+
+    /**
+     * This registers a sub command
+     *
+     * Sub commands have their own options and use their own function (not main()).
+     *
+     * @param string $command
+     * @param string $help
+     * @throws Exception
+     */
+    public function registerCommand($command, $help)
+    {
+        if (isset($this->setup[$command])) {
+            throw new Exception("Command $command already registered");
+        }
+
+        $this->setup[$command] = array(
+            'opts' => array(),
+            'args' => array(),
+            'help' => $help
+        );
+
+    }
+
+    /**
+     * Register an option for option parsing and help generation
+     *
+     * @param string $long multi character option (specified with --)
+     * @param string $help help text for this option
+     * @param string|null $short one character option (specified with -)
+     * @param bool|string $needsarg does this option require an argument? give it a name here
+     * @param string $command what command does this option apply to
+     * @throws Exception
+     */
+    public function registerOption($long, $help, $short = null, $needsarg = false, $command = '')
+    {
+        if (!isset($this->setup[$command])) {
+            throw new Exception("Command $command not registered");
+        }
+
+        $this->setup[$command]['opts'][$long] = array(
+            'needsarg' => $needsarg,
+            'help' => $help,
+            'short' => $short
+        );
+
+        if ($short) {
+            if (strlen($short) > 1) {
+                throw new Exception("Short options should be exactly one ASCII character");
+            }
+
+            $this->setup[$command]['short'][$short] = $long;
+        }
+    }
+
+    /**
+     * Checks the actual number of arguments against the required number
+     *
+     * Throws an exception if arguments are missing.
+     *
+     * This is run from CLI automatically and usually does not need to be called directly
+     *
+     * @throws Exception
+     */
+    public function checkArguments()
+    {
+        $argc = count($this->args);
+
+        $req = 0;
+        foreach ($this->setup[$this->command]['args'] as $arg) {
+            if (!$arg['required']) {
+                break;
+            } // last required arguments seen
+            $req++;
+        }
+
+        if ($req > $argc) {
+            throw new Exception("Not enough arguments", Exception::E_OPT_ARG_REQUIRED);
+        }
+    }
+
+    /**
+     * Parses the given arguments for known options and command
+     *
+     * The given $args array should NOT contain the executed file as first item anymore! The $args
+     * array is stripped from any options and possible command. All found otions can be accessed via the
+     * getOpt() function
+     *
+     * Note that command options will overwrite any global options with the same name
+     *
+     * This is run from CLI automatically and usually does not need to be called directly
+     *
+     * @throws Exception
+     */
+    public function parseOptions()
+    {
+        $non_opts = array();
+
+        $argc = count($this->args);
+        for ($i = 0; $i < $argc; $i++) {
+            $arg = $this->args[$i];
+
+            // The special element '--' means explicit end of options. Treat the rest of the arguments as non-options
+            // and end the loop.
+            if ($arg == '--') {
+                $non_opts = array_merge($non_opts, array_slice($this->args, $i + 1));
+                break;
+            }
+
+            // '-' is stdin - a normal argument
+            if ($arg == '-') {
+                $non_opts = array_merge($non_opts, array_slice($this->args, $i));
+                break;
+            }
+
+            // first non-option
+            if ($arg{0} != '-') {
+                $non_opts = array_merge($non_opts, array_slice($this->args, $i));
+                break;
+            }
+
+            // long option
+            if (strlen($arg) > 1 && $arg{1} == '-') {
+                $arg = explode('=', substr($arg, 2), 2);
+                $opt = array_shift($arg);
+                $val = array_shift($arg);
+
+                if (!isset($this->setup[$this->command]['opts'][$opt])) {
+                    throw new Exception("No such option '$opt'", Exception::E_UNKNOWN_OPT);
+                }
+
+                // argument required?
+                if ($this->setup[$this->command]['opts'][$opt]['needsarg']) {
+                    if (is_null($val) && $i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) {
+                        $val = $this->args[++$i];
+                    }
+                    if (is_null($val)) {
+                        throw new Exception("Option $opt requires an argument",
+                            Exception::E_OPT_ARG_REQUIRED);
+                    }
+                    $this->options[$opt] = $val;
+                } else {
+                    $this->options[$opt] = true;
+                }
+
+                continue;
+            }
+
+            // short option
+            $opt = substr($arg, 1);
+            if (!isset($this->setup[$this->command]['short'][$opt])) {
+                throw new Exception("No such option $arg", Exception::E_UNKNOWN_OPT);
+            } else {
+                $opt = $this->setup[$this->command]['short'][$opt]; // store it under long name
+            }
+
+            // argument required?
+            if ($this->setup[$this->command]['opts'][$opt]['needsarg']) {
+                $val = null;
+                if ($i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) {
+                    $val = $this->args[++$i];
+                }
+                if (is_null($val)) {
+                    throw new Exception("Option $arg requires an argument",
+                        Exception::E_OPT_ARG_REQUIRED);
+                }
+                $this->options[$opt] = $val;
+            } else {
+                $this->options[$opt] = true;
+            }
+        }
+
+        // parsing is now done, update args array
+        $this->args = $non_opts;
+
+        // if not done yet, check if first argument is a command and reexecute argument parsing if it is
+        if (!$this->command && $this->args && isset($this->setup[$this->args[0]])) {
+            // it is a command!
+            $this->command = array_shift($this->args);
+            $this->parseOptions(); // second pass
+        }
+    }
+
+    /**
+     * Get the value of the given option
+     *
+     * Please note that all options are accessed by their long option names regardless of how they were
+     * specified on commandline.
+     *
+     * Can only be used after parseOptions() has been run
+     *
+     * @param mixed $option
+     * @param bool|string $default what to return if the option was not set
+     * @return bool|string|string[]
+     */
+    public function getOpt($option = null, $default = false)
+    {
+        if ($option === null) {
+            return $this->options;
+        }
+
+        if (isset($this->options[$option])) {
+            return $this->options[$option];
+        }
+        return $default;
+    }
+
+    /**
+     * Return the found command if any
+     *
+     * @return string
+     */
+    public function getCmd()
+    {
+        return $this->command;
+    }
+
+    /**
+     * Get all the arguments passed to the script
+     *
+     * This will not contain any recognized options or the script name itself
+     *
+     * @return array
+     */
+    public function getArgs()
+    {
+        return $this->args;
+    }
+
+    /**
+     * Builds a help screen from the available options. You may want to call it from -h or on error
+     *
+     * @return string
+     *
+     * @throws Exception
+     */
+    public function help()
+    {
+        $tf = new TableFormatter($this->colors);
+        $text = '';
+
+        $hascommands = (count($this->setup) > 1);
+        foreach ($this->setup as $command => $config) {
+            $hasopts = (bool)$this->setup[$command]['opts'];
+            $hasargs = (bool)$this->setup[$command]['args'];
+
+            // usage or command syntax line
+            if (!$command) {
+                $text .= $this->colors->wrap('USAGE:', Colors::C_BROWN);
+                $text .= "\n";
+                $text .= '   ' . $this->bin;
+                $mv = 2;
+            } else {
+                $text .= "\n";
+                $text .= $this->colors->wrap('   ' . $command, Colors::C_PURPLE);
+                $mv = 4;
+            }
+
+            if ($hasopts) {
+                $text .= ' ' . $this->colors->wrap('<OPTIONS>', Colors::C_GREEN);
+            }
+
+            if (!$command && $hascommands) {
+                $text .= ' ' . $this->colors->wrap('<COMMAND> ...', Colors::C_PURPLE);
+            }
+
+            foreach ($this->setup[$command]['args'] as $arg) {
+                $out = $this->colors->wrap('<' . $arg['name'] . '>', Colors::C_CYAN);
+
+                if (!$arg['required']) {
+                    $out = '[' . $out . ']';
+                }
+                $text .= ' ' . $out;
+            }
+            $text .= "\n";
+
+            // usage or command intro
+            if ($this->setup[$command]['help']) {
+                $text .= "\n";
+                $text .= $tf->format(
+                    array($mv, '*'),
+                    array('', $this->setup[$command]['help'] . "\n")
+                );
+            }
+
+            // option description
+            if ($hasopts) {
+                if (!$command) {
+                    $text .= "\n";
+                    $text .= $this->colors->wrap('OPTIONS:', Colors::C_BROWN);
+                }
+                $text .= "\n";
+                foreach ($this->setup[$command]['opts'] as $long => $opt) {
+
+                    $name = '';
+                    if ($opt['short']) {
+                        $name .= '-' . $opt['short'];
+                        if ($opt['needsarg']) {
+                            $name .= ' <' . $opt['needsarg'] . '>';
+                        }
+                        $name .= ', ';
+                    }
+                    $name .= "--$long";
+                    if ($opt['needsarg']) {
+                        $name .= ' <' . $opt['needsarg'] . '>';
+                    }
+
+                    $text .= $tf->format(
+                        array($mv, '30%', '*'),
+                        array('', $name, $opt['help']),
+                        array('', 'green', '')
+                    );
+                    $text .= "\n";
+                }
+            }
+
+            // argument description
+            if ($hasargs) {
+                if (!$command) {
+                    $text .= "\n";
+                    $text .= $this->colors->wrap('ARGUMENTS:', Colors::C_BROWN);
+                }
+                $text .= "\n";
+                foreach ($this->setup[$command]['args'] as $arg) {
+                    $name = '<' . $arg['name'] . '>';
+
+                    $text .= $tf->format(
+                        array($mv, '30%', '*'),
+                        array('', $name, $arg['help']),
+                        array('', 'cyan', '')
+                    );
+                }
+            }
+
+            // head line and intro for following command documentation
+            if (!$command && $hascommands) {
+                $text .= "\n";
+                $text .= $this->colors->wrap('COMMANDS:', Colors::C_BROWN);
+                $text .= "\n";
+                $text .= $tf->format(
+                    array($mv, '*'),
+                    array('', 'This tool accepts a command as first parameter as outlined below:')
+                );
+                $text .= "\n";
+            }
+        }
+
+        return $text;
+    }
+
+    /**
+     * Safely read the $argv PHP array across different PHP configurations.
+     * Will take care on register_globals and register_argc_argv ini directives
+     *
+     * @throws Exception
+     * @return array the $argv PHP array or PEAR error if not registered
+     */
+    private function readPHPArgv()
+    {
+        global $argv;
+        if (!is_array($argv)) {
+            if (!@is_array($_SERVER['argv'])) {
+                if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
+                    throw new Exception(
+                        "Could not read cmd args (register_argc_argv=Off?)",
+                        Exception::E_ARG_READ
+                    );
+                }
+                return $GLOBALS['HTTP_SERVER_VARS']['argv'];
+            }
+            return $_SERVER['argv'];
+        }
+        return $argv;
+    }
+}
+
diff --git a/vendor/splitbrain/php-cli/src/PSR3CLI.php b/vendor/splitbrain/php-cli/src/PSR3CLI.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef744f342aa146fe2255c2be2ab9e575f443fd93
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/PSR3CLI.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class PSR3CLI
+ *
+ * The same as CLI, but implements the PSR-3 logger interface
+ */
+abstract class PSR3CLI extends CLI implements LoggerInterface {
+}
\ No newline at end of file
diff --git a/vendor/splitbrain/php-cli/src/TableFormatter.php b/vendor/splitbrain/php-cli/src/TableFormatter.php
new file mode 100644
index 0000000000000000000000000000000000000000..73fd6b36ea9556503fac670d2c41e2b76a5bc201
--- /dev/null
+++ b/vendor/splitbrain/php-cli/src/TableFormatter.php
@@ -0,0 +1,307 @@
+<?php
+
+namespace splitbrain\phpcli;
+
+/**
+ * Class TableFormatter
+ *
+ * Output text in multiple columns
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ */
+class TableFormatter
+{
+    /** @var string border between columns */
+    protected $border = ' ';
+
+    /** @var int the terminal width */
+    protected $max = 74;
+
+    /** @var Colors for coloring output */
+    protected $colors;
+
+    /**
+     * TableFormatter constructor.
+     *
+     * @param Colors|null $colors
+     */
+    public function __construct(Colors $colors = null)
+    {
+        // try to get terminal width
+        $width = 0;
+        if (isset($_SERVER['COLUMNS'])) {
+            // from environment
+            $width = (int)$_SERVER['COLUMNS'];
+        }
+        if (!$width) {
+            // via tput command
+            $width = @exec('tput cols');
+        }
+        if ($width) {
+            $this->max = $width - 1;
+        }
+
+        if ($colors) {
+            $this->colors = $colors;
+        } else {
+            $this->colors = new Colors();
+        }
+    }
+
+    /**
+     * The currently set border (defaults to ' ')
+     *
+     * @return string
+     */
+    public function getBorder()
+    {
+        return $this->border;
+    }
+
+    /**
+     * Set the border. The border is set between each column. Its width is
+     * added to the column widths.
+     *
+     * @param string $border
+     */
+    public function setBorder($border)
+    {
+        $this->border = $border;
+    }
+
+    /**
+     * Width of the terminal in characters
+     *
+     * initially autodetected
+     *
+     * @return int
+     */
+    public function getMaxWidth()
+    {
+        return $this->max;
+    }
+
+    /**
+     * Set the width of the terminal to assume (in characters)
+     *
+     * @param int $max
+     */
+    public function setMaxWidth($max)
+    {
+        $this->max = $max;
+    }
+
+    /**
+     * Takes an array with dynamic column width and calculates the correct width
+     *
+     * Column width can be given as fixed char widths, percentages and a single * width can be given
+     * for taking the remaining available space. When mixing percentages and fixed widths, percentages
+     * refer to the remaining space after allocating the fixed width
+     *
+     * @param array $columns
+     * @return int[]
+     * @throws Exception
+     */
+    protected function calculateColLengths($columns)
+    {
+        $idx = 0;
+        $border = $this->strlen($this->border);
+        $fixed = (count($columns) - 1) * $border; // borders are used already
+        $fluid = -1;
+
+        // first pass for format check and fixed columns
+        foreach ($columns as $idx => $col) {
+            // handle fixed columns
+            if ((string)intval($col) === (string)$col) {
+                $fixed += $col;
+                continue;
+            }
+            // check if other colums are using proper units
+            if (substr($col, -1) == '%') {
+                continue;
+            }
+            if ($col == '*') {
+                // only one fluid
+                if ($fluid < 0) {
+                    $fluid = $idx;
+                    continue;
+                } else {
+                    throw new Exception('Only one fluid column allowed!');
+                }
+            }
+            throw new Exception("unknown column format $col");
+        }
+
+        $alloc = $fixed;
+        $remain = $this->max - $alloc;
+
+        // second pass to handle percentages
+        foreach ($columns as $idx => $col) {
+            if (substr($col, -1) != '%') {
+                continue;
+            }
+            $perc = floatval($col);
+
+            $real = (int)floor(($perc * $remain) / 100);
+
+            $columns[$idx] = $real;
+            $alloc += $real;
+        }
+
+        $remain = $this->max - $alloc;
+        if ($remain < 0) {
+            throw new Exception("Wanted column widths exceed available space");
+        }
+
+        // assign remaining space
+        if ($fluid < 0) {
+            $columns[$idx] += ($remain); // add to last column
+        } else {
+            $columns[$fluid] = $remain;
+        }
+
+        return $columns;
+    }
+
+    /**
+     * Displays text in multiple word wrapped columns
+     *
+     * @param int[] $columns list of column widths (in characters, percent or '*')
+     * @param string[] $texts list of texts for each column
+     * @param array $colors A list of color names to use for each column. use empty string for default
+     * @return string
+     * @throws Exception
+     */
+    public function format($columns, $texts, $colors = array())
+    {
+        $columns = $this->calculateColLengths($columns);
+
+        $wrapped = array();
+        $maxlen = 0;
+
+        foreach ($columns as $col => $width) {
+            $wrapped[$col] = explode("\n", $this->wordwrap($texts[$col], $width, "\n", true));
+            $len = count($wrapped[$col]);
+            if ($len > $maxlen) {
+                $maxlen = $len;
+            }
+
+        }
+
+        $last = count($columns) - 1;
+        $out = '';
+        for ($i = 0; $i < $maxlen; $i++) {
+            foreach ($columns as $col => $width) {
+                if (isset($wrapped[$col][$i])) {
+                    $val = $wrapped[$col][$i];
+                } else {
+                    $val = '';
+                }
+                $chunk = $this->pad($val, $width);
+                if (isset($colors[$col]) && $colors[$col]) {
+                    $chunk = $this->colors->wrap($chunk, $colors[$col]);
+                }
+                $out .= $chunk;
+
+                // border
+                if ($col != $last) {
+                    $out .= $this->border;
+                }
+            }
+            $out .= "\n";
+        }
+        return $out;
+
+    }
+
+    /**
+     * Pad the given string to the correct length
+     *
+     * @param string $string
+     * @param int $len
+     * @return string
+     */
+    protected function pad($string, $len)
+    {
+        $strlen = $this->strlen($string);
+        if ($strlen > $len) return $string;
+
+        $pad = $len - $strlen;
+        return $string . str_pad('', $pad, ' ');
+    }
+
+    /**
+     * Measures char length in UTF-8 when possible
+     *
+     * @param $string
+     * @return int
+     */
+    protected function strlen($string)
+    {
+        // don't count color codes
+        $string = preg_replace("/\33\\[\\d+(;\\d+)?m/", '', $string);
+
+        if (function_exists('mb_strlen')) {
+            return mb_strlen($string, 'utf-8');
+        }
+
+        return strlen($string);
+    }
+
+    /**
+     * @param string $string
+     * @param int $start
+     * @param int|null $length
+     * @return string
+     */
+    protected function substr($string, $start = 0, $length = null)
+    {
+        if (function_exists('mb_substr')) {
+            return mb_substr($string, $start, $length);
+        } else {
+            return substr($string, $start, $length);
+        }
+    }
+
+    /**
+     * @param string $str
+     * @param int $width
+     * @param string $break
+     * @param bool $cut
+     * @return string
+     * @link http://stackoverflow.com/a/4988494
+     */
+    protected function wordwrap($str, $width = 75, $break = "\n", $cut = false)
+    {
+        $lines = explode($break, $str);
+        foreach ($lines as &$line) {
+            $line = rtrim($line);
+            if ($this->strlen($line) <= $width) {
+                continue;
+            }
+            $words = explode(' ', $line);
+            $line = '';
+            $actual = '';
+            foreach ($words as $word) {
+                if ($this->strlen($actual . $word) <= $width) {
+                    $actual .= $word . ' ';
+                } else {
+                    if ($actual != '') {
+                        $line .= rtrim($actual) . $break;
+                    }
+                    $actual = $word;
+                    if ($cut) {
+                        while ($this->strlen($actual) > $width) {
+                            $line .= $this->substr($actual, 0, $width) . $break;
+                            $actual = $this->substr($actual, $width);
+                        }
+                    }
+                    $actual .= ' ';
+                }
+            }
+            $line .= trim($actual);
+        }
+        return implode($break, $lines);
+    }
+}
\ No newline at end of file