]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #1038 from ArthurHoaro/feature/public-only-filter
authorArthurHoaro <arthur@hoa.ro>
Fri, 2 Feb 2018 18:22:37 +0000 (19:22 +0100)
committerGitHub <noreply@github.com>
Fri, 2 Feb 2018 18:22:37 +0000 (19:22 +0100)
Add a filter to only display public links

33 files changed:
.github/mailmap
.travis.yml
AUTHORS
CHANGELOG.md
README.md
application/HttpUtils.php
application/Languages.php
application/LinkUtils.php
application/Url.php
application/config/ConfigPhp.php
composer.json
composer.lock
doc/md/Backup,-restore,-import-and-export.md
doc/md/Bookmarklet.md
doc/md/Browsing-and-searching.md
doc/md/Community-&-Related-software.md
doc/md/Download-and-Installation.md
doc/md/Features.md [deleted file]
doc/md/Firefox-share.md
doc/md/Server-requirements.md
doc/md/docker/shaarli-images.md
doc/md/index.md
docker/alpine/Dockerfile.armhf.latest [new file with mode: 0644]
docker/alpine/Dockerfile.armhf.master [new file with mode: 0644]
index.php
mkdocs.yml
tests/HttpUtils/ServerUrlTest.php
tests/LinkUtilsTest.php
tests/api/controllers/PostLinkTest.php
tests/config/ConfigPhpTest.php
tests/utils/config/emptyConfigPhp.php [new file with mode: 0644]
tpl/default/page.header.html
tpl/default/pluginsadmin.html

index bbdb7908fe9f91cddb04ac090fbd1226a1b7cb95..7633afcf23829481372b4810045db893ec4feaf5 100644 (file)
@@ -1,6 +1,8 @@
 ArthurHoaro <arthur@hoa.ro>
 Florian Eula <eula.florian@gmail.com> feula
 Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
+Immánuel Fodor <immanuelfactor+github@gmail.com>
+kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
 Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm
 Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar>
 Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com>
index 322e4337fbbb2f8a2ba35de3ccba63e93ab09749..758aa9f40f7c738bfe1a6f24d1e24fc7f01b0316 100644 (file)
@@ -5,10 +5,10 @@ cache:
   directories:
     - $HOME/.composer/cache
 php:
+  - 7.2
   - 7.1
   - 7.0
   - 5.6
-  - 5.5
 install:
   - composer self-update
   - composer install --prefer-dist
diff --git a/AUTHORS b/AUTHORS
index 105561c1ef3c303a28063a68dc1bd82a2b95adec..c0414c0e6ec487ebb4396d5bee42b5f7af7ca134 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,6 @@
-   537 ArthurHoaro <arthur@hoa.ro>
-   252 VirtualTam <virtualtam@flibidi.net>
-   148 nodiscc <nodiscc@gmail.com>
+   588 ArthurHoaro <arthur@hoa.ro>
+   283 VirtualTam <virtualtam@flibidi.net>
+   179 nodiscc <nodiscc@gmail.com>
     56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
     15 Florian Eula <eula.florian@gmail.com>
     13 Emilien Klein <emilien@klein.st>
@@ -11,8 +11,9 @@
      5 Lucas Cimon <lucas.cimon@gmail.com>
      4 Alexandre Alapetite <alexandre@alapetite.fr>
      4 David Sferruzza <david.sferruzza@gmail.com>
+     4 Immánuel Fodor <immanuelfactor+github@gmail.com>
+     4 kalvn <kalvnthereal@gmail.com>
      3 Teromene <teromene@teromene.fr>
-     3 kalvn <kalvnthereal@gmail.com>
      2 Chris Kuethe <chris.kuethe@gmail.com>
      2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
      2 Mathieu Chabanon <git@matchab.fr>
      1 BoboTiG <bobotig@gmail.com>
      1 Bronco <bronco@warriordudimanche.net>
      1 D Low <daniellowtw@gmail.com>
+     1 Daniel Jakots <vigdis@chown.me>
      1 Dimtion <zizou.xena@gmail.com>
      1 Fanch <fanch-github@qth.fr>
      1 Felix Bartels <felix@host-consultants.de>
      1 Felix Kästner <github.com-fpunktk@fpunktk.de>
      1 Florian Voigt <flvoigt@me.com>
+     1 Franck Kerbiriou <FranckKe@users.noreply.github.com>
      1 Gary Marigliano <gmarigliano93@gmail.com>
      1 Guillaume Virlet <github@virlet.org>
      1 Jonathan Druart <jonathan.druart@gmail.com>
@@ -41,6 +44,8 @@
      1 Lionel Martin <renarddesmers@gmail.com>
      1 Mark Gerarts <mark.gerarts@gmail.com>
      1 Marsup <marsup@gmail.com>
+     1 Neros <contact@neros.fr>
      1 Sbgodin <Sbgodin@users.noreply.github.com>
      1 TsT <tst2005@gmail.com>
      1 dimtion <zizou.xena@gmail.com>
+     1 durcheinandr <jochen@durcheinandr.de>
index 33feac2096c173645b5c3a400e7d191e16a0edaf..0e737d8cbbc4ef45c51a7d304c65c12c9eff5bec 100644 (file)
@@ -4,6 +4,49 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [v0.10.0](https://github.com/shaarli/Shaarli/releases/tag/v0.10.0) - UNPUBLISHED
+
+## [v0.9.5](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5) - 2018-02-02
+### Fixed
+- Fix a warning happening when `php-intl` is not installed on the system
+- Fix warnings happening when updating from legacy SebSauvage version
+
+## [v0.9.4](https://github.com/shaarli/Shaarli/releases/tag/v0.9.4) - 2018-01-30
+### Added
+- Enable translations: Shaarli is now also available in French. Other language translations are welcome!
+- Add EditorConfig configuration
+- Add favicons for mobile devices
+- Add Alpine Linux arm32v7 Dockerfiles (master, latest)
+
+### Changed
+- Do not write bookmark edition history during file imports (performance)
+- Migrate Docker images (master, latest) to Alpine Linux
+- Improve unitary tests and code coverage
+- Improve thumbnail display
+- Improve theme ergonomics
+- Improve messages if there is no plugin or parameter available in the admin page
+- Increase buffer size for cURL download
+- Force HTTPS if the original port is 443 behind a reverse proxy (workaround)
+- Improve page title retrieval performances
+
+### Removed
+- Remove redirector setting from Configure page
+
+### Fixed
+- Fix broken links in the documentation
+- Enable access to `data/user.css` (Apache 2.2 & 2.4)
+- Don't URL encode description links if parameter `redirector.encode_url` is set to false
+- Fix an issue preventing the Save button to appear for plugin parameters
+
+
+## [v0.9.3](https://github.com/shaarli/Shaarli/releases/tag/v0.9.3) - 2018-01-04
+**XSS vulnerability fixed. Please update.**
+
+## Security
+- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
+  [CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
+
+
 ## [v0.9.2](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2) - 2017-10-07
 
 **Major security issue fixed. Please update.**
@@ -42,6 +85,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 - Fixed reflected XSS vulnerability introduced in v0.9.1, discovered by @chb9 ([CVE-2017-15215](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15215)).
 
+
 ## [v0.9.1](https://github.com/shaarli/Shaarli/releases/tag/v0.9.1) - 2017-08-23
 
 The documentation has been migrated to ReadTheDocs:
@@ -115,7 +159,7 @@ Theming:
     - Introduce a new theme
     - Allow selecting themes/templates from the configuration page
     - New/Edit link form can be submitted using CTRL+Enter in the textarea
-    - Shaarli version is displayed in the footer when logged in 
+    - Shaarli version is displayed in the footer when logged in
 - Add plugin placeholders to Atom/RSS feed templates
 - Add OpenSearch to feed templates
 - Add `campaign_` to the URL cleanup pattern list
@@ -145,7 +189,7 @@ Theming:
 - Improved date time display depending on the locale
 - Partial namespace support for Shaarli classes
 - Shaarli version is now only present in `shaarli_version.php`
-- Human readable maximum file size upload 
+- Human readable maximum file size upload
 
 
 ### Removed
@@ -171,6 +215,13 @@ Theming:
 - Markdown plugin: escape HTML entities by default
 
 
+## [v0.8.5](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5) - 2018-01-04
+**XSS vulnerability fixed. Please update.**
+
+## Security
+- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
+  [CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
+
 ## [v0.8.4](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4) - 2017-03-04
 ### Security
 - Markdown plugin: escape HTML entities by default
@@ -186,7 +237,7 @@ Theming:
 
 ## [v0.8.1](https://github.com/shaarli/Shaarli/releases/tag/v0.8.1) - 2016-12-12
 
-> Note: this version will create an automatic backup of your database if anything goes wrong. 
+> Note: this version will create an automatic backup of your database if anything goes wrong.
 
 ### Added
 - Add CHANGELOG.md to track the whole project's history
@@ -203,7 +254,7 @@ Theming:
 - Link ID complete refactoring:
     - Links now have a numeric ID instead of dates
     - Short URLs are now created once and can't change over time (previous URL are kept)
-- Templates: 
+- Templates:
     - Changed placeholder behaviour for: `buttons_toolbar`, `fields_toolbar` and `action_plugin`
     - Cleanup `{loop}` declarations in templates
     - Tools: hide Firefox Social button when not in HTTPS
@@ -221,7 +272,7 @@ Theming:
 - Plugins:
     - Tools: only display parameter description when it exists
     - archive.org: do not propose archival of private notes
-    - Markdown: 
+    - Markdown:
         - render links properly in code blocks
         - bug regarding the `nomarkdown` tag
     - W3C compliance
@@ -360,7 +411,7 @@ Please use our release archives, or follow the
 ### Fixed
 - Fix a bug where renaming a tag was causing a 404
 - Fix a bug allowing to search blank terms
-- Fix a bug preventing to remove a tag with special chars when searching 
+- Fix a bug preventing to remove a tag with special chars when searching
 
 
 ## [v0.6.2](https://github.com/shaarli/Shaarli/releases/tag/v0.6.2) - 2015-12-23
@@ -666,7 +717,7 @@ Initial release on GitHub.
 - When you click the key to see only private links, it turns yellow
 
 ### Changed
-- The "Daily" page now automatically skips empty days. 
+- The "Daily" page now automatically skips empty days.
 
 ### Fixed
 - Corrected the tag encoding (there was a bug when selecting a second tag which contains accented characters)
@@ -964,7 +1015,7 @@ Initial release on GitHub.
 - Nicer timezone selection patch by killruana
 
 ### Fixed
-- New lines now appear correctly in the RSS feed descriptions. 
+- New lines now appear correctly in the RSS feed descriptions.
 
 
 ## [v0.0.17beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
@@ -1018,7 +1069,7 @@ Initial release on GitHub.
 ## [v0.0.14beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
 ### Added
 - You no longer need to disable `magic_quotes` on your host.
-  Shaarli will cope with this option beeing activated. 
+  Shaarli will cope with this option beeing activated.
 
 
 ## [v0.0.13beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
index c10500274477551047071a1e76b25aee689e06b9..da324abc6e4774f4b5b9d42ecfb139cc2bc20714 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,13 +6,13 @@ _Do you want to share the links you discover?_
 _Shaarli is a minimalist link sharing service that you can install on your own server._
 _It is designed to be personal (single-user), fast and handy._
 
-[![](https://img.shields.io/badge/stable-v0.8.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4)
+[![](https://img.shields.io/badge/stable-v0.8.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5)
 [![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/latest-v0.9.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2)
+[![](https://img.shields.io/badge/latest-v0.9.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5)
 [![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/master-v0.9.x-blue.svg)](https://github.com/shaarli/Shaarli)
+[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
 [![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
 
 [![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
index ec54dcd4faa78a92bd3fb6533b7c4f9a6b608776..83a4c5e28699eff2472e4b7c132cef1e8bc53e8b 100644 (file)
@@ -3,9 +3,11 @@
  * GET an HTTP URL to retrieve its content
  * Uses the cURL library or a fallback method 
  *
- * @param string $url      URL to get (http://...)
- * @param int    $timeout  network timeout (in seconds)
- * @param int    $maxBytes maximum downloaded bytes (default: 4 MiB)
+ * @param string          $url               URL to get (http://...)
+ * @param int             $timeout           network timeout (in seconds)
+ * @param int             $maxBytes          maximum downloaded bytes (default: 4 MiB)
+ * @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
+ *                                           Can be used to add download conditions on the headers (response code, content type, etc.).
  *
  * @return array HTTP response headers, downloaded content
  *
@@ -29,7 +31,7 @@
  * @see http://stackoverflow.com/q/9183178
  * @see http://stackoverflow.com/q/1462720
  */
-function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
+function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteFunction = null)
 {
     $urlObj = new Url($url);
     $cleanUrl = $urlObj->idnToAscii();
@@ -75,6 +77,10 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
     curl_setopt($ch, CURLOPT_TIMEOUT,           $timeout);
     curl_setopt($ch, CURLOPT_USERAGENT,         $userAgent);
 
+    if (is_callable($curlWriteFunction)) {
+        curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction);
+    }
+
     // Max download size management
     curl_setopt($ch, CURLOPT_BUFFERSIZE,        1024*16);
     curl_setopt($ch, CURLOPT_NOPROGRESS,        false);
@@ -302,6 +308,13 @@ function server_url($server)
                 $port = $server['HTTP_X_FORWARDED_PORT'];
             }
 
+            // This is a workaround for proxies that don't forward the scheme properly.
+            // Connecting over port 443 has to be in HTTPS.
+            // See https://github.com/shaarli/Shaarli/issues/1022
+            if ($port == '443') {
+                $scheme = 'https';
+            }
+
             if (($scheme == 'http' && $port != '80')
                 || ($scheme == 'https' && $port != '443')
             ) {
index 357c7524ed458a128148522b124dd17876faac87..3eb3388f48f6a01ac87c872c408018c9c574cdec 100644 (file)
@@ -69,6 +69,8 @@ class Languages
     {
         $this->conf = $conf;
         $confLanguage = $this->conf->get('translation.language', 'auto');
+        // Auto mode or invalid parameter, use the detected language.
+        // If the detected language is invalid, it doesn't matter, it will use English.
         if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
             $this->language = substr($language, 0, 5);
         } else {
index e3d95d0860d872dd371173a3b45eecf5c558f4f3..3705f7e919c4a1ea021830d65565639a6694df1f 100644 (file)
@@ -1,60 +1,81 @@
 <?php
 
 /**
- * Extract title from an HTML document.
+ * Get cURL callback function for CURLOPT_WRITEFUNCTION
  *
- * @param string $html HTML content where to look for a title.
+ * @param string $charset     to extract from the downloaded page (reference)
+ * @param string $title       to extract from the downloaded page (reference)
+ * @param string $curlGetInfo Optionnaly overrides curl_getinfo function
  *
- * @return bool|string Extracted title if found, false otherwise.
+ * @return Closure
  */
-function html_extract_title($html)
+function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_getinfo')
 {
-    if (preg_match('!<title.*?>(.*?)</title>!is', $html, $matches)) {
-        return trim(str_replace("\n", '', $matches[1]));
-    }
-    return false;
+    /**
+     * cURL callback function for CURLOPT_WRITEFUNCTION (called during the download).
+     *
+     * While downloading the remote page, we check that the HTTP code is 200 and content type is 'html/text'
+     * Then we extract the title and the charset and stop the download when it's done.
+     *
+     * @param resource $ch   cURL resource
+     * @param string   $data chunk of data being downloaded
+     *
+     * @return int|bool length of $data or false if we need to stop the download
+     */
+    return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title) {
+        $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
+        if (!empty($responseCode) && $responseCode != 200) {
+            return false;
+        }
+        $contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE);
+        if (!empty($contentType) && strpos($contentType, 'text/html') === false) {
+            return false;
+        }
+        if (empty($charset)) {
+            $charset = header_extract_charset($contentType);
+        }
+        if (empty($charset)) {
+            $charset = html_extract_charset($data);
+        }
+        if (empty($title)) {
+            $title = html_extract_title($data);
+        }
+        // We got everything we want, stop the download.
+        if (!empty($responseCode) && !empty($contentType) && !empty($charset) && !empty($title)) {
+            return false;
+        }
+
+        return strlen($data);
+    };
 }
 
 /**
- * Determine charset from downloaded page.
- * Priority:
- *   1. HTTP headers (Content type).
- *   2. HTML content page (tag <meta charset>).
- *   3. Use a default charset (default: UTF-8).
+ * Extract title from an HTML document.
  *
- * @param array  $headers           HTTP headers array.
- * @param string $htmlContent       HTML content where to look for charset.
- * @param string $defaultCharset    Default charset to apply if other methods failed.
+ * @param string $html HTML content where to look for a title.
  *
- * @return string Determined charset.
+ * @return bool|string Extracted title if found, false otherwise.
  */
-function get_charset($headers, $htmlContent, $defaultCharset = 'utf-8')
+function html_extract_title($html)
 {
-    if ($charset = headers_extract_charset($headers)) {
-        return $charset;
-    }
-
-    if ($charset = html_extract_charset($htmlContent)) {
-        return $charset;
+    if (preg_match('!<title.*?>(.*?)</title>!is', $html, $matches)) {
+        return trim(str_replace("\n", '', $matches[1]));
     }
-
-    return $defaultCharset;
+    return false;
 }
 
 /**
- * Extract charset from HTTP headers if it's defined.
+ * Extract charset from HTTP header if it's defined.
  *
- * @param array $headers HTTP headers array.
+ * @param string $header HTTP header Content-Type line.
  *
  * @return bool|string Charset string if found (lowercase), false otherwise.
  */
-function headers_extract_charset($headers)
+function header_extract_charset($header)
 {
-    if (! empty($headers['Content-Type']) && strpos($headers['Content-Type'], 'charset=') !== false) {
-        preg_match('/charset="?([^; ]+)/i', $headers['Content-Type'], $match);
-        if (! empty($match[1])) {
-            return strtolower(trim($match[1]));
-        }
+    preg_match('/charset="?([^; ]+)/i', $header, $match);
+    if (! empty($match[1])) {
+        return strtolower(trim($match[1]));
     }
 
     return false;
index b37593773b920c26d3a9e5332d197dc17fb44449..21c17eccaa25644c72134795570cff816e2dad8d 100644 (file)
@@ -260,7 +260,7 @@ class Url
         if (! function_exists('idn_to_ascii') || ! isset($this->parts['host'])) {
             return $out;
         }
-        $asciiHost = idn_to_ascii($this->parts['host']);
+        $asciiHost = idn_to_ascii($this->parts['host'], 0, INTL_IDNA_VARIANT_UTS46);
         return str_replace($this->parts['host'], $asciiHost, $out);
     }
 
index 2f66e8e00ac18a537db96d77e2bf66e175c87c29..8add8bcd776009e1cff804f3b8f47e5417ff4c6f 100644 (file)
@@ -83,10 +83,10 @@ class ConfigPhp implements ConfigIO
 
         $out = array();
         foreach (self::$ROOT_KEYS as $key) {
-            $out[$key] = $GLOBALS[$key];
+            $out[$key] = isset($GLOBALS[$key]) ? $GLOBALS[$key] : '';
         }
-        $out['config'] = $GLOBALS['config'];
-        $out['plugins'] = !empty($GLOBALS['plugins']) ? $GLOBALS['plugins'] : array();
+        $out['config'] = isset($GLOBALS['config']) ? $GLOBALS['config'] : [];
+        $out['plugins'] = isset($GLOBALS['plugins']) ? $GLOBALS['plugins'] : [];
         return $out;
     }
 
index f331d6caf265174a86c537a303b2b38f95fe2d6b..bbef28af84e406b25ce9f75ebc02513471820e9f 100644 (file)
     "keywords": ["bookmark", "link", "share", "web"],
     "config": {
         "platform": {
-            "php": "5.5.38"
+            "php": "5.6.31"
         }
     },
     "require": {
-        "php": ">=5.5",
+        "php": ">=5.6",
         "shaarli/netscape-bookmark-parser": "^2.0",
         "erusev/parsedown": "1.6",
         "slim/slim": "^3.0",
@@ -24,7 +24,7 @@
     },
     "require-dev": {
         "phpmd/phpmd" : "@stable",
-        "phpunit/phpunit": "4.8.*",
+        "phpunit/phpunit": "^5.0",
         "sebastian/phpcpd": "*",
         "squizlabs/php_codesniffer": "2.*",
         "phpunit/phpcov": "*"
index 39909b8fd2347813c39b2db6b60f9e9a1aabedaa..0a3fbd831f8ccb410e1d922290293e05f34326d0 100644 (file)
@@ -4,7 +4,7 @@
         "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": "13b7e1e474fe9264b098ba86face0feb",
+    "content-hash": "bc39afd7f6d37c76509f96bea69f6131",
     "packages": [
         {
             "name": "container-interop/container-interop",
         },
         {
             "name": "pimple/pimple",
-            "version": "v3.2.2",
+            "version": "v3.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/silexphp/Pimple.git",
-                "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a"
+                "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/silexphp/Pimple/zipball/4d45fb62d96418396ec58ba76e6f065bca16e10a",
-                "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a",
+                "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
+                "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32",
                 "shasum": ""
             },
             "require": {
                 "container",
                 "dependency injection"
             ],
-            "time": "2017-07-23T07:32:15+00:00"
+            "time": "2018-01-21T07:42:36+00:00"
         },
         {
             "name": "psr/container",
         },
         {
             "name": "shaarli/netscape-bookmark-parser",
-            "version": "v2.0.4",
+            "version": "v2.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/shaarli/netscape-bookmark-parser.git",
-                "reference": "81023979c981514f5dda5582e9c0be2ed6688a6b"
+                "reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/81023979c981514f5dda5582e9c0be2ed6688a6b",
-                "reference": "81023979c981514f5dda5582e9c0be2ed6688a6b",
+                "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/ea6911a0ea3dd372fa7002593c5aef9c15a49315",
+                "reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315",
                 "shasum": ""
             },
             "require": {
                 "netscape",
                 "parse"
             ],
-            "time": "2017-07-30T21:08:03+00:00"
+            "time": "2018-01-30T17:34:48+00:00"
         },
         {
             "name": "slim/slim",
-            "version": "3.8.1",
+            "version": "3.9.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim.git",
-                "reference": "5385302707530b2bccee1769613ad769859b826d"
+                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d",
-                "reference": "5385302707530b2bccee1769613ad769859b826d",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
+                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
                 "shasum": ""
             },
             "require": {
                 "micro",
                 "router"
             ],
-            "time": "2017-03-19T17:55:20+00:00"
+            "time": "2017-11-26T19:13:09+00:00"
         }
     ],
     "packages-dev": [
             ],
             "time": "2015-06-14T21:17:01+00:00"
         },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "doctrine/collections": "^1.0",
+                "doctrine/common": "^2.6",
+                "phpunit/phpunit": "^4.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                },
+                "files": [
+                    "src/DeepCopy/deep_copy.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "time": "2017-10-19T19:58:43+00:00"
+        },
         {
             "name": "pdepend/pdepend",
-            "version": "2.5.0",
+            "version": "2.5.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/pdepend/pdepend.git",
-                "reference": "0c50874333149c0dad5a2877801aed148f2767ff"
+                "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/pdepend/pdepend/zipball/0c50874333149c0dad5a2877801aed148f2767ff",
-                "reference": "0c50874333149c0dad5a2877801aed148f2767ff",
+                "url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
+                "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.7",
-                "symfony/config": "^2.3.0|^3",
-                "symfony/dependency-injection": "^2.3.0|^3",
-                "symfony/filesystem": "^2.3.0|^3"
+                "symfony/config": "^2.3.0|^3|^4",
+                "symfony/dependency-injection": "^2.3.0|^3|^4",
+                "symfony/filesystem": "^2.3.0|^3|^4"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.4.0,<4.8",
+                "phpunit/phpunit": "^4.8|^5.7",
                 "squizlabs/php_codesniffer": "^2.0.0"
             },
             "bin": [
                 "BSD-3-Clause"
             ],
             "description": "Official version of pdepend to be handled with Composer",
-            "time": "2017-01-19T14:23:36+00:00"
+            "time": "2017-12-13T13:21:38+00:00"
         },
         {
             "name": "phpdocumentor/reflection-common",
         },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "3.2.2",
+            "version": "3.3.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157"
+                "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157",
-                "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2",
+                "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.5",
-                "phpdocumentor/reflection-common": "^1.0@dev",
-                "phpdocumentor/type-resolver": "^0.3.0",
+                "php": "^5.6 || ^7.0",
+                "phpdocumentor/reflection-common": "^1.0.0",
+                "phpdocumentor/type-resolver": "^0.4.0",
                 "webmozart/assert": "^1.0"
             },
             "require-dev": {
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2017-08-08T06:39:58+00:00"
+            "time": "2017-11-10T14:09:06+00:00"
         },
         {
             "name": "phpdocumentor/type-resolver",
-            "version": "0.3.0",
+            "version": "0.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773"
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773",
-                "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
                 "shasum": ""
             },
             "require": {
                     "email": "me@mikevanriel.com"
                 }
             ],
-            "time": "2017-06-03T08:32:36+00:00"
+            "time": "2017-07-14T14:27:02+00:00"
         },
         {
             "name": "phpmd/phpmd",
         },
         {
             "name": "phpspec/prophecy",
-            "version": "v1.7.2",
+            "version": "1.7.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6"
+                "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
-                "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
+                "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "phpspec/phpspec": "^2.5|^3.2",
-                "phpunit/phpunit": "^4.8 || ^5.6.5"
+                "phpunit/phpunit": "^4.8.35 || ^5.7"
             },
             "type": "library",
             "extra": {
                 "spy",
                 "stub"
             ],
-            "time": "2017-09-04T11:05:03+00:00"
+            "time": "2017-11-24T13:59:53+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "2.2.4",
+            "version": "4.0.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+                "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
+                "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
                 "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"
+                "ext-dom": "*",
+                "ext-xmlwriter": "*",
+                "php": "^5.6 || ^7.0",
+                "phpunit/php-file-iterator": "^1.3",
+                "phpunit/php-text-template": "^1.2",
+                "phpunit/php-token-stream": "^1.4.2 || ^2.0",
+                "sebastian/code-unit-reverse-lookup": "^1.0",
+                "sebastian/environment": "^1.3.2 || ^2.0",
+                "sebastian/version": "^1.0 || ^2.0"
             },
             "require-dev": {
-                "ext-xdebug": ">=2.1.4",
-                "phpunit/phpunit": "~4"
+                "ext-xdebug": "^2.1.4",
+                "phpunit/phpunit": "^5.7"
             },
             "suggest": {
-                "ext-dom": "*",
-                "ext-xdebug": ">=2.2.1",
-                "ext-xmlwriter": "*"
+                "ext-xdebug": "^2.5.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2.x-dev"
+                    "dev-master": "4.0.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2015-10-06T15:47:00+00:00"
+            "time": "2017-04-02T07:44:40+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
-            "version": "1.4.2",
+            "version": "1.4.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
                 "shasum": ""
             },
             "require": {
                 "filesystem",
                 "iterator"
             ],
-            "time": "2016-10-03T07:40:28+00:00"
+            "time": "2017-11-27T13:52:08+00:00"
         },
         {
             "name": "phpunit/php-text-template",
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "1.4.11",
+            "version": "1.4.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
+                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
-                "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
+                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
                 "shasum": ""
             },
             "require": {
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2017-02-27T10:12:30+00:00"
+            "time": "2017-12-04T08:55:13+00:00"
         },
         {
             "name": "phpunit/phpcov",
-            "version": "2.0.2",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpcov.git",
-                "reference": "9ef291483ff65eefd8639584d61bbfb044d747f3"
+                "reference": "2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpcov/zipball/9ef291483ff65eefd8639584d61bbfb044d747f3",
-                "reference": "9ef291483ff65eefd8639584d61bbfb044d747f3",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpcov/zipball/2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d",
+                "reference": "2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "phpunit/php-code-coverage": "~2.0",
-                "phpunit/phpunit": ">=4.1",
-                "sebastian/diff": "~1.1",
-                "sebastian/finder-facade": "~1.1",
-                "sebastian/version": "~1.0",
-                "symfony/console": "~2.2"
+                "php": "^5.6 || ^7.0",
+                "phpunit/php-code-coverage": "^4.0",
+                "phpunit/phpunit": "^5.0",
+                "sebastian/diff": "^1.1",
+                "sebastian/finder-facade": "^1.1",
+                "sebastian/version": "^1.0|^2.0",
+                "symfony/console": "^2|^3"
             },
             "bin": [
                 "phpcov"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0.x-dev"
+                    "dev-master": "3.1.x-dev"
                 }
             },
             "autoload": {
             ],
             "description": "CLI frontend for PHP_CodeCoverage",
             "homepage": "https://github.com/sebastianbergmann/phpcov",
-            "time": "2015-10-05T09:24:23+00:00"
+            "time": "2016-06-03T07:01:55+00:00"
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.8.36",
+            "version": "5.7.27",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
+                "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
-                "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
+                "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
                 "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",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "myclabs/deep-copy": "~1.3",
+                "php": "^5.6 || ^7.0",
+                "phpspec/prophecy": "^1.6.2",
+                "phpunit/php-code-coverage": "^4.0.4",
                 "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.2.2",
-                "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"
+                "phpunit/phpunit-mock-objects": "^3.2",
+                "sebastian/comparator": "^1.2.4",
+                "sebastian/diff": "^1.4.3",
+                "sebastian/environment": "^1.3.4 || ^2.0",
+                "sebastian/exporter": "~2.0",
+                "sebastian/global-state": "^1.1",
+                "sebastian/object-enumerator": "~2.0",
+                "sebastian/resource-operations": "~1.0",
+                "sebastian/version": "^1.0.6|^2.0.1",
+                "symfony/yaml": "~2.1|~3.0|~4.0"
+            },
+            "conflict": {
+                "phpdocumentor/reflection-docblock": "3.0.2"
+            },
+            "require-dev": {
+                "ext-pdo": "*"
             },
             "suggest": {
+                "ext-xdebug": "*",
                 "phpunit/php-invoker": "~1.1"
             },
             "bin": [
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.8.x-dev"
+                    "dev-master": "5.7.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2017-06-21T08:07:12+00:00"
+            "time": "2018-02-01T05:50:59+00:00"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
-            "version": "2.3.8",
+            "version": "3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+                "reference": "a23b761686d50a560cc56233b9ecf49597cc9118"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118",
+                "reference": "a23b761686d50a560cc56233b9ecf49597cc9118",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
-                "php": ">=5.3.3",
-                "phpunit/php-text-template": "~1.2",
-                "sebastian/exporter": "~1.2"
+                "php": "^5.6 || ^7.0",
+                "phpunit/php-text-template": "^1.2",
+                "sebastian/exporter": "^1.2 || ^2.0"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<5.4.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^5.4"
             },
             "suggest": {
                 "ext-soap": "*"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.3.x-dev"
+                    "dev-master": "3.2.x-dev"
                 }
             },
             "autoload": {
                 "mock",
                 "xunit"
             ],
-            "time": "2015-10-02T06:51:40+00:00"
+            "time": "2017-06-30T09:13:00+00:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7 || ^6.0"
+            },
+            "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": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "time": "2017-03-04T06:30:41+00:00"
         },
         {
             "name": "sebastian/comparator",
         },
         {
             "name": "sebastian/environment",
-            "version": "1.3.8",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
+                "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
+                "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0"
+                "php": "^5.6 || ^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8 || ^5.0"
+                "phpunit/phpunit": "^5.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
                 "environment",
                 "hhvm"
             ],
-            "time": "2016-08-18T05:49:44+00:00"
+            "time": "2016-11-26T07:53:53+00:00"
         },
         {
             "name": "sebastian/exporter",
-            "version": "1.2.2",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
+                "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
+                "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3",
-                "sebastian/recursion-context": "~1.0"
+                "sebastian/recursion-context": "~2.0"
             },
             "require-dev": {
                 "ext-mbstring": "*",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
                 "export",
                 "exporter"
             ],
-            "time": "2016-06-17T09:04:28+00:00"
+            "time": "2016-11-19T08:54:04+00:00"
         },
         {
             "name": "sebastian/finder-facade",
-            "version": "1.2.1",
+            "version": "1.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/finder-facade.git",
-                "reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9"
+                "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9",
-                "reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9",
+                "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
+                "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
                 "shasum": ""
             },
             "require": {
-                "symfony/finder": "~2.3|~3.0",
+                "symfony/finder": "~2.3|~3.0|~4.0",
                 "theseer/fdomdocument": "~1.3"
             },
             "type": "library",
             ],
             "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
             "homepage": "https://github.com/sebastianbergmann/finder-facade",
-            "time": "2016-02-17T07:02:23+00:00"
+            "time": "2017-11-18T17:31:49+00:00"
         },
         {
             "name": "sebastian/global-state",
             ],
             "time": "2015-10-12T03:26:01+00:00"
         },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
+                "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6",
+                "sebastian/recursion-context": "~2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "time": "2017-02-18T15:18:39+00:00"
+        },
         {
             "name": "sebastian/phpcpd",
-            "version": "2.0.4",
+            "version": "3.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpcpd.git",
-                "reference": "24d9a880deadb0b8c9680e9cfe78e30b704225db"
+                "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/24d9a880deadb0b8c9680e9cfe78e30b704225db",
-                "reference": "24d9a880deadb0b8c9680e9cfe78e30b704225db",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564",
+                "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "phpunit/php-timer": ">=1.0.6",
-                "sebastian/finder-facade": "~1.1",
-                "sebastian/version": "~1.0|~2.0",
-                "symfony/console": "~2.7|^3.0",
-                "theseer/fdomdocument": "~1.4"
+                "php": "^5.6|^7.0",
+                "phpunit/php-timer": "^1.0.6",
+                "sebastian/finder-facade": "^1.1",
+                "sebastian/version": "^1.0|^2.0",
+                "symfony/console": "^2.7|^3.0|^4.0"
             },
             "bin": [
                 "phpcpd"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-master": "3.0-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Copy/Paste Detector (CPD) for PHP code.",
             "homepage": "https://github.com/sebastianbergmann/phpcpd",
-            "time": "2016-04-17T19:32:49+00:00"
+            "time": "2017-11-16T08:49:28+00:00"
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "1.0.5",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
+                "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
-                "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
+                "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Provides functionality to recursively process PHP variables",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2016-10-03T07:41:43+00:00"
+            "time": "2016-11-19T07:33:16+00:00"
+        },
+        {
+            "name": "sebastian/resource-operations",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/resource-operations.git",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6.0"
+            },
+            "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": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides a list of PHP built-in functions that operate on resources",
+            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "time": "2015-07-28T20:34:47+00:00"
         },
         {
             "name": "sebastian/version",
-            "version": "1.0.6",
+            "version": "2.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
                 "shasum": ""
             },
+            "require": {
+                "php": ">=5.6"
+            },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
             "autoload": {
                 "classmap": [
                     "src/"
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21T13:59:46+00:00"
+            "time": "2016-10-03T07:35:21+00:00"
         },
         {
             "name": "squizlabs/php_codesniffer",
         },
         {
             "name": "symfony/config",
-            "version": "v3.3.10",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd"
+                "reference": "72689b934d6c6ecf73eca874e98933bf055313c9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
-                "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
+                "url": "https://api.github.com/repos/symfony/config/zipball/72689b934d6c6ecf73eca874e98933bf055313c9",
+                "reference": "72689b934d6c6ecf73eca874e98933bf055313c9",
                 "shasum": ""
             },
             "require": {
                 "php": "^5.5.9|>=7.0.8",
-                "symfony/filesystem": "~2.8|~3.0"
+                "symfony/filesystem": "~2.8|~3.0|~4.0"
             },
             "conflict": {
                 "symfony/dependency-injection": "<3.3",
                 "symfony/finder": "<3.3"
             },
             "require-dev": {
-                "symfony/dependency-injection": "~3.3",
-                "symfony/finder": "~3.3",
-                "symfony/yaml": "~3.0"
+                "symfony/dependency-injection": "~3.3|~4.0",
+                "symfony/finder": "~3.3|~4.0",
+                "symfony/yaml": "~3.0|~4.0"
             },
             "suggest": {
                 "symfony/yaml": "To use the yaml reference dumper"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-04T18:56:58+00:00"
+            "time": "2018-01-21T19:05:02+00:00"
         },
         {
             "name": "symfony/console",
-            "version": "v2.8.28",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853"
+                "reference": "26b6f419edda16c19775211987651cb27baea7f1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
-                "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
+                "url": "https://api.github.com/repos/symfony/console/zipball/26b6f419edda16c19775211987651cb27baea7f1",
+                "reference": "26b6f419edda16c19775211987651cb27baea7f1",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
-                "symfony/debug": "^2.7.2|~3.0.0",
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/debug": "~2.8|~3.0|~4.0",
                 "symfony/polyfill-mbstring": "~1.0"
             },
+            "conflict": {
+                "symfony/dependency-injection": "<3.4",
+                "symfony/process": "<3.3"
+            },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/event-dispatcher": "~2.1|~3.0.0",
-                "symfony/process": "~2.1|~3.0.0"
+                "symfony/config": "~3.3|~4.0",
+                "symfony/dependency-injection": "~3.4|~4.0",
+                "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
+                "symfony/lock": "~3.4|~4.0",
+                "symfony/process": "~3.3|~4.0"
             },
             "suggest": {
                 "psr/log": "For using the console logger",
                 "symfony/event-dispatcher": "",
+                "symfony/lock": "",
                 "symfony/process": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-01T21:00:16+00:00"
+            "time": "2018-01-29T09:03:43+00:00"
         },
         {
             "name": "symfony/debug",
-            "version": "v3.0.9",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
-                "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a"
+                "reference": "53f6af2805daf52a43b393b93d2f24925d35c937"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a",
-                "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/53f6af2805daf52a43b393b93d2f24925d35c937",
+                "reference": "53f6af2805daf52a43b393b93d2f24925d35c937",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.5.9",
+                "php": "^5.5.9|>=7.0.8",
                 "psr/log": "~1.0"
             },
             "conflict": {
                 "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
             },
             "require-dev": {
-                "symfony/class-loader": "~2.8|~3.0",
-                "symfony/http-kernel": "~2.8|~3.0"
+                "symfony/http-kernel": "~2.8|~3.0|~4.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Debug Component",
             "homepage": "https://symfony.com",
-            "time": "2016-07-30T07:22:48+00:00"
+            "time": "2018-01-18T22:16:57+00:00"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v3.3.10",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1"
+                "reference": "4b2717ee2499390e371e1fc7abaf886c1c83e83d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1",
-                "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4b2717ee2499390e371e1fc7abaf886c1c83e83d",
+                "reference": "4b2717ee2499390e371e1fc7abaf886c1c83e83d",
                 "shasum": ""
             },
             "require": {
                 "psr/container": "^1.0"
             },
             "conflict": {
-                "symfony/config": "<3.3.1",
+                "symfony/config": "<3.3.7",
                 "symfony/finder": "<3.3",
-                "symfony/yaml": "<3.3"
+                "symfony/proxy-manager-bridge": "<3.4",
+                "symfony/yaml": "<3.4"
             },
             "provide": {
                 "psr/container-implementation": "1.0"
             },
             "require-dev": {
-                "symfony/config": "~3.3",
-                "symfony/expression-language": "~2.8|~3.0",
-                "symfony/yaml": "~3.3"
+                "symfony/config": "~3.3|~4.0",
+                "symfony/expression-language": "~2.8|~3.0|~4.0",
+                "symfony/yaml": "~3.4|~4.0"
             },
             "suggest": {
                 "symfony/config": "",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-04T17:15:30+00:00"
+            "time": "2018-01-29T09:16:57+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v3.3.10",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1"
+                "reference": "e078773ad6354af38169faf31c21df0f18ace03d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1",
-                "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/e078773ad6354af38169faf31c21df0f18ace03d",
+                "reference": "e078773ad6354af38169faf31c21df0f18ace03d",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-03T13:33:10+00:00"
+            "time": "2018-01-03T07:37:34+00:00"
         },
         {
             "name": "symfony/finder",
-            "version": "v3.3.10",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "773e19a491d97926f236942484cb541560ce862d"
+                "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d",
-                "reference": "773e19a491d97926f236942484cb541560ce862d",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/613e26310776f49a1773b6737c6bd554b8bc8c6f",
+                "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-01-03T07:37:34+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.6.0",
+            "version": "v1.7.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.6-dev"
+                    "dev-master": "1.7-dev"
                 }
             },
             "autoload": {
                 "portable",
                 "shim"
             ],
-            "time": "2017-10-11T12:05:26+00:00"
+            "time": "2018-01-30T19:27:44+00:00"
         },
         {
             "name": "symfony/yaml",
-            "version": "v3.3.10",
+            "version": "v3.4.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46"
+                "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
-                "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/eab73b6c21d27ae4cd037c417618dfd4befb0bfe",
+                "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe",
                 "shasum": ""
             },
             "require": {
                 "php": "^5.5.9|>=7.0.8"
             },
+            "conflict": {
+                "symfony/console": "<3.4"
+            },
             "require-dev": {
-                "symfony/console": "~2.8|~3.0"
+                "symfony/console": "~3.4|~4.0"
             },
             "suggest": {
                 "symfony/console": "For validating YAML files using the lint command"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-05T14:43:42+00:00"
+            "time": "2018-01-21T19:05:02+00:00"
         },
         {
             "name": "theseer/fdomdocument",
         },
         {
             "name": "webmozart/assert",
-            "version": "1.2.0",
+            "version": "1.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
                 "shasum": ""
             },
             "require": {
                 "check",
                 "validate"
             ],
-            "time": "2016-11-23T20:04:58+00:00"
+            "time": "2018-01-29T19:49:41+00:00"
         }
     ],
     "aliases": [],
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": ">=5.5"
+        "php": ">=5.6"
     },
     "platform-dev": [],
     "platform-overrides": {
-        "php": "5.5.38"
+        "php": "5.6.31"
     }
 }
index 897248576b678c95f45e4021e4c250f6697897a9..bb790074c9973dfe45a9c8b9e0a1d3c29aa628fa 100644 (file)
@@ -45,6 +45,10 @@ Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/s
 However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli)
 tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer.
 
+### Refind
+
+You can use the third-party tool [Derefind](https://github.com/ShawnPConroy/Derefind) to convert refind.com bookmark exports to a format that can be imported into Shaarli.
+
 ## Import Shaarli links to Firefox
 
 - Export your Shaarli links as described above.
index e53e3261980fa7b86d082d22b255e1ea295291f6..c899e3cf6a8fc41c340a119d2b361774b1b8531a 100644 (file)
@@ -21,7 +21,7 @@ _This bookmarklet button is compatible with Firefox, Opera, Chrome and Safari. U
 
 Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunatly, there is nothing Shaarli can do about it.
 
-See [#196](https://github.com/shaarli/Shaarli#196).
+See [#196](https://github.com/shaarli/Shaarli/issues/196).
 
 There is an open bug for both Firefox and Chromium:
 
index 35707482a5399677a254335dcf371897af8b38bd..16c69855cd9e4c92d876947f881e1dc02097f3f7 100644 (file)
@@ -14,10 +14,24 @@ Use the `Filter by tags` field to restrict displayed links to entries tagged wit
 
 **Hidden tags:** Tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in.
 
-Alternatively you can use the `Tag cloud` to discover all tags and click on any of them to display related links.
+### Tag cloud
 
-To search for links that are not tagged, enter `""` in the tag search field.
+The `Tag cloud` page diplays a "cloud" view of all tags in your Shaarli.
+
+ * The most frequently used tags are displayed with a bigger font size.
+ * When sorting by `Most used` or `Alphabetical`, tags are displayed as a _list_, along with counters and edit/delete buttons for each tag.
+ * Clicking on any tag will display a list of all Shaares matching this tag.
+ * Clicking on the counter next to a tag `example`, will filter the tag cloud to only display tags found in Shaares tagged `example`. Repeat this any number of times to further filter the tag cloud. Click `List all links with those tags` to display Shaares matching your current tag filter.
 
 ## Filtering RSS feeds/Picture wall
 
-RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS feeds).
+RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS-feeds).
+
+## Filter buttons
+
+Filter buttons can be found at the top left of the link list. They allow you to apply different filters to the list:
+
+ * **Private links:** When this toggle button is enabled, only shaares set to `private` will be shown.
+ * **Untagged links:** When the this toggle button is enabled (top left of the link list), only shaares _without any tags_ will be shown in the link list.
+Filter buttons are only available when logged in.
index 2b7c65992e97698d486045c97888baa3cbce4846..207153b61eb075621a100f8ffc3b5e44b73008ee 100644 (file)
@@ -1,23 +1,7 @@
 _Unofficial but related work on Shaarli. If you maintain one of these,
 please get in touch with us to help us find a way to adapt your work to our fork._
 
-## Community
-- [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
-- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
-- [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
-- [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)
-- [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_
-- [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)
-- [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)
-- [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
-- [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
-
-
-### Articles and social media discussions
-- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
-- 2015-08-15 - Reddit - [Question about migrating from WordPress to Shaarli.](https://www.reddit.com/r/selfhosted/comments/3h3zwh/question_about_migrating_from_wordpress_to_shaarli/)
-- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
-- 2015-05-12 - Reddit - [shaarli - Self hosted Bookmarking / Delicious (PHP, MySQL)](https://www.reddit.com/r/selfhosted/comments/35pkkc/shaarli_self_hosted_bookmarking_delicious_php/)
+## Related software
 
 
 ### REST API clients
@@ -29,29 +13,34 @@ See [REST API](REST-API) for a list of official and community clients.
 - [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
 - [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
 - [emojione](https://github.com/NerosTie/emojione) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli.
+- [twemoji](https://github.com/NerosTie/twemoji) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli (Twemoji version) 
 - [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support
 - [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli.
+- [markdown-toolbar](https://github.com/immanuelfodor/shaarli-markdown-toolbar) by [@immanuelfodor](https://github.com/immanuelfodor) - Easily insert markdown syntax into the Description field when editing a link.
 - [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags.
 - [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
 - [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli
 - [shaarli2mastodon](https://github.com/kalvn/shaarli2mastodon) by [@kalvn](https://github.com/kalvn) - This Shaarli plugin allows you to automatically publish links you post on your Mastodon timeline.
+- [shaarli-descriptor](https://github.com/immanuelfodor/shaarli-descriptor) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the default height/number of rows of the Description field when editing a link.
 
 
 ### Third-party themes
 See [Theming](Theming) for a list of community-contributed themes, and an installation guide.
 
 
-## Integration with other platforms 
+### Integration with other platforms 
 - [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [Tiny-Tiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli
 - [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar
 - [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle
 
 
 ### Mobile Apps
-- [ShaarliOS](https://github.com/mro/ShaarliOS) iOS share extension - see [#308](https://github.com/shaarli/Shaarli/issues/308#issuecomment-184592070) for some promo codes,
+- [ShaarliOS](https://github.com/mro/ShaarliOS) - Apple iOS share extension.
 - [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
 - [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
 
+### Browser addons
+ * [Shaarli Web Extension](https://github.com/ikipatang/shaarli-web-extension) - toolbar button to share your current tab with Shaarli.
 
 ### Server apps
 - [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
@@ -62,7 +51,22 @@ See [Theming](Theming) for a list of community-contributed themes, and an instal
 - [Self dead link](https://github.com/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. [Another version](https://github.com/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for other shaarli instances (but is more resource consuming).
 - [Bookmark Archiver](https://github.com/pirate/bookmark-archiver) - Save an archived copy of all websites starred using browser bookmarks/Shaarli/Delicious/Instapaper/Unmark.it/Pocket/Pinboard. Outputs browseable html. 
 
-
 ## Alternatives to Shaarli
-See the [bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing)
-section on [awesome-selfhosted](https://github.com/Kickball/awesome-selfhosted/).
+See [awesome-selfhosted: bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing).
+
+## Community
+- [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
+- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
+- [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
+- [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)
+- [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_
+- [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)
+- [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)
+- [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
+- [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
+
+### Articles and social media discussions
+- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
+- 2015-08-15 - Reddit - [Question about migrating from WordPress to Shaarli.](https://www.reddit.com/r/selfhosted/comments/3h3zwh/question_about_migrating_from_wordpress_to_shaarli/)
+- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
+- 2015-05-12 - Reddit - [shaarli - Self hosted Bookmarking / Delicious (PHP, MySQL)](https://www.reddit.com/r/selfhosted/comments/35pkkc/shaarli_self_hosted_bookmarking_delicious_php/)
index e64d1a43e25b55c4d53e64579e625335eb02b2b4..0fdbd27de59ab5b184b3c9812cb1479d6ab40e76 100644 (file)
@@ -15,7 +15,7 @@ Using one of the following methods:
 - by downloading full release archives including all dependencies
 - by downloading Github archives
 - by cloning the Git repository
-- using Docker: [see the documentation](docker/shaarli-images)
+- using Docker: [see the documentation](docker/shaarli-images.md)
 
 --------------------------------------------------------------------------------
 
@@ -25,11 +25,11 @@ Using one of the following methods:
 
 In most cases, you should download the latest Shaarli release from the [releases](https://github.com/shaarli/Shaarli/releases) page. **Download our *shaarli-full* archive** to include dependencies.
 
-The current latest released version is `v0.9.1`
+The current latest released version is `v0.9.3`
 
 ```bash
-$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.1/shaarli-v0.9.1-full.zip
-$ unzip shaarli-v0.9.1-full.zip
+$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.3/shaarli-v0.9.3-full.zip
+$ unzip shaarli-v0.9.3-full.zip
 $ mv Shaarli /path/to/shaarli/
 ```
 
@@ -96,7 +96,7 @@ Install [Composer](Unit-tests.md#install_composer) to manage Shaarli dependencie
 To get the latest changes from the `master` branch:
 
 ```bash
-# clone the repository  
+# clone the repository
 $ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/
 # install/update third-party dependencies
 $ cd /path/to/shaarli
diff --git a/doc/md/Features.md b/doc/md/Features.md
deleted file mode 100644 (file)
index eef88d0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-### Main features
-Shaarli is intended:
-
-- to share, comment and save interesting links and news
-- to bookmark useful/frequent personal links (as private links) and share them between computers
-- as a minimal blog/microblog/writing platform (no character limit)
-- as a read-it-later list (for example items tagged `readlater`)
-- to draft and save articles/ideas
-- to keep code snippets
-- to keep notes and documentation
-- as a shared clipboard between machines
-- as a todo list
-- to store playlists (e.g. with the `music` or `video` tags)
-- to keep extracts/comments from webpages that may disappear
-- to keep track of ongoing discussions (for example items tagged `discussion`)
-- [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags
-- to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)
-
-### Using Shaarli as a blog, notepad, pastebin...
-
-- Go to your Shaarli setup and log in
-- Click the `Add Link` button
-- To share text only, do not enter any URL in the corresponding input field and click `Add Link`
-- Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
-- Voilà!  Your article is now published (privately if you selected that option) and accessible using its permalink.
index 878884a497e9bc67879576db27ff0216cd2a24ba..9a46b1854c401dc736fba9495ea12b214a79c08d 100644 (file)
@@ -1,3 +1,6 @@
+| Note | Firefox Share is no longer available for Firefox 57 and later versions. |
+|---------|---------|
+
 ### Add Shaarli as a sharing service to Firefox
 
 - Open your Shaarli and `Login`
index 400b85a9ed28d90e2da596abea24e03aacf9d5b7..2dc442df27240eae55974dd99befb11746666359 100644 (file)
@@ -35,7 +35,7 @@ Library | Required? | Usage
 Extension | Required? | Usage
 ---|:---:|---
 [`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS
-[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows | multibyte (Unicode) string support
+[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support
 [`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing
 [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
 [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
index 1d19510af8e2cee09bf1e1a720e70881bf803f1f..12f7b5d1ffaf8672acd7b0e5c58f45c44f5132ca 100644 (file)
@@ -1,3 +1,6 @@
+A brief guide on getting starting using docker is given in [Docker 101](docker-101.md).
+To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](../Upgrade-and-migration.md).
+
 ## Get and run a Shaarli image
 
 ### DockerHub repository
@@ -21,6 +24,7 @@ The `stable` image relies on:
 - [PHP5-FPM](http://php-fpm.org/)
 - [Nginx](http://nginx.org/)
 
+Additional [Dockerfiles](https://github.com/shaarli/Shaarli/tree/master/docker) are provided for the `arm32v7` platform, relying on [Linuxserver.io Alpine armhf images](https://hub.docker.com/r/lsiobase/alpine.armhf/). These images must be built using [`docker build`](https://docs.docker.com/engine/reference/commandline/build/) on an `arm32v7` machine or using an emulator such as [qemu](https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/).
 
 ### Download from DockerHub
 ```bash
@@ -78,3 +82,14 @@ backstabbing_galileo
 $ docker ps -a
 CONTAINER ID  IMAGE            COMMAND               CREATED         STATUS        PORTS                 NAMES
 ```
+
+### Automatic builds
+
+Docker users can start a personal instance from an [autobuild image](https://hub.docker.com/r/shaarli/shaarli/). For example to start a temporary Shaarli at ``localhost:8000``, and keep session data (config, storage):
+```
+MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
+docker run -ti --rm \
+         -p 8000:80 \
+         -v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
+         shaarli/shaarli
+```
index 2b7d0f0070de616c3de1f48d0250ef62b451b67f..e77b4d3a18c59468663fbfbc0c783fb677222f03 100644 (file)
@@ -22,20 +22,25 @@ It runs the latest development version of Shaarli and is updated/reset daily.
 
 Login: `demo`; Password: `demo`
 
-Docker users can start a personal instance from an [autobuild image](https://hub.docker.com/r/shaarli/shaarli/). For example to start a temporary Shaarli at ``localhost:8000``, and keep session data (config, storage):
-```
-MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
-docker run -ti --rm \
-         -p 8000:80 \
-         -v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
-         shaarli/shaarli
-```
-
-A brief guide on getting starting using docker is given in [Docker 101](docker/docker-101).
-To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](Upgrade-and-migration) documentation.
-
 ## Features
 
+Shaarli can be used:
+
+- to share, comment and save interesting links and news.
+- to bookmark useful/frequent personal links (as private links) and share them between computers.
+- as a minimal blog/microblog/writing platform (no character limit).
+- as a read-it-later list (for example items tagged `readlater`).
+- to draft and save articles/posts/ideas.
+- to keep code snippets.
+- to keep notes and documentation.
+- as a shared clipboard/notepad/pastebin between machines.
+- as a todo list.
+- to store playlists (e.g. with the `music` or `video` tags).
+- to keep extracts/comments from webpages that may disappear.
+- to keep track of ongoing discussions (for example items tagged `discussion`).
+- [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags.
+- to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...).
+
 ### Interface
 - minimalist design (simple is beautiful)
 - FAST
@@ -89,14 +94,12 @@ Easily extensible by any client using the REST API exposed by Shaarli.
 
 See the [API documentation](http://shaarli.github.io/api-documentation/).
 
-### Other usages
-Though Shaarli is primarily a bookmarking application, it can serve other purposes
-(see [Features](Features)):
-
-- micro-blogging
-- pastebin
-- online notepad
-- snippet archive
+### Using Shaarli as a blog, notepad, pastebin...
+- Go to your Shaarli setup and log in
+- Click the `Add Link` button
+- To share text only, do not enter any URL in the corresponding input field and click `Add Link`
+- Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
+- Voilà!  Your article is now published (privately if you selected that option) and accessible using its permalink.
 
 ## About
 ### Shaarli community fork
diff --git a/docker/alpine/Dockerfile.armhf.latest b/docker/alpine/Dockerfile.armhf.latest
new file mode 100644 (file)
index 0000000..c923834
--- /dev/null
@@ -0,0 +1,47 @@
+FROM lsiobase/alpine.armhf:3.6
+MAINTAINER Shaarli Community
+
+RUN apk --update --no-cache add \
+        ca-certificates \
+        curl \
+        nginx \
+        php7 \
+        php7-ctype \
+        php7-curl \
+        php7-fpm \
+        php7-gd \
+        php7-iconv \
+        php7-intl \
+        php7-json \
+        php7-mbstring \
+        php7-openssl \
+        php7-phar \
+        php7-session \
+        php7-xml \
+        php7-zlib \
+        s6
+
+COPY nginx.conf /etc/nginx/nginx.conf
+COPY php-fpm.conf /etc/php7/php-fpm.conf
+COPY services.d /etc/services.d
+
+RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
+    && rm -rf /etc/php7/php-fpm.d/www.conf \
+    && sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
+    && sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
+
+
+WORKDIR /var/www
+RUN curl -L https://github.com/shaarli/Shaarli/archive/latest.tar.gz | tar xzf - \
+    && mv Shaarli-latest shaarli \
+    && cd shaarli \
+    && composer --prefer-dist --no-dev install \
+    && rm -rf ~/.composer \
+    && chown -R nginx:nginx .
+
+VOLUME /var/www/shaarli/data
+
+EXPOSE 80
+
+ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
+CMD []
diff --git a/docker/alpine/Dockerfile.armhf.master b/docker/alpine/Dockerfile.armhf.master
new file mode 100644 (file)
index 0000000..7f1bdf8
--- /dev/null
@@ -0,0 +1,47 @@
+FROM lsiobase/alpine.armhf:3.6
+MAINTAINER Shaarli Community
+
+RUN apk --update --no-cache add \
+        ca-certificates \
+        curl \
+        nginx \
+        php7 \
+        php7-ctype \
+        php7-curl \
+        php7-fpm \
+        php7-gd \
+        php7-iconv \
+        php7-intl \
+        php7-json \
+        php7-mbstring \
+        php7-openssl \
+        php7-phar \
+        php7-session \
+        php7-xml \
+        php7-zlib \
+        s6
+
+COPY nginx.conf /etc/nginx/nginx.conf
+COPY php-fpm.conf /etc/php7/php-fpm.conf
+COPY services.d /etc/services.d
+
+RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
+    && rm -rf /etc/php7/php-fpm.d/www.conf \
+    && sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
+    && sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
+
+
+WORKDIR /var/www
+RUN curl -L https://github.com/shaarli/Shaarli/archive/master.tar.gz | tar xzf - \
+    && mv Shaarli-master shaarli \
+    && cd shaarli \
+    && composer --prefer-dist --no-dev install \
+    && rm -rf ~/.composer \
+    && chown -R nginx:nginx .
+
+VOLUME /var/www/shaarli/data
+
+EXPOSE 80
+
+ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
+CMD []
index 8770b6694c184ffe5e6e974caa3152571a1803a8..c2aaf84a14959590279bb07d809459141e49c7e5 100644 (file)
--- a/index.php
+++ b/index.php
@@ -124,6 +124,11 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli']))
 $conf = new ConfigManager();
 $sessionManager = new SessionManager($_SESSION, $conf);
 
+// LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead.
+if (! defined('LC_MESSAGES')) {
+    define('LC_MESSAGES', LC_COLLATE);
+}
+
 // Sniff browser language and set date format accordingly.
 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
     autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
@@ -436,7 +441,7 @@ if (isset($_POST['login']))
     else
     {
         ban_loginFailed($conf);
-        $redir = '&username='. $_POST['login'];
+        $redir = '&username='. urlencode($_POST['login']);
         if (isset($_GET['post'])) {
             $redir .= '&post=' . urlencode($_GET['post']);
             foreach (array('description', 'source', 'title', 'tags') as $param) {
@@ -1436,16 +1441,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager)
             // If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
             if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) {
                 // Short timeout to keep the application responsive
-                list($headers, $content) = get_http_response($url, 4);
-                if (strpos($headers[0], '200 OK') !== false) {
-                    // Retrieve charset.
-                    $charset = get_charset($headers, $content);
-                    // Extract title.
-                    $title = html_extract_title($content);
-                    // Re-encode title in utf-8 if necessary.
-                    if (! empty($title) && strtolower($charset) != 'utf-8') {
-                        $title = mb_convert_encoding($title, 'utf-8', $charset);
-                    }
+                // The callback will fill $charset and $title with data from the downloaded page.
+                get_http_response($url, 25, 4194304, get_curl_download_callback($charset, $title));
+                if (! empty($title) && strtolower($charset) != 'utf-8') {
+                    $title = mb_convert_encoding($title, 'utf-8', $charset);
                 }
             }
 
index 8617ea4515d5bbaff888dc1dd1ae525cac854fd4..443c3a08d4059e0dc0c10757da49290d6bed3a89 100644 (file)
@@ -22,16 +22,15 @@ pages:
     - Reverse proxy configuration: docker/reverse-proxy-configuration.md
     - Docker resources: docker/resources.md
 - Usage:
-    - Features: Features.md
     - Bookmarklet: Bookmarklet.md
     - Browsing and searching: Browsing-and-searching.md
     - Firefox share: Firefox-share.md
     - RSS feeds: RSS-feeds.md 
     - REST API: REST-API.md
+    - Community & Related software: Community-&-Related-software.md
 - How To:
     - Backup, restore, import and export: Backup,-restore,-import-and-export.md
     - Various hacks: Various-hacks.md
-- Troubleshooting: Troubleshooting.md
 - Development:
     - Development guidelines: Development-guidelines.md
     - Continuous integration tools: Continuous-integration-tools.md
@@ -47,6 +46,5 @@ pages:
     - Theming: Theming.md
     - Unit tests: Unit-tests.md
     - Unit tests inside Docker: Unit-tests-Docker.md
-- About:
-    - FAQ: FAQ.md
-    - Community & Related software: Community-&-Related-software.md
+- FAQ: FAQ.md
+- Troubleshooting: Troubleshooting.md
index dac02b3e77cab58cdf05a57fbecfa3cabae1247b..324b827acc11e9612c933fa89893dfd318f523a3 100644 (file)
@@ -186,4 +186,36 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
             )
         );
     }
+
+    /**
+     * Misconfigured server (see #1022): Proxy HTTP but 443
+     */
+    public function testHttpWithPort433()
+    {
+        $this->assertEquals(
+            'https://host.tld',
+            server_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'HTTP_X_FORWARDED_PROTO' => 'http',
+                    'HTTP_X_FORWARDED_PORT' => '443'
+                )
+            )
+        );
+
+        $this->assertEquals(
+            'https://host.tld',
+            server_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'HTTP_X_FORWARDED_PROTO' => 'https, http',
+                    'HTTP_X_FORWARDED_PORT' => '443, 80'
+                )
+            )
+        );
+    }
 }
index 99679320ae3ea696762abea4d127ac6b8e5dde84..7fbd59b0b80489d7b9e3521664e8aeb7d204b19d 100644 (file)
@@ -28,28 +28,14 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
         $this->assertFalse(html_extract_title($html));
     }
 
-    /**
-     * Test get_charset() with all priorities.
-     */
-    public function testGetCharset()
-    {
-        $headers = array('Content-Type' => 'text/html; charset=Headers');
-        $html = '<html><meta>stuff</meta><meta charset="Html"/></html>';
-        $default = 'default';
-        $this->assertEquals('headers', get_charset($headers, $html, $default));
-        $this->assertEquals('html', get_charset(array(), $html, $default));
-        $this->assertEquals($default, get_charset(array(), '', $default));
-        $this->assertEquals('utf-8', get_charset(array(), ''));
-    }
-
     /**
      * Test headers_extract_charset() when the charset is found.
      */
     public function testHeadersExtractExistentCharset()
     {
         $charset = 'x-MacCroatian';
-        $headers = array('Content-Type' => 'text/html; charset='. $charset);
-        $this->assertEquals(strtolower($charset), headers_extract_charset($headers));
+        $headers = 'text/html; charset='. $charset;
+        $this->assertEquals(strtolower($charset), header_extract_charset($headers));
     }
 
     /**
@@ -57,11 +43,11 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
      */
     public function testHeadersExtractNonExistentCharset()
     {
-        $headers = array();
-        $this->assertFalse(headers_extract_charset($headers));
+        $headers = '';
+        $this->assertFalse(header_extract_charset($headers));
 
-        $headers = array('Content-Type' => 'text/html');
-        $this->assertFalse(headers_extract_charset($headers));
+        $headers = 'text/html';
+        $this->assertFalse(header_extract_charset($headers));
     }
 
     /**
@@ -85,6 +71,131 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
         $this->assertFalse(html_extract_charset($html));
     }
 
+    /**
+     * Test the download callback with valid value
+     */
+    public function testCurlDownloadCallbackOk()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
+        $data = [
+            'HTTP/1.1 200 OK',
+            'Server: GitHub.com',
+            'Date: Sat, 28 Oct 2017 12:01:33 GMT',
+            'Content-Type: text/html; charset=utf-8',
+            'Status: 200 OK',
+            'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
+            '<title>ignored</title>',
+        ];
+        foreach ($data as $key => $line) {
+            $ignore = null;
+            $expected = $key !== 'end' ? strlen($line) : false;
+            $this->assertEquals($expected, $callback($ignore, $line));
+            if ($expected === false) {
+                break;
+            }
+        }
+        $this->assertEquals('utf-8', $charset);
+        $this->assertEquals('Refactoring · GitHub', $title);
+    }
+
+    /**
+     * Test the download callback with valid values and no charset
+     */
+    public function testCurlDownloadCallbackOkNoCharset()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
+        $data = [
+            'HTTP/1.1 200 OK',
+            'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
+            '<title>ignored</title>',
+        ];
+        foreach ($data as $key => $line) {
+            $ignore = null;
+            $this->assertEquals(strlen($line), $callback($ignore, $line));
+        }
+        $this->assertEmpty($charset);
+        $this->assertEquals('Refactoring · GitHub', $title);
+    }
+
+    /**
+     * Test the download callback with valid values and no charset
+     */
+    public function testCurlDownloadCallbackOkHtmlCharset()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
+        $data = [
+            'HTTP/1.1 200 OK',
+            '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
+            'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
+            '<title>ignored</title>',
+        ];
+        foreach ($data as $key => $line) {
+            $ignore = null;
+            $expected = $key !== 'end' ? strlen($line) : false;
+            $this->assertEquals($expected, $callback($ignore, $line));
+            if ($expected === false) {
+                break;
+            }
+        }
+        $this->assertEquals('utf-8', $charset);
+        $this->assertEquals('Refactoring · GitHub', $title);
+    }
+
+    /**
+     * Test the download callback with valid values and no title
+     */
+    public function testCurlDownloadCallbackOkNoTitle()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
+        $data = [
+            'HTTP/1.1 200 OK',
+            'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
+            'ignored',
+        ];
+        foreach ($data as $key => $line) {
+            $ignore = null;
+            $this->assertEquals(strlen($line), $callback($ignore, $line));
+        }
+        $this->assertEquals('utf-8', $charset);
+        $this->assertEmpty($title);
+    }
+
+    /**
+     * Test the download callback with an invalid content type.
+     */
+    public function testCurlDownloadCallbackInvalidContentType()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
+        $ignore = null;
+        $this->assertFalse($callback($ignore, ''));
+        $this->assertEmpty($charset);
+        $this->assertEmpty($title);
+    }
+
+    /**
+     * Test the download callback with an invalid response code.
+     */
+    public function testCurlDownloadCallbackInvalidResponseCode()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
+        $ignore = null;
+        $this->assertFalse($callback($ignore, ''));
+        $this->assertEmpty($charset);
+        $this->assertEmpty($title);
+    }
+
+    /**
+     * Test the download callback with an invalid content type and response code.
+     */
+    public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
+    {
+        $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
+        $ignore = null;
+        $this->assertFalse($callback($ignore, ''));
+        $this->assertEmpty($charset);
+        $this->assertEmpty($title);
+    }
+
     /**
      * Test count_private.
      */
@@ -207,3 +318,96 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
         return str_replace('$1', $hashtag, $hashtagLink);
     }
 }
+
+// old style mock: PHPUnit doesn't allow function mock
+
+/**
+ * Returns code 200 or html content type.
+ *
+ * @param resource $ch   cURL resource
+ * @param int      $type cURL info type
+ *
+ * @return int|string 200 or 'text/html'
+ */
+function ut_curl_getinfo_ok($ch, $type)
+{
+    switch ($type) {
+        case CURLINFO_RESPONSE_CODE:
+            return 200;
+        case CURLINFO_CONTENT_TYPE:
+            return 'text/html; charset=utf-8';
+    }
+}
+
+/**
+ * Returns code 200 or html content type without charset.
+ *
+ * @param resource $ch   cURL resource
+ * @param int      $type cURL info type
+ *
+ * @return int|string 200 or 'text/html'
+ */
+function ut_curl_getinfo_no_charset($ch, $type)
+{
+    switch ($type) {
+        case CURLINFO_RESPONSE_CODE:
+            return 200;
+        case CURLINFO_CONTENT_TYPE:
+            return 'text/html';
+    }
+}
+
+/**
+ * Invalid response code.
+ *
+ * @param resource $ch   cURL resource
+ * @param int      $type cURL info type
+ *
+ * @return int|string 404 or 'text/html'
+ */
+function ut_curl_getinfo_rc_ko($ch, $type)
+{
+    switch ($type) {
+        case CURLINFO_RESPONSE_CODE:
+            return 404;
+        case CURLINFO_CONTENT_TYPE:
+            return 'text/html; charset=utf-8';
+    }
+}
+
+/**
+ * Invalid content type.
+ *
+ * @param resource $ch   cURL resource
+ * @param int      $type cURL info type
+ *
+ * @return int|string 200 or 'text/plain'
+ */
+function ut_curl_getinfo_ct_ko($ch, $type)
+{
+    switch ($type) {
+        case CURLINFO_RESPONSE_CODE:
+            return 200;
+        case CURLINFO_CONTENT_TYPE:
+            return 'text/plain';
+    }
+}
+
+/**
+ * Invalid response code and content type.
+ *
+ * @param resource $ch   cURL resource
+ * @param int      $type cURL info type
+ *
+ * @return int|string 404 or 'text/plain'
+ */
+function ut_curl_getinfo_rs_ct_ko($ch, $type)
+{
+    switch ($type) {
+        case CURLINFO_RESPONSE_CODE:
+            return 404;
+        case CURLINFO_CONTENT_TYPE:
+            return 'text/plain';
+    }
+}
+
index 31954e396d2d95b56b24bb08f7fe1876ce83ed21..100a91704f866e383430cf2e690522302ba20957 100644 (file)
@@ -3,11 +3,13 @@
 namespace Shaarli\Api\Controllers;
 
 
+use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Slim\Container;
 use Slim\Http\Environment;
 use Slim\Http\Request;
 use Slim\Http\Response;
+use Slim\Router;
 
 /**
  * Class PostLinkTest
@@ -16,7 +18,7 @@ use Slim\Http\Response;
  *
  * @package Shaarli\Api\Controllers
  */
-class PostLinkTest extends \PHPUnit_Framework_TestCase
+class PostLinkTest extends TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -78,7 +80,7 @@ class PostLinkTest extends \PHPUnit_Framework_TestCase
 
         $this->controller = new Links($this->container);
 
-        $mock = $this->getMock('\Slim\Router', ['relativePathFor']);
+        $mock = $this->createMock(Router::class);
         $mock->expects($this->any())
              ->method('relativePathFor')
              ->willReturn('api/v1/links/1');
index abfbb30538f7f27b06468a3be6887a0ebe1f3de1..be23eea1563a909ecce1a981d1194040d8d9fe3a 100644 (file)
@@ -36,6 +36,20 @@ class ConfigPhpTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals(array(), $this->configIO->read('nope'));
     }
 
+    /**
+     * Read an empty existent config file -> array with blank default values.
+     */
+    public function testReadEmpty()
+    {
+        $dataFile = 'tests/utils/config/emptyConfigPhp.php';
+        $conf = $this->configIO->read($dataFile);
+        $this->assertEmpty($conf['login']);
+        $this->assertEmpty($conf['title']);
+        $this->assertEmpty($conf['titleLink']);
+        $this->assertEmpty($conf['config']);
+        $this->assertEmpty($conf['plugins']);
+    }
+
     /**
      * Write a new config file.
      */
diff --git a/tests/utils/config/emptyConfigPhp.php b/tests/utils/config/emptyConfigPhp.php
new file mode 100644 (file)
index 0000000..b3d9bbc
--- /dev/null
@@ -0,0 +1 @@
+<?php
index 2411703c7e7925aa3106ef7510cf26a1888d6b0c..6f15c1c5adfd5ee4a2cb5e83306fd9c6b470b165 100644 (file)
@@ -1,7 +1,7 @@
 <div class="shaarli-menu pure-g" id="shaarli-menu">
   <div class="pure-u-lg-0 pure-u-1">
     <div class="pure-menu">
-      <a href="{$titleLink}" class="pure-menu-link">
+      <a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
         <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
         {$shaarlititle}
       </a>
     <div class="pure-menu menu-transform pure-menu-horizontal pure-g">
       <ul class="pure-menu-list pure-u-lg-5-6 pure-u-1">
         <li class="pure-menu-item pure-u-0 pure-u-lg-visible">
-          <a href="{$titleLink}" class="pure-menu-link">
+          <a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-desktop">
             <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
             {$shaarlititle}
           </a>
         </li>
         {if="isLoggedIn() || $openshaarli"}
           <li class="pure-menu-item">
-            <a href="?do=addlink" class="pure-menu-link">
+            <a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
               <i class="fa fa-plus" ></i> {'Shaare'|t}
             </a>
           </li>
-          <li class="pure-menu-item">
+          <li class="pure-menu-item" id="shaarli-menu-tools">
             <a href="?do=tools" class="pure-menu-link">{'Tools'|t}</a>
           </li>
         {/if}
-        <li class="pure-menu-item">
+        <li class="pure-menu-item" id="shaarli-menu-tags">
           <a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a>
         </li>
-        <li class="pure-menu-item">
+        <li class="pure-menu-item" id="shaarli-menu-picwall">
           <a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
         </li>
-        <li class="pure-menu-item">
+        <li class="pure-menu-item" id="shaarli-menu-daily">
           <a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a>
         </li>
         {loop="$plugins_header.buttons_toolbar"}
-          <li class="pure-menu-item">
+          <li class="pure-menu-item shaarli-menu-plugin">
             <a
               {$value.attr.class=isset($value.class) ? $value.attr.class . ' pure-menu-link' : 'pure-menu-link'}
               {loop="$value.attr"}
             </a>
           </li>
         {/loop}
-        <li class="pure-menu-item pure-u-lg-0">
+        <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-rss">
             <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a>
         </li>
         {if="isLoggedIn()"}
-          <li class="pure-menu-item pure-u-lg-0">
+          <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout">
             <a href="?do=logout" class="pure-menu-link">{'Logout'|t}</a>
           </li>
         {else}
-          <li class="pure-menu-item pure-u-lg-0">
+          <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login">
             <a href="?do=login" class="pure-menu-link">{'Login'|t}</a>
           </li>
         {/if}
       </ul>
       <div class="header-buttons pure-u-lg-1-6 pure-u-0 pure-u-lg-visible">
         <ul class="pure-menu-list">
-          <li class="pure-menu-item">
+          <li class="pure-menu-item" id="shaarli-menu-desktop-search">
             <a href="#" class="pure-menu-link subheader-opener"
                data-open-id="search"
                id="search-button" title="{'Search'|t}">
               <i class="fa fa-search"></i>
             </a>
           </li>
-          <li class="pure-menu-item">
+          <li class="pure-menu-item" id="shaarli-menu-desktop-rss">
             <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}">
               <i class="fa fa-rss"></i>
             </a>
           </li>
           {if="!isLoggedIn()"}
-          <li class="pure-menu-item">
-            <a href="?do=login" class="pure-menu-link"
-               data-open-id="header-login-form"
-               id="login-button" title="{'Login'|t}">
-              <i class="fa fa-user"></i>
-            </a>
-          </li>
+            <li class="pure-menu-item" id="shaarli-menu-desktop-login">
+              <a href="?do=login" class="pure-menu-link"
+                 data-open-id="header-login-form"
+                 id="login-button" title="{'Login'|t}">
+                <i class="fa fa-user"></i>
+              </a>
+            </li>
           {else}
-          <li class="pure-menu-item">
-            <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}">
-              <i class="fa fa-sign-out"></i>
-            </a>
-          </li>
+            <li class="pure-menu-item" id="shaarli-menu-desktop-logout">
+              <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}">
+                <i class="fa fa-sign-out"></i>
+              </a>
+            </li>
           {/if}
         </ul>
       </div>
 {/if}
 
 {if="!empty($plugin_errors) && isLoggedIn()"}
-  <div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable">
+  <div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable" id="shaarli-errors-alert">
     <div class="pure-u-2-24"></div>
     <div class="pure-u-20-24">
         {loop="plugin_errors"}
index ca17b435cd3fdff42cca0d5d1b65269ca406ce6b..b2d7cdc5900fff5967f6d0f6acc9afee1c7c0920 100644 (file)
           {if="count($enabledPlugins)==0"}
             <p class="center">{'No plugin enabled.'|t}</p>
           {else}
-            {$counter=0}
+            {$nbParameters=0}
             {loop="$enabledPlugins"}
-              {$counter=$counter+count($value.parameters)}
+              {$nbParameters=$nbParameters+count($value.parameters)}
               {if="count($value.parameters) > 0"}
                 <div class="plugin_parameters">
                   <h3 class="window-subtitle">{function="str_replace('_', ' ', $key)"}</h3>
                 </div>
               {/if}
             {/loop}
-            {if="$counter===0"}
+            {if="$nbParameters===0"}
               <p class="center">{'No parameter available.'|t}</p>
             {else}
               <div class="center">