diff --git a/.dev/.eslintrc.js b/.dev/.eslintrc.js
new file mode 100644
index 0000000..151b785
--- /dev/null
+++ b/.dev/.eslintrc.js
@@ -0,0 +1,12 @@
+module.exports = {
+ "extends": "airbnb-base",
+ "env": {
+ "browser": true,
+ },
+ "rules": {
+ "no-param-reassign": 0, // manipulate DOM style properties
+ "no-restricted-globals": 0, // currently Shaarli uses alert/confirm, could be be improved later
+ "no-alert": 0, // currently Shaarli uses alert/confirm, could be be improved later
+ "no-cond-assign": [2, "except-parens"], // assignment in while loops is readable and avoid assignment duplication
+ }
+};
diff --git a/.dev/.sasslintrc b/.dev/.sasslintrc
new file mode 100644
index 0000000..ac406d7
--- /dev/null
+++ b/.dev/.sasslintrc
@@ -0,0 +1,15 @@
+options:
+ max-warnings: 0
+rules:
+ property-sort-order:
+ - 1
+ -
+ order: 'concentric'
+ no-important:
+ - 0
+ no-vendor-prefixes:
+ - 0 # this will be fixed with v2: see https://github.com/sasstools/sass-lint/pull/1137
+ nesting-depth:
+ - 1
+ -
+ max-depth: 4
diff --git a/.dockerignore b/.dockerignore
index cdd0a89..96fd31c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -4,6 +4,9 @@
.github
tests
+# Docker Compose resources
+docker-compose.yml
+
# Shaarli runtime resources
cache/*
data/*
@@ -35,10 +38,17 @@ phpmd.html
# User plugin configuration
plugins/*/config.php
-# HTML documentation
-doc/html/
-
# 3rd party themes
tpl/*
!tpl/default
!tpl/vintage
+
+# Front end
+node_modules
+tpl/default/js
+tpl/default/css
+tpl/default/fonts
+tpl/default/img
+tpl/vintage/js
+tpl/vintage/css
+tpl/vintage/img
diff --git a/.editorconfig b/.editorconfig
index 4a6589a..34bd799 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,7 +10,7 @@ trim_trailing_whitespace = true
indent_style = space
indent_size = 4
-[*.{htaccess,html,xml}]
+[*.{htaccess,html,scss,js,json,xml,yml}]
indent_size = 2
[*.php]
diff --git a/.gitattributes b/.gitattributes
index 0007056..9a92bc3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -25,18 +25,21 @@ Dockerfile text
*.mo binary
# Exclude from Git archives
-.editorconfig export-ignore
-.gitattributes export-ignore
-.github export-ignore
-.gitignore export-ignore
-.travis.yml export-ignore
-doc/**/*.json export-ignore
-doc/**/*.md export-ignore
-.docker/ export-ignore
-.dockerignore export-ignore
-Dockerfile* export-ignore
-Doxyfile export-ignore
-Makefile export-ignore
-mkdocs.yml export-ignore
-phpunit.xml export-ignore
-tests/ export-ignore
+.editorconfig export-ignore
+.dev export-ignore
+.gitattributes export-ignore
+.github export-ignore
+.gitignore export-ignore
+.travis.yml export-ignore
+doc/**/*.json export-ignore
+doc/**/*.md export-ignore
+.docker/ export-ignore
+.dockerignore export-ignore
+docker-compose.* export-ignore
+Dockerfile* export-ignore
+Doxyfile export-ignore
+Makefile export-ignore
+node_modules/ export-ignore
+mkdocs.yml export-ignore
+phpunit.xml export-ignore
+tests/ export-ignore
diff --git a/.gitignore b/.gitignore
index dc05c17..ac78042 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,13 @@ tpl/*
contact.php
formStyle.css
+
+# Front end
+node_modules
+tpl/default/js
+tpl/default/css
+tpl/default/fonts
+tpl/default/img
+tpl/vintage/js
+tpl/vintage/css
+tpl/vintage/img
diff --git a/.htaccess b/.htaccess
index 7ba4744..4c00427 100644
--- a/.htaccess
+++ b/.htaccess
@@ -14,3 +14,35 @@ RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
+
+
+
+ = 2.4>
+ Require all granted
+
+
+ Allow from all
+ Deny from none
+
+
+
+
+ Require all granted
+
+
+
+
+
+ = 2.4>
+ Require all denied
+
+
+ Allow from none
+ Deny from all
+
+
+
+
+ Require all denied
+
+
diff --git a/.travis.yml b/.travis.yml
index 322e433..cb81846 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,20 +1,53 @@
sudo: false
dist: trusty
-language: php
+
+matrix:
+ include:
+ - language: php
+ php: 7.2
+ - language: php
+ php: 7.1
+ - language: php
+ php: 7.0
+ - language: php
+ php: 5.6
+ - language: node_js
+ node_js: 8
+ cache:
+ yarn: true
+ directories:
+ - $HOME/.cache/yarn
+
+ install:
+ - yarn install
+
+ before_script:
+ - PATH=${PATH//:\.\/node_modules\/\.bin/}
+
+ script:
+ - yarn run build # Just to be sure that the build isn't broken
+ - make eslint
+ - make sasslint
+ - language: python
+ python: 3.6
+ cache:
+ directories:
+ - $HOME/.cache/pip
+ install:
+ - pip install mkdocs
+ script:
+ - mkdocs build --clean
+
cache:
directories:
- $HOME/.composer/cache
-php:
- - 7.1
- - 7.0
- - 5.6
- - 5.5
+
install:
- - composer self-update
- composer install --prefer-dist
- - locale -a
+
before_script:
- PATH=${PATH//:\.\/node_modules\/\.bin/}
+
script:
- make clean
- make check_permissions
diff --git a/AUTHORS b/AUTHORS
index c0414c0..db23ad3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,6 @@
- 588 ArthurHoaro
- 283 VirtualTam
- 179 nodiscc
+ 687 ArthurHoaro
+ 355 VirtualTam
+ 195 nodiscc
56 Sébastien Sauvage
15 Florian Eula
13 Emilien Klein
@@ -9,12 +9,15 @@
8 Christophe HENRY
6 B. van Berkum
5 Lucas Cimon
+ 5 Mark Schmitz
+ 5 kalvn
4 Alexandre Alapetite
4 David Sferruzza
4 Immánuel Fodor
- 4 kalvn
3 Teromene
+ 3 llune
2 Chris Kuethe
+ 2 Felix Bartels
2 Knah Tsaeb
2 Mathieu Chabanon
2 Miloš Jovanović
@@ -23,20 +26,26 @@
2 Timo Van Neerden
2 julienCXX
2 philipp-r
+ 2 pips
1 Adrien Oliva
+ 1 Adrien le Maire
+ 1 Alexandre G.-Raymond
1 Alexis J
+ 1 Angristan
1 BoboTiG
1 Bronco
+ 1 Buster One <37770318+buster-one@users.noreply.github.com>
1 D Low
1 Daniel Jakots
+ 1 Dennis Verspuij
1 Dimtion
1 Fanch
- 1 Felix Bartels
1 Felix Kästner
1 Florian Voigt
1 Franck Kerbiriou
1 Gary Marigliano
1 Guillaume Virlet
+ 1 Jonathan Amiez
1 Jonathan Druart
1 Julien Pivotto
1 Kevin Canévet
@@ -49,3 +58,4 @@
1 TsT
1 dimtion
1 durcheinandr
+ 1 lapineige
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5fd3f2..67ac59e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,89 @@ 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.2](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) - 2018-08-11
+
+### Fixed
+
+- Docker build
+
+## [v0.10.1](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1) - 2018-08-11
+
+### Changed
+
+- Accessibility:
+ - Remove alt text on the logo
+ - Remove redundant title in tools page
+
+### Fixed
+
+- Fixed an error on the daily page and daily RSS
+- Fixed an issue causing 'You are not authorized to add a link' error while logged out
+- Fixed thumbnail path when Shaarli's path uses symbolic links
+- Add a `mod_version` check in Shaarli's root `.htaccess` file for Apache 2.2 syntax
+- Include assets in the release Makefile target
+
+### Removed
+
+- Firefox Social API shaare has been removed
+
+## [v0.10.0](https://github.com/shaarli/Shaarli/releases/tag/v0.10.0) - 2018-07-28
+**PHP 5.5 compatibility has been dropped.** Shaarli now requires at least PHP 5.6.
+
+### Added
+- Add a filter to display public links only
+- Add PHP 7.2 support
+- Add German translation
+- Resolve front-end dependencies from NPM
+- Build front-end bundles with Yarn and Webpack
+- Lint Javascript code with ESLint
+- Lint SASS code with SASSLint
+- Support redirection in cURL download callback
+- Introduce multi-stage builds for Docker images
+- Use Travis matrix and stages to run Javascript tests in a dedicated environment
+- Add tag endpoint in the REST API
+- Build the documentation in Travis builds
+- Provide a Docker Compose example
+
+### Changed
+- Use web-thumbnailer to retrieve thumbnails (see #687)
+- Use a specific page title in all pages
+- Daily: run hooks before creating the columns
+- Load theme translations files automatically
+- Make max download size and timeout configurable
+- Make Nginx logs accessible as stdout/stderr for Docker images
+- Update buttons used to toggle link visibility filters
+- Rewrite Javascript code for ES6 compliance
+- Refactor IP ban management
+- Refactor user login management
+- Refactor server-side session management
+- Update Doxygen configuration
+- Update Parsedown
+- Improve documentation
+- Docker: build the images from the local sources
+- Docker: bump alpine version to 3.7
+- Docker: expose a volume for the thumbnail cache
+
+### Removed
+- Drop support for PHP 5.5
+- Remove vendored front-end libraries
+- Remove environment specific .gitignore entries
+
+### Fixed
+- Ignore the case while checking DOCTYPE during the file import
+- Fix removal of on=... attributes from html generated from Markdown
+- httpd: always forward the 'Authorization' header
+- Ensure user-specific CSS file is loaded
+- Fix feed permalink rendering when Markdown escaping is enabled
+- Fix order of tags with the same number of occurrences
+- Fixed the referrer meta tag in default template
+- Disable MkDocs' strict mode for ReadTheDocs builds to pass
+- fix and simplify Dockerfile for armhf
+
+### Security
+- Update `.htaccess` to prevent accessing Git metadata when using a Git-based installation
+
+
## [v0.9.7](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7) - 2018-06-20
### Changed
- Build the Docker images from the local Git sources
@@ -240,6 +323,19 @@ Theming:
- Editing a link created before the new ID system would change its permalink.
+## [v0.8.7](https://github.com/shaarli/Shaarli/releases/tag/v0.8.7) - 2018-06-20
+### Changed
+- Build the Docker image from the local Git sources
+
+### Removed
+- Disable PHP 5.3 Travis build (unsupported)
+
+
+## [v0.8.6](https://github.com/shaarli/Shaarli/releases/tag/v0.8.6) - 2018-02-19
+### Changed
+- Run version check tests against the 'stable' branch
+
+
## [v0.8.5](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5) - 2018-01-04
**XSS vulnerability fixed. Please update.**
diff --git a/COPYING b/COPYING
index 0520215..af13975 100644
--- a/COPYING
+++ b/COPYING
@@ -1,55 +1,57 @@
Files: *
License: zlib/libpng
Copyright: (c) 2011-2015 Sébastien SAUVAGE
- (c) 2011-2017 The Shaarli Community, see AUTHORS
+ (c) 2011-2018 The Shaarli Community, see AUTHORS
-Files: inc/reset.css
+Files: assets/vintage/css/reset.css
License: BSD (http://opensource.org/licenses/BSD-3-Clause)
Copyright: (c) 2010, Yahoo! Inc.
-Files: images/calendar.png, images/edit_icon.png, images/feed-icon-14x14.png, images/private.png, images/private_16x16.png, images/private_16x16_active.png, images/tag_blue.png
+Files: assets/vintage/img/calendar.png
+ assets/vintage/img/edit_icon.png
+ assets/vintage/img/feed-icon-14x14.png
+ assets/vintage/img/private.png
+ assets/vintage/img/private_16x16.png
+ assets/vintage/img/private_16x16_active.png
+ assets/vintage/img/tag_blue.png
License: CC-BY (http://creativecommons.org/licenses/by/3.0/)
Copyright: (c) 2014 Yusuke Kamiyamane
Source: http://p.yusukekamiyamane.com/
-Files: images/delete_icon.png
+Files: assets/vintage/img/delete_icon.png
License: CC-BY (http://creativecommons.org/licenses/by/3.0/)
Copyright: (c) 2014 Designmodo
Source: http://designmodo.com/linecons-free/
-Files: images/floral_left.png, images/floral_right.png, images/squiggle.png, images/squiggle_closing.png
+Files: assets/vintage/img/floral_left.png
+ assets/vintage/img/floral_right.png
+ assets/vintage/img/squiggle.png
+ assets/vintage/img/squiggle_closing.png
Licence: Public Domain
Source: https://openclipart.org/people/j4p4n/j4p4n_ornimental_bookend_-_left.svg
-Files: images/Paper_texture_v5_by_bashcorpo_w1000.jpg
+Files: assets/vintage/img/Paper_texture_v5_by_bashcorpo_w1000.jpg
Licence: Public Domain
Source: http://bashcorpo.deviantart.com/art/Grungy-paper-texture-v-5-22966998
-Files: images/logo.png
+Files: assets/vintage/img/logo.png
+ assets/vintage/img/logo.png
License: zlib/libpng
Copyright: (c) 2011-2014 idleman idleman@idleman.fr
-Files: inc/blazy*.js
+Files: assets/default/img/sad_star.png
License: MIT License (http://opensource.org/licenses/MIT)
-Copyright: (C) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
+Copyright: (C) 2015 kalvn - https://github.com/kalvn/Shaarli-Material
Files: inc/rain.tpl.class.php
+License: LGPL-3+ (https://www.gnu.org/licenses/lgpl-3.0.txt)
Copyright: 2011-2012, Federico Ulfo
2011-2012, The Rain Team
-License: LGPL-3+ (https://www.gnu.org/licenses/lgpl-3.0.txt)
-
-Files: inc/awesomplete*
-License: MIT License (http://opensource.org/licenses/MIT)
-Copyright: (C) 2015 Lea Verou - https://github.com/LeaVerou/awesomplete
Files: plugins/wallabag/wallabag.png
License: MIT License (http://opensource.org/licenses/MIT)
Copyright: (C) 2015 Nicolas Lœuillet - https://github.com/wallabag/wallabag
-Files: tpl/default/sad_star.png
-License: MIT License (http://opensource.org/licenses/MIT)
-Copyright: (C) 2015 kalvn - https://github.com/kalvn/Shaarli-Material
-
----------------------------------------------------
ZLIB/LIBPNG LICENSE
diff --git a/Dockerfile b/Dockerfile
index 93146c5..d8921ce 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,7 @@ FROM python:3-alpine as docs
ADD . /usr/src/app/shaarli
RUN cd /usr/src/app/shaarli \
&& pip install --no-cache-dir mkdocs \
- && mkdocs build
+ && mkdocs build --clean
# Stage 2:
# - Resolve PHP dependencies with Composer
@@ -15,8 +15,17 @@ RUN cd shaarli \
&& composer --prefer-dist --no-dev install
# Stage 3:
+# - Frontend dependencies
+FROM node:9.9-alpine as node
+COPY --from=composer /app/shaarli shaarli
+RUN cd shaarli \
+ && yarn install \
+ && yarn run build \
+ && rm -rf node_modules
+
+# Stage 4:
# - Shaarli image
-FROM alpine:3.6
+FROM alpine:3.8
LABEL maintainer="Shaarli Community"
RUN apk --update --no-cache add \
@@ -47,12 +56,13 @@ RUN rm -rf /etc/php7/php-fpm.d/www.conf \
WORKDIR /var/www
-COPY --from=composer /app/shaarli shaarli
+COPY --from=node /shaarli shaarli
RUN chown -R nginx:nginx . \
&& ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
&& ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
+VOLUME /var/www/shaarli/cache
VOLUME /var/www/shaarli/data
EXPOSE 80
diff --git a/Doxyfile b/Doxyfile
index 9a596b5..a7f6e04 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "The personal, minimalist, super-fast, no-database deli
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
-PROJECT_LOGO = images/logo.png
+PROJECT_LOGO = doc/md/images/logo.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -804,6 +804,7 @@ RECURSIVE = YES
# run.
EXCLUDE = vendor \
+ data \
tpl \
inc \
doc \
diff --git a/Makefile b/Makefile
index d659d90..56cf09b 100644
--- a/Makefile
+++ b/Makefile
@@ -157,21 +157,32 @@ composer_dependencies: clean
composer install --no-dev --prefer-dist
find vendor/ -name ".git" -type d -exec rm -rf {} +
+### download 3rd-party frontend libraries
+frontend_dependencies:
+ yarn install
+
+### Build frontend dependencies
+build_frontend: frontend_dependencies
+ yarn run build
+
### generate a release tarball and include 3rd-party dependencies and translations
-release_tar: composer_dependencies htmldoc translate
+release_tar: composer_dependencies htmldoc translate build_frontend
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD
tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/
tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/
+ tar rvf $(ARCHIVE_VERSION).tar --transform "s|^tpl|$(ARCHIVE_PREFIX)tpl|" tpl/
gzip $(ARCHIVE_VERSION).tar
### generate a release zip and include 3rd-party dependencies and translations
-release_zip: composer_dependencies htmldoc translate
+release_zip: composer_dependencies htmldoc translate build_frontend
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD
mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor}
rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/
zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)doc/
rsync -a vendor/ $(ARCHIVE_PREFIX)vendor/
zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)vendor/
+ rsync -a tpl/ $(ARCHIVE_PREFIX)tpl/
+ zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)tpl/
rm -rf $(ARCHIVE_PREFIX)
##
@@ -192,18 +203,27 @@ authors:
### generate Doxygen documentation
doxygen: clean
@rm -rf doxygen
- @( cat Doxyfile ; echo "PROJECT_NUMBER=`git describe`" ) | doxygen -
+ @doxygen Doxyfile
### generate HTML documentation from Markdown pages with MkDocs
htmldoc:
python3 -m venv venv/
bash -c 'source venv/bin/activate; \
pip install mkdocs; \
- mkdocs build'
+ mkdocs build --clean'
find doc/html/ -type f -exec chmod a-x '{}' \;
rm -r venv
### Generate Shaarli's translation compiled file (.mo)
translate:
- @find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \;
\ No newline at end of file
+ @find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \;
+
+### Run ESLint check against Shaarli's JS files
+eslint:
+ @yarn run eslint -c .dev/.eslintrc.js assets/vintage/js/
+ @yarn run eslint -c .dev/.eslintrc.js assets/default/js/
+
+### Run CSSLint check against Shaarli's SCSS files
+sasslint:
+ @yarn run sass-lint -c .dev/.sasslintrc 'assets/default/scss/*.scss' -v -q
diff --git a/README.md b/README.md
index 7744d2f..2ff5460 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,10 @@ _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.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5)
+[![](https://img.shields.io/badge/stable-v0.9.7-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7)
[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
•
-[![](https://img.shields.io/badge/latest-v0.9.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.4)
+[![](https://img.shields.io/badge/latest-v0.10.1-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1)
[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
•
[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
diff --git a/application/FileUtils.php b/application/FileUtils.php
index 918cb83..b89ea12 100644
--- a/application/FileUtils.php
+++ b/application/FileUtils.php
@@ -37,7 +37,7 @@ class FileUtils
if (is_file($file) && !is_writeable($file)) {
// The datastore exists but is not writeable
throw new IOException($file);
- } else if (!is_file($file) && !is_writeable(dirname($file))) {
+ } elseif (!is_file($file) && !is_writeable(dirname($file))) {
// The datastore does not exist and its parent directory is not writeable
throw new IOException(dirname($file));
}
diff --git a/application/HttpUtils.php b/application/HttpUtils.php
index 83a4c5e..e928250 100644
--- a/application/HttpUtils.php
+++ b/application/HttpUtils.php
@@ -1,7 +1,7 @@
translator->setLanguage($this->language);
$this->translator->loadDomain(self::DEFAULT_DOMAIN, 'inc/languages');
+ // Default extension translation from the current theme
+ $themeTransFolder = rtrim($this->conf->get('raintpl_tpl'), '/') .'/'. $this->conf->get('theme') .'/language';
+ if (is_dir($themeTransFolder)) {
+ $this->translator->loadDomain($this->conf->get('theme'), $themeTransFolder, false);
+ }
+
foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
if ($domain !== self::DEFAULT_DOMAIN) {
$this->translator->loadDomain($domain, $translationPath, false);
@@ -116,12 +122,23 @@ class Languages
$translations = new Translations();
// Core translations
try {
- /** @var Translations $translations */
$translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
$translations->setDomain('shaarli');
$this->translator->loadTranslations($translations);
} catch (\InvalidArgumentException $e) {}
+ // Default extension translation from the current theme
+ $theme = $this->conf->get('theme');
+ $themeTransFolder = rtrim($this->conf->get('raintpl_tpl'), '/') .'/'. $theme .'/language';
+ if (is_dir($themeTransFolder)) {
+ try {
+ $translations = Translations::fromPoFile(
+ $themeTransFolder .'/'. $this->language .'/LC_MESSAGES/'. $theme .'.po'
+ );
+ $translations->setDomain($theme);
+ $this->translator->loadTranslations($translations);
+ } catch (\InvalidArgumentException $e) {}
+ }
// Extension translations (plugins, themes, etc.).
foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
@@ -130,7 +147,6 @@ class Languages
}
try {
- /** @var Translations $extension */
$extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po');
$extension->setDomain($domain);
$this->translator->loadTranslations($extension);
@@ -161,6 +177,7 @@ class Languages
'auto' => t('Automatic'),
'en' => t('English'),
'fr' => t('French'),
+ 'de' => t('German'),
];
}
}
diff --git a/application/LinkDB.php b/application/LinkDB.php
index c1661d5..cd0f296 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -436,15 +436,17 @@ You use the community supported version of the original Shaarli project, by Seba
/**
* Returns the list tags appearing in the links with the given tags
- * @param $filteringTags: tags selecting the links to consider
- * @param $visibility: process only all/private/public links
- * @return: a tag=>linksCount array
+ *
+ * @param array $filteringTags tags selecting the links to consider
+ * @param string $visibility process only all/private/public links
+ *
+ * @return array tag => linksCount
*/
public function linksCountPerTag($filteringTags = [], $visibility = 'all')
{
- $links = empty($filteringTags) ? $this->links : $this->filterSearch(['searchtags' => $filteringTags], false, $visibility);
- $tags = array();
- $caseMapping = array();
+ $links = $this->filterSearch(['searchtags' => $filteringTags], false, $visibility);
+ $tags = [];
+ $caseMapping = [];
foreach ($links as $link) {
foreach (preg_split('/\s+/', $link['tags'], 0, PREG_SPLIT_NO_EMPTY) as $tag) {
if (empty($tag)) {
@@ -458,8 +460,19 @@ You use the community supported version of the original Shaarli project, by Seba
$tags[$caseMapping[strtolower($tag)]]++;
}
}
- // Sort tags by usage (most used tag first)
- arsort($tags);
+
+ /*
+ * Formerly used arsort(), which doesn't define the sort behaviour for equal values.
+ * Also, this function doesn't produce the same result between PHP 5.6 and 7.
+ *
+ * So we now use array_multisort() to sort tags by DESC occurrences,
+ * then ASC alphabetically for equal values.
+ *
+ * @see https://github.com/shaarli/Shaarli/issues/1142
+ */
+ $keys = array_keys($tags);
+ $tmpTags = array_combine($keys, $keys);
+ array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags);
return $tags;
}
diff --git a/application/LinkFilter.php b/application/LinkFilter.php
index 12376e2..e52239b 100644
--- a/application/LinkFilter.php
+++ b/application/LinkFilter.php
@@ -117,7 +117,7 @@ class LinkFilter
foreach ($this->links as $key => $value) {
if ($value['private'] && $visibility === 'private') {
$out[$key] = $value;
- } else if (! $value['private'] && $visibility === 'public') {
+ } elseif (! $value['private'] && $visibility === 'public') {
$out[$key] = $value;
}
}
@@ -210,7 +210,7 @@ class LinkFilter
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
@@ -337,7 +337,7 @@ class LinkFilter
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
@@ -380,7 +380,7 @@ class LinkFilter
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
diff --git a/application/LinkUtils.php b/application/LinkUtils.php
index 3705f7e..4df5c0c 100644
--- a/application/LinkUtils.php
+++ b/application/LinkUtils.php
@@ -11,6 +11,7 @@
*/
function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_getinfo')
{
+ $isRedirected = false;
/**
* cURL callback function for CURLOPT_WRITEFUNCTION (called during the download).
*
@@ -22,16 +23,24 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get
*
* @return int|bool length of $data or false if we need to stop the download
*/
- return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title) {
+ return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
$responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
- if (!empty($responseCode) && $responseCode != 200) {
+ if (!empty($responseCode) && in_array($responseCode, [301, 302])) {
+ $isRedirected = true;
+ return strlen($data);
+ }
+ if (!empty($responseCode) && $responseCode !== 200) {
return false;
}
- $contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE);
+ // After a redirection, the content type will keep the previous request value
+ // until it finds the next content-type header.
+ if (! $isRedirected || strpos(strtolower($data), 'content-type') !== false) {
+ $contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE);
+ }
if (!empty($contentType) && strpos($contentType, 'text/html') === false) {
return false;
}
- if (empty($charset)) {
+ if (!empty($contentType) && empty($charset)) {
$charset = header_extract_charset($contentType);
}
if (empty($charset)) {
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php
index dd7057f..b4d16d0 100644
--- a/application/NetscapeBookmarkUtils.php
+++ b/application/NetscapeBookmarkUtils.php
@@ -108,7 +108,7 @@ class NetscapeBookmarkUtils
$filesize = $files['filetoupload']['size'];
$data = file_get_contents($files['filetoupload']['tmp_name']);
- if (strpos($data, '') === false) {
+ if (preg_match('//i', $data) === 0) {
return self::importStatus($filename, $filesize);
}
@@ -154,13 +154,13 @@ class NetscapeBookmarkUtils
if (empty($post['privacy']) || $post['privacy'] == 'default') {
// use value from the imported file
$private = $bkm['pub'] == '1' ? 0 : 1;
- } else if ($post['privacy'] == 'private') {
+ } elseif ($post['privacy'] == 'private') {
// all imported links are private
$private = 1;
- } else if ($post['privacy'] == 'public') {
+ } elseif ($post['privacy'] == 'public') {
// all imported links are public
$private = 0;
- }
+ }
$newLink = array(
'title' => $bkm['title'],
diff --git a/application/PageBuilder.php b/application/PageBuilder.php
index 468f144..b1abe0d 100644
--- a/application/PageBuilder.php
+++ b/application/PageBuilder.php
@@ -1,6 +1,7 @@
tpl = false;
$this->conf = $conf;
+ $this->session = $session;
$this->linkDB = $linkDB;
$this->token = $token;
+ $this->isLoggedIn = $isLoggedIn;
}
/**
@@ -55,7 +73,7 @@ class PageBuilder
$this->conf->get('resource.update_check'),
$this->conf->get('updates.check_updates_interval'),
$this->conf->get('updates.check_updates'),
- isLoggedIn(),
+ $this->isLoggedIn,
$this->conf->get('updates.check_updates_branch')
);
$this->tpl->assign('newVersion', escape($version));
@@ -67,6 +85,7 @@ class PageBuilder
$this->tpl->assign('versionError', escape($exc->getMessage()));
}
+ $this->tpl->assign('is_logged_in', $this->isLoggedIn);
$this->tpl->assign('feedurl', escape(index_url($_SERVER)));
$searchcrits = ''; // Search criteria
if (!empty($_GET['searchtags'])) {
@@ -83,7 +102,8 @@ class PageBuilder
ApplicationUtils::getVersionHash(SHAARLI_VERSION, $this->conf->get('credentials.salt'))
);
$this->tpl->assign('scripturl', index_url($_SERVER));
- $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links?
+ $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
+ $this->tpl->assign('visibility', $visibility);
$this->tpl->assign('untaggedonly', !empty($_SESSION['untaggedonly']));
$this->tpl->assign('pagetitle', $this->conf->get('general.title', 'Shaarli'));
if ($this->conf->exists('general.header_link')) {
@@ -99,6 +119,19 @@ class PageBuilder
if ($this->linkDB !== null) {
$this->tpl->assign('tags', $this->linkDB->linksCountPerTag());
}
+
+ $this->tpl->assign(
+ 'thumbnails_enabled',
+ $this->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
+ );
+ $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width'));
+ $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height'));
+
+ if (! empty($_SESSION['warnings'])) {
+ $this->tpl->assign('global_warnings', $_SESSION['warnings']);
+ unset($_SESSION['warnings']);
+ }
+
// To be removed with a proper theme configuration.
$this->tpl->assign('conf', $this->conf);
}
diff --git a/application/Router.php b/application/Router.php
index 4df0387..bf86b88 100644
--- a/application/Router.php
+++ b/application/Router.php
@@ -7,6 +7,8 @@
*/
class Router
{
+ public static $AJAX_THUMB_UPDATE = 'ajax_thumb_update';
+
public static $PAGE_LOGIN = 'login';
public static $PAGE_PICWALL = 'picwall';
@@ -47,6 +49,8 @@ class Router
public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin';
+ public static $PAGE_THUMBS_UPDATE = 'thumbs_update';
+
public static $GET_TOKEN = 'token';
/**
@@ -101,6 +105,14 @@ class Router
return self::$PAGE_FEED_RSS;
}
+ if (startsWith($query, 'do='. self::$PAGE_THUMBS_UPDATE)) {
+ return self::$PAGE_THUMBS_UPDATE;
+ }
+
+ if (startsWith($query, 'do='. self::$AJAX_THUMB_UPDATE)) {
+ return self::$AJAX_THUMB_UPDATE;
+ }
+
// At this point, only loggedin pages.
if (!$loggedIn) {
return self::$PAGE_LINKLIST;
diff --git a/application/SessionManager.php b/application/SessionManager.php
deleted file mode 100644
index 71f0b38..0000000
--- a/application/SessionManager.php
+++ /dev/null
@@ -1,83 +0,0 @@
-session = &$session;
- $this->conf = $conf;
- }
-
- /**
- * Generates a session token
- *
- * @return string token
- */
- public function generateToken()
- {
- $token = sha1(uniqid('', true) .'_'. mt_rand() . $this->conf->get('credentials.salt'));
- $this->session['tokens'][$token] = 1;
- return $token;
- }
-
- /**
- * Checks the validity of a session token, and destroys it afterwards
- *
- * @param string $token The token to check
- *
- * @return bool true if the token is valid, else false
- */
- public function checkToken($token)
- {
- if (! isset($this->session['tokens'][$token])) {
- // the token is wrong, or has already been used
- return false;
- }
-
- // destroy the token to prevent future use
- unset($this->session['tokens'][$token]);
- return true;
- }
-
- /**
- * Validate session ID to prevent Full Path Disclosure.
- *
- * See #298.
- * The session ID's format depends on the hash algorithm set in PHP settings
- *
- * @param string $sessionId Session ID
- *
- * @return true if valid, false otherwise.
- *
- * @see http://php.net/manual/en/function.hash-algos.php
- * @see http://php.net/manual/en/session.configuration.php
- */
- public static function checkId($sessionId)
- {
- if (empty($sessionId)) {
- return false;
- }
-
- if (!$sessionId) {
- return false;
- }
-
- if (!preg_match('/^[a-zA-Z0-9,-]{2,128}$/', $sessionId)) {
- return false;
- }
-
- return true;
- }
-}
diff --git a/application/Thumbnailer.php b/application/Thumbnailer.php
new file mode 100644
index 0000000..7d0d9c3
--- /dev/null
+++ b/application/Thumbnailer.php
@@ -0,0 +1,127 @@
+conf = $conf;
+
+ if (! $this->checkRequirements()) {
+ $this->conf->set('thumbnails.enabled', false);
+ $this->conf->write(true);
+ // TODO: create a proper error handling system able to catch exceptions...
+ die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.'));
+ }
+
+ $this->wt = new WebThumbnailer();
+ WTConfigManager::addFile('inc/web-thumbnailer.json');
+ $this->wt->maxWidth($this->conf->get('thumbnails.width'))
+ ->maxHeight($this->conf->get('thumbnails.height'))
+ ->crop(true)
+ ->debug($this->conf->get('dev.debug', false));
+ }
+
+ /**
+ * Retrieve a thumbnail for given URL
+ *
+ * @param string $url where to look for a thumbnail.
+ *
+ * @return bool|string The thumbnail relative cache file path, or false if none has been found.
+ */
+ public function get($url)
+ {
+ if ($this->conf->get('thumbnails.mode') === self::MODE_COMMON
+ && ! $this->isCommonMediaOrImage($url)
+ ) {
+ return false;
+ }
+
+ try {
+ return $this->wt->thumbnail($url);
+ } catch (WebThumbnailerException $e) {
+ // Exceptions are only thrown in debug mode.
+ error_log(get_class($e) . ': ' . $e->getMessage());
+ }
+ return false;
+ }
+
+ /**
+ * We check weather the given URL is from a common media domain,
+ * or if the file extension is an image.
+ *
+ * @param string $url to check
+ *
+ * @return bool true if it's an image or from a common media domain, false otherwise.
+ */
+ public function isCommonMediaOrImage($url)
+ {
+ foreach (self::COMMON_MEDIA_DOMAINS as $domain) {
+ if (strpos($url, $domain) !== false) {
+ return true;
+ }
+ }
+
+ if (endsWith($url, '.jpg') || endsWith($url, '.png') || endsWith($url, '.jpeg')) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Make sure that requirements are match to use thumbnails:
+ * - php-gd is loaded
+ */
+ protected function checkRequirements()
+ {
+ return extension_loaded('gd');
+ }
+}
diff --git a/application/Updater.php b/application/Updater.php
index 8d2bd57..480bff8 100644
--- a/application/Updater.php
+++ b/application/Updater.php
@@ -2,6 +2,7 @@
use Shaarli\Config\ConfigJson;
use Shaarli\Config\ConfigPhp;
use Shaarli\Config\ConfigManager;
+use Shaarli\Thumbnailer;
/**
* Class Updater.
@@ -30,6 +31,11 @@ class Updater
*/
protected $isLoggedIn;
+ /**
+ * @var array $_SESSION
+ */
+ protected $session;
+
/**
* @var ReflectionMethod[] List of current class methods.
*/
@@ -42,13 +48,17 @@ class Updater
* @param LinkDB $linkDB LinkDB instance.
* @param ConfigManager $conf Configuration Manager instance.
* @param boolean $isLoggedIn True if the user is logged in.
+ * @param array $session $_SESSION (by reference)
+ *
+ * @throws ReflectionException
*/
- public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
+ public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn, &$session = [])
{
$this->doneUpdates = $doneUpdates;
$this->linkDB = $linkDB;
$this->conf = $conf;
$this->isLoggedIn = $isLoggedIn;
+ $this->session = &$session;
// Retrieve all update methods.
$class = new ReflectionClass($this);
@@ -445,6 +455,68 @@ class Updater
$this->linkDB->save($this->conf->get('resource.page_cache'));
return true;
}
+
+ /**
+ * Change privateonly session key to visibility.
+ */
+ public function updateMethodVisibilitySession()
+ {
+ if (isset($_SESSION['privateonly'])) {
+ unset($_SESSION['privateonly']);
+ $_SESSION['visibility'] = 'private';
+ }
+ return true;
+ }
+
+ /**
+ * Add download size and timeout to the configuration file
+ *
+ * @return bool true if the update is successful, false otherwise.
+ */
+ public function updateMethodDownloadSizeAndTimeoutConf()
+ {
+ if ($this->conf->exists('general.download_max_size')
+ && $this->conf->exists('general.download_timeout')
+ ) {
+ return true;
+ }
+
+ if (! $this->conf->exists('general.download_max_size')) {
+ $this->conf->set('general.download_max_size', 1024*1024*4);
+ }
+
+ if (! $this->conf->exists('general.download_timeout')) {
+ $this->conf->set('general.download_timeout', 30);
+ }
+
+ $this->conf->write($this->isLoggedIn);
+ return true;
+ }
+
+ /**
+ * * Move thumbnails management to WebThumbnailer, coming with new settings.
+ */
+ public function updateMethodWebThumbnailer()
+ {
+ if ($this->conf->exists('thumbnails.mode')) {
+ return true;
+ }
+
+ $thumbnailsEnabled = extension_loaded('gd') && $this->conf->get('thumbnail.enable_thumbnails', true);
+ $this->conf->set('thumbnails.mode', $thumbnailsEnabled ? Thumbnailer::MODE_ALL : Thumbnailer::MODE_NONE);
+ $this->conf->set('thumbnails.width', 125);
+ $this->conf->set('thumbnails.height', 90);
+ $this->conf->remove('thumbnail');
+ $this->conf->write(true);
+
+ if ($thumbnailsEnabled) {
+ $this->session['warnings'][] = t(
+ 'You have enabled or changed thumbnails mode. Please synchronize them.'
+ );
+ }
+
+ return true;
+ }
}
/**
diff --git a/application/Url.php b/application/Url.php
index b375937..6b9870f 100644
--- a/application/Url.php
+++ b/application/Url.php
@@ -81,7 +81,7 @@ function whitelist_protocols($url, $protocols)
// Protocol not allowed: we remove it and replace it with http
if ($protocol === 1 && ! in_array($match[1], $protocols)) {
$url = str_replace($match[0], 'http://', $url);
- } else if ($protocol !== 1) {
+ } elseif ($protocol !== 1) {
$url = 'http://' . $url;
}
return $url;
@@ -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);
}
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php
index f154bb5..fc5ecaf 100644
--- a/application/api/ApiUtils.php
+++ b/application/api/ApiUtils.php
@@ -134,4 +134,20 @@ class ApiUtils
return $oldLink;
}
+
+ /**
+ * Format a Tag for the REST API.
+ *
+ * @param string $tag Tag name
+ * @param int $occurrences Number of links using this tag
+ *
+ * @return array Link data formatted for the REST API.
+ */
+ public static function formatTag($tag, $occurences)
+ {
+ return [
+ 'name' => $tag,
+ 'occurrences' => $occurences,
+ ];
+ }
}
diff --git a/application/api/controllers/History.php b/application/api/controllers/History.php
index 2ff9dea..5cc453b 100644
--- a/application/api/controllers/History.php
+++ b/application/api/controllers/History.php
@@ -36,7 +36,7 @@ class History extends ApiController
if (empty($offset)) {
$offset = 0;
}
- else if (ctype_digit($offset)) {
+ elseif (ctype_digit($offset)) {
$offset = (int) $offset;
} else {
throw new ApiBadParametersException('Invalid offset');
@@ -46,7 +46,7 @@ class History extends ApiController
$limit = $request->getParam('limit');
if (empty($limit)) {
$limit = count($history);
- } else if (ctype_digit($limit)) {
+ } elseif (ctype_digit($limit)) {
$limit = (int) $limit;
} else {
throw new ApiBadParametersException('Invalid limit');
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php
index eb78dd2..ffcfd4c 100644
--- a/application/api/controllers/Links.php
+++ b/application/api/controllers/Links.php
@@ -59,25 +59,25 @@ class Links extends ApiController
$limit = $request->getParam('limit');
if (empty($limit)) {
$limit = self::$DEFAULT_LIMIT;
- } else if (ctype_digit($limit)) {
+ } elseif (ctype_digit($limit)) {
$limit = intval($limit);
- } else if ($limit === 'all') {
+ } elseif ($limit === 'all') {
$limit = count($links);
} else {
throw new ApiBadParametersException('Invalid limit');
}
// 'environment' is set by Slim and encapsulate $_SERVER.
- $index = index_url($this->ci['environment']);
+ $indexUrl = index_url($this->ci['environment']);
$out = [];
- $cpt = 0;
+ $index = 0;
foreach ($links as $link) {
if (count($out) >= $limit) {
break;
}
- if ($cpt++ >= $offset) {
- $out[] = ApiUtils::formatLink($link, $index);
+ if ($index++ >= $offset) {
+ $out[] = ApiUtils::formatLink($link, $indexUrl);
}
}
diff --git a/application/api/controllers/Tags.php b/application/api/controllers/Tags.php
new file mode 100644
index 0000000..6dd7875
--- /dev/null
+++ b/application/api/controllers/Tags.php
@@ -0,0 +1,161 @@
+getParam('visibility');
+ $tags = $this->linkDb->linksCountPerTag([], $visibility);
+
+ // Return tags from the {offset}th tag, starting from 0.
+ $offset = $request->getParam('offset');
+ if (! empty($offset) && ! ctype_digit($offset)) {
+ throw new ApiBadParametersException('Invalid offset');
+ }
+ $offset = ! empty($offset) ? intval($offset) : 0;
+ if ($offset > count($tags)) {
+ return $response->withJson([], 200, $this->jsonStyle);
+ }
+
+ // limit parameter is either a number of links or 'all' for everything.
+ $limit = $request->getParam('limit');
+ if (empty($limit)) {
+ $limit = self::$DEFAULT_LIMIT;
+ }
+ if (ctype_digit($limit)) {
+ $limit = intval($limit);
+ } elseif ($limit === 'all') {
+ $limit = count($tags);
+ } else {
+ throw new ApiBadParametersException('Invalid limit');
+ }
+
+ $out = [];
+ $index = 0;
+ foreach ($tags as $tag => $occurrences) {
+ if (count($out) >= $limit) {
+ break;
+ }
+ if ($index++ >= $offset) {
+ $out[] = ApiUtils::formatTag($tag, $occurrences);
+ }
+ }
+
+ return $response->withJson($out, 200, $this->jsonStyle);
+ }
+
+ /**
+ * Return a single formatted tag by its name.
+ *
+ * @param Request $request Slim request.
+ * @param Response $response Slim response.
+ * @param array $args Path parameters. including the tag name.
+ *
+ * @return Response containing the link array.
+ *
+ * @throws ApiTagNotFoundException generating a 404 error.
+ */
+ public function getTag($request, $response, $args)
+ {
+ $tags = $this->linkDb->linksCountPerTag();
+ if (!isset($tags[$args['tagName']])) {
+ throw new ApiTagNotFoundException();
+ }
+ $out = ApiUtils::formatTag($args['tagName'], $tags[$args['tagName']]);
+
+ return $response->withJson($out, 200, $this->jsonStyle);
+ }
+
+ /**
+ * Rename a tag from the given name.
+ * If the new name provided matches an existing tag, they will be merged.
+ *
+ * @param Request $request Slim request.
+ * @param Response $response Slim response.
+ * @param array $args Path parameters. including the tag name.
+ *
+ * @return Response response.
+ *
+ * @throws ApiTagNotFoundException generating a 404 error.
+ * @throws ApiBadParametersException new tag name not provided
+ */
+ public function putTag($request, $response, $args)
+ {
+ $tags = $this->linkDb->linksCountPerTag();
+ if (! isset($tags[$args['tagName']])) {
+ throw new ApiTagNotFoundException();
+ }
+
+ $data = $request->getParsedBody();
+ if (empty($data['name'])) {
+ throw new ApiBadParametersException('New tag name is required in the request body');
+ }
+
+ $updated = $this->linkDb->renameTag($args['tagName'], $data['name']);
+ $this->linkDb->save($this->conf->get('resource.page_cache'));
+ foreach ($updated as $link) {
+ $this->history->updateLink($link);
+ }
+
+ $tags = $this->linkDb->linksCountPerTag();
+ $out = ApiUtils::formatTag($data['name'], $tags[$data['name']]);
+ return $response->withJson($out, 200, $this->jsonStyle);
+ }
+
+ /**
+ * Delete an existing tag by its name.
+ *
+ * @param Request $request Slim request.
+ * @param Response $response Slim response.
+ * @param array $args Path parameters. including the tag name.
+ *
+ * @return Response response.
+ *
+ * @throws ApiTagNotFoundException generating a 404 error.
+ */
+ public function deleteTag($request, $response, $args)
+ {
+ $tags = $this->linkDb->linksCountPerTag();
+ if (! isset($tags[$args['tagName']])) {
+ throw new ApiTagNotFoundException();
+ }
+ $updated = $this->linkDb->renameTag($args['tagName'], null);
+ $this->linkDb->save($this->conf->get('resource.page_cache'));
+ foreach ($updated as $link) {
+ $this->history->updateLink($link);
+ }
+
+ return $response->withStatus(204);
+ }
+}
diff --git a/application/api/exceptions/ApiTagNotFoundException.php b/application/api/exceptions/ApiTagNotFoundException.php
new file mode 100644
index 0000000..eed5afa
--- /dev/null
+++ b/application/api/exceptions/ApiTagNotFoundException.php
@@ -0,0 +1,32 @@
+message = 'Tag not found';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getApiResponse()
+ {
+ return $this->buildApiResponse(404);
+ }
+}
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
index 9e4c9f6..32aaea4 100644
--- a/application/config/ConfigManager.php
+++ b/application/config/ConfigManager.php
@@ -123,7 +123,7 @@ class ConfigManager
* Supports nested settings with dot separated keys.
*
* @param string $setting Asked setting, keys separated with dots.
- * @param string $value Value to set.
+ * @param mixed $value Value to set.
* @param bool $write Write the new setting in the config file, default false.
* @param bool $isLoggedIn User login state, default false.
*
@@ -147,6 +147,33 @@ class ConfigManager
}
}
+ /**
+ * Remove a config element from the config file.
+ *
+ * @param string $setting Asked setting, keys separated with dots.
+ * @param bool $write Write the new setting in the config file, default false.
+ * @param bool $isLoggedIn User login state, default false.
+ *
+ * @throws \Exception Invalid
+ */
+ public function remove($setting, $write = false, $isLoggedIn = false)
+ {
+ if (empty($setting) || ! is_string($setting)) {
+ throw new \Exception(t('Invalid setting key parameter. String expected, got: '). gettype($setting));
+ }
+
+ // During the ConfigIO transition, map legacy settings to the new ones.
+ if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) {
+ $setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting];
+ }
+
+ $settings = explode('.', $setting);
+ self::removeConfig($settings, $this->loadedConfig);
+ if ($write) {
+ $this->write($isLoggedIn);
+ }
+ }
+
/**
* Check if a settings exists.
*
@@ -272,7 +299,7 @@ class ConfigManager
*
* @param array $settings Ordered array which contains keys to find.
* @param mixed $value
- * @param array $conf Loaded settings, then sub-array.
+ * @param array $conf Loaded settings, then sub-array.
*
* @return mixed Found setting or NOT_FOUND flag.
*/
@@ -289,6 +316,27 @@ class ConfigManager
$conf[$setting] = $value;
}
+ /**
+ * Recursive function which find asked setting in the loaded config and deletes it.
+ *
+ * @param array $settings Ordered array which contains keys to find.
+ * @param array $conf Loaded settings, then sub-array.
+ *
+ * @return mixed Found setting or NOT_FOUND flag.
+ */
+ protected static function removeConfig($settings, &$conf)
+ {
+ if (!is_array($settings) || count($settings) == 0) {
+ return self::$NOT_FOUND;
+ }
+
+ $setting = array_shift($settings);
+ if (count($settings) > 0) {
+ return self::removeConfig($settings, $conf[$setting]);
+ }
+ unset($conf[$setting]);
+ }
+
/**
* Set a bunch of default values allowing Shaarli to start without a config file.
*/
@@ -333,12 +381,12 @@ class ConfigManager
// default state of the 'remember me' checkbox of the login form
$this->setEmpty('privacy.remember_user_default', true);
- $this->setEmpty('thumbnail.enable_thumbnails', true);
- $this->setEmpty('thumbnail.enable_localcache', true);
-
$this->setEmpty('redirector.url', '');
$this->setEmpty('redirector.encode_url', true);
+ $this->setEmpty('thumbnails.width', '125');
+ $this->setEmpty('thumbnails.height', '90');
+
$this->setEmpty('translation.language', 'auto');
$this->setEmpty('translation.mode', 'php');
$this->setEmpty('translation.extensions', []);
diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php
new file mode 100644
index 0000000..d6784d6
--- /dev/null
+++ b/application/security/LoginManager.php
@@ -0,0 +1,265 @@
+globals = &$globals;
+ $this->configManager = $configManager;
+ $this->sessionManager = $sessionManager;
+ $this->banFile = $this->configManager->get('resource.ban_file', 'data/ipbans.php');
+ $this->readBanFile();
+ if ($this->configManager->get('security.open_shaarli') === true) {
+ $this->openShaarli = true;
+ }
+ }
+
+ /**
+ * Generate a token depending on deployment salt, user password and client IP
+ *
+ * @param string $clientIpAddress The remote client IP address
+ */
+ public function generateStaySignedInToken($clientIpAddress)
+ {
+ $this->staySignedInToken = sha1(
+ $this->configManager->get('credentials.hash')
+ . $clientIpAddress
+ . $this->configManager->get('credentials.salt')
+ );
+ }
+
+ /**
+ * Return the user's client stay-signed-in token
+ *
+ * @return string User's client stay-signed-in token
+ */
+ public function getStaySignedInToken()
+ {
+ return $this->staySignedInToken;
+ }
+
+ /**
+ * Check user session state and validity (expiration)
+ *
+ * @param array $cookie The $_COOKIE array
+ * @param string $clientIpId Client IP address identifier
+ */
+ public function checkLoginState($cookie, $clientIpId)
+ {
+ if (! $this->configManager->exists('credentials.login')) {
+ // Shaarli is not configured yet
+ $this->isLoggedIn = false;
+ return;
+ }
+
+ if (isset($cookie[self::$STAY_SIGNED_IN_COOKIE])
+ && $cookie[self::$STAY_SIGNED_IN_COOKIE] === $this->staySignedInToken
+ ) {
+ // The user client has a valid stay-signed-in cookie
+ // Session information is updated with the current client information
+ $this->sessionManager->storeLoginInfo($clientIpId);
+
+ } elseif ($this->sessionManager->hasSessionExpired()
+ || $this->sessionManager->hasClientIpChanged($clientIpId)
+ ) {
+ $this->sessionManager->logout();
+ $this->isLoggedIn = false;
+ return;
+ }
+
+ $this->isLoggedIn = true;
+ $this->sessionManager->extendSession();
+ }
+
+ /**
+ * Return whether the user is currently logged in
+ *
+ * @return true when the user is logged in, false otherwise
+ */
+ public function isLoggedIn()
+ {
+ if ($this->openShaarli) {
+ return true;
+ }
+ return $this->isLoggedIn;
+ }
+
+ /**
+ * Check user credentials are valid
+ *
+ * @param string $remoteIp Remote client IP address
+ * @param string $clientIpId Client IP address identifier
+ * @param string $login Username
+ * @param string $password Password
+ *
+ * @return bool true if the provided credentials are valid, false otherwise
+ */
+ public function checkCredentials($remoteIp, $clientIpId, $login, $password)
+ {
+ $hash = sha1($password . $login . $this->configManager->get('credentials.salt'));
+
+ if ($login != $this->configManager->get('credentials.login')
+ || $hash != $this->configManager->get('credentials.hash')
+ ) {
+ logm(
+ $this->configManager->get('resource.log'),
+ $remoteIp,
+ 'Login failed for user ' . $login
+ );
+ return false;
+ }
+
+ $this->sessionManager->storeLoginInfo($clientIpId);
+ logm(
+ $this->configManager->get('resource.log'),
+ $remoteIp,
+ 'Login successful'
+ );
+ return true;
+ }
+
+ /**
+ * Read a file containing banned IPs
+ */
+ protected function readBanFile()
+ {
+ if (! file_exists($this->banFile)) {
+ return;
+ }
+ include $this->banFile;
+ }
+
+ /**
+ * Write the banned IPs to a file
+ */
+ protected function writeBanFile()
+ {
+ if (! array_key_exists('IPBANS', $this->globals)) {
+ return;
+ }
+ file_put_contents(
+ $this->banFile,
+ "globals['IPBANS'], true) . ";\n?>"
+ );
+ }
+
+ /**
+ * Handle a failed login and ban the IP after too many failed attempts
+ *
+ * @param array $server The $_SERVER array
+ */
+ public function handleFailedLogin($server)
+ {
+ $ip = $server['REMOTE_ADDR'];
+ $trusted = $this->configManager->get('security.trusted_proxies', []);
+
+ if (in_array($ip, $trusted)) {
+ $ip = getIpAddressFromProxy($server, $trusted);
+ if (! $ip) {
+ // the IP is behind a trusted forward proxy, but is not forwarded
+ // in the HTTP headers, so we do nothing
+ return;
+ }
+ }
+
+ // increment the fail count for this IP
+ if (isset($this->globals['IPBANS']['FAILURES'][$ip])) {
+ $this->globals['IPBANS']['FAILURES'][$ip]++;
+ } else {
+ $this->globals['IPBANS']['FAILURES'][$ip] = 1;
+ }
+
+ if ($this->globals['IPBANS']['FAILURES'][$ip] >= $this->configManager->get('security.ban_after')) {
+ $this->globals['IPBANS']['BANS'][$ip] = time() + $this->configManager->get('security.ban_duration', 1800);
+ logm(
+ $this->configManager->get('resource.log'),
+ $server['REMOTE_ADDR'],
+ 'IP address banned from login'
+ );
+ }
+ $this->writeBanFile();
+ }
+
+ /**
+ * Handle a successful login
+ *
+ * @param array $server The $_SERVER array
+ */
+ public function handleSuccessfulLogin($server)
+ {
+ $ip = $server['REMOTE_ADDR'];
+ // FIXME unban when behind a trusted proxy?
+
+ unset($this->globals['IPBANS']['FAILURES'][$ip]);
+ unset($this->globals['IPBANS']['BANS'][$ip]);
+
+ $this->writeBanFile();
+ }
+
+ /**
+ * Check if the user can login from this IP
+ *
+ * @param array $server The $_SERVER array
+ *
+ * @return bool true if the user is allowed to login
+ */
+ public function canLogin($server)
+ {
+ $ip = $server['REMOTE_ADDR'];
+
+ if (! isset($this->globals['IPBANS']['BANS'][$ip])) {
+ // the user is not banned
+ return true;
+ }
+
+ if ($this->globals['IPBANS']['BANS'][$ip] > time()) {
+ // the user is still banned
+ return false;
+ }
+
+ // the ban has expired, the user can attempt to log in again
+ logm($this->configManager->get('resource.log'), $server['REMOTE_ADDR'], 'Ban lifted.');
+ unset($this->globals['IPBANS']['FAILURES'][$ip]);
+ unset($this->globals['IPBANS']['BANS'][$ip]);
+
+ $this->writeBanFile();
+ return true;
+ }
+}
diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php
new file mode 100644
index 0000000..b8b8ab8
--- /dev/null
+++ b/application/security/SessionManager.php
@@ -0,0 +1,199 @@
+session = &$session;
+ $this->conf = $conf;
+ }
+
+ /**
+ * Define whether the user should stay signed in across browser sessions
+ *
+ * @param bool $staySignedIn Keep the user signed in
+ */
+ public function setStaySignedIn($staySignedIn)
+ {
+ $this->staySignedIn = $staySignedIn;
+ }
+
+ /**
+ * Generates a session token
+ *
+ * @return string token
+ */
+ public function generateToken()
+ {
+ $token = sha1(uniqid('', true) .'_'. mt_rand() . $this->conf->get('credentials.salt'));
+ $this->session['tokens'][$token] = 1;
+ return $token;
+ }
+
+ /**
+ * Checks the validity of a session token, and destroys it afterwards
+ *
+ * @param string $token The token to check
+ *
+ * @return bool true if the token is valid, else false
+ */
+ public function checkToken($token)
+ {
+ if (! isset($this->session['tokens'][$token])) {
+ // the token is wrong, or has already been used
+ return false;
+ }
+
+ // destroy the token to prevent future use
+ unset($this->session['tokens'][$token]);
+ return true;
+ }
+
+ /**
+ * Validate session ID to prevent Full Path Disclosure.
+ *
+ * See #298.
+ * The session ID's format depends on the hash algorithm set in PHP settings
+ *
+ * @param string $sessionId Session ID
+ *
+ * @return true if valid, false otherwise.
+ *
+ * @see http://php.net/manual/en/function.hash-algos.php
+ * @see http://php.net/manual/en/session.configuration.php
+ */
+ public static function checkId($sessionId)
+ {
+ if (empty($sessionId)) {
+ return false;
+ }
+
+ if (!$sessionId) {
+ return false;
+ }
+
+ if (!preg_match('/^[a-zA-Z0-9,-]{2,128}$/', $sessionId)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Store user login information after a successful login
+ *
+ * @param string $clientIpId Client IP address identifier
+ */
+ public function storeLoginInfo($clientIpId)
+ {
+ $this->session['ip'] = $clientIpId;
+ $this->session['username'] = $this->conf->get('credentials.login');
+ $this->extendTimeValidityBy(self::$SHORT_TIMEOUT);
+ }
+
+ /**
+ * Extend session validity
+ */
+ public function extendSession()
+ {
+ if ($this->staySignedIn) {
+ return $this->extendTimeValidityBy(self::$LONG_TIMEOUT);
+ }
+ return $this->extendTimeValidityBy(self::$SHORT_TIMEOUT);
+ }
+
+ /**
+ * Extend expiration time
+ *
+ * @param int $duration Expiration time extension (seconds)
+ *
+ * @return int New session expiration time
+ */
+ protected function extendTimeValidityBy($duration)
+ {
+ $expirationTime = time() + $duration;
+ $this->session['expires_on'] = $expirationTime;
+ return $expirationTime;
+ }
+
+ /**
+ * Logout a user by unsetting all login information
+ *
+ * See:
+ * - https://secure.php.net/manual/en/function.setcookie.php
+ */
+ public function logout()
+ {
+ if (isset($this->session)) {
+ unset($this->session['ip']);
+ unset($this->session['expires_on']);
+ unset($this->session['username']);
+ unset($this->session['visibility']);
+ unset($this->session['untaggedonly']);
+ }
+ }
+
+ /**
+ * Check whether the session has expired
+ *
+ * @param string $clientIpId Client IP address identifier
+ *
+ * @return bool true if the session has expired, false otherwise
+ */
+ public function hasSessionExpired()
+ {
+ if (empty($this->session['expires_on'])) {
+ return true;
+ }
+ if (time() >= $this->session['expires_on']) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check whether the client IP address has changed
+ *
+ * @param string $clientIpId Client IP address identifier
+ *
+ * @return bool true if the IP has changed, false if it has not, or
+ * if session protection has been disabled
+ */
+ public function hasClientIpChanged($clientIpId)
+ {
+ if ($this->conf->get('security.session_protection_disabled') === true) {
+ return false;
+ }
+ if (isset($this->session['ip']) && $this->session['ip'] === $clientIpId) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/assets/.htaccess b/assets/.htaccess
new file mode 100644
index 0000000..f601c1e
--- /dev/null
+++ b/assets/.htaccess
@@ -0,0 +1,13 @@
+
+ = 2.4>
+ Require all denied
+
+
+ Allow from none
+ Deny from all
+
+
+
+
+ Require all denied
+
diff --git a/assets/common/js/thumbnails-update.js b/assets/common/js/thumbnails-update.js
new file mode 100644
index 0000000..b66ca3a
--- /dev/null
+++ b/assets/common/js/thumbnails-update.js
@@ -0,0 +1,51 @@
+/**
+ * Script used in the thumbnails update page.
+ *
+ * It retrieves the list of link IDs to update, and execute AJAX requests
+ * to update their thumbnails, while updating the progress bar.
+ */
+
+/**
+ * Update the thumbnail of the link with the current i index in ids.
+ * It contains a recursive call to retrieve the thumb of the next link when it succeed.
+ * It also update the progress bar and other visual feedback elements.
+ *
+ * @param {array} ids List of LinkID to update
+ * @param {int} i Current index in ids
+ * @param {object} elements List of DOM element to avoid retrieving them at each iteration
+ */
+function updateThumb(ids, i, elements) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', '?do=ajax_thumb_update');
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status !== 200) {
+ alert(`An error occurred. Return code: ${xhr.status}`);
+ } else {
+ const { response } = xhr;
+ i += 1;
+ elements.progressBar.style.width = `${(i * 100) / ids.length}%`;
+ elements.current.innerHTML = i;
+ elements.title.innerHTML = response.title;
+ if (response.thumbnail !== false) {
+ elements.thumbnail.innerHTML = ``;
+ }
+ if (i < ids.length) {
+ updateThumb(ids, i, elements);
+ }
+ }
+ };
+ xhr.send(`id=${ids[i]}`);
+}
+
+(() => {
+ const ids = document.getElementsByName('ids')[0].value.split(',');
+ const elements = {
+ progressBar: document.querySelector('.progressbar > div'),
+ current: document.querySelector('.progress-current'),
+ thumbnail: document.querySelector('.thumbnail-placeholder'),
+ title: document.querySelector('.thumbnail-link-title'),
+ };
+ updateThumb(ids, 0, elements);
+})();
diff --git a/assets/common/js/thumbnails.js b/assets/common/js/thumbnails.js
new file mode 100644
index 0000000..c28322b
--- /dev/null
+++ b/assets/common/js/thumbnails.js
@@ -0,0 +1,7 @@
+import Blazy from 'blazy';
+
+(() => {
+ // Suppress ESLint error because that's how bLazy works
+ /* eslint-disable no-new */
+ new Blazy();
+})();
diff --git a/tpl/default/fonts/Roboto-Bold.woff b/assets/default/fonts/Roboto-Bold.woff
similarity index 100%
rename from tpl/default/fonts/Roboto-Bold.woff
rename to assets/default/fonts/Roboto-Bold.woff
diff --git a/tpl/default/fonts/Roboto-Bold.woff2 b/assets/default/fonts/Roboto-Bold.woff2
similarity index 100%
rename from tpl/default/fonts/Roboto-Bold.woff2
rename to assets/default/fonts/Roboto-Bold.woff2
diff --git a/tpl/default/fonts/Roboto-Regular.woff b/assets/default/fonts/Roboto-Regular.woff
similarity index 100%
rename from tpl/default/fonts/Roboto-Regular.woff
rename to assets/default/fonts/Roboto-Regular.woff
diff --git a/tpl/default/fonts/Roboto-Regular.woff2 b/assets/default/fonts/Roboto-Regular.woff2
similarity index 100%
rename from tpl/default/fonts/Roboto-Regular.woff2
rename to assets/default/fonts/Roboto-Regular.woff2
diff --git a/tpl/default/img/apple-touch-icon.png b/assets/default/img/apple-touch-icon.png
similarity index 100%
rename from tpl/default/img/apple-touch-icon.png
rename to assets/default/img/apple-touch-icon.png
diff --git a/tpl/default/img/favicon.png b/assets/default/img/favicon.png
similarity index 100%
rename from tpl/default/img/favicon.png
rename to assets/default/img/favicon.png
diff --git a/tpl/default/img/icon.png b/assets/default/img/icon.png
similarity index 100%
rename from tpl/default/img/icon.png
rename to assets/default/img/icon.png
diff --git a/tpl/default/img/sad_star.png b/assets/default/img/sad_star.png
similarity index 100%
rename from tpl/default/img/sad_star.png
rename to assets/default/img/sad_star.png
diff --git a/assets/default/js/base.js b/assets/default/js/base.js
new file mode 100644
index 0000000..8bf79d3
--- /dev/null
+++ b/assets/default/js/base.js
@@ -0,0 +1,573 @@
+import Awesomplete from 'awesomplete';
+
+/**
+ * Find a parent element according to its tag and its attributes
+ *
+ * @param element Element where to start the search
+ * @param tagName Expected parent tag name
+ * @param attributes Associative array of expected attributes (name=>value).
+ *
+ * @returns Found element or null.
+ */
+function findParent(element, tagName, attributes) {
+ const parentMatch = key => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1;
+ while (element) {
+ if (element.tagName.toLowerCase() === tagName) {
+ if (Object.keys(attributes).find(parentMatch)) {
+ return element;
+ }
+ }
+ element = element.parentElement;
+ }
+ return null;
+}
+
+/**
+ * Ajax request to refresh the CSRF token.
+ */
+function refreshToken() {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', '?do=token');
+ xhr.onload = () => {
+ const token = document.getElementById('token');
+ token.setAttribute('value', xhr.responseText);
+ };
+ xhr.send();
+}
+
+function createAwesompleteInstance(element, tags = []) {
+ const awesome = new Awesomplete(Awesomplete.$(element));
+ // Tags are separated by a space
+ awesome.filter = (text, input) => Awesomplete.FILTER_CONTAINS(text, input.match(/[^ ]*$/)[0]);
+ // Insert new selected tag in the input
+ awesome.replace = (text) => {
+ const before = awesome.input.value.match(/^.+ \s*|/)[0];
+ awesome.input.value = `${before}${text} `;
+ };
+ // Highlight found items
+ awesome.item = (text, input) => Awesomplete.ITEM(text, input.match(/[^ ]*$/)[0]);
+ // Don't display already selected items
+ const reg = /(\w+) /g;
+ let match;
+ awesome.data = (item, input) => {
+ while ((match = reg.exec(input))) {
+ if (item === match[1]) {
+ return '';
+ }
+ }
+ return item;
+ };
+ awesome.minChars = 1;
+ if (tags.length) {
+ awesome.list = tags;
+ }
+
+ return awesome;
+}
+
+/**
+ * Update awesomplete list of tag for all elements matching the given selector
+ *
+ * @param selector CSS selector
+ * @param tags Array of tags
+ * @param instances List of existing awesomplete instances
+ */
+function updateAwesompleteList(selector, tags, instances) {
+ if (instances.length === 0) {
+ // First load: create Awesomplete instances
+ const elements = document.querySelectorAll(selector);
+ [...elements].forEach((element) => {
+ instances.push(createAwesompleteInstance(element, tags));
+ });
+ } else {
+ // Update awesomplete tag list
+ instances.map((item) => {
+ item.list = tags;
+ return item;
+ });
+ }
+ return instances;
+}
+
+/**
+ * html_entities in JS
+ *
+ * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript
+ */
+function htmlEntities(str) {
+ return str.replace(/[\u00A0-\u9999<>&]/gim, i => `${i.charCodeAt(0)};`);
+}
+
+/**
+ * Add the class 'hidden' to city options not attached to the current selected continent.
+ *
+ * @param cities List of
\ No newline at end of file
diff --git a/tests/plugins/test/test.php b/tests/plugins/test/test.php
index 3d750c9..2aaf512 100644
--- a/tests/plugins/test/test.php
+++ b/tests/plugins/test/test.php
@@ -11,7 +11,7 @@ function hook_test_random($data)
{
if (isset($data['_PAGE_']) && $data['_PAGE_'] == 'test') {
$data[1] = 'page test';
- } else if (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
+ } elseif (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
$data[1] = 'loggedin';
} else {
$data[1] = $data[0];
diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php
new file mode 100644
index 0000000..f26cd1e
--- /dev/null
+++ b/tests/security/LoginManagerTest.php
@@ -0,0 +1,374 @@
+banFile)) {
+ unlink($this->banFile);
+ }
+
+ $this->passwordHash = sha1($this->password . $this->login . $this->salt);
+
+ $this->configManager = new \FakeConfigManager([
+ 'credentials.login' => $this->login,
+ 'credentials.hash' => $this->passwordHash,
+ 'credentials.salt' => $this->salt,
+ 'resource.ban_file' => $this->banFile,
+ 'resource.log' => $this->logFile,
+ 'security.ban_after' => 4,
+ 'security.ban_duration' => 3600,
+ 'security.trusted_proxies' => [$this->trustedProxy],
+ ]);
+
+ $this->cookie = [];
+
+ $this->globals = &$GLOBALS;
+ unset($this->globals['IPBANS']);
+
+ $this->session = [];
+
+ $this->sessionManager = new SessionManager($this->session, $this->configManager);
+ $this->loginManager = new LoginManager($this->globals, $this->configManager, $this->sessionManager);
+ $this->server['REMOTE_ADDR'] = $this->ipAddr;
+ }
+
+ /**
+ * Wipe test resources
+ */
+ public function tearDown()
+ {
+ unset($this->globals['IPBANS']);
+ }
+
+ /**
+ * Instantiate a LoginManager and load ban records
+ */
+ public function testReadBanFile()
+ {
+ file_put_contents(
+ $this->banFile,
+ " array('127.0.0.1' => 99));\n?>"
+ );
+ new LoginManager($this->globals, $this->configManager, null);
+ $this->assertEquals(99, $this->globals['IPBANS']['FAILURES']['127.0.0.1']);
+ }
+
+ /**
+ * Record a failed login attempt
+ */
+ public function testHandleFailedLogin()
+ {
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ }
+
+ /**
+ * Record a failed login attempt - IP behind a trusted proxy
+ */
+ public function testHandleFailedLoginBehindTrustedProxy()
+ {
+ $server = [
+ 'REMOTE_ADDR' => $this->trustedProxy,
+ 'HTTP_X_FORWARDED_FOR' => $this->ipAddr,
+ ];
+ $this->loginManager->handleFailedLogin($server);
+ $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+
+ $this->loginManager->handleFailedLogin($server);
+ $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ }
+
+ /**
+ * Record a failed login attempt - IP behind a trusted proxy but not forwarded
+ */
+ public function testHandleFailedLoginBehindTrustedProxyNoIp()
+ {
+ $server = [
+ 'REMOTE_ADDR' => $this->trustedProxy,
+ ];
+ $this->loginManager->handleFailedLogin($server);
+ $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr]));
+
+ $this->loginManager->handleFailedLogin($server);
+ $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr]));
+ }
+
+ /**
+ * Record a failed login attempt and ban the IP after too many failures
+ */
+ public function testHandleFailedLoginBanIp()
+ {
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(3, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(4, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertFalse($this->loginManager->canLogin($this->server));
+
+ // handleFailedLogin is not supposed to be called at this point:
+ // - no login form should be displayed once an IP has been banned
+ // - yet this could happen when using custom templates / scripts
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(5, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertFalse($this->loginManager->canLogin($this->server));
+ }
+
+ /**
+ * Nothing to do
+ */
+ public function testHandleSuccessfulLogin()
+ {
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+
+ $this->loginManager->handleSuccessfulLogin($this->server);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+ }
+
+ /**
+ * Erase failure records after successfully logging in from this IP
+ */
+ public function testHandleSuccessfulLoginAfterFailure()
+ {
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->loginManager->handleFailedLogin($this->server);
+ $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+
+ $this->loginManager->handleSuccessfulLogin($this->server);
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+ $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr]));
+ $this->assertFalse(isset($this->globals['IPBANS']['BANS'][$this->ipAddr]));
+ }
+
+ /**
+ * The IP is not banned
+ */
+ public function testCanLoginIpNotBanned()
+ {
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+ }
+
+ /**
+ * The IP is banned
+ */
+ public function testCanLoginIpBanned()
+ {
+ // ban the IP for an hour
+ $this->globals['IPBANS']['FAILURES'][$this->ipAddr] = 10;
+ $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() + 3600;
+
+ $this->assertFalse($this->loginManager->canLogin($this->server));
+ }
+
+ /**
+ * The IP is banned, and the ban duration is over
+ */
+ public function testCanLoginIpBanExpired()
+ {
+ // ban the IP for an hour
+ $this->globals['IPBANS']['FAILURES'][$this->ipAddr] = 10;
+ $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() + 3600;
+ $this->assertFalse($this->loginManager->canLogin($this->server));
+
+ // lift the ban
+ $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() - 3600;
+ $this->assertTrue($this->loginManager->canLogin($this->server));
+ }
+
+ /**
+ * Generate a token depending on the user credentials and client IP
+ */
+ public function testGenerateStaySignedInToken()
+ {
+ $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
+
+ $this->assertEquals(
+ sha1($this->passwordHash . $this->clientIpAddress . $this->salt),
+ $this->loginManager->getStaySignedInToken()
+ );
+ }
+
+ /**
+ * Check user login - Shaarli has not yet been configured
+ */
+ public function testCheckLoginStateNotConfigured()
+ {
+ $configManager = new \FakeConfigManager([
+ 'resource.ban_file' => $this->banFile,
+ ]);
+ $loginManager = new LoginManager($this->globals, $configManager, null);
+ $loginManager->checkLoginState([], '');
+
+ $this->assertFalse($loginManager->isLoggedIn());
+ }
+
+ /**
+ * Check user login - the client cookie does not match the server token
+ */
+ public function testCheckLoginStateStaySignedInWithInvalidToken()
+ {
+ // simulate a previous login
+ $this->session = [
+ 'ip' => $this->clientIpAddress,
+ 'expires_on' => time() + 100,
+ ];
+ $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
+ $this->cookie[LoginManager::$STAY_SIGNED_IN_COOKIE] = 'nope';
+
+ $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+
+ $this->assertTrue($this->loginManager->isLoggedIn());
+ $this->assertTrue(empty($this->session['username']));
+ }
+
+ /**
+ * Check user login - the client cookie matches the server token
+ */
+ public function testCheckLoginStateStaySignedInWithValidToken()
+ {
+ $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
+ $this->cookie[LoginManager::$STAY_SIGNED_IN_COOKIE] = $this->loginManager->getStaySignedInToken();
+
+ $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+
+ $this->assertTrue($this->loginManager->isLoggedIn());
+ $this->assertEquals($this->login, $this->session['username']);
+ $this->assertEquals($this->clientIpAddress, $this->session['ip']);
+ }
+
+ /**
+ * Check user login - the session has expired
+ */
+ public function testCheckLoginStateSessionExpired()
+ {
+ $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
+ $this->session['expires_on'] = time() - 100;
+
+ $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+
+ $this->assertFalse($this->loginManager->isLoggedIn());
+ }
+
+ /**
+ * Check user login - the remote client IP has changed
+ */
+ public function testCheckLoginStateClientIpChanged()
+ {
+ $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
+
+ $this->loginManager->checkLoginState($this->cookie, '10.7.157.98');
+
+ $this->assertFalse($this->loginManager->isLoggedIn());
+ }
+
+ /**
+ * Check user credentials - wrong login supplied
+ */
+ public function testCheckCredentialsWrongLogin()
+ {
+ $this->assertFalse(
+ $this->loginManager->checkCredentials('', '', 'b4dl0g1n', $this->password)
+ );
+ }
+
+ /**
+ * Check user credentials - wrong password supplied
+ */
+ public function testCheckCredentialsWrongPassword()
+ {
+ $this->assertFalse(
+ $this->loginManager->checkCredentials('', '', $this->login, 'b4dp455wd')
+ );
+ }
+
+ /**
+ * Check user credentials - wrong login and password supplied
+ */
+ public function testCheckCredentialsWrongLoginAndPassword()
+ {
+ $this->assertFalse(
+ $this->loginManager->checkCredentials('', '', 'b4dl0g1n', 'b4dp455wd')
+ );
+ }
+
+ /**
+ * Check user credentials - correct login and password supplied
+ */
+ public function testCheckCredentialsGoodLoginAndPassword()
+ {
+ $this->assertTrue(
+ $this->loginManager->checkCredentials('', '', $this->login, $this->password)
+ );
+ }
+}
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
new file mode 100644
index 0000000..9bd868f
--- /dev/null
+++ b/tests/security/SessionManagerTest.php
@@ -0,0 +1,273 @@
+conf = new FakeConfigManager([
+ 'credentials.login' => 'johndoe',
+ 'credentials.salt' => 'salt',
+ 'security.session_protection_disabled' => false,
+ ]);
+ $this->session = [];
+ $this->sessionManager = new SessionManager($this->session, $this->conf);
+ }
+
+ /**
+ * Generate a session token
+ */
+ public function testGenerateToken()
+ {
+ $token = $this->sessionManager->generateToken();
+
+ $this->assertEquals(1, $this->session['tokens'][$token]);
+ $this->assertEquals(40, strlen($token));
+ }
+
+ /**
+ * Check a session token
+ */
+ public function testCheckToken()
+ {
+ $token = '4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b';
+ $session = [
+ 'tokens' => [
+ $token => 1,
+ ],
+ ];
+ $sessionManager = new SessionManager($session, $this->conf);
+
+ // check and destroy the token
+ $this->assertTrue($sessionManager->checkToken($token));
+ $this->assertFalse(isset($session['tokens'][$token]));
+
+ // ensure the token has been destroyed
+ $this->assertFalse($sessionManager->checkToken($token));
+ }
+
+ /**
+ * Generate and check a session token
+ */
+ public function testGenerateAndCheckToken()
+ {
+ $token = $this->sessionManager->generateToken();
+
+ // ensure a token has been generated
+ $this->assertEquals(1, $this->session['tokens'][$token]);
+ $this->assertEquals(40, strlen($token));
+
+ // check and destroy the token
+ $this->assertTrue($this->sessionManager->checkToken($token));
+ $this->assertFalse(isset($this->session['tokens'][$token]));
+
+ // ensure the token has been destroyed
+ $this->assertFalse($this->sessionManager->checkToken($token));
+ }
+
+ /**
+ * Check an invalid session token
+ */
+ public function testCheckInvalidToken()
+ {
+ $this->assertFalse($this->sessionManager->checkToken('4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b'));
+ }
+
+ /**
+ * Test SessionManager::checkId with a valid ID - TEST ALL THE HASHES!
+ *
+ * This tests extensively covers all hash algorithms / bit representations
+ */
+ public function testIsAnyHashSessionIdValid()
+ {
+ foreach (self::$sidHashes as $algo => $bpcs) {
+ foreach ($bpcs as $bpc => $hash) {
+ $this->assertTrue(SessionManager::checkId($hash));
+ }
+ }
+ }
+
+ /**
+ * Test checkId with a valid ID - SHA-1 hashes
+ */
+ public function testIsSha1SessionIdValid()
+ {
+ $this->assertTrue(SessionManager::checkId(sha1('shaarli')));
+ }
+
+ /**
+ * Test checkId with a valid ID - SHA-256 hashes
+ */
+ public function testIsSha256SessionIdValid()
+ {
+ $this->assertTrue(SessionManager::checkId(hash('sha256', 'shaarli')));
+ }
+
+ /**
+ * Test checkId with a valid ID - SHA-512 hashes
+ */
+ public function testIsSha512SessionIdValid()
+ {
+ $this->assertTrue(SessionManager::checkId(hash('sha512', 'shaarli')));
+ }
+
+ /**
+ * Test checkId with invalid IDs.
+ */
+ public function testIsSessionIdInvalid()
+ {
+ $this->assertFalse(SessionManager::checkId(''));
+ $this->assertFalse(SessionManager::checkId([]));
+ $this->assertFalse(
+ SessionManager::checkId('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
+ );
+ }
+
+ /**
+ * Store login information after a successful login
+ */
+ public function testStoreLoginInfo()
+ {
+ $this->sessionManager->storeLoginInfo('ip_id');
+
+ $this->assertGreaterThan(time(), $this->session['expires_on']);
+ $this->assertEquals('ip_id', $this->session['ip']);
+ $this->assertEquals('johndoe', $this->session['username']);
+ }
+
+ /**
+ * Extend a server-side session by SessionManager::$SHORT_TIMEOUT
+ */
+ public function testExtendSession()
+ {
+ $this->sessionManager->extendSession();
+
+ $this->assertGreaterThan(time(), $this->session['expires_on']);
+ $this->assertLessThanOrEqual(
+ time() + SessionManager::$SHORT_TIMEOUT,
+ $this->session['expires_on']
+ );
+ }
+
+ /**
+ * Extend a server-side session by SessionManager::$LONG_TIMEOUT
+ */
+ public function testExtendSessionStaySignedIn()
+ {
+ $this->sessionManager->setStaySignedIn(true);
+ $this->sessionManager->extendSession();
+
+ $this->assertGreaterThan(time(), $this->session['expires_on']);
+ $this->assertGreaterThan(
+ time() + SessionManager::$LONG_TIMEOUT - 10,
+ $this->session['expires_on']
+ );
+ $this->assertLessThanOrEqual(
+ time() + SessionManager::$LONG_TIMEOUT,
+ $this->session['expires_on']
+ );
+ }
+
+ /**
+ * Unset session variables after logging out
+ */
+ public function testLogout()
+ {
+ $this->session = [
+ 'ip' => 'ip_id',
+ 'expires_on' => time() + 1000,
+ 'username' => 'johndoe',
+ 'visibility' => 'public',
+ 'untaggedonly' => false,
+ ];
+ $this->sessionManager->logout();
+
+ $this->assertFalse(isset($this->session['ip']));
+ $this->assertFalse(isset($this->session['expires_on']));
+ $this->assertFalse(isset($this->session['username']));
+ $this->assertFalse(isset($this->session['visibility']));
+ $this->assertFalse(isset($this->session['untaggedonly']));
+ }
+
+ /**
+ * The session is active and expiration time has been reached
+ */
+ public function testHasExpiredTimeElapsed()
+ {
+ $this->session['expires_on'] = time() - 10;
+
+ $this->assertTrue($this->sessionManager->hasSessionExpired());
+ }
+
+ /**
+ * The session is active and expiration time has not been reached
+ */
+ public function testHasNotExpired()
+ {
+ $this->session['expires_on'] = time() + 1000;
+
+ $this->assertFalse($this->sessionManager->hasSessionExpired());
+ }
+
+ /**
+ * Session hijacking protection is disabled, we assume the IP has not changed
+ */
+ public function testHasClientIpChangedNoSessionProtection()
+ {
+ $this->conf->set('security.session_protection_disabled', true);
+
+ $this->assertFalse($this->sessionManager->hasClientIpChanged(''));
+ }
+
+ /**
+ * The client IP identifier has not changed
+ */
+ public function testHasClientIpChangedNope()
+ {
+ $this->session['ip'] = 'ip_id';
+ $this->assertFalse($this->sessionManager->hasClientIpChanged('ip_id'));
+ }
+
+ /**
+ * The client IP identifier has changed
+ */
+ public function testHasClientIpChanged()
+ {
+ $this->session['ip'] = 'ip_id_one';
+ $this->assertTrue($this->sessionManager->hasClientIpChanged('ip_id_two'));
+ }
+}
diff --git a/tests/utils/FakeConfigManager.php b/tests/utils/FakeConfigManager.php
index f29760c..360b34a 100644
--- a/tests/utils/FakeConfigManager.php
+++ b/tests/utils/FakeConfigManager.php
@@ -5,8 +5,53 @@
*/
class FakeConfigManager
{
- public static function get($key)
+ protected $values = [];
+
+ /**
+ * Initialize with test values
+ *
+ * @param array $values Initial values
+ */
+ public function __construct($values = [])
{
+ $this->values = $values;
+ }
+
+ /**
+ * Set a given value
+ *
+ * @param string $key Key of the value to set
+ * @param mixed $value Value to set
+ */
+ public function set($key, $value)
+ {
+ $this->values[$key] = $value;
+ }
+
+ /**
+ * Get a given configuration value
+ *
+ * @param string $key Index of the value to retrieve
+ *
+ * @return mixed The value if set, else the name of the key
+ */
+ public function get($key)
+ {
+ if (isset($this->values[$key])) {
+ return $this->values[$key];
+ }
return $key;
}
+
+ /**
+ * Check if a setting exists
+ *
+ * @param string $setting Asked setting, keys separated with dots
+ *
+ * @return bool true if the setting exists, false otherwise
+ */
+ public function exists($setting)
+ {
+ return array_key_exists($setting, $this->values);
+ }
}
diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php
index 9c9288f..1549ddf 100644
--- a/tests/utils/config/configJson.json.php
+++ b/tests/utils/config/configJson.json.php
@@ -1,35 +1,84 @@
-
diff --git a/tests/utils/config/wt.json b/tests/utils/config/wt.json
new file mode 100644
index 0000000..69ce49a
--- /dev/null
+++ b/tests/utils/config/wt.json
@@ -0,0 +1,12 @@
+{
+ "settings": {
+ "default": {
+ "_comment": "infinite cache",
+ "cache_duration": -1,
+ "timeout": 10
+ },
+ "path": {
+ "cache": "sandbox/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.mo b/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.mo
new file mode 100644
index 0000000..8daae0c
Binary files /dev/null and b/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.mo differ
diff --git a/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.po b/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.po
new file mode 100644
index 0000000..90d1abb
--- /dev/null
+++ b/tests/utils/customtpl/dummy/language/fr/LC_MESSAGES/dummy.po
@@ -0,0 +1,16 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Theme extension test\n"
+"POT-Creation-Date: 2017-05-20 13:54+0200\n"
+"PO-Revision-Date: 2018-03-26 19:09+0200\n"
+"Last-Translator: \n"
+"Language-Team: Shaarli\n"
+"Language: fr_FR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 2.0.6\n"
+
+msgid "rooster"
+msgstr "coq"
diff --git a/tpl/default/404.html b/tpl/default/404.html
index 2de6b6d..fd337ca 100644
--- a/tpl/default/404.html
+++ b/tpl/default/404.html
@@ -6,7 +6,7 @@
+
diff --git a/tpl/default/css/font-awesome.css b/tpl/default/css/font-awesome.css
deleted file mode 100644
index b2a5fe2..0000000
--- a/tpl/default/css/font-awesome.css
+++ /dev/null
@@ -1,2086 +0,0 @@
-/*!
- * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
- * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */
-/* FONT PATH
- * -------------------------- */
-@font-face {
- font-family: 'FontAwesome';
- src: url('../fonts/fontawesome-webfont.eot?v=4.5.0');
- src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
- font-weight: normal;
- font-style: normal;
-}
-.fa {
- display: inline-block;
- font: normal normal normal 14px/1 FontAwesome;
- font-size: inherit;
- text-rendering: auto;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-/* makes the font 33% larger relative to the icon container */
-.fa-lg {
- font-size: 1.33333333em;
- line-height: 0.75em;
- vertical-align: -15%;
-}
-.fa-2x {
- font-size: 2em;
-}
-.fa-3x {
- font-size: 3em;
-}
-.fa-4x {
- font-size: 4em;
-}
-.fa-5x {
- font-size: 5em;
-}
-.fa-fw {
- width: 1.28571429em;
- text-align: center;
-}
-.fa-ul {
- padding-left: 0;
- margin-left: 2.14285714em;
- list-style-type: none;
-}
-.fa-ul > li {
- position: relative;
-}
-.fa-li {
- position: absolute;
- left: -2.14285714em;
- width: 2.14285714em;
- top: 0.14285714em;
- text-align: center;
-}
-.fa-li.fa-lg {
- left: -1.85714286em;
-}
-.fa-border {
- padding: .2em .25em .15em;
- border: solid 0.08em #eeeeee;
- border-radius: .1em;
-}
-.fa-pull-left {
- float: left;
-}
-.fa-pull-right {
- float: right;
-}
-.fa.fa-pull-left {
- margin-right: .3em;
-}
-.fa.fa-pull-right {
- margin-left: .3em;
-}
-/* Deprecated as of 4.4.0 */
-.pull-right {
- float: right;
-}
-.pull-left {
- float: left;
-}
-.fa.pull-left {
- margin-right: .3em;
-}
-.fa.pull-right {
- margin-left: .3em;
-}
-.fa-spin {
- -webkit-animation: fa-spin 2s infinite linear;
- animation: fa-spin 2s infinite linear;
-}
-.fa-pulse {
- -webkit-animation: fa-spin 1s infinite steps(8);
- animation: fa-spin 1s infinite steps(8);
-}
-@-webkit-keyframes fa-spin {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(359deg);
- transform: rotate(359deg);
- }
-}
-@keyframes fa-spin {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(359deg);
- transform: rotate(359deg);
- }
-}
-.fa-rotate-90 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
- -webkit-transform: rotate(90deg);
- -ms-transform: rotate(90deg);
- transform: rotate(90deg);
-}
-.fa-rotate-180 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
- -webkit-transform: rotate(180deg);
- -ms-transform: rotate(180deg);
- transform: rotate(180deg);
-}
-.fa-rotate-270 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
- -webkit-transform: rotate(270deg);
- -ms-transform: rotate(270deg);
- transform: rotate(270deg);
-}
-.fa-flip-horizontal {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
- -webkit-transform: scale(-1, 1);
- -ms-transform: scale(-1, 1);
- transform: scale(-1, 1);
-}
-.fa-flip-vertical {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
- -webkit-transform: scale(1, -1);
- -ms-transform: scale(1, -1);
- transform: scale(1, -1);
-}
-:root .fa-rotate-90,
-:root .fa-rotate-180,
-:root .fa-rotate-270,
-:root .fa-flip-horizontal,
-:root .fa-flip-vertical {
- filter: none;
-}
-.fa-stack {
- position: relative;
- display: inline-block;
- width: 2em;
- height: 2em;
- line-height: 2em;
- vertical-align: middle;
-}
-.fa-stack-1x,
-.fa-stack-2x {
- position: absolute;
- left: 0;
- width: 100%;
- text-align: center;
-}
-.fa-stack-1x {
- line-height: inherit;
-}
-.fa-stack-2x {
- font-size: 2em;
-}
-.fa-inverse {
- color: #ffffff;
-}
-/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
- readers do not read off random characters that represent icons */
-.fa-glass:before {
- content: "\f000";
-}
-.fa-music:before {
- content: "\f001";
-}
-.fa-search:before {
- content: "\f002";
-}
-.fa-envelope-o:before {
- content: "\f003";
-}
-.fa-heart:before {
- content: "\f004";
-}
-.fa-star:before {
- content: "\f005";
-}
-.fa-star-o:before {
- content: "\f006";
-}
-.fa-user:before {
- content: "\f007";
-}
-.fa-film:before {
- content: "\f008";
-}
-.fa-th-large:before {
- content: "\f009";
-}
-.fa-th:before {
- content: "\f00a";
-}
-.fa-th-list:before {
- content: "\f00b";
-}
-.fa-check:before {
- content: "\f00c";
-}
-.fa-remove:before,
-.fa-close:before,
-.fa-times:before {
- content: "\f00d";
-}
-.fa-search-plus:before {
- content: "\f00e";
-}
-.fa-search-minus:before {
- content: "\f010";
-}
-.fa-power-off:before {
- content: "\f011";
-}
-.fa-signal:before {
- content: "\f012";
-}
-.fa-gear:before,
-.fa-cog:before {
- content: "\f013";
-}
-.fa-trash-o:before {
- content: "\f014";
-}
-.fa-home:before {
- content: "\f015";
-}
-.fa-file-o:before {
- content: "\f016";
-}
-.fa-clock-o:before {
- content: "\f017";
-}
-.fa-road:before {
- content: "\f018";
-}
-.fa-download:before {
- content: "\f019";
-}
-.fa-arrow-circle-o-down:before {
- content: "\f01a";
-}
-.fa-arrow-circle-o-up:before {
- content: "\f01b";
-}
-.fa-inbox:before {
- content: "\f01c";
-}
-.fa-play-circle-o:before {
- content: "\f01d";
-}
-.fa-rotate-right:before,
-.fa-repeat:before {
- content: "\f01e";
-}
-.fa-refresh:before {
- content: "\f021";
-}
-.fa-list-alt:before {
- content: "\f022";
-}
-.fa-lock:before {
- content: "\f023";
-}
-.fa-flag:before {
- content: "\f024";
-}
-.fa-headphones:before {
- content: "\f025";
-}
-.fa-volume-off:before {
- content: "\f026";
-}
-.fa-volume-down:before {
- content: "\f027";
-}
-.fa-volume-up:before {
- content: "\f028";
-}
-.fa-qrcode:before {
- content: "\f029";
-}
-.fa-barcode:before {
- content: "\f02a";
-}
-.fa-tag:before {
- content: "\f02b";
-}
-.fa-tags:before {
- content: "\f02c";
-}
-.fa-book:before {
- content: "\f02d";
-}
-.fa-bookmark:before {
- content: "\f02e";
-}
-.fa-print:before {
- content: "\f02f";
-}
-.fa-camera:before {
- content: "\f030";
-}
-.fa-font:before {
- content: "\f031";
-}
-.fa-bold:before {
- content: "\f032";
-}
-.fa-italic:before {
- content: "\f033";
-}
-.fa-text-height:before {
- content: "\f034";
-}
-.fa-text-width:before {
- content: "\f035";
-}
-.fa-align-left:before {
- content: "\f036";
-}
-.fa-align-center:before {
- content: "\f037";
-}
-.fa-align-right:before {
- content: "\f038";
-}
-.fa-align-justify:before {
- content: "\f039";
-}
-.fa-list:before {
- content: "\f03a";
-}
-.fa-dedent:before,
-.fa-outdent:before {
- content: "\f03b";
-}
-.fa-indent:before {
- content: "\f03c";
-}
-.fa-video-camera:before {
- content: "\f03d";
-}
-.fa-photo:before,
-.fa-image:before,
-.fa-picture-o:before {
- content: "\f03e";
-}
-.fa-pencil:before {
- content: "\f040";
-}
-.fa-map-marker:before {
- content: "\f041";
-}
-.fa-adjust:before {
- content: "\f042";
-}
-.fa-tint:before {
- content: "\f043";
-}
-.fa-edit:before,
-.fa-pencil-square-o:before {
- content: "\f044";
-}
-.fa-share-square-o:before {
- content: "\f045";
-}
-.fa-check-square-o:before {
- content: "\f046";
-}
-.fa-arrows:before {
- content: "\f047";
-}
-.fa-step-backward:before {
- content: "\f048";
-}
-.fa-fast-backward:before {
- content: "\f049";
-}
-.fa-backward:before {
- content: "\f04a";
-}
-.fa-play:before {
- content: "\f04b";
-}
-.fa-pause:before {
- content: "\f04c";
-}
-.fa-stop:before {
- content: "\f04d";
-}
-.fa-forward:before {
- content: "\f04e";
-}
-.fa-fast-forward:before {
- content: "\f050";
-}
-.fa-step-forward:before {
- content: "\f051";
-}
-.fa-eject:before {
- content: "\f052";
-}
-.fa-chevron-left:before {
- content: "\f053";
-}
-.fa-chevron-right:before {
- content: "\f054";
-}
-.fa-plus-circle:before {
- content: "\f055";
-}
-.fa-minus-circle:before {
- content: "\f056";
-}
-.fa-times-circle:before {
- content: "\f057";
-}
-.fa-check-circle:before {
- content: "\f058";
-}
-.fa-question-circle:before {
- content: "\f059";
-}
-.fa-info-circle:before {
- content: "\f05a";
-}
-.fa-crosshairs:before {
- content: "\f05b";
-}
-.fa-times-circle-o:before {
- content: "\f05c";
-}
-.fa-check-circle-o:before {
- content: "\f05d";
-}
-.fa-ban:before {
- content: "\f05e";
-}
-.fa-arrow-left:before {
- content: "\f060";
-}
-.fa-arrow-right:before {
- content: "\f061";
-}
-.fa-arrow-up:before {
- content: "\f062";
-}
-.fa-arrow-down:before {
- content: "\f063";
-}
-.fa-mail-forward:before,
-.fa-share:before {
- content: "\f064";
-}
-.fa-expand:before {
- content: "\f065";
-}
-.fa-compress:before {
- content: "\f066";
-}
-.fa-plus:before {
- content: "\f067";
-}
-.fa-minus:before {
- content: "\f068";
-}
-.fa-asterisk:before {
- content: "\f069";
-}
-.fa-exclamation-circle:before {
- content: "\f06a";
-}
-.fa-gift:before {
- content: "\f06b";
-}
-.fa-leaf:before {
- content: "\f06c";
-}
-.fa-fire:before {
- content: "\f06d";
-}
-.fa-eye:before {
- content: "\f06e";
-}
-.fa-eye-slash:before {
- content: "\f070";
-}
-.fa-warning:before,
-.fa-exclamation-triangle:before {
- content: "\f071";
-}
-.fa-plane:before {
- content: "\f072";
-}
-.fa-calendar:before {
- content: "\f073";
-}
-.fa-random:before {
- content: "\f074";
-}
-.fa-comment:before {
- content: "\f075";
-}
-.fa-magnet:before {
- content: "\f076";
-}
-.fa-chevron-up:before {
- content: "\f077";
-}
-.fa-chevron-down:before {
- content: "\f078";
-}
-.fa-retweet:before {
- content: "\f079";
-}
-.fa-shopping-cart:before {
- content: "\f07a";
-}
-.fa-folder:before {
- content: "\f07b";
-}
-.fa-folder-open:before {
- content: "\f07c";
-}
-.fa-arrows-v:before {
- content: "\f07d";
-}
-.fa-arrows-h:before {
- content: "\f07e";
-}
-.fa-bar-chart-o:before,
-.fa-bar-chart:before {
- content: "\f080";
-}
-.fa-twitter-square:before {
- content: "\f081";
-}
-.fa-facebook-square:before {
- content: "\f082";
-}
-.fa-camera-retro:before {
- content: "\f083";
-}
-.fa-key:before {
- content: "\f084";
-}
-.fa-gears:before,
-.fa-cogs:before {
- content: "\f085";
-}
-.fa-comments:before {
- content: "\f086";
-}
-.fa-thumbs-o-up:before {
- content: "\f087";
-}
-.fa-thumbs-o-down:before {
- content: "\f088";
-}
-.fa-star-half:before {
- content: "\f089";
-}
-.fa-heart-o:before {
- content: "\f08a";
-}
-.fa-sign-out:before {
- content: "\f08b";
-}
-.fa-linkedin-square:before {
- content: "\f08c";
-}
-.fa-thumb-tack:before {
- content: "\f08d";
-}
-.fa-external-link:before {
- content: "\f08e";
-}
-.fa-sign-in:before {
- content: "\f090";
-}
-.fa-trophy:before {
- content: "\f091";
-}
-.fa-github-square:before {
- content: "\f092";
-}
-.fa-upload:before {
- content: "\f093";
-}
-.fa-lemon-o:before {
- content: "\f094";
-}
-.fa-phone:before {
- content: "\f095";
-}
-.fa-square-o:before {
- content: "\f096";
-}
-.fa-bookmark-o:before {
- content: "\f097";
-}
-.fa-phone-square:before {
- content: "\f098";
-}
-.fa-twitter:before {
- content: "\f099";
-}
-.fa-facebook-f:before,
-.fa-facebook:before {
- content: "\f09a";
-}
-.fa-github:before {
- content: "\f09b";
-}
-.fa-unlock:before {
- content: "\f09c";
-}
-.fa-credit-card:before {
- content: "\f09d";
-}
-.fa-feed:before,
-.fa-rss:before {
- content: "\f09e";
-}
-.fa-hdd-o:before {
- content: "\f0a0";
-}
-.fa-bullhorn:before {
- content: "\f0a1";
-}
-.fa-bell:before {
- content: "\f0f3";
-}
-.fa-certificate:before {
- content: "\f0a3";
-}
-.fa-hand-o-right:before {
- content: "\f0a4";
-}
-.fa-hand-o-left:before {
- content: "\f0a5";
-}
-.fa-hand-o-up:before {
- content: "\f0a6";
-}
-.fa-hand-o-down:before {
- content: "\f0a7";
-}
-.fa-arrow-circle-left:before {
- content: "\f0a8";
-}
-.fa-arrow-circle-right:before {
- content: "\f0a9";
-}
-.fa-arrow-circle-up:before {
- content: "\f0aa";
-}
-.fa-arrow-circle-down:before {
- content: "\f0ab";
-}
-.fa-globe:before {
- content: "\f0ac";
-}
-.fa-wrench:before {
- content: "\f0ad";
-}
-.fa-tasks:before {
- content: "\f0ae";
-}
-.fa-filter:before {
- content: "\f0b0";
-}
-.fa-briefcase:before {
- content: "\f0b1";
-}
-.fa-arrows-alt:before {
- content: "\f0b2";
-}
-.fa-group:before,
-.fa-users:before {
- content: "\f0c0";
-}
-.fa-chain:before,
-.fa-link:before {
- content: "\f0c1";
-}
-.fa-cloud:before {
- content: "\f0c2";
-}
-.fa-flask:before {
- content: "\f0c3";
-}
-.fa-cut:before,
-.fa-scissors:before {
- content: "\f0c4";
-}
-.fa-copy:before,
-.fa-files-o:before {
- content: "\f0c5";
-}
-.fa-paperclip:before {
- content: "\f0c6";
-}
-.fa-save:before,
-.fa-floppy-o:before {
- content: "\f0c7";
-}
-.fa-square:before {
- content: "\f0c8";
-}
-.fa-navicon:before,
-.fa-reorder:before,
-.fa-bars:before {
- content: "\f0c9";
-}
-.fa-list-ul:before {
- content: "\f0ca";
-}
-.fa-list-ol:before {
- content: "\f0cb";
-}
-.fa-strikethrough:before {
- content: "\f0cc";
-}
-.fa-underline:before {
- content: "\f0cd";
-}
-.fa-table:before {
- content: "\f0ce";
-}
-.fa-magic:before {
- content: "\f0d0";
-}
-.fa-truck:before {
- content: "\f0d1";
-}
-.fa-pinterest:before {
- content: "\f0d2";
-}
-.fa-pinterest-square:before {
- content: "\f0d3";
-}
-.fa-google-plus-square:before {
- content: "\f0d4";
-}
-.fa-google-plus:before {
- content: "\f0d5";
-}
-.fa-money:before {
- content: "\f0d6";
-}
-.fa-caret-down:before {
- content: "\f0d7";
-}
-.fa-caret-up:before {
- content: "\f0d8";
-}
-.fa-caret-left:before {
- content: "\f0d9";
-}
-.fa-caret-right:before {
- content: "\f0da";
-}
-.fa-columns:before {
- content: "\f0db";
-}
-.fa-unsorted:before,
-.fa-sort:before {
- content: "\f0dc";
-}
-.fa-sort-down:before,
-.fa-sort-desc:before {
- content: "\f0dd";
-}
-.fa-sort-up:before,
-.fa-sort-asc:before {
- content: "\f0de";
-}
-.fa-envelope:before {
- content: "\f0e0";
-}
-.fa-linkedin:before {
- content: "\f0e1";
-}
-.fa-rotate-left:before,
-.fa-undo:before {
- content: "\f0e2";
-}
-.fa-legal:before,
-.fa-gavel:before {
- content: "\f0e3";
-}
-.fa-dashboard:before,
-.fa-tachometer:before {
- content: "\f0e4";
-}
-.fa-comment-o:before {
- content: "\f0e5";
-}
-.fa-comments-o:before {
- content: "\f0e6";
-}
-.fa-flash:before,
-.fa-bolt:before {
- content: "\f0e7";
-}
-.fa-sitemap:before {
- content: "\f0e8";
-}
-.fa-umbrella:before {
- content: "\f0e9";
-}
-.fa-paste:before,
-.fa-clipboard:before {
- content: "\f0ea";
-}
-.fa-lightbulb-o:before {
- content: "\f0eb";
-}
-.fa-exchange:before {
- content: "\f0ec";
-}
-.fa-cloud-download:before {
- content: "\f0ed";
-}
-.fa-cloud-upload:before {
- content: "\f0ee";
-}
-.fa-user-md:before {
- content: "\f0f0";
-}
-.fa-stethoscope:before {
- content: "\f0f1";
-}
-.fa-suitcase:before {
- content: "\f0f2";
-}
-.fa-bell-o:before {
- content: "\f0a2";
-}
-.fa-coffee:before {
- content: "\f0f4";
-}
-.fa-cutlery:before {
- content: "\f0f5";
-}
-.fa-file-text-o:before {
- content: "\f0f6";
-}
-.fa-building-o:before {
- content: "\f0f7";
-}
-.fa-hospital-o:before {
- content: "\f0f8";
-}
-.fa-ambulance:before {
- content: "\f0f9";
-}
-.fa-medkit:before {
- content: "\f0fa";
-}
-.fa-fighter-jet:before {
- content: "\f0fb";
-}
-.fa-beer:before {
- content: "\f0fc";
-}
-.fa-h-square:before {
- content: "\f0fd";
-}
-.fa-plus-square:before {
- content: "\f0fe";
-}
-.fa-angle-double-left:before {
- content: "\f100";
-}
-.fa-angle-double-right:before {
- content: "\f101";
-}
-.fa-angle-double-up:before {
- content: "\f102";
-}
-.fa-angle-double-down:before {
- content: "\f103";
-}
-.fa-angle-left:before {
- content: "\f104";
-}
-.fa-angle-right:before {
- content: "\f105";
-}
-.fa-angle-up:before {
- content: "\f106";
-}
-.fa-angle-down:before {
- content: "\f107";
-}
-.fa-desktop:before {
- content: "\f108";
-}
-.fa-laptop:before {
- content: "\f109";
-}
-.fa-tablet:before {
- content: "\f10a";
-}
-.fa-mobile-phone:before,
-.fa-mobile:before {
- content: "\f10b";
-}
-.fa-circle-o:before {
- content: "\f10c";
-}
-.fa-quote-left:before {
- content: "\f10d";
-}
-.fa-quote-right:before {
- content: "\f10e";
-}
-.fa-spinner:before {
- content: "\f110";
-}
-.fa-circle:before {
- content: "\f111";
-}
-.fa-mail-reply:before,
-.fa-reply:before {
- content: "\f112";
-}
-.fa-github-alt:before {
- content: "\f113";
-}
-.fa-folder-o:before {
- content: "\f114";
-}
-.fa-folder-open-o:before {
- content: "\f115";
-}
-.fa-smile-o:before {
- content: "\f118";
-}
-.fa-frown-o:before {
- content: "\f119";
-}
-.fa-meh-o:before {
- content: "\f11a";
-}
-.fa-gamepad:before {
- content: "\f11b";
-}
-.fa-keyboard-o:before {
- content: "\f11c";
-}
-.fa-flag-o:before {
- content: "\f11d";
-}
-.fa-flag-checkered:before {
- content: "\f11e";
-}
-.fa-terminal:before {
- content: "\f120";
-}
-.fa-code:before {
- content: "\f121";
-}
-.fa-mail-reply-all:before,
-.fa-reply-all:before {
- content: "\f122";
-}
-.fa-star-half-empty:before,
-.fa-star-half-full:before,
-.fa-star-half-o:before {
- content: "\f123";
-}
-.fa-location-arrow:before {
- content: "\f124";
-}
-.fa-crop:before {
- content: "\f125";
-}
-.fa-code-fork:before {
- content: "\f126";
-}
-.fa-unlink:before,
-.fa-chain-broken:before {
- content: "\f127";
-}
-.fa-question:before {
- content: "\f128";
-}
-.fa-info:before {
- content: "\f129";
-}
-.fa-exclamation:before {
- content: "\f12a";
-}
-.fa-superscript:before {
- content: "\f12b";
-}
-.fa-subscript:before {
- content: "\f12c";
-}
-.fa-eraser:before {
- content: "\f12d";
-}
-.fa-puzzle-piece:before {
- content: "\f12e";
-}
-.fa-microphone:before {
- content: "\f130";
-}
-.fa-microphone-slash:before {
- content: "\f131";
-}
-.fa-shield:before {
- content: "\f132";
-}
-.fa-calendar-o:before {
- content: "\f133";
-}
-.fa-fire-extinguisher:before {
- content: "\f134";
-}
-.fa-rocket:before {
- content: "\f135";
-}
-.fa-maxcdn:before {
- content: "\f136";
-}
-.fa-chevron-circle-left:before {
- content: "\f137";
-}
-.fa-chevron-circle-right:before {
- content: "\f138";
-}
-.fa-chevron-circle-up:before {
- content: "\f139";
-}
-.fa-chevron-circle-down:before {
- content: "\f13a";
-}
-.fa-html5:before {
- content: "\f13b";
-}
-.fa-css3:before {
- content: "\f13c";
-}
-.fa-anchor:before {
- content: "\f13d";
-}
-.fa-unlock-alt:before {
- content: "\f13e";
-}
-.fa-bullseye:before {
- content: "\f140";
-}
-.fa-ellipsis-h:before {
- content: "\f141";
-}
-.fa-ellipsis-v:before {
- content: "\f142";
-}
-.fa-rss-square:before {
- content: "\f143";
-}
-.fa-play-circle:before {
- content: "\f144";
-}
-.fa-ticket:before {
- content: "\f145";
-}
-.fa-minus-square:before {
- content: "\f146";
-}
-.fa-minus-square-o:before {
- content: "\f147";
-}
-.fa-level-up:before {
- content: "\f148";
-}
-.fa-level-down:before {
- content: "\f149";
-}
-.fa-check-square:before {
- content: "\f14a";
-}
-.fa-pencil-square:before {
- content: "\f14b";
-}
-.fa-external-link-square:before {
- content: "\f14c";
-}
-.fa-share-square:before {
- content: "\f14d";
-}
-.fa-compass:before {
- content: "\f14e";
-}
-.fa-toggle-down:before,
-.fa-caret-square-o-down:before {
- content: "\f150";
-}
-.fa-toggle-up:before,
-.fa-caret-square-o-up:before {
- content: "\f151";
-}
-.fa-toggle-right:before,
-.fa-caret-square-o-right:before {
- content: "\f152";
-}
-.fa-euro:before,
-.fa-eur:before {
- content: "\f153";
-}
-.fa-gbp:before {
- content: "\f154";
-}
-.fa-dollar:before,
-.fa-usd:before {
- content: "\f155";
-}
-.fa-rupee:before,
-.fa-inr:before {
- content: "\f156";
-}
-.fa-cny:before,
-.fa-rmb:before,
-.fa-yen:before,
-.fa-jpy:before {
- content: "\f157";
-}
-.fa-ruble:before,
-.fa-rouble:before,
-.fa-rub:before {
- content: "\f158";
-}
-.fa-won:before,
-.fa-krw:before {
- content: "\f159";
-}
-.fa-bitcoin:before,
-.fa-btc:before {
- content: "\f15a";
-}
-.fa-file:before {
- content: "\f15b";
-}
-.fa-file-text:before {
- content: "\f15c";
-}
-.fa-sort-alpha-asc:before {
- content: "\f15d";
-}
-.fa-sort-alpha-desc:before {
- content: "\f15e";
-}
-.fa-sort-amount-asc:before {
- content: "\f160";
-}
-.fa-sort-amount-desc:before {
- content: "\f161";
-}
-.fa-sort-numeric-asc:before {
- content: "\f162";
-}
-.fa-sort-numeric-desc:before {
- content: "\f163";
-}
-.fa-thumbs-up:before {
- content: "\f164";
-}
-.fa-thumbs-down:before {
- content: "\f165";
-}
-.fa-youtube-square:before {
- content: "\f166";
-}
-.fa-youtube:before {
- content: "\f167";
-}
-.fa-xing:before {
- content: "\f168";
-}
-.fa-xing-square:before {
- content: "\f169";
-}
-.fa-youtube-play:before {
- content: "\f16a";
-}
-.fa-dropbox:before {
- content: "\f16b";
-}
-.fa-stack-overflow:before {
- content: "\f16c";
-}
-.fa-instagram:before {
- content: "\f16d";
-}
-.fa-flickr:before {
- content: "\f16e";
-}
-.fa-adn:before {
- content: "\f170";
-}
-.fa-bitbucket:before {
- content: "\f171";
-}
-.fa-bitbucket-square:before {
- content: "\f172";
-}
-.fa-tumblr:before {
- content: "\f173";
-}
-.fa-tumblr-square:before {
- content: "\f174";
-}
-.fa-long-arrow-down:before {
- content: "\f175";
-}
-.fa-long-arrow-up:before {
- content: "\f176";
-}
-.fa-long-arrow-left:before {
- content: "\f177";
-}
-.fa-long-arrow-right:before {
- content: "\f178";
-}
-.fa-apple:before {
- content: "\f179";
-}
-.fa-windows:before {
- content: "\f17a";
-}
-.fa-android:before {
- content: "\f17b";
-}
-.fa-linux:before {
- content: "\f17c";
-}
-.fa-dribbble:before {
- content: "\f17d";
-}
-.fa-skype:before {
- content: "\f17e";
-}
-.fa-foursquare:before {
- content: "\f180";
-}
-.fa-trello:before {
- content: "\f181";
-}
-.fa-female:before {
- content: "\f182";
-}
-.fa-male:before {
- content: "\f183";
-}
-.fa-gittip:before,
-.fa-gratipay:before {
- content: "\f184";
-}
-.fa-sun-o:before {
- content: "\f185";
-}
-.fa-moon-o:before {
- content: "\f186";
-}
-.fa-archive:before {
- content: "\f187";
-}
-.fa-bug:before {
- content: "\f188";
-}
-.fa-vk:before {
- content: "\f189";
-}
-.fa-weibo:before {
- content: "\f18a";
-}
-.fa-renren:before {
- content: "\f18b";
-}
-.fa-pagelines:before {
- content: "\f18c";
-}
-.fa-stack-exchange:before {
- content: "\f18d";
-}
-.fa-arrow-circle-o-right:before {
- content: "\f18e";
-}
-.fa-arrow-circle-o-left:before {
- content: "\f190";
-}
-.fa-toggle-left:before,
-.fa-caret-square-o-left:before {
- content: "\f191";
-}
-.fa-dot-circle-o:before {
- content: "\f192";
-}
-.fa-wheelchair:before {
- content: "\f193";
-}
-.fa-vimeo-square:before {
- content: "\f194";
-}
-.fa-turkish-lira:before,
-.fa-try:before {
- content: "\f195";
-}
-.fa-plus-square-o:before {
- content: "\f196";
-}
-.fa-space-shuttle:before {
- content: "\f197";
-}
-.fa-slack:before {
- content: "\f198";
-}
-.fa-envelope-square:before {
- content: "\f199";
-}
-.fa-wordpress:before {
- content: "\f19a";
-}
-.fa-openid:before {
- content: "\f19b";
-}
-.fa-institution:before,
-.fa-bank:before,
-.fa-university:before {
- content: "\f19c";
-}
-.fa-mortar-board:before,
-.fa-graduation-cap:before {
- content: "\f19d";
-}
-.fa-yahoo:before {
- content: "\f19e";
-}
-.fa-google:before {
- content: "\f1a0";
-}
-.fa-reddit:before {
- content: "\f1a1";
-}
-.fa-reddit-square:before {
- content: "\f1a2";
-}
-.fa-stumbleupon-circle:before {
- content: "\f1a3";
-}
-.fa-stumbleupon:before {
- content: "\f1a4";
-}
-.fa-delicious:before {
- content: "\f1a5";
-}
-.fa-digg:before {
- content: "\f1a6";
-}
-.fa-pied-piper:before {
- content: "\f1a7";
-}
-.fa-pied-piper-alt:before {
- content: "\f1a8";
-}
-.fa-drupal:before {
- content: "\f1a9";
-}
-.fa-joomla:before {
- content: "\f1aa";
-}
-.fa-language:before {
- content: "\f1ab";
-}
-.fa-fax:before {
- content: "\f1ac";
-}
-.fa-building:before {
- content: "\f1ad";
-}
-.fa-child:before {
- content: "\f1ae";
-}
-.fa-paw:before {
- content: "\f1b0";
-}
-.fa-spoon:before {
- content: "\f1b1";
-}
-.fa-cube:before {
- content: "\f1b2";
-}
-.fa-cubes:before {
- content: "\f1b3";
-}
-.fa-behance:before {
- content: "\f1b4";
-}
-.fa-behance-square:before {
- content: "\f1b5";
-}
-.fa-steam:before {
- content: "\f1b6";
-}
-.fa-steam-square:before {
- content: "\f1b7";
-}
-.fa-recycle:before {
- content: "\f1b8";
-}
-.fa-automobile:before,
-.fa-car:before {
- content: "\f1b9";
-}
-.fa-cab:before,
-.fa-taxi:before {
- content: "\f1ba";
-}
-.fa-tree:before {
- content: "\f1bb";
-}
-.fa-spotify:before {
- content: "\f1bc";
-}
-.fa-deviantart:before {
- content: "\f1bd";
-}
-.fa-soundcloud:before {
- content: "\f1be";
-}
-.fa-database:before {
- content: "\f1c0";
-}
-.fa-file-pdf-o:before {
- content: "\f1c1";
-}
-.fa-file-word-o:before {
- content: "\f1c2";
-}
-.fa-file-excel-o:before {
- content: "\f1c3";
-}
-.fa-file-powerpoint-o:before {
- content: "\f1c4";
-}
-.fa-file-photo-o:before,
-.fa-file-picture-o:before,
-.fa-file-image-o:before {
- content: "\f1c5";
-}
-.fa-file-zip-o:before,
-.fa-file-archive-o:before {
- content: "\f1c6";
-}
-.fa-file-sound-o:before,
-.fa-file-audio-o:before {
- content: "\f1c7";
-}
-.fa-file-movie-o:before,
-.fa-file-video-o:before {
- content: "\f1c8";
-}
-.fa-file-code-o:before {
- content: "\f1c9";
-}
-.fa-vine:before {
- content: "\f1ca";
-}
-.fa-codepen:before {
- content: "\f1cb";
-}
-.fa-jsfiddle:before {
- content: "\f1cc";
-}
-.fa-life-bouy:before,
-.fa-life-buoy:before,
-.fa-life-saver:before,
-.fa-support:before,
-.fa-life-ring:before {
- content: "\f1cd";
-}
-.fa-circle-o-notch:before {
- content: "\f1ce";
-}
-.fa-ra:before,
-.fa-rebel:before {
- content: "\f1d0";
-}
-.fa-ge:before,
-.fa-empire:before {
- content: "\f1d1";
-}
-.fa-git-square:before {
- content: "\f1d2";
-}
-.fa-git:before {
- content: "\f1d3";
-}
-.fa-y-combinator-square:before,
-.fa-yc-square:before,
-.fa-hacker-news:before {
- content: "\f1d4";
-}
-.fa-tencent-weibo:before {
- content: "\f1d5";
-}
-.fa-qq:before {
- content: "\f1d6";
-}
-.fa-wechat:before,
-.fa-weixin:before {
- content: "\f1d7";
-}
-.fa-send:before,
-.fa-paper-plane:before {
- content: "\f1d8";
-}
-.fa-send-o:before,
-.fa-paper-plane-o:before {
- content: "\f1d9";
-}
-.fa-history:before {
- content: "\f1da";
-}
-.fa-circle-thin:before {
- content: "\f1db";
-}
-.fa-header:before {
- content: "\f1dc";
-}
-.fa-paragraph:before {
- content: "\f1dd";
-}
-.fa-sliders:before {
- content: "\f1de";
-}
-.fa-share-alt:before {
- content: "\f1e0";
-}
-.fa-share-alt-square:before {
- content: "\f1e1";
-}
-.fa-bomb:before {
- content: "\f1e2";
-}
-.fa-soccer-ball-o:before,
-.fa-futbol-o:before {
- content: "\f1e3";
-}
-.fa-tty:before {
- content: "\f1e4";
-}
-.fa-binoculars:before {
- content: "\f1e5";
-}
-.fa-plug:before {
- content: "\f1e6";
-}
-.fa-slideshare:before {
- content: "\f1e7";
-}
-.fa-twitch:before {
- content: "\f1e8";
-}
-.fa-yelp:before {
- content: "\f1e9";
-}
-.fa-newspaper-o:before {
- content: "\f1ea";
-}
-.fa-wifi:before {
- content: "\f1eb";
-}
-.fa-calculator:before {
- content: "\f1ec";
-}
-.fa-paypal:before {
- content: "\f1ed";
-}
-.fa-google-wallet:before {
- content: "\f1ee";
-}
-.fa-cc-visa:before {
- content: "\f1f0";
-}
-.fa-cc-mastercard:before {
- content: "\f1f1";
-}
-.fa-cc-discover:before {
- content: "\f1f2";
-}
-.fa-cc-amex:before {
- content: "\f1f3";
-}
-.fa-cc-paypal:before {
- content: "\f1f4";
-}
-.fa-cc-stripe:before {
- content: "\f1f5";
-}
-.fa-bell-slash:before {
- content: "\f1f6";
-}
-.fa-bell-slash-o:before {
- content: "\f1f7";
-}
-.fa-trash:before {
- content: "\f1f8";
-}
-.fa-copyright:before {
- content: "\f1f9";
-}
-.fa-at:before {
- content: "\f1fa";
-}
-.fa-eyedropper:before {
- content: "\f1fb";
-}
-.fa-paint-brush:before {
- content: "\f1fc";
-}
-.fa-birthday-cake:before {
- content: "\f1fd";
-}
-.fa-area-chart:before {
- content: "\f1fe";
-}
-.fa-pie-chart:before {
- content: "\f200";
-}
-.fa-line-chart:before {
- content: "\f201";
-}
-.fa-lastfm:before {
- content: "\f202";
-}
-.fa-lastfm-square:before {
- content: "\f203";
-}
-.fa-toggle-off:before {
- content: "\f204";
-}
-.fa-toggle-on:before {
- content: "\f205";
-}
-.fa-bicycle:before {
- content: "\f206";
-}
-.fa-bus:before {
- content: "\f207";
-}
-.fa-ioxhost:before {
- content: "\f208";
-}
-.fa-angellist:before {
- content: "\f209";
-}
-.fa-cc:before {
- content: "\f20a";
-}
-.fa-shekel:before,
-.fa-sheqel:before,
-.fa-ils:before {
- content: "\f20b";
-}
-.fa-meanpath:before {
- content: "\f20c";
-}
-.fa-buysellads:before {
- content: "\f20d";
-}
-.fa-connectdevelop:before {
- content: "\f20e";
-}
-.fa-dashcube:before {
- content: "\f210";
-}
-.fa-forumbee:before {
- content: "\f211";
-}
-.fa-leanpub:before {
- content: "\f212";
-}
-.fa-sellsy:before {
- content: "\f213";
-}
-.fa-shirtsinbulk:before {
- content: "\f214";
-}
-.fa-simplybuilt:before {
- content: "\f215";
-}
-.fa-skyatlas:before {
- content: "\f216";
-}
-.fa-cart-plus:before {
- content: "\f217";
-}
-.fa-cart-arrow-down:before {
- content: "\f218";
-}
-.fa-diamond:before {
- content: "\f219";
-}
-.fa-ship:before {
- content: "\f21a";
-}
-.fa-user-secret:before {
- content: "\f21b";
-}
-.fa-motorcycle:before {
- content: "\f21c";
-}
-.fa-street-view:before {
- content: "\f21d";
-}
-.fa-heartbeat:before {
- content: "\f21e";
-}
-.fa-venus:before {
- content: "\f221";
-}
-.fa-mars:before {
- content: "\f222";
-}
-.fa-mercury:before {
- content: "\f223";
-}
-.fa-intersex:before,
-.fa-transgender:before {
- content: "\f224";
-}
-.fa-transgender-alt:before {
- content: "\f225";
-}
-.fa-venus-double:before {
- content: "\f226";
-}
-.fa-mars-double:before {
- content: "\f227";
-}
-.fa-venus-mars:before {
- content: "\f228";
-}
-.fa-mars-stroke:before {
- content: "\f229";
-}
-.fa-mars-stroke-v:before {
- content: "\f22a";
-}
-.fa-mars-stroke-h:before {
- content: "\f22b";
-}
-.fa-neuter:before {
- content: "\f22c";
-}
-.fa-genderless:before {
- content: "\f22d";
-}
-.fa-facebook-official:before {
- content: "\f230";
-}
-.fa-pinterest-p:before {
- content: "\f231";
-}
-.fa-whatsapp:before {
- content: "\f232";
-}
-.fa-server:before {
- content: "\f233";
-}
-.fa-user-plus:before {
- content: "\f234";
-}
-.fa-user-times:before {
- content: "\f235";
-}
-.fa-hotel:before,
-.fa-bed:before {
- content: "\f236";
-}
-.fa-viacoin:before {
- content: "\f237";
-}
-.fa-train:before {
- content: "\f238";
-}
-.fa-subway:before {
- content: "\f239";
-}
-.fa-medium:before {
- content: "\f23a";
-}
-.fa-yc:before,
-.fa-y-combinator:before {
- content: "\f23b";
-}
-.fa-optin-monster:before {
- content: "\f23c";
-}
-.fa-opencart:before {
- content: "\f23d";
-}
-.fa-expeditedssl:before {
- content: "\f23e";
-}
-.fa-battery-4:before,
-.fa-battery-full:before {
- content: "\f240";
-}
-.fa-battery-3:before,
-.fa-battery-three-quarters:before {
- content: "\f241";
-}
-.fa-battery-2:before,
-.fa-battery-half:before {
- content: "\f242";
-}
-.fa-battery-1:before,
-.fa-battery-quarter:before {
- content: "\f243";
-}
-.fa-battery-0:before,
-.fa-battery-empty:before {
- content: "\f244";
-}
-.fa-mouse-pointer:before {
- content: "\f245";
-}
-.fa-i-cursor:before {
- content: "\f246";
-}
-.fa-object-group:before {
- content: "\f247";
-}
-.fa-object-ungroup:before {
- content: "\f248";
-}
-.fa-sticky-note:before {
- content: "\f249";
-}
-.fa-sticky-note-o:before {
- content: "\f24a";
-}
-.fa-cc-jcb:before {
- content: "\f24b";
-}
-.fa-cc-diners-club:before {
- content: "\f24c";
-}
-.fa-clone:before {
- content: "\f24d";
-}
-.fa-balance-scale:before {
- content: "\f24e";
-}
-.fa-hourglass-o:before {
- content: "\f250";
-}
-.fa-hourglass-1:before,
-.fa-hourglass-start:before {
- content: "\f251";
-}
-.fa-hourglass-2:before,
-.fa-hourglass-half:before {
- content: "\f252";
-}
-.fa-hourglass-3:before,
-.fa-hourglass-end:before {
- content: "\f253";
-}
-.fa-hourglass:before {
- content: "\f254";
-}
-.fa-hand-grab-o:before,
-.fa-hand-rock-o:before {
- content: "\f255";
-}
-.fa-hand-stop-o:before,
-.fa-hand-paper-o:before {
- content: "\f256";
-}
-.fa-hand-scissors-o:before {
- content: "\f257";
-}
-.fa-hand-lizard-o:before {
- content: "\f258";
-}
-.fa-hand-spock-o:before {
- content: "\f259";
-}
-.fa-hand-pointer-o:before {
- content: "\f25a";
-}
-.fa-hand-peace-o:before {
- content: "\f25b";
-}
-.fa-trademark:before {
- content: "\f25c";
-}
-.fa-registered:before {
- content: "\f25d";
-}
-.fa-creative-commons:before {
- content: "\f25e";
-}
-.fa-gg:before {
- content: "\f260";
-}
-.fa-gg-circle:before {
- content: "\f261";
-}
-.fa-tripadvisor:before {
- content: "\f262";
-}
-.fa-odnoklassniki:before {
- content: "\f263";
-}
-.fa-odnoklassniki-square:before {
- content: "\f264";
-}
-.fa-get-pocket:before {
- content: "\f265";
-}
-.fa-wikipedia-w:before {
- content: "\f266";
-}
-.fa-safari:before {
- content: "\f267";
-}
-.fa-chrome:before {
- content: "\f268";
-}
-.fa-firefox:before {
- content: "\f269";
-}
-.fa-opera:before {
- content: "\f26a";
-}
-.fa-internet-explorer:before {
- content: "\f26b";
-}
-.fa-tv:before,
-.fa-television:before {
- content: "\f26c";
-}
-.fa-contao:before {
- content: "\f26d";
-}
-.fa-500px:before {
- content: "\f26e";
-}
-.fa-amazon:before {
- content: "\f270";
-}
-.fa-calendar-plus-o:before {
- content: "\f271";
-}
-.fa-calendar-minus-o:before {
- content: "\f272";
-}
-.fa-calendar-times-o:before {
- content: "\f273";
-}
-.fa-calendar-check-o:before {
- content: "\f274";
-}
-.fa-industry:before {
- content: "\f275";
-}
-.fa-map-pin:before {
- content: "\f276";
-}
-.fa-map-signs:before {
- content: "\f277";
-}
-.fa-map-o:before {
- content: "\f278";
-}
-.fa-map:before {
- content: "\f279";
-}
-.fa-commenting:before {
- content: "\f27a";
-}
-.fa-commenting-o:before {
- content: "\f27b";
-}
-.fa-houzz:before {
- content: "\f27c";
-}
-.fa-vimeo:before {
- content: "\f27d";
-}
-.fa-black-tie:before {
- content: "\f27e";
-}
-.fa-fonticons:before {
- content: "\f280";
-}
-.fa-reddit-alien:before {
- content: "\f281";
-}
-.fa-edge:before {
- content: "\f282";
-}
-.fa-credit-card-alt:before {
- content: "\f283";
-}
-.fa-codiepie:before {
- content: "\f284";
-}
-.fa-modx:before {
- content: "\f285";
-}
-.fa-fort-awesome:before {
- content: "\f286";
-}
-.fa-usb:before {
- content: "\f287";
-}
-.fa-product-hunt:before {
- content: "\f288";
-}
-.fa-mixcloud:before {
- content: "\f289";
-}
-.fa-scribd:before {
- content: "\f28a";
-}
-.fa-pause-circle:before {
- content: "\f28b";
-}
-.fa-pause-circle-o:before {
- content: "\f28c";
-}
-.fa-stop-circle:before {
- content: "\f28d";
-}
-.fa-stop-circle-o:before {
- content: "\f28e";
-}
-.fa-shopping-bag:before {
- content: "\f290";
-}
-.fa-shopping-basket:before {
- content: "\f291";
-}
-.fa-hashtag:before {
- content: "\f292";
-}
-.fa-bluetooth:before {
- content: "\f293";
-}
-.fa-bluetooth-b:before {
- content: "\f294";
-}
-.fa-percent:before {
- content: "\f295";
-}
diff --git a/tpl/default/css/font-awesome.min.css b/tpl/default/css/font-awesome.min.css
deleted file mode 100644
index d0603cb..0000000
--- a/tpl/default/css/font-awesome.min.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/*!
- * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
- * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.5.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}
diff --git a/tpl/default/css/grids-responsive.css b/tpl/default/css/grids-responsive.css
deleted file mode 100644
index dc9f771..0000000
--- a/tpl/default/css/grids-responsive.css
+++ /dev/null
@@ -1,861 +0,0 @@
-/*!
-Pure v0.6.0
-Copyright 2014 Yahoo! Inc. All rights reserved.
-Licensed under the BSD License.
-https://github.com/yahoo/pure/blob/master/LICENSE.md
-*/
-@media screen and (min-width: 35.5em) {
- .pure-u-sm-1,
- .pure-u-sm-1-1,
- .pure-u-sm-1-2,
- .pure-u-sm-1-3,
- .pure-u-sm-2-3,
- .pure-u-sm-1-4,
- .pure-u-sm-3-4,
- .pure-u-sm-1-5,
- .pure-u-sm-2-5,
- .pure-u-sm-3-5,
- .pure-u-sm-4-5,
- .pure-u-sm-5-5,
- .pure-u-sm-1-6,
- .pure-u-sm-5-6,
- .pure-u-sm-1-8,
- .pure-u-sm-3-8,
- .pure-u-sm-5-8,
- .pure-u-sm-7-8,
- .pure-u-sm-1-12,
- .pure-u-sm-5-12,
- .pure-u-sm-7-12,
- .pure-u-sm-11-12,
- .pure-u-sm-1-24,
- .pure-u-sm-2-24,
- .pure-u-sm-3-24,
- .pure-u-sm-4-24,
- .pure-u-sm-5-24,
- .pure-u-sm-6-24,
- .pure-u-sm-7-24,
- .pure-u-sm-8-24,
- .pure-u-sm-9-24,
- .pure-u-sm-10-24,
- .pure-u-sm-11-24,
- .pure-u-sm-12-24,
- .pure-u-sm-13-24,
- .pure-u-sm-14-24,
- .pure-u-sm-15-24,
- .pure-u-sm-16-24,
- .pure-u-sm-17-24,
- .pure-u-sm-18-24,
- .pure-u-sm-19-24,
- .pure-u-sm-20-24,
- .pure-u-sm-21-24,
- .pure-u-sm-22-24,
- .pure-u-sm-23-24,
- .pure-u-sm-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
- }
-
- .pure-u-sm-1-24 {
- width: 4.1667%;
- *width: 4.1357%;
- }
-
- .pure-u-sm-1-12,
- .pure-u-sm-2-24 {
- width: 8.3333%;
- *width: 8.3023%;
- }
-
- .pure-u-sm-1-8,
- .pure-u-sm-3-24 {
- width: 12.5000%;
- *width: 12.4690%;
- }
-
- .pure-u-sm-1-6,
- .pure-u-sm-4-24 {
- width: 16.6667%;
- *width: 16.6357%;
- }
-
- .pure-u-sm-1-5 {
- width: 20%;
- *width: 19.9690%;
- }
-
- .pure-u-sm-5-24 {
- width: 20.8333%;
- *width: 20.8023%;
- }
-
- .pure-u-sm-1-4,
- .pure-u-sm-6-24 {
- width: 25%;
- *width: 24.9690%;
- }
-
- .pure-u-sm-7-24 {
- width: 29.1667%;
- *width: 29.1357%;
- }
-
- .pure-u-sm-1-3,
- .pure-u-sm-8-24 {
- width: 33.3333%;
- *width: 33.3023%;
- }
-
- .pure-u-sm-3-8,
- .pure-u-sm-9-24 {
- width: 37.5000%;
- *width: 37.4690%;
- }
-
- .pure-u-sm-2-5 {
- width: 40%;
- *width: 39.9690%;
- }
-
- .pure-u-sm-5-12,
- .pure-u-sm-10-24 {
- width: 41.6667%;
- *width: 41.6357%;
- }
-
- .pure-u-sm-11-24 {
- width: 45.8333%;
- *width: 45.8023%;
- }
-
- .pure-u-sm-1-2,
- .pure-u-sm-12-24 {
- width: 50%;
- *width: 49.9690%;
- }
-
- .pure-u-sm-13-24 {
- width: 54.1667%;
- *width: 54.1357%;
- }
-
- .pure-u-sm-7-12,
- .pure-u-sm-14-24 {
- width: 58.3333%;
- *width: 58.3023%;
- }
-
- .pure-u-sm-3-5 {
- width: 60%;
- *width: 59.9690%;
- }
-
- .pure-u-sm-5-8,
- .pure-u-sm-15-24 {
- width: 62.5000%;
- *width: 62.4690%;
- }
-
- .pure-u-sm-2-3,
- .pure-u-sm-16-24 {
- width: 66.6667%;
- *width: 66.6357%;
- }
-
- .pure-u-sm-17-24 {
- width: 70.8333%;
- *width: 70.8023%;
- }
-
- .pure-u-sm-3-4,
- .pure-u-sm-18-24 {
- width: 75%;
- *width: 74.9690%;
- }
-
- .pure-u-sm-19-24 {
- width: 79.1667%;
- *width: 79.1357%;
- }
-
- .pure-u-sm-4-5 {
- width: 80%;
- *width: 79.9690%;
- }
-
- .pure-u-sm-5-6,
- .pure-u-sm-20-24 {
- width: 83.3333%;
- *width: 83.3023%;
- }
-
- .pure-u-sm-7-8,
- .pure-u-sm-21-24 {
- width: 87.5000%;
- *width: 87.4690%;
- }
-
- .pure-u-sm-11-12,
- .pure-u-sm-22-24 {
- width: 91.6667%;
- *width: 91.6357%;
- }
-
- .pure-u-sm-23-24 {
- width: 95.8333%;
- *width: 95.8023%;
- }
-
- .pure-u-sm-1,
- .pure-u-sm-1-1,
- .pure-u-sm-5-5,
- .pure-u-sm-24-24 {
- width: 100%;
- }
-}
-
-@media screen and (min-width: 48em) {
- .pure-u-md-1,
- .pure-u-md-1-1,
- .pure-u-md-1-2,
- .pure-u-md-1-3,
- .pure-u-md-2-3,
- .pure-u-md-1-4,
- .pure-u-md-3-4,
- .pure-u-md-1-5,
- .pure-u-md-2-5,
- .pure-u-md-3-5,
- .pure-u-md-4-5,
- .pure-u-md-5-5,
- .pure-u-md-1-6,
- .pure-u-md-5-6,
- .pure-u-md-1-8,
- .pure-u-md-3-8,
- .pure-u-md-5-8,
- .pure-u-md-7-8,
- .pure-u-md-1-12,
- .pure-u-md-5-12,
- .pure-u-md-7-12,
- .pure-u-md-11-12,
- .pure-u-md-1-24,
- .pure-u-md-2-24,
- .pure-u-md-3-24,
- .pure-u-md-4-24,
- .pure-u-md-5-24,
- .pure-u-md-6-24,
- .pure-u-md-7-24,
- .pure-u-md-8-24,
- .pure-u-md-9-24,
- .pure-u-md-10-24,
- .pure-u-md-11-24,
- .pure-u-md-12-24,
- .pure-u-md-13-24,
- .pure-u-md-14-24,
- .pure-u-md-15-24,
- .pure-u-md-16-24,
- .pure-u-md-17-24,
- .pure-u-md-18-24,
- .pure-u-md-19-24,
- .pure-u-md-20-24,
- .pure-u-md-21-24,
- .pure-u-md-22-24,
- .pure-u-md-23-24,
- .pure-u-md-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
- }
-
- .pure-u-md-1-24 {
- width: 4.1667%;
- *width: 4.1357%;
- }
-
- .pure-u-md-1-12,
- .pure-u-md-2-24 {
- width: 8.3333%;
- *width: 8.3023%;
- }
-
- .pure-u-md-1-8,
- .pure-u-md-3-24 {
- width: 12.5000%;
- *width: 12.4690%;
- }
-
- .pure-u-md-1-6,
- .pure-u-md-4-24 {
- width: 16.6667%;
- *width: 16.6357%;
- }
-
- .pure-u-md-1-5 {
- width: 20%;
- *width: 19.9690%;
- }
-
- .pure-u-md-5-24 {
- width: 20.8333%;
- *width: 20.8023%;
- }
-
- .pure-u-md-1-4,
- .pure-u-md-6-24 {
- width: 25%;
- *width: 24.9690%;
- }
-
- .pure-u-md-7-24 {
- width: 29.1667%;
- *width: 29.1357%;
- }
-
- .pure-u-md-1-3,
- .pure-u-md-8-24 {
- width: 33.3333%;
- *width: 33.3023%;
- }
-
- .pure-u-md-3-8,
- .pure-u-md-9-24 {
- width: 37.5000%;
- *width: 37.4690%;
- }
-
- .pure-u-md-2-5 {
- width: 40%;
- *width: 39.9690%;
- }
-
- .pure-u-md-5-12,
- .pure-u-md-10-24 {
- width: 41.6667%;
- *width: 41.6357%;
- }
-
- .pure-u-md-11-24 {
- width: 45.8333%;
- *width: 45.8023%;
- }
-
- .pure-u-md-1-2,
- .pure-u-md-12-24 {
- width: 50%;
- *width: 49.9690%;
- }
-
- .pure-u-md-13-24 {
- width: 54.1667%;
- *width: 54.1357%;
- }
-
- .pure-u-md-7-12,
- .pure-u-md-14-24 {
- width: 58.3333%;
- *width: 58.3023%;
- }
-
- .pure-u-md-3-5 {
- width: 60%;
- *width: 59.9690%;
- }
-
- .pure-u-md-5-8,
- .pure-u-md-15-24 {
- width: 62.5000%;
- *width: 62.4690%;
- }
-
- .pure-u-md-2-3,
- .pure-u-md-16-24 {
- width: 66.6667%;
- *width: 66.6357%;
- }
-
- .pure-u-md-17-24 {
- width: 70.8333%;
- *width: 70.8023%;
- }
-
- .pure-u-md-3-4,
- .pure-u-md-18-24 {
- width: 75%;
- *width: 74.9690%;
- }
-
- .pure-u-md-19-24 {
- width: 79.1667%;
- *width: 79.1357%;
- }
-
- .pure-u-md-4-5 {
- width: 80%;
- *width: 79.9690%;
- }
-
- .pure-u-md-5-6,
- .pure-u-md-20-24 {
- width: 83.3333%;
- *width: 83.3023%;
- }
-
- .pure-u-md-7-8,
- .pure-u-md-21-24 {
- width: 87.5000%;
- *width: 87.4690%;
- }
-
- .pure-u-md-11-12,
- .pure-u-md-22-24 {
- width: 91.6667%;
- *width: 91.6357%;
- }
-
- .pure-u-md-23-24 {
- width: 95.8333%;
- *width: 95.8023%;
- }
-
- .pure-u-md-1,
- .pure-u-md-1-1,
- .pure-u-md-5-5,
- .pure-u-md-24-24 {
- width: 100%;
- }
-}
-
-@media screen and (min-width: 64em) {
- .pure-u-lg-1,
- .pure-u-lg-1-1,
- .pure-u-lg-1-2,
- .pure-u-lg-1-3,
- .pure-u-lg-2-3,
- .pure-u-lg-1-4,
- .pure-u-lg-3-4,
- .pure-u-lg-1-5,
- .pure-u-lg-2-5,
- .pure-u-lg-3-5,
- .pure-u-lg-4-5,
- .pure-u-lg-5-5,
- .pure-u-lg-1-6,
- .pure-u-lg-5-6,
- .pure-u-lg-1-8,
- .pure-u-lg-3-8,
- .pure-u-lg-5-8,
- .pure-u-lg-7-8,
- .pure-u-lg-1-12,
- .pure-u-lg-5-12,
- .pure-u-lg-7-12,
- .pure-u-lg-11-12,
- .pure-u-lg-1-24,
- .pure-u-lg-2-24,
- .pure-u-lg-3-24,
- .pure-u-lg-4-24,
- .pure-u-lg-5-24,
- .pure-u-lg-6-24,
- .pure-u-lg-7-24,
- .pure-u-lg-8-24,
- .pure-u-lg-9-24,
- .pure-u-lg-10-24,
- .pure-u-lg-11-24,
- .pure-u-lg-12-24,
- .pure-u-lg-13-24,
- .pure-u-lg-14-24,
- .pure-u-lg-15-24,
- .pure-u-lg-16-24,
- .pure-u-lg-17-24,
- .pure-u-lg-18-24,
- .pure-u-lg-19-24,
- .pure-u-lg-20-24,
- .pure-u-lg-21-24,
- .pure-u-lg-22-24,
- .pure-u-lg-23-24,
- .pure-u-lg-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
- }
-
- .pure-u-lg-1-24 {
- width: 4.1667%;
- *width: 4.1357%;
- }
-
- .pure-u-lg-1-12,
- .pure-u-lg-2-24 {
- width: 8.3333%;
- *width: 8.3023%;
- }
-
- .pure-u-lg-1-8,
- .pure-u-lg-3-24 {
- width: 12.5000%;
- *width: 12.4690%;
- }
-
- .pure-u-lg-1-6,
- .pure-u-lg-4-24 {
- width: 16.6667%;
- *width: 16.6357%;
- }
-
- .pure-u-lg-1-5 {
- width: 20%;
- *width: 19.9690%;
- }
-
- .pure-u-lg-5-24 {
- width: 20.8333%;
- *width: 20.8023%;
- }
-
- .pure-u-lg-1-4,
- .pure-u-lg-6-24 {
- width: 25%;
- *width: 24.9690%;
- }
-
- .pure-u-lg-7-24 {
- width: 29.1667%;
- *width: 29.1357%;
- }
-
- .pure-u-lg-1-3,
- .pure-u-lg-8-24 {
- width: 33.3333%;
- *width: 33.3023%;
- }
-
- .pure-u-lg-3-8,
- .pure-u-lg-9-24 {
- width: 37.5000%;
- *width: 37.4690%;
- }
-
- .pure-u-lg-2-5 {
- width: 40%;
- *width: 39.9690%;
- }
-
- .pure-u-lg-5-12,
- .pure-u-lg-10-24 {
- width: 41.6667%;
- *width: 41.6357%;
- }
-
- .pure-u-lg-11-24 {
- width: 45.8333%;
- *width: 45.8023%;
- }
-
- .pure-u-lg-1-2,
- .pure-u-lg-12-24 {
- width: 50%;
- *width: 49.9690%;
- }
-
- .pure-u-lg-13-24 {
- width: 54.1667%;
- *width: 54.1357%;
- }
-
- .pure-u-lg-7-12,
- .pure-u-lg-14-24 {
- width: 58.3333%;
- *width: 58.3023%;
- }
-
- .pure-u-lg-3-5 {
- width: 60%;
- *width: 59.9690%;
- }
-
- .pure-u-lg-5-8,
- .pure-u-lg-15-24 {
- width: 62.5000%;
- *width: 62.4690%;
- }
-
- .pure-u-lg-2-3,
- .pure-u-lg-16-24 {
- width: 66.6667%;
- *width: 66.6357%;
- }
-
- .pure-u-lg-17-24 {
- width: 70.8333%;
- *width: 70.8023%;
- }
-
- .pure-u-lg-3-4,
- .pure-u-lg-18-24 {
- width: 75%;
- *width: 74.9690%;
- }
-
- .pure-u-lg-19-24 {
- width: 79.1667%;
- *width: 79.1357%;
- }
-
- .pure-u-lg-4-5 {
- width: 80%;
- *width: 79.9690%;
- }
-
- .pure-u-lg-5-6,
- .pure-u-lg-20-24 {
- width: 83.3333%;
- *width: 83.3023%;
- }
-
- .pure-u-lg-7-8,
- .pure-u-lg-21-24 {
- width: 87.5000%;
- *width: 87.4690%;
- }
-
- .pure-u-lg-11-12,
- .pure-u-lg-22-24 {
- width: 91.6667%;
- *width: 91.6357%;
- }
-
- .pure-u-lg-23-24 {
- width: 95.8333%;
- *width: 95.8023%;
- }
-
- .pure-u-lg-1,
- .pure-u-lg-1-1,
- .pure-u-lg-5-5,
- .pure-u-lg-24-24 {
- width: 100%;
- }
-}
-
-@media screen and (min-width: 80em) {
- .pure-u-xl-1,
- .pure-u-xl-1-1,
- .pure-u-xl-1-2,
- .pure-u-xl-1-3,
- .pure-u-xl-2-3,
- .pure-u-xl-1-4,
- .pure-u-xl-3-4,
- .pure-u-xl-1-5,
- .pure-u-xl-2-5,
- .pure-u-xl-3-5,
- .pure-u-xl-4-5,
- .pure-u-xl-5-5,
- .pure-u-xl-1-6,
- .pure-u-xl-5-6,
- .pure-u-xl-1-8,
- .pure-u-xl-3-8,
- .pure-u-xl-5-8,
- .pure-u-xl-7-8,
- .pure-u-xl-1-12,
- .pure-u-xl-5-12,
- .pure-u-xl-7-12,
- .pure-u-xl-11-12,
- .pure-u-xl-1-24,
- .pure-u-xl-2-24,
- .pure-u-xl-3-24,
- .pure-u-xl-4-24,
- .pure-u-xl-5-24,
- .pure-u-xl-6-24,
- .pure-u-xl-7-24,
- .pure-u-xl-8-24,
- .pure-u-xl-9-24,
- .pure-u-xl-10-24,
- .pure-u-xl-11-24,
- .pure-u-xl-12-24,
- .pure-u-xl-13-24,
- .pure-u-xl-14-24,
- .pure-u-xl-15-24,
- .pure-u-xl-16-24,
- .pure-u-xl-17-24,
- .pure-u-xl-18-24,
- .pure-u-xl-19-24,
- .pure-u-xl-20-24,
- .pure-u-xl-21-24,
- .pure-u-xl-22-24,
- .pure-u-xl-23-24,
- .pure-u-xl-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
- }
-
- .pure-u-xl-1-24 {
- width: 4.1667%;
- *width: 4.1357%;
- }
-
- .pure-u-xl-1-12,
- .pure-u-xl-2-24 {
- width: 8.3333%;
- *width: 8.3023%;
- }
-
- .pure-u-xl-1-8,
- .pure-u-xl-3-24 {
- width: 12.5000%;
- *width: 12.4690%;
- }
-
- .pure-u-xl-1-6,
- .pure-u-xl-4-24 {
- width: 16.6667%;
- *width: 16.6357%;
- }
-
- .pure-u-xl-1-5 {
- width: 20%;
- *width: 19.9690%;
- }
-
- .pure-u-xl-5-24 {
- width: 20.8333%;
- *width: 20.8023%;
- }
-
- .pure-u-xl-1-4,
- .pure-u-xl-6-24 {
- width: 25%;
- *width: 24.9690%;
- }
-
- .pure-u-xl-7-24 {
- width: 29.1667%;
- *width: 29.1357%;
- }
-
- .pure-u-xl-1-3,
- .pure-u-xl-8-24 {
- width: 33.3333%;
- *width: 33.3023%;
- }
-
- .pure-u-xl-3-8,
- .pure-u-xl-9-24 {
- width: 37.5000%;
- *width: 37.4690%;
- }
-
- .pure-u-xl-2-5 {
- width: 40%;
- *width: 39.9690%;
- }
-
- .pure-u-xl-5-12,
- .pure-u-xl-10-24 {
- width: 41.6667%;
- *width: 41.6357%;
- }
-
- .pure-u-xl-11-24 {
- width: 45.8333%;
- *width: 45.8023%;
- }
-
- .pure-u-xl-1-2,
- .pure-u-xl-12-24 {
- width: 50%;
- *width: 49.9690%;
- }
-
- .pure-u-xl-13-24 {
- width: 54.1667%;
- *width: 54.1357%;
- }
-
- .pure-u-xl-7-12,
- .pure-u-xl-14-24 {
- width: 58.3333%;
- *width: 58.3023%;
- }
-
- .pure-u-xl-3-5 {
- width: 60%;
- *width: 59.9690%;
- }
-
- .pure-u-xl-5-8,
- .pure-u-xl-15-24 {
- width: 62.5000%;
- *width: 62.4690%;
- }
-
- .pure-u-xl-2-3,
- .pure-u-xl-16-24 {
- width: 66.6667%;
- *width: 66.6357%;
- }
-
- .pure-u-xl-17-24 {
- width: 70.8333%;
- *width: 70.8023%;
- }
-
- .pure-u-xl-3-4,
- .pure-u-xl-18-24 {
- width: 75%;
- *width: 74.9690%;
- }
-
- .pure-u-xl-19-24 {
- width: 79.1667%;
- *width: 79.1357%;
- }
-
- .pure-u-xl-4-5 {
- width: 80%;
- *width: 79.9690%;
- }
-
- .pure-u-xl-5-6,
- .pure-u-xl-20-24 {
- width: 83.3333%;
- *width: 83.3023%;
- }
-
- .pure-u-xl-7-8,
- .pure-u-xl-21-24 {
- width: 87.5000%;
- *width: 87.4690%;
- }
-
- .pure-u-xl-11-12,
- .pure-u-xl-22-24 {
- width: 91.6667%;
- *width: 91.6357%;
- }
-
- .pure-u-xl-23-24 {
- width: 95.8333%;
- *width: 95.8023%;
- }
-
- .pure-u-xl-1,
- .pure-u-xl-1-1,
- .pure-u-xl-5-5,
- .pure-u-xl-24-24 {
- width: 100%;
- }
-}
\ No newline at end of file
diff --git a/tpl/default/css/grids-responsive.min.css b/tpl/default/css/grids-responsive.min.css
deleted file mode 100644
index 1df05db..0000000
--- a/tpl/default/css/grids-responsive.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
-Pure v0.6.0
-Copyright 2014 Yahoo! Inc. All rights reserved.
-Licensed under the BSD License.
-https://github.com/yahoo/pure/blob/master/LICENSE.md
-*/
-@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-2,.pure-u-sm-1-3,.pure-u-sm-2-3,.pure-u-sm-1-4,.pure-u-sm-3-4,.pure-u-sm-1-5,.pure-u-sm-2-5,.pure-u-sm-3-5,.pure-u-sm-4-5,.pure-u-sm-5-5,.pure-u-sm-1-6,.pure-u-sm-5-6,.pure-u-sm-1-8,.pure-u-sm-3-8,.pure-u-sm-5-8,.pure-u-sm-7-8,.pure-u-sm-1-12,.pure-u-sm-5-12,.pure-u-sm-7-12,.pure-u-sm-11-12,.pure-u-sm-1-24,.pure-u-sm-2-24,.pure-u-sm-3-24,.pure-u-sm-4-24,.pure-u-sm-5-24,.pure-u-sm-6-24,.pure-u-sm-7-24,.pure-u-sm-8-24,.pure-u-sm-9-24,.pure-u-sm-10-24,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%;*width:4.1357%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%;*width:8.3023%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%;*width:12.469%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%;*width:16.6357%}.pure-u-sm-1-5{width:20%;*width:19.969%}.pure-u-sm-5-24{width:20.8333%;*width:20.8023%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%;*width:24.969%}.pure-u-sm-7-24{width:29.1667%;*width:29.1357%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%;*width:33.3023%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%;*width:37.469%}.pure-u-sm-2-5{width:40%;*width:39.969%}.pure-u-sm-5-12,.pure-u-sm-10-24{width:41.6667%;*width:41.6357%}.pure-u-sm-11-24{width:45.8333%;*width:45.8023%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%;*width:49.969%}.pure-u-sm-13-24{width:54.1667%;*width:54.1357%}.pure-u-sm-7-12,.pure-u-sm-14-24{width:58.3333%;*width:58.3023%}.pure-u-sm-3-5{width:60%;*width:59.969%}.pure-u-sm-5-8,.pure-u-sm-15-24{width:62.5%;*width:62.469%}.pure-u-sm-2-3,.pure-u-sm-16-24{width:66.6667%;*width:66.6357%}.pure-u-sm-17-24{width:70.8333%;*width:70.8023%}.pure-u-sm-3-4,.pure-u-sm-18-24{width:75%;*width:74.969%}.pure-u-sm-19-24{width:79.1667%;*width:79.1357%}.pure-u-sm-4-5{width:80%;*width:79.969%}.pure-u-sm-5-6,.pure-u-sm-20-24{width:83.3333%;*width:83.3023%}.pure-u-sm-7-8,.pure-u-sm-21-24{width:87.5%;*width:87.469%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%;*width:91.6357%}.pure-u-sm-23-24{width:95.8333%;*width:95.8023%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-5-5,.pure-u-sm-24-24{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-2,.pure-u-md-1-3,.pure-u-md-2-3,.pure-u-md-1-4,.pure-u-md-3-4,.pure-u-md-1-5,.pure-u-md-2-5,.pure-u-md-3-5,.pure-u-md-4-5,.pure-u-md-5-5,.pure-u-md-1-6,.pure-u-md-5-6,.pure-u-md-1-8,.pure-u-md-3-8,.pure-u-md-5-8,.pure-u-md-7-8,.pure-u-md-1-12,.pure-u-md-5-12,.pure-u-md-7-12,.pure-u-md-11-12,.pure-u-md-1-24,.pure-u-md-2-24,.pure-u-md-3-24,.pure-u-md-4-24,.pure-u-md-5-24,.pure-u-md-6-24,.pure-u-md-7-24,.pure-u-md-8-24,.pure-u-md-9-24,.pure-u-md-10-24,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%;*width:4.1357%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%;*width:8.3023%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%;*width:12.469%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%;*width:16.6357%}.pure-u-md-1-5{width:20%;*width:19.969%}.pure-u-md-5-24{width:20.8333%;*width:20.8023%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%;*width:24.969%}.pure-u-md-7-24{width:29.1667%;*width:29.1357%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%;*width:33.3023%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%;*width:37.469%}.pure-u-md-2-5{width:40%;*width:39.969%}.pure-u-md-5-12,.pure-u-md-10-24{width:41.6667%;*width:41.6357%}.pure-u-md-11-24{width:45.8333%;*width:45.8023%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%;*width:49.969%}.pure-u-md-13-24{width:54.1667%;*width:54.1357%}.pure-u-md-7-12,.pure-u-md-14-24{width:58.3333%;*width:58.3023%}.pure-u-md-3-5{width:60%;*width:59.969%}.pure-u-md-5-8,.pure-u-md-15-24{width:62.5%;*width:62.469%}.pure-u-md-2-3,.pure-u-md-16-24{width:66.6667%;*width:66.6357%}.pure-u-md-17-24{width:70.8333%;*width:70.8023%}.pure-u-md-3-4,.pure-u-md-18-24{width:75%;*width:74.969%}.pure-u-md-19-24{width:79.1667%;*width:79.1357%}.pure-u-md-4-5{width:80%;*width:79.969%}.pure-u-md-5-6,.pure-u-md-20-24{width:83.3333%;*width:83.3023%}.pure-u-md-7-8,.pure-u-md-21-24{width:87.5%;*width:87.469%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%;*width:91.6357%}.pure-u-md-23-24{width:95.8333%;*width:95.8023%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-5-5,.pure-u-md-24-24{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-2,.pure-u-lg-1-3,.pure-u-lg-2-3,.pure-u-lg-1-4,.pure-u-lg-3-4,.pure-u-lg-1-5,.pure-u-lg-2-5,.pure-u-lg-3-5,.pure-u-lg-4-5,.pure-u-lg-5-5,.pure-u-lg-1-6,.pure-u-lg-5-6,.pure-u-lg-1-8,.pure-u-lg-3-8,.pure-u-lg-5-8,.pure-u-lg-7-8,.pure-u-lg-1-12,.pure-u-lg-5-12,.pure-u-lg-7-12,.pure-u-lg-11-12,.pure-u-lg-1-24,.pure-u-lg-2-24,.pure-u-lg-3-24,.pure-u-lg-4-24,.pure-u-lg-5-24,.pure-u-lg-6-24,.pure-u-lg-7-24,.pure-u-lg-8-24,.pure-u-lg-9-24,.pure-u-lg-10-24,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%;*width:4.1357%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%;*width:8.3023%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%;*width:12.469%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%;*width:16.6357%}.pure-u-lg-1-5{width:20%;*width:19.969%}.pure-u-lg-5-24{width:20.8333%;*width:20.8023%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%;*width:24.969%}.pure-u-lg-7-24{width:29.1667%;*width:29.1357%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%;*width:33.3023%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%;*width:37.469%}.pure-u-lg-2-5{width:40%;*width:39.969%}.pure-u-lg-5-12,.pure-u-lg-10-24{width:41.6667%;*width:41.6357%}.pure-u-lg-11-24{width:45.8333%;*width:45.8023%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%;*width:49.969%}.pure-u-lg-13-24{width:54.1667%;*width:54.1357%}.pure-u-lg-7-12,.pure-u-lg-14-24{width:58.3333%;*width:58.3023%}.pure-u-lg-3-5{width:60%;*width:59.969%}.pure-u-lg-5-8,.pure-u-lg-15-24{width:62.5%;*width:62.469%}.pure-u-lg-2-3,.pure-u-lg-16-24{width:66.6667%;*width:66.6357%}.pure-u-lg-17-24{width:70.8333%;*width:70.8023%}.pure-u-lg-3-4,.pure-u-lg-18-24{width:75%;*width:74.969%}.pure-u-lg-19-24{width:79.1667%;*width:79.1357%}.pure-u-lg-4-5{width:80%;*width:79.969%}.pure-u-lg-5-6,.pure-u-lg-20-24{width:83.3333%;*width:83.3023%}.pure-u-lg-7-8,.pure-u-lg-21-24{width:87.5%;*width:87.469%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%;*width:91.6357%}.pure-u-lg-23-24{width:95.8333%;*width:95.8023%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-5-5,.pure-u-lg-24-24{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-2,.pure-u-xl-1-3,.pure-u-xl-2-3,.pure-u-xl-1-4,.pure-u-xl-3-4,.pure-u-xl-1-5,.pure-u-xl-2-5,.pure-u-xl-3-5,.pure-u-xl-4-5,.pure-u-xl-5-5,.pure-u-xl-1-6,.pure-u-xl-5-6,.pure-u-xl-1-8,.pure-u-xl-3-8,.pure-u-xl-5-8,.pure-u-xl-7-8,.pure-u-xl-1-12,.pure-u-xl-5-12,.pure-u-xl-7-12,.pure-u-xl-11-12,.pure-u-xl-1-24,.pure-u-xl-2-24,.pure-u-xl-3-24,.pure-u-xl-4-24,.pure-u-xl-5-24,.pure-u-xl-6-24,.pure-u-xl-7-24,.pure-u-xl-8-24,.pure-u-xl-9-24,.pure-u-xl-10-24,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%;*width:4.1357%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%;*width:8.3023%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%;*width:12.469%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%;*width:16.6357%}.pure-u-xl-1-5{width:20%;*width:19.969%}.pure-u-xl-5-24{width:20.8333%;*width:20.8023%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%;*width:24.969%}.pure-u-xl-7-24{width:29.1667%;*width:29.1357%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%;*width:33.3023%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%;*width:37.469%}.pure-u-xl-2-5{width:40%;*width:39.969%}.pure-u-xl-5-12,.pure-u-xl-10-24{width:41.6667%;*width:41.6357%}.pure-u-xl-11-24{width:45.8333%;*width:45.8023%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%;*width:49.969%}.pure-u-xl-13-24{width:54.1667%;*width:54.1357%}.pure-u-xl-7-12,.pure-u-xl-14-24{width:58.3333%;*width:58.3023%}.pure-u-xl-3-5{width:60%;*width:59.969%}.pure-u-xl-5-8,.pure-u-xl-15-24{width:62.5%;*width:62.469%}.pure-u-xl-2-3,.pure-u-xl-16-24{width:66.6667%;*width:66.6357%}.pure-u-xl-17-24{width:70.8333%;*width:70.8023%}.pure-u-xl-3-4,.pure-u-xl-18-24{width:75%;*width:74.969%}.pure-u-xl-19-24{width:79.1667%;*width:79.1357%}.pure-u-xl-4-5{width:80%;*width:79.969%}.pure-u-xl-5-6,.pure-u-xl-20-24{width:83.3333%;*width:83.3023%}.pure-u-xl-7-8,.pure-u-xl-21-24{width:87.5%;*width:87.469%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%;*width:91.6357%}.pure-u-xl-23-24{width:95.8333%;*width:95.8023%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-5-5,.pure-u-xl-24-24{width:100%}}
\ No newline at end of file
diff --git a/tpl/default/css/pure-extras.css b/tpl/default/css/pure-extras.css
deleted file mode 100644
index d72fc94..0000000
--- a/tpl/default/css/pure-extras.css
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Images */
-.pure-img-eliptical {
- border-radius: 80%;
-}
-.pure-img-rounded {
- border-radius: 3px;
-}
-.pure-img-bordered {
- background-color: #FFFFFF;
- border: 1px solid rgba(0, 0, 0, 0.2);
- padding: 5px;
-}
-
-
-/* Thumbnails */
-.pure-thumbnails li {
- text-align: center;
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
- *zoom: 1;
- vertical-align: top;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- padding: 0.5em;
-}
-.pure-thumbnails {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.pure-thumbnails a:focus {
- outline: 0 none;
-}
-
-.pure-thumb {
- display: block;
- text-decoration: none;
- color: inherit;
-}
-.pure-thumb img {
- max-width: 100%;
- margin-right: auto;
- margin-left: auto;
- vertical-align: middle; /* this will remove a thin line below the image */
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.pure-thumb-bordered {
- border: 1px solid rgba(0, 0, 0, 0.2);
-}
-.pure-thumb .caption {
- text-align: left;
- display: block;
- margin: 0 5px 6px;
-
-}
-.pure-thumb .caption p {
- margin: 0.3em 0 0;
- font-size: 75%;
-}
-.pure-thumb .caption .caption-head {
- font-weight: bold;
- margin-top: 0.3em;
-}
-
-.pure-thumb-eliptical img {
- border-radius: 50%;
-}
-.pure-thumb-rounded img {
- border-radius: 3px;
-}
-
-/* Badges/Pills */
-.pure-badge,
-.pure-badge-error,
-.pure-badge-warning,
-.pure-badge-success,
-.pure-badge-info,
-.pure-badge-inverse {
- padding: 0.35em 0.9em 0.35em;
- background-color: #9D988E;
- color: #fff;
- display: inline-block;
- font-size: 11.844px;
- font-weight: bold;
- line-height: 1.2em;
- vertical-align: baseline;
- white-space: nowrap;
- border-radius: 20px;
- margin: 0.2em;
-}
-.pure-badge-error {
- background-color: #D13C38;
-}
-.pure-badge-warning {
- background-color: #E78C05;
-}
-.pure-badge-success {
- background-color: rgb(83, 180, 79);
-}
-.pure-badge-info {
- background-color: rgb(18, 169, 218);
-}
-.pure-badge-inverse {
- background-color: #4D370C;
-}
-
-/* Alerts */
-.pure-alert {
- position: relative;
- margin-bottom: 1em;
- padding: 1em;
- background: #ccc;
- border-radius: 3px;
-}
-
-.pure-alert label {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
- *zoom: 1;
- white-space: nowrap;
-}
-
-.pure-alert {
- background-color: rgb(209, 235, 238);
- color: rgb(102, 131, 145);
-}
-.pure-alert-error {
- background-color: #D13C38;
- color: #fff;
-}
-
-.pure-alert-warning {
- background-color: rgb(250, 191, 103);
- color: rgb(151, 96, 13);
-}
-
-.pure-alert-success {
- background-color: rgb(83, 180, 79);
- color: #fff;
-}
-
-
-/* Contextual Modals */
-
-.pure-popover {
- position: relative;
- width: 300px;
- background-color: #f0f1f3;
- color: #2f3034;
- padding: 15px;
- border: 1px solid #bfc0c8;
- border-radius: 2px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- box-padding: border-box;
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding;
- background-clip: padding-box;
-}
-
-.pure-arrow-border, .pure-arrow {
- border-style: solid;
- border-width: 10px;
- height:0;
- width:0;
- position:absolute;
-}
-
-
-/* POPOVER ARROW POSITIONING BOTTOM */
-
-.pure-popover.bottom .pure-arrow-border {
- border-color: #bfc0c8 transparent transparent transparent;
- bottom: -20px;
- left: 50%;
-}
-.pure-popover.bottom .pure-arrow {
- border-color: #f0f1f3 transparent transparent transparent;
- bottom:-19px;
- left: 50%;
-}
-
-/* POPOVER ARROW POSITIONING TOP*/
-
-.pure-popover.top .pure-arrow-border {
- border-color: transparent transparent #bfc0c8 transparent;
- top: -21px;
- left: 50%;
-}
-.pure-popover.top .pure-arrow {
- border-color: transparent transparent #f0f1f3 transparent;
- top:-20px;
- left: 50%;
-}
-
-/* POPOVER ARROW POSITIONING RIGHT*/
-
-.pure-popover.right .pure-arrow-border {
- border-color: transparent transparent transparent #bfc0c8;
- top: 45%;
- right: -21px;
-}
-.pure-popover.right .pure-arrow {
- border-color: transparent transparent transparent #f0f1f3;
- top:45%;
- right: -20px;
-}
-
-
-/* POPOVER ARROW POSITIONING LEFT*/
-
-.pure-popover.left .pure-arrow-border {
- border-color: transparent #bfc0c8 transparent transparent;
- top: 45%;
- left: -21px;
-}
-.pure-popover.left .pure-arrow {
- border-color: transparent #f0f1f3 transparent transparent;
- top:45%;
- left: -20px;
-}
-
-
-/* BUTTON IMPROVEMENTS */
-.pure-button-block {
- display: block;
-}
-.pure-button-small {
- padding: .6em 2em .65em;
- font-size:70%;
-}
-.pure-button-large {
- padding: .8em 5em .9em;
- font-size:110%;
-}
-.pure-button-selected {
- background-color: #345fcb;
- color: #fff;
-}
-.pure-button-secondary {
- background: rgb(161, 195, 238);
- color: rgb(26, 88, 122);
-}
-.pure-button-error {
- background: rgb(214, 86, 75);
- color: white;
-}
-.pure-button-success {
- background: rgb(54, 197, 71);
- color: white;
-}
-.pure-button-warning {
- background: rgb(255, 163, 0);
- color: white;
-}
-
diff --git a/tpl/default/css/pure.css b/tpl/default/css/pure.css
deleted file mode 100644
index a07d74c..0000000
--- a/tpl/default/css/pure.css
+++ /dev/null
@@ -1,1475 +0,0 @@
-/*!
-Pure v0.6.0
-Copyright 2014 Yahoo! Inc. All rights reserved.
-Licensed under the BSD License.
-https://github.com/yahoo/pure/blob/master/LICENSE.md
-*/
-/*!
-normalize.css v^3.0 | MIT License | git.io/normalize
-Copyright (c) Nicolas Gallagher and Jonathan Neal
-*/
-/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
- */
-
-audio,
-canvas,
-progress,
-video {
- display: inline-block; /* 1 */
- vertical-align: baseline; /* 2 */
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
- */
-
-[hidden],
-template {
- display: none;
-}
-
-/* Links
- ========================================================================== */
-
-/**
- * Remove the gray background color from active links in IE 10.
- */
-
-a {
- background-color: transparent;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* Text-level semantics
- ========================================================================== */
-
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* Grouping content
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-
-figure {
- margin: 1em 40px;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Contain overflow in all browsers.
- */
-
-pre {
- overflow: auto;
-}
-
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-/* Forms
- ========================================================================== */
-
-/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-
-/**
- * 1. Correct color not being inherited.
- * Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
- color: inherit; /* 1 */
- font: inherit; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
- */
-
-button {
- overflow: visible;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-input {
- line-height: normal;
-}
-
-/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
- */
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
- */
-
-textarea {
- overflow: auto;
-}
-
-/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
- */
-
-optgroup {
- font-weight: bold;
-}
-
-/* Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-td,
-th {
- padding: 0;
-}
-
-/*csslint important:false*/
-
-/* ==========================================================================
- Pure Base Extras
- ========================================================================== */
-
-/**
- * Extra rules that Pure adds on top of Normalize.css
- */
-
-/**
- * Always hide an element when it has the `hidden` HTML attribute.
- */
-
-.hidden,
-[hidden] {
- display: none !important;
-}
-
-/**
- * Add this class to an image to make it fit within it's fluid parent wrapper while maintaining
- * aspect ratio.
- */
-.pure-img {
- max-width: 100%;
- height: auto;
- display: block;
-}
-
-/*csslint regex-selectors:false, known-properties:false, duplicate-properties:false*/
-
-.pure-g {
- letter-spacing: -0.31em; /* Webkit: collapse white-space between units */
- *letter-spacing: normal; /* reset IE < 8 */
- *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */
- text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */
-
- /*
- Sets the font stack to fonts known to work properly with the above letter
- and word spacings. See: https://github.com/yahoo/pure/issues/41/
-
- The following font stack makes Pure Grids work on all known environments.
-
- * FreeSans: Ships with many Linux distros, including Ubuntu
-
- * Arimo: Ships with Chrome OS. Arimo has to be defined before Helvetica and
- Arial to get picked up by the browser, even though neither is available
- in Chrome OS.
-
- * Droid Sans: Ships with all versions of Android.
-
- * Helvetica, Arial, sans-serif: Common font stack on OS X and Windows.
- */
- font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif;
-
- /*
- Use flexbox when possible to avoid `letter-spacing` side-effects.
-
- NOTE: Firefox (as of 25) does not currently support flex-wrap, so the
- `-moz-` prefix version is omitted.
- */
-
- display: -webkit-flex;
- -webkit-flex-flow: row wrap;
-
- /* IE10 uses display: flexbox */
- display: -ms-flexbox;
- -ms-flex-flow: row wrap;
-
- /* Prevents distributing space between rows */
- -ms-align-content: flex-start;
- -webkit-align-content: flex-start;
- align-content: flex-start;
-}
-
-/* Opera as of 12 on Windows needs word-spacing.
- The ".opera-only" selector is used to prevent actual prefocus styling
- and is not required in markup.
-*/
-.opera-only :-o-prefocus,
-.pure-g {
- word-spacing: -0.43em;
-}
-
-.pure-u {
- display: inline-block;
- *display: inline; /* IE < 8: fake inline-block */
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
-}
-
-/*
-Resets the font family back to the OS/browser's default sans-serif font,
-this the same font stack that Normalize.css sets for the `body`.
-*/
-.pure-g [class *= "pure-u"] {
- font-family: sans-serif;
-}
-
-.pure-u-1,
-.pure-u-1-1,
-.pure-u-1-2,
-.pure-u-1-3,
-.pure-u-2-3,
-.pure-u-1-4,
-.pure-u-3-4,
-.pure-u-1-5,
-.pure-u-2-5,
-.pure-u-3-5,
-.pure-u-4-5,
-.pure-u-5-5,
-.pure-u-1-6,
-.pure-u-5-6,
-.pure-u-1-8,
-.pure-u-3-8,
-.pure-u-5-8,
-.pure-u-7-8,
-.pure-u-1-12,
-.pure-u-5-12,
-.pure-u-7-12,
-.pure-u-11-12,
-.pure-u-1-24,
-.pure-u-2-24,
-.pure-u-3-24,
-.pure-u-4-24,
-.pure-u-5-24,
-.pure-u-6-24,
-.pure-u-7-24,
-.pure-u-8-24,
-.pure-u-9-24,
-.pure-u-10-24,
-.pure-u-11-24,
-.pure-u-12-24,
-.pure-u-13-24,
-.pure-u-14-24,
-.pure-u-15-24,
-.pure-u-16-24,
-.pure-u-17-24,
-.pure-u-18-24,
-.pure-u-19-24,
-.pure-u-20-24,
-.pure-u-21-24,
-.pure-u-22-24,
-.pure-u-23-24,
-.pure-u-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto;
-}
-
-.pure-u-1-24 {
- width: 4.1667%;
- *width: 4.1357%;
-}
-
-.pure-u-1-12,
-.pure-u-2-24 {
- width: 8.3333%;
- *width: 8.3023%;
-}
-
-.pure-u-1-8,
-.pure-u-3-24 {
- width: 12.5000%;
- *width: 12.4690%;
-}
-
-.pure-u-1-6,
-.pure-u-4-24 {
- width: 16.6667%;
- *width: 16.6357%;
-}
-
-.pure-u-1-5 {
- width: 20%;
- *width: 19.9690%;
-}
-
-.pure-u-5-24 {
- width: 20.8333%;
- *width: 20.8023%;
-}
-
-.pure-u-1-4,
-.pure-u-6-24 {
- width: 25%;
- *width: 24.9690%;
-}
-
-.pure-u-7-24 {
- width: 29.1667%;
- *width: 29.1357%;
-}
-
-.pure-u-1-3,
-.pure-u-8-24 {
- width: 33.3333%;
- *width: 33.3023%;
-}
-
-.pure-u-3-8,
-.pure-u-9-24 {
- width: 37.5000%;
- *width: 37.4690%;
-}
-
-.pure-u-2-5 {
- width: 40%;
- *width: 39.9690%;
-}
-
-.pure-u-5-12,
-.pure-u-10-24 {
- width: 41.6667%;
- *width: 41.6357%;
-}
-
-.pure-u-11-24 {
- width: 45.8333%;
- *width: 45.8023%;
-}
-
-.pure-u-1-2,
-.pure-u-12-24 {
- width: 50%;
- *width: 49.9690%;
-}
-
-.pure-u-13-24 {
- width: 54.1667%;
- *width: 54.1357%;
-}
-
-.pure-u-7-12,
-.pure-u-14-24 {
- width: 58.3333%;
- *width: 58.3023%;
-}
-
-.pure-u-3-5 {
- width: 60%;
- *width: 59.9690%;
-}
-
-.pure-u-5-8,
-.pure-u-15-24 {
- width: 62.5000%;
- *width: 62.4690%;
-}
-
-.pure-u-2-3,
-.pure-u-16-24 {
- width: 66.6667%;
- *width: 66.6357%;
-}
-
-.pure-u-17-24 {
- width: 70.8333%;
- *width: 70.8023%;
-}
-
-.pure-u-3-4,
-.pure-u-18-24 {
- width: 75%;
- *width: 74.9690%;
-}
-
-.pure-u-19-24 {
- width: 79.1667%;
- *width: 79.1357%;
-}
-
-.pure-u-4-5 {
- width: 80%;
- *width: 79.9690%;
-}
-
-.pure-u-5-6,
-.pure-u-20-24 {
- width: 83.3333%;
- *width: 83.3023%;
-}
-
-.pure-u-7-8,
-.pure-u-21-24 {
- width: 87.5000%;
- *width: 87.4690%;
-}
-
-.pure-u-11-12,
-.pure-u-22-24 {
- width: 91.6667%;
- *width: 91.6357%;
-}
-
-.pure-u-23-24 {
- width: 95.8333%;
- *width: 95.8023%;
-}
-
-.pure-u-1,
-.pure-u-1-1,
-.pure-u-5-5,
-.pure-u-24-24 {
- width: 100%;
-}
-.pure-button {
- /* Structure */
- display: inline-block;
- zoom: 1;
- line-height: normal;
- white-space: nowrap;
- vertical-align: middle;
- text-align: center;
- cursor: pointer;
- -webkit-user-drag: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-/* Firefox: Get rid of the inner focus border */
-.pure-button::-moz-focus-inner {
- padding: 0;
- border: 0;
-}
-
-/*csslint outline-none:false*/
-
-.pure-button {
- font-family: inherit;
- font-size: 100%;
- padding: 0.5em 1em;
- color: #444; /* rgba not supported (IE 8) */
- color: rgba(0, 0, 0, 0.80); /* rgba supported */
- border: 1px solid #999; /*IE 6/7/8*/
- border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
- background-color: #E6E6E6;
- text-decoration: none;
- border-radius: 2px;
-}
-
-.pure-button-hover,
-.pure-button:hover,
-.pure-button:focus {
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000',GradientType=0);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10)));
- background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
- background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.10));
- background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
- background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
-}
-.pure-button:focus {
- outline: 0;
-}
-.pure-button-active,
-.pure-button:active {
- box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
- border-color: #000\9;
-}
-
-.pure-button[disabled],
-.pure-button-disabled,
-.pure-button-disabled:hover,
-.pure-button-disabled:focus,
-.pure-button-disabled:active {
- border: none;
- background-image: none;
- filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
- filter: alpha(opacity=40);
- -khtml-opacity: 0.40;
- -moz-opacity: 0.40;
- opacity: 0.40;
- cursor: not-allowed;
- box-shadow: none;
-}
-
-.pure-button-hidden {
- display: none;
-}
-
-/* Firefox: Get rid of the inner focus border */
-.pure-button::-moz-focus-inner{
- padding: 0;
- border: 0;
-}
-
-.pure-button-primary,
-.pure-button-selected,
-a.pure-button-primary,
-a.pure-button-selected {
- background-color: rgb(0, 120, 231);
- color: #fff;
-}
-
-/*csslint box-model:false*/
-/*
-Box-model set to false because we're setting a height on select elements, which
-also have border and padding. This is done because some browsers don't render
-the padding. We explicitly set the box-model for select elements to border-box,
-so we can ignore the csslint warning.
-*/
-
-.pure-form input[type="text"],
-.pure-form input[type="password"],
-.pure-form input[type="email"],
-.pure-form input[type="url"],
-.pure-form input[type="date"],
-.pure-form input[type="month"],
-.pure-form input[type="time"],
-.pure-form input[type="datetime"],
-.pure-form input[type="datetime-local"],
-.pure-form input[type="week"],
-.pure-form input[type="number"],
-.pure-form input[type="search"],
-.pure-form input[type="tel"],
-.pure-form input[type="color"],
-.pure-form select,
-.pure-form textarea {
- padding: 0.5em 0.6em;
- display: inline-block;
- border: 1px solid #ccc;
- box-shadow: inset 0 1px 3px #ddd;
- border-radius: 4px;
- vertical-align: middle;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-/*
-Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
-since IE8 won't execute CSS that contains a CSS3 selector.
-*/
-.pure-form input:not([type]) {
- padding: 0.5em 0.6em;
- display: inline-block;
- border: 1px solid #ccc;
- box-shadow: inset 0 1px 3px #ddd;
- border-radius: 4px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-
-/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */
-/* May be able to remove this tweak as color inputs become more standardized across browsers. */
-.pure-form input[type="color"] {
- padding: 0.2em 0.5em;
-}
-
-
-.pure-form input[type="text"]:focus,
-.pure-form input[type="password"]:focus,
-.pure-form input[type="email"]:focus,
-.pure-form input[type="url"]:focus,
-.pure-form input[type="date"]:focus,
-.pure-form input[type="month"]:focus,
-.pure-form input[type="time"]:focus,
-.pure-form input[type="datetime"]:focus,
-.pure-form input[type="datetime-local"]:focus,
-.pure-form input[type="week"]:focus,
-.pure-form input[type="number"]:focus,
-.pure-form input[type="search"]:focus,
-.pure-form input[type="tel"]:focus,
-.pure-form input[type="color"]:focus,
-.pure-form select:focus,
-.pure-form textarea:focus {
- outline: 0;
- border-color: #129FEA;
-}
-
-/*
-Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
-since IE8 won't execute CSS that contains a CSS3 selector.
-*/
-.pure-form input:not([type]):focus {
- outline: 0;
- border-color: #129FEA;
-}
-
-.pure-form input[type="file"]:focus,
-.pure-form input[type="radio"]:focus,
-.pure-form input[type="checkbox"]:focus {
- outline: thin solid #129FEA;
- outline: 1px auto #129FEA;
-}
-.pure-form .pure-checkbox,
-.pure-form .pure-radio {
- margin: 0.5em 0;
- display: block;
-}
-
-.pure-form input[type="text"][disabled],
-.pure-form input[type="password"][disabled],
-.pure-form input[type="email"][disabled],
-.pure-form input[type="url"][disabled],
-.pure-form input[type="date"][disabled],
-.pure-form input[type="month"][disabled],
-.pure-form input[type="time"][disabled],
-.pure-form input[type="datetime"][disabled],
-.pure-form input[type="datetime-local"][disabled],
-.pure-form input[type="week"][disabled],
-.pure-form input[type="number"][disabled],
-.pure-form input[type="search"][disabled],
-.pure-form input[type="tel"][disabled],
-.pure-form input[type="color"][disabled],
-.pure-form select[disabled],
-.pure-form textarea[disabled] {
- cursor: not-allowed;
- background-color: #eaeded;
- color: #cad2d3;
-}
-
-/*
-Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
-since IE8 won't execute CSS that contains a CSS3 selector.
-*/
-.pure-form input:not([type])[disabled] {
- cursor: not-allowed;
- background-color: #eaeded;
- color: #cad2d3;
-}
-.pure-form input[readonly],
-.pure-form select[readonly],
-.pure-form textarea[readonly] {
- background-color: #eee; /* menu hover bg color */
- color: #777; /* menu text color */
- border-color: #ccc;
-}
-
-.pure-form input:focus:invalid,
-.pure-form textarea:focus:invalid,
-.pure-form select:focus:invalid {
- color: #b94a48;
- border-color: #e9322d;
-}
-.pure-form input[type="file"]:focus:invalid:focus,
-.pure-form input[type="radio"]:focus:invalid:focus,
-.pure-form input[type="checkbox"]:focus:invalid:focus {
- outline-color: #e9322d;
-}
-.pure-form select {
- /* Normalizes the height; padding is not sufficient. */
- height: 2.25em;
- border: 1px solid #ccc;
- background-color: white;
-}
-.pure-form select[multiple] {
- height: auto;
-}
-.pure-form label {
- margin: 0.5em 0 0.2em;
-}
-.pure-form fieldset {
- margin: 0;
- padding: 0.35em 0 0.75em;
- border: 0;
-}
-.pure-form legend {
- display: block;
- width: 100%;
- padding: 0.3em 0;
- margin-bottom: 0.3em;
- color: #333;
- border-bottom: 1px solid #e5e5e5;
-}
-
-.pure-form-stacked input[type="text"],
-.pure-form-stacked input[type="password"],
-.pure-form-stacked input[type="email"],
-.pure-form-stacked input[type="url"],
-.pure-form-stacked input[type="date"],
-.pure-form-stacked input[type="month"],
-.pure-form-stacked input[type="time"],
-.pure-form-stacked input[type="datetime"],
-.pure-form-stacked input[type="datetime-local"],
-.pure-form-stacked input[type="week"],
-.pure-form-stacked input[type="number"],
-.pure-form-stacked input[type="search"],
-.pure-form-stacked input[type="tel"],
-.pure-form-stacked input[type="color"],
-.pure-form-stacked input[type="file"],
-.pure-form-stacked select,
-.pure-form-stacked label,
-.pure-form-stacked textarea {
- display: block;
- margin: 0.25em 0;
-}
-
-/*
-Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
-since IE8 won't execute CSS that contains a CSS3 selector.
-*/
-.pure-form-stacked input:not([type]) {
- display: block;
- margin: 0.25em 0;
-}
-.pure-form-aligned input,
-.pure-form-aligned textarea,
-.pure-form-aligned select,
-/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
-.pure-form-aligned .pure-help-inline,
-.pure-form-message-inline {
- display: inline-block;
- *display: inline;
- *zoom: 1;
- vertical-align: middle;
-}
-.pure-form-aligned textarea {
- vertical-align: top;
-}
-
-/* Aligned Forms */
-.pure-form-aligned .pure-control-group {
- margin-bottom: 0.5em;
-}
-.pure-form-aligned .pure-control-group label {
- text-align: right;
- display: inline-block;
- vertical-align: middle;
- width: 10em;
- margin: 0 1em 0 0;
-}
-.pure-form-aligned .pure-controls {
- margin: 1.5em 0 0 11em;
-}
-
-/* Rounded Inputs */
-.pure-form input.pure-input-rounded,
-.pure-form .pure-input-rounded {
- border-radius: 2em;
- padding: 0.5em 1em;
-}
-
-/* Grouped Inputs */
-.pure-form .pure-group fieldset {
- margin-bottom: 10px;
-}
-.pure-form .pure-group input,
-.pure-form .pure-group textarea {
- display: block;
- padding: 10px;
- margin: 0 0 -1px;
- border-radius: 0;
- position: relative;
- top: -1px;
-}
-.pure-form .pure-group input:focus,
-.pure-form .pure-group textarea:focus {
- z-index: 3;
-}
-.pure-form .pure-group input:first-child,
-.pure-form .pure-group textarea:first-child {
- top: 1px;
- border-radius: 4px 4px 0 0;
- margin: 0;
-}
-.pure-form .pure-group input:first-child:last-child,
-.pure-form .pure-group textarea:first-child:last-child {
- top: 1px;
- border-radius: 4px;
- margin: 0;
-}
-.pure-form .pure-group input:last-child,
-.pure-form .pure-group textarea:last-child {
- top: -2px;
- border-radius: 0 0 4px 4px;
- margin: 0;
-}
-.pure-form .pure-group button {
- margin: 0.35em 0;
-}
-
-.pure-form .pure-input-1 {
- width: 100%;
-}
-.pure-form .pure-input-2-3 {
- width: 66%;
-}
-.pure-form .pure-input-1-2 {
- width: 50%;
-}
-.pure-form .pure-input-1-3 {
- width: 33%;
-}
-.pure-form .pure-input-1-4 {
- width: 25%;
-}
-
-/* Inline help for forms */
-/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
-.pure-form .pure-help-inline,
-.pure-form-message-inline {
- display: inline-block;
- padding-left: 0.3em;
- color: #666;
- vertical-align: middle;
- font-size: 0.875em;
-}
-
-/* Block help for forms */
-.pure-form-message {
- display: block;
- color: #666;
- font-size: 0.875em;
-}
-
-@media only screen and (max-width : 480px) {
- .pure-form button[type="submit"] {
- margin: 0.7em 0 0;
- }
-
- .pure-form input:not([type]),
- .pure-form input[type="text"],
- .pure-form input[type="password"],
- .pure-form input[type="email"],
- .pure-form input[type="url"],
- .pure-form input[type="date"],
- .pure-form input[type="month"],
- .pure-form input[type="time"],
- .pure-form input[type="datetime"],
- .pure-form input[type="datetime-local"],
- .pure-form input[type="week"],
- .pure-form input[type="number"],
- .pure-form input[type="search"],
- .pure-form input[type="tel"],
- .pure-form input[type="color"],
- .pure-form label {
- margin-bottom: 0.3em;
- display: block;
- }
-
- .pure-group input:not([type]),
- .pure-group input[type="text"],
- .pure-group input[type="password"],
- .pure-group input[type="email"],
- .pure-group input[type="url"],
- .pure-group input[type="date"],
- .pure-group input[type="month"],
- .pure-group input[type="time"],
- .pure-group input[type="datetime"],
- .pure-group input[type="datetime-local"],
- .pure-group input[type="week"],
- .pure-group input[type="number"],
- .pure-group input[type="search"],
- .pure-group input[type="tel"],
- .pure-group input[type="color"] {
- margin-bottom: 0;
- }
-
- .pure-form-aligned .pure-control-group label {
- margin-bottom: 0.3em;
- text-align: left;
- display: block;
- width: 100%;
- }
-
- .pure-form-aligned .pure-controls {
- margin: 1.5em 0 0 0;
- }
-
- /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
- .pure-form .pure-help-inline,
- .pure-form-message-inline,
- .pure-form-message {
- display: block;
- font-size: 0.75em;
- /* Increased bottom padding to make it group with its related input element. */
- padding: 0.2em 0 0.8em;
- }
-}
-
-/*csslint adjoining-classes: false, box-model:false*/
-.pure-menu {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.pure-menu-fixed {
- position: fixed;
- left: 0;
- top: 0;
- z-index: 3;
-}
-
-.pure-menu-list,
-.pure-menu-item {
- position: relative;
-}
-
-.pure-menu-list {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.pure-menu-item {
- padding: 0;
- margin: 0;
- height: 100%;
-}
-
-.pure-menu-link,
-.pure-menu-heading {
- display: block;
- text-decoration: none;
- white-space: nowrap;
-}
-
-/* HORIZONTAL MENU */
-.pure-menu-horizontal {
- width: 100%;
- white-space: nowrap;
-}
-
-.pure-menu-horizontal .pure-menu-list {
- display: inline-block;
-}
-
-/* Initial menus should be inline-block so that they are horizontal */
-.pure-menu-horizontal .pure-menu-item,
-.pure-menu-horizontal .pure-menu-heading,
-.pure-menu-horizontal .pure-menu-separator {
- display: inline-block;
- *display: inline;
- zoom: 1;
- vertical-align: middle;
-}
-
-/* Submenus should still be display: block; */
-.pure-menu-item .pure-menu-item {
- display: block;
-}
-
-.pure-menu-children {
- display: none;
- position: absolute;
- left: 100%;
- top: 0;
- margin: 0;
- padding: 0;
- z-index: 3;
-}
-
-.pure-menu-horizontal .pure-menu-children {
- left: 0;
- top: auto;
- width: inherit;
-}
-
-.pure-menu-allow-hover:hover > .pure-menu-children,
-.pure-menu-active > .pure-menu-children {
- display: block;
- position: absolute;
-}
-
-/* Vertical Menus - show the dropdown arrow */
-.pure-menu-has-children > .pure-menu-link:after {
- padding-left: 0.5em;
- content: "\25B8";
- font-size: small;
-}
-
-/* Horizontal Menus - show the dropdown arrow */
-.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after {
- content: "\25BE";
-}
-
-/* scrollable menus */
-.pure-menu-scrollable {
- overflow-y: scroll;
- overflow-x: hidden;
-}
-
-.pure-menu-scrollable .pure-menu-list {
- display: block;
-}
-
-.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list {
- display: inline-block;
-}
-
-.pure-menu-horizontal.pure-menu-scrollable {
- white-space: nowrap;
- overflow-y: hidden;
- overflow-x: auto;
- -ms-overflow-style: none;
- -webkit-overflow-scrolling: touch;
- /* a little extra padding for this style to allow for scrollbars */
- padding: .5em 0;
-}
-
-.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar {
- display: none;
-}
-
-/* misc default styling */
-
-.pure-menu-separator {
- background-color: #ccc;
- height: 1px;
- margin: .3em 0;
-}
-
-.pure-menu-horizontal .pure-menu-separator {
- width: 1px;
- height: 1.3em;
- margin: 0 .3em ;
-}
-
-.pure-menu-heading {
- text-transform: uppercase;
- color: #565d64;
-}
-
-.pure-menu-link {
- color: #777;
-}
-
-.pure-menu-children {
- background-color: #fff;
-}
-
-.pure-menu-link,
-.pure-menu-disabled,
-.pure-menu-heading {
- padding: .5em 1em;
-}
-
-.pure-menu-disabled {
- opacity: .5;
-}
-
-.pure-menu-disabled .pure-menu-link:hover {
- background-color: transparent;
-}
-
-.pure-menu-active > .pure-menu-link,
-.pure-menu-link:hover,
-.pure-menu-link:focus {
- background-color: #eee;
-}
-
-.pure-menu-selected .pure-menu-link,
-.pure-menu-selected .pure-menu-link:visited {
- color: #000;
-}
-
-.pure-table {
- /* Remove spacing between table cells (from Normalize.css) */
- border-collapse: collapse;
- border-spacing: 0;
- empty-cells: show;
- border: 1px solid #cbcbcb;
-}
-
-.pure-table caption {
- color: #000;
- font: italic 85%/1 arial, sans-serif;
- padding: 1em 0;
- text-align: center;
-}
-
-.pure-table td,
-.pure-table th {
- border-left: 1px solid #cbcbcb;/* inner column border */
- border-width: 0 0 0 1px;
- font-size: inherit;
- margin: 0;
- overflow: visible; /*to make ths where the title is really long work*/
- padding: 0.5em 1em; /* cell padding */
-}
-
-/* Consider removing this next declaration block, as it causes problems when
-there's a rowspan on the first cell. Case added to the tests. issue#432 */
-.pure-table td:first-child,
-.pure-table th:first-child {
- border-left-width: 0;
-}
-
-.pure-table thead {
- background-color: #e0e0e0;
- color: #000;
- text-align: left;
- vertical-align: bottom;
-}
-
-/*
-striping:
- even - #fff (white)
- odd - #f2f2f2 (light gray)
-*/
-.pure-table td {
- background-color: transparent;
-}
-.pure-table-odd td {
- background-color: #f2f2f2;
-}
-
-/* nth-child selector for modern browsers */
-.pure-table-striped tr:nth-child(2n-1) td {
- background-color: #f2f2f2;
-}
-
-/* BORDERED TABLES */
-.pure-table-bordered td {
- border-bottom: 1px solid #cbcbcb;
-}
-.pure-table-bordered tbody > tr:last-child > td {
- border-bottom-width: 0;
-}
-
-
-/* HORIZONTAL BORDERED TABLES */
-
-.pure-table-horizontal td,
-.pure-table-horizontal th {
- border-width: 0 0 1px 0;
- border-bottom: 1px solid #cbcbcb;
-}
-.pure-table-horizontal tbody > tr:last-child > td {
- border-bottom-width: 0;
-}
diff --git a/tpl/default/css/pure.min.css b/tpl/default/css/pure.min.css
deleted file mode 100644
index f0aa374..0000000
--- a/tpl/default/css/pure.min.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/*!
-Pure v0.6.0
-Copyright 2014 Yahoo! Inc. All rights reserved.
-Licensed under the BSD License.
-https://github.com/yahoo/pure/blob/master/LICENSE.md
-*/
-/*!
-normalize.css v^3.0 | MIT License | git.io/normalize
-Copyright (c) Nicolas Gallagher and Jonathan Neal
-*/
-/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap;-ms-align-content:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-list,.pure-menu-item{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-link,.pure-menu-heading{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-separator{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-allow-hover:hover>.pure-menu-children,.pure-menu-active>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-link,.pure-menu-disabled,.pure-menu-heading{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:hover,.pure-menu-link:focus{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}
\ No newline at end of file
diff --git a/tpl/default/css/shaarli.css b/tpl/default/css/shaarli.css
deleted file mode 100644
index 1443940..0000000
--- a/tpl/default/css/shaarli.css
+++ /dev/null
@@ -1,1348 +0,0 @@
-/**
- * General
- */
-body {
- background: #d0d0d0;
-}
-
-.strong {
- font-weight: bold;
-}
-
-.clear {
- clear: both;
-}
-
-.center {
- text-align: center;
- margin: auto;
-}
-
-.label {
- display: inline-block;
- padding: .25em .4em;
- font-size: 75%;
- font-weight: 700;
- line-height: 1;
- text-align: center;
- white-space: nowrap;
- vertical-align: baseline;
- border-radius: .25rem;
-}
-
-pre {
- max-width: 100%;
-}
-
-@font-face {
- font-family: 'Roboto';
- font-weight: 400;
- font-style: normal;
- src:
- local('Roboto'),
- local('Roboto-Regular'),
- url('../fonts/Roboto-Regular.woff2') format('woff2'),
- url('../fonts/Roboto-Regular.woff') format('woff');
-}
-
-@font-face {
- font-family: 'Roboto';
- font-weight: 700;
- font-style: normal;
- src:
- local('Roboto'),
- local('Roboto-Bold'),
- url('../fonts/Roboto-Bold.woff2') format('woff2'),
- url('../fonts/Roboto-Bold.woff') format('woff');
-}
-
-body, .pure-g [class*="pure-u"] {
- font-family: Roboto, Arial, sans-serif;
-}
-
-/**
- * Extends Pure grids responsive to hide items.
- * Use xx-0 to hide an item on xx screen.
- * Display it at any level with xx-visible.
- */
-.pure-u-0 { display: none !important; }
-@media screen and (min-width: 35.5em) {
- .pure-u-sm-0 { display: none !important; }
- .pure-u-sm-visible { display: inline-block !important; }
-}
-@media screen and (min-width: 48em) {
- .pure-u-md-0 { display: none !important; }
- .pure-u-md-visible { display: inline-block !important; }
-}
-@media screen and (min-width: 64em) {
- .pure-u-lg-0 { display: none !important; }
- .pure-u-lg-visible { display: inline-block !important; }
-}
-@media screen and (min-width: 80em) {
- .pure-u-xl-0 { display: none !important; }
- .pure-u-xl-visible { display: inline-block !important; }
-}
-
-/**
- * Make pure-extras alert closable.
- */
-.pure-alert-closable .fa-times {
- float: right;
-}
-.pure-alert-close {
- cursor: pointer;
-}
-
-.pure-alert-success {
- background-color: #1b926c;
-}
-
-.anchor:target {
- padding-top: 40px;
-}
-/**
- * MENU
- **/
-.shaarli-menu {
- position: fixed;
- top: 0;
- width: 100%;
- --height: 50px;
- background: #1b926c;
- -webkit-font-smoothing: antialiased;
- /* Hack to transition with auto height: http://stackoverflow.com/a/8331169/1484919 */
- max-height: 45px;
- transition: max-height 0.5s;
- overflow: hidden;
- z-index: 999;
-}
-
-/* Chrome bugfix: with 100% height, it only displays the first element. */
-.pure-menu-item {
- height: 45px;
-}
-
-.shaarli-menu.open {
- max-height: 500px;
- transition: max-height 0.75s;
-}
-
-.head-logo {
- float: left;
- margin: 0 5px 0 0;
-}
-
-.pure-menu-link,
-.pure-menu-link:visited,
-.pure-menu-selected .pure-menu-link,
-.pure-menu-selected .pure-menu-link:visited {
- padding: 0.8em 1em;
- color: #f5f5f5;
-}
-
-.pure-menu-link:hover, .pure-menu-link:focus,
-.pure-menu-selected .pure-menu-link:hover,
-.pure-menu-selected .pure-menu-link:focus {
- color: #fff;
- background: transparent;
-}
-
-.pure-menu-item:hover::after {
- margin: -4px auto 0 auto;
- display: block;
- content:"";
- background: #fff;
- height: 4px;
- width: 100%;
-}
-
-.menu-toggle {
- width: 34px;
- height: 45px;
- position: absolute;
- top: 5px;
- right: 0;
- display: none;
-}
-
-.menu-toggle .bar {
- background-color: #b0ddce;
- display: block;
- width: 20px;
- height: 2px;
- border-radius: 100px;
- position: absolute;
- top: 18px;
- right: 7px;
- transition: all 0.5s;
-}
-
-.menu-toggle .bar:first-child {
- transform: translateY(-6px);
-}
-
-.menu-toggle.x .bar {
- transform: rotate(45deg);
-}
-
-.menu-toggle.x .bar:first-child {
- transform: rotate(-45deg);
-}
-
-@media screen and (max-width: 64em) {
- .menu-toggle {
- display: block;
- }
-}
-
-.header-buttons {
- text-align: right;
-}
-
-.linkcount {
- color: #252525;
- font-size: 0.8em;
-}
-
-@media screen and (min-width: 64em) {
- .linkcount {
- position: absolute;
- right: 5px;
- }
-}
-
-#search, #search-linklist, #search-tagcloud {
- text-align: center;
- width: 100%;
-}
-
-#search input[type="text"], #search-linklist input[type="text"] {
- padding: 0 5px;
- height: 30px;
- width: 260px;
- background: #f5f5f5;
- border: medium none currentColor;
- box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 1px rgba(0, 0, 0, 0.298) inset;
- border-radius: 2px;
- color: #252525;
-}
-@media screen and (max-width: 64em) {
- .searchform {
- max-width: 260px;
- margin: 0 auto;
- }
-}
-
-/* because chrome */
-#search input[type="text"]::-webkit-input-placeholder,
-#search-linklist input[type="text"]::-webkit-input-placeholder {
- color: #777777;
-}
-
-#search button,
-#search-tagcloud button,
-#search-linklist button {
- padding: 4px 8px 6px 8px;
- background-color: #1B926C;
- color: #f5f5f5;
- border: none;
- border-radius: 2px;
-}
-
-#search-tagcloud button {
- width: 90%;
-}
-
-@media screen and (max-width: 64em) {
- #search-linklist button {
- width: 100%;
- }
- #search-linklist .awesomplete {
- margin: 5px 0;
- }
-}
-
-#search button:hover,
-#search-linklist button:hover,
-#search-tagcloud button:hover {
- color: #d0d0d0;
-}
-
-#search,
-#search-linklist {
- padding: 6px 0;
-}
-
-@media screen and (max-width: 64em) {
- #search, #search * {
- visibility: hidden;
- }
-}
-
-.subheader-form a.button {
- color: #f5f5f5;
- font-weight: bold;
- text-decoration: none;
- border: 2px solid #f5f5f5;
- border-radius: 5px;
- padding: 3px 10px;
-}
-
-.linklist-item-editbuttons .delete-checkbox {
- display: none;
-}
-
-#header-login-form input[type="text"], #header-login-form input[type="password"] {
- width: 200px;
-}
-
-/* because chrome */
-#header-login-form input[type="text"]::-webkit-input-placeholder,
-#header-login-form input[type="password"]::-webkit-input-placeholder {
- color: #777777;
-}
-
-.subheader-form {
- visibility: hidden;
- position: fixed;
- width: 100%;
- text-align: center;
- background: #1b926c;
- display: block;
- z-index: 999;
- height: 30px;
- padding: 5px 0;
-}
-
-@media screen and (min-width: 64em) {
- .subheader-form.open, .subheader-form.open * {
- visibility: visible;
- }
-}
-
-.subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me {
- padding: 5px 5px 3px 15px;
- height: 20px;
- width: 20%;
- background: #f5f5f5;
- border: medium none currentColor;
- border-radius: 2px;
- box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 4px rgba(0, 0, 0, 0.298) inset;
- color: #252525;
-}
-
-/* because chrome */
-.subheader-form input[type="text"]::-webkit-input-placeholder,
-.subheader-form input[type="password"]::-webkit-input-placeholder
-{
- color: #252525;
-}
-
-.subheader-form .remember-me {
- display: inline-block;
- width: auto;
- padding: 5px 20px 3px 20px;
- cursor: pointer;
-}
-
-.subheader-form .remember-me label, .subheader-form .remember-me input {
- cursor: pointer;
-}
-
-.subheader-form input[type="submit"] {
- display: inline-block;
- margin: 0 0 5px 0;
- padding: 4px 0 4px 0;
- height: 28px;
- width: 100px;
- background: #1b926c;
- border: 1px solid #f5f5f5;
- color: #f5f5f5;
- border-radius: 2px;
-}
-
-.subheader-form input[type="submit"]:hover {
- background: #f5f5f5;
- color: #1b926c;
-}
-
-.new-version-message {
- text-align: center;
-}
-
-.new-version-message a {
- color: rgb(151, 96, 13);
- font-weight: bold;
-}
-
-/**
- * CONTENT - GENERAL
- */
-#content {
- position: relative;
- z-index: 2;
- margin-top: 45px;
-}
-
-/**
- * Plugins additional forms
- */
-.toolbar-plugin {
- margin: 5px 0;
- text-align: center;
-}
-
-.toolbar-plugin input[type="text"] {
- padding: 0 5px;
- height: 30px;
- width: 300px;
- background: #f5f5f5;
- border: medium none currentColor;
- box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 1px rgba(0, 0, 0, 0.298) inset;
- border-radius: 2px;
- color: #252525;
-}
-
-/* because chrome */
-.toolbar-plugin input[type="text"]::-webkit-input-placeholder {
- color: #777777;
-}
-
-.toolbar-plugin input[type="submit"] {
- padding: 0 10px;
- height: 30px;
- background: #f5f5f5;
- border: medium none currentColor;
- border-radius: 2px;
- color: #252525;
-}
-
-.toolbar-plugin input[type="submit"]:hover {
- background: #fff;
-}
-
-@media screen and (max-width: 64em) {
- .toolbar-plugin input[type="text"] {
- width: 70%;
-
- }
-}
-
-/**
- * CONTENT - LINKLIST PAGING
- * 64em -> lg
- */
-.linklist-filters {
- margin: 5px 0;
- color: #252525;
- font-size: 0.9em;
-}
-
-.linklist-filters a {
- padding: 5px 8px;
- text-decoration: none;
-}
-
-.linklist-filters .filter-off {
- color: #252525;
- background: #f5f5f5;
-}
-
-.linklist-filters .filter-on {
- color: #b0ddce;
- background: #1b926c;
-}
-
-.linklist-pages {
- margin: 5px 0;
- color: #252525;
- text-align: center;
-}
-
-.linklist-pages a {
- color: #252525;
- text-decoration: none;
-}
-
-.linklist-pages a:hover {
- color: #fff;
-}
-
-.linksperpage {
- margin: 5px 0;
- text-align: right;
- color: #252525;
- font-size: 0.9em;
-}
-
-.linksperpage a {
- padding: 5px 5px;
- text-decoration: none;
- color: #252525;
- background: #f5f5f5;
-}
-
-.linksperpage a, .linksperpage input[type="text"] {
- display: inline-block;
- width: 20px;
- text-align: center;
-}
-
-.linksperpage form {
- display: inline;
-}
-
-.linksperpage input[type="text"] {
- height: 20px;
- margin: 0;
- padding: 4px 5px 3px 8px;
- background: #f5f5f5;
- border: medium none currentColor;
- color: #252525;
- font-size: 0.8em;
-}
-
-/**
- * CONTENT - LINKLIST ITEMS
- */
-.linklist-item {
- margin: 0 0 10px 0;
- background: #f5f5f5;
- box-shadow: 1px 1px 3px #797979;
-}
-
-.linklist-item-buttons {
- background: transparent;
- position: relative;
- width: 23px;
- z-index: 99;
-}
-
-.linklist-item-buttons-right {
- float: right;
- margin-right: -25px;
-}
-
-.linklist-item-buttons * {
- display: block;
- float: left;
- width:100%;
- margin: auto;
- text-align: center;
-}
-
-.linklist-item-title, .linklist-item-title h2 {
- margin: 0;
- word-wrap: break-word;
-}
-
-.linklist-item-title {
- position: relative;
- background: #f5f5f5;
-}
-
-.linklist-item-title h2 {
- padding: 3px 10px 0 10px;
- line-height: 30px;
-}
-
-.linklist-item-title h2 a {
- font-size: 0.7em;
- color: #252525;
- text-decoration: none;
- vertical-align: middle;
-}
-
-.linklist-item-title .linklist-link {
- font-size: 1.1em;
- color: #1b926c;
-}
-
-.linklist-item-title h2 a:visited .linklist-link {
- color: #2a4c41;
-}
-
-.linklist-item-title h2 a:hover, .linklist-item-title .linklist-link:hover{
- color: #252525;
-}
-
-
-.linklist-item-title .label-private {
- border: solid 1px #F89406;
- font-family: Arial, sans-serif;
- font-size: 0.65em;
- color: #F89406;
-}
-
-.fold-button {
- display: none;
- color: #252525;
-}
-
-.linklist-item-editbuttons {
- float: right;
- padding: 8px 5px;
-}
-
-.linklist-item-editbuttons * {
- display: block;
- float: left;
- margin: 0 1px;
-}
-
-.linklist-item-editbuttons a {
- font-size: 1em;
-}
-
-.edit-link {
- font-size: 1.2em;
- color: #0b5ea6;
-}
-
-.delete-link {
- font-size: 1.3em;
- color: #ac2925 !important;
-}
-
-.linklist-item-description {
- position: relative;
- padding: 0 10px;
- word-wrap: break-word;
- color: #252525;
- line-height: 1.3em;
-}
-
-.linklist-item-description a {
- text-decoration: none;
- color: #1b926c;
-}
-
-.linklist-item-description a:hover {
- color: #252525;
-}
-
-.linklist-item-description a:visited {
- color: #14553f;
-}
-
-.linklist-item-thumbnail {
- position: relative;
- padding: 0 0 0 5px;
- margin: 0;
- float: right;
- z-index: 50;
- height: 90px;
-}
-
-.linklist-item.private .linklist-item-title::before,
-.linklist-item.private .linklist-item-description::before {
- position: absolute;
- left: 3px;
- top: 0;
- display: block;
- content:"";
- background: #F89406;
- height: 96%;
- width: 2px;
- z-index: 1;
-}
-
-.linklist-item.private .linklist-item-description::before {
- height: 100%;
-}
-
-.linklist-item.private .linklist-item-title::before {
- margin-top: 3px;
-}
-
-.linklist-item-infos {
- padding: 4px 8px 4px 8px;
- background: #ddd;
- color: #252525;
-}
-
-.linklist-item-infos a {
- color: #252525;
- text-decoration: none;
-}
-
-.linklist-item-infos a:hover {
- color: #000;
-}
-
-.linklist-item-infos .linklist-item-tags {
- font-size: 0.8em;
-}
-
-.linklist-item-infos .label-tag {
- font-size: 1em;
-}
-
-.linklist-item-infos-dateblock {
- font-size: 0.9em;
-}
-
-.linklist-plugin-icon {
- width: 13px;
- height: 13px;
-}
-
-.linklist-item-infos-url {
- text-align: right;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- font-size: 0.8em;
- height:23px;
- line-height:23px;
-}
-
-.linklist-item-infos .mobile-buttons {
- text-align: right;
-}
-
-.linklist-item-infos .linklist-plugin-icon {
- display: inline-block;
- margin: 0 2px;
- width: 16px;
- height: 16px;
-}
-
-.linklist-item-infos-controls-group {
- display: inline-block;
- border-right: 1px solid #5d5d5d;
- padding-right: 6px;
-}
-
-.ctrl-edit {
- margin: 0 7px;
-}
-
-/** 64em -> lg **/
-@media screen and (max-width: 64em) {
- .linklist-item-infos-url {
- text-align: left;
- }
-}
-
-/**
- * Footer
- */
-#footer {
- margin: 20px 0;
- padding: 5px;
- text-align: center;
- color: #252525;
-}
-
-#footer:before {
- display: block;
- content:"";
- background: linear-gradient(to right, #949393, #252525, #949393);
- height: 1px;
- width: 80%;
- margin: 10px auto;
-}
-
-#footer a {
- color: #252525;
-}
-
-/**
- * PAGE FORM
- */
-.page-form {
- margin: 20px 0 0 0;
- background: #f5f5f5;
- box-shadow: 1px 1px 2px #797979;
- color: #252525;
- overflow: hidden;
-}
-
-.page-form .window-title {
- margin: 0 0 10px 0;
- padding: 10px 0;
- width: 100%;
- color: #1b926c;
- background: #f5f5f5;
- text-align: center;
-}
-
-.page-form .window-subtitle {
- text-align: center;
-}
-
-.page-form a {
- color: #1b926c;
- font-weight: bold;
- text-decoration: none;
-}
-
-.page-form p {
- padding: 5px 10px;
- margin: 0;
-}
-
-.page-form input[type="text"],
-.page-form input[type="password"],
-.page-form textarea {
- box-sizing: border-box;
- margin: 10px 0;
- padding: 5px 5px 3px 15px;
- height: 35px;
- width: 90%;
- background: #eeeeee;
- border: solid 1px #d8d8d8;
- border-radius: 2px;
- color: #252525;
-}
-
-.page-form textarea {
- min-height: 240px;
- padding: 15px 5px 3px 15px;
- resize: vertical;
- overflow-y: auto;
- word-wrap:break-word
-}
-
-/* because chrome */
-.page-form input[type="text"]::-webkit-input-placeholder,
-.page-form input[type="password"]::-webkit-input-placeholder {
- color: #777777;
-}
-
-.page-form input[type="submit"], .page-form a.button {
- margin: 15px 5px;
- height: 35px;
- line-height: 35px;
- width: 150px;
- background: #1b926c;
- color: #f5f5f5;
- border: none;
- box-shadow: 1px 1px 1px #ddd, -1px -1px 6px #ddd, -1px 1px 2px #ddd, 1px -1px 2px #ddd;
- font-size: 1.2em;
- text-decoration: none;
- vertical-align: center;
- font-weight: normal;
- display: inline-block;
-}
-
-
-.page-form .button.button-red {
- background: #ac2925;
-}
-
-.page-form .submit-buttons {
- margin-bottom: 10px;
-}
-
-@media screen and (min-width: 64em) {
- .page-form .submit-buttons {
- position: relative;
- }
-
- .page-form .submit-buttons .button.button-red {
- position: absolute;
- right: 5%;
- }
-}
-
-@media screen and (max-width: 64em) {
- .page-form .submit-buttons .button {
- display: block;
- margin: auto;
- }
-}
-
-.page-form select {
- color: #252525;
-}
-
-/**
- * PAGE FORM - LIGHT
- */
-.page-form-light div, .page-form-light p {
- text-align: center;
-}
-
-/**
- * PAGE FORM - COMPLETE
- */
-.page-form-complete {
- #background: #f5f5f5;
-}
-
-.page-form-complete div, .page-form-complete p {
- color: #252525;
-}
-
-.page-form-complete .form-label, .page-form-complete .form-input {
- position: relative;
- height: 60px;
-}
-
-.page-form-complete .form-label label,
-.page-form-complete .form-input input,
-.page-form-complete .form-input select.align,
-.page-form-complete .timezone {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
-}
-
-.page-form-complete .form-label label {
- text-align: right;
- right: 0;
- padding: 0 20px;
-}
-
-.page-form-complete .label-name {
- font-weight: bold;
-}
-
-.page-form-complete .label-desc {
- font-size: 0.8em;
-}
-
-.page-form-complete input[type="text"],
-.page-form-complete input[type="password"],
-.page-form-complete textarea {
- margin: 0;
-}
-
-.page-form section {
- margin: 10px 0 25px 0;
-}
-
-.page-form table {
- margin: auto;
- width: 90%;
-}
-
-.page-form table .order {
- text-decoration: none;
- color: #252525;
-}
-
-.page-form table, .page-form th, .page-form td {
- border-width: 1px 0;
- border-style: solid;
- border-color: #aaaaaa;
-}
-
-.page-form th, .page-form td {
- padding: 5px;
-
-}
-
-/* Awesomeplete fix */
-div.awesomplete {
- width: inherit;
-}
-
-div.awesomplete > input {
- display: inherit;
-}
-
-div.awesomplete > ul {
- z-index: 9999;
-}
-
-.page-form .awesomplete {
- width: 90%;
-}
-
-.page-form .awesomplete input {
- width: 100%;
-}
-
-.page-form div.awesomplete > ul {
- color: black;
-}
-
-form[name="linkform"].page-form {
- overflow: visible;
-}
-
-@media screen and (max-width: 64em) {
- .page-form-complete .form-label {
- height: inherit;
- }
-
- .page-form-complete .form-label label,
- .page-form-complete .form-input input,
- .page-form-complete .timezone {
- position: inherit;
- top: inherit;
- transform: translateY(0);
- }
-
- .page-form-complete .form-input input[type="checkbox"] {
- position: absolute;
- top: 50%;
- right: 50%;
- transform: translateY(-50%);
- }
-
- .page-form-complete .form-input {
- text-align: center;
- }
-
- .page-form-complete .form-label label {
- display: block;
- text-align: left;
- margin: 10px 0 0 0;
- }
-
- .timezone-continent:after {
- content:"\a\a";
- white-space: pre;
- }
-
- .page-form-complete .radio-buttons {
- text-align: left;
- padding: 5px 15px;
- }
-}
-
-/**
- * Page visitor (page form extended)
- */
-.page-visitor {
- color: #252525;
-}
-
-#page404 {
- color: #3f3f3f;
-}
-
-/**
- * EDIT LINK
- */
-#editlinkform .created-date {
- color: #767676;
- margin-bottom: 10px;
-}
-
-/**
- * LOGIN
- */
-#login-form .remember-me {
- margin: 5px 0;
-}
-
-/**
- * Search results
- */
-.search-result a {
- color: white;
- text-decoration: none;
-}
-
-.search-result .label-tag {
- border-color: white;
-}
-
-.search-result .label-tag .remove {
- border-left: white 1px solid;
- padding: 0 0 0 5px;
- margin: 0 0 0 5px;
-}
-
-.search-result .label-private {
- border: 1px solid white;
-}
-
-/**
- * TOOLS
- */
-.tools-item {
- margin: 10px 0;
-}
-
-.tools-item .pure-button:hover {
- background-image: none;
- background-color: #1b926c;
- color: #f5f5f5;
-}
-
-/**
- * PLUGIN ADMIN
- */
-#pluginform .mobile-row {
- font-size: 0.9em;
-}
-
-#pluginform .more {
- margin-top: 10px;
-}
-
-@media screen and (max-width: 64em) {
- #pluginform .main-row, #pluginform .main-row td {
- border-bottom-style: none;
- }
-
- #pluginform .mobile-row, #pluginform .mobile-row td {
- border-top-style: none;
- }
-}
-
-/**
- * IMPORT
- */
-#import-field {
- margin: 15px 0;
-}
-
-/**
- * TAG CLOUD
- */
-#cloudtag {
- padding: 10px;
- text-align: center;
-}
-
-#cloudtag, #cloudtag a {
- color: #252525;
- text-decoration: none;
-}
-
-#cloudtag .count {
- color: #7f7f7f;
-}
-
-/**
- * TAG LIST
- */
-#taglist {
- padding: 0 10px;
-}
-
-#taglist a {
- color: #252525;
- text-decoration: none;
-}
-
-#taglist .count {
- display: inline-block;
- width: 35px;
- text-align: right;
- color: #7f7f7f;
-}
-
-#taglist .rename-tag-form {
- display: none;
-}
-
-#taglist .delete-tag {
- color: #ac2925;
- display: none;
-}
-
-#taglist .rename-tag {
- color: #0b5ea6;
-}
-
-#taglist .validate-rename-tag {
- color: #1b926c;
-}
-
-/**
- * Picture wall CSS
- */
-#picwall_container {
- margin: 0 10px 10px 10px;
- color: #252525;
- background-color: #f5f5f5;
- clear: both;
-}
-
-.picwall_pictureframe {
- margin: 2px;
- background-color: #f5f5f5;
- z-index: 5;
- position: relative;
- display: table-cell;
- vertical-align: middle;
- width: 90px;
- height: 90px;
- overflow: hidden;
- text-align: center;
- float: left;
-}
-
-.b-lazy {
- -webkit-transition: opacity 500ms ease-in-out;
- -moz-transition: opacity 500ms ease-in-out;
- -o-transition: opacity 500ms ease-in-out;
- transition: opacity 500ms ease-in-out;
- opacity: 0;
-}
-.b-lazy.b-loaded {
- opacity: 1;
-}
-
-.picwall_pictureframe img {
- max-width: 100%;
- height: auto;
- color: transparent;
-} /* Adapt the width of the image */
-
-.picwall_pictureframe a {
- text-decoration: none;
-}
-
-/* CSS to show title when hovering an image - no javascript required. */
-.picwall_pictureframe span.info {
- display: none;
- font-family: Arial, sans-serif;
-}
-
-.picwall_pictureframe:hover span.info {
- display: block;
- position: absolute;
- top: 0;
- left: 0;
- width: 90px;
- height: 90px;
- font-weight: bold;
- font-size: 9pt;
- color: #f5f5f5;
- text-align: left;
- background-color: rgba(0, 0, 0, 0.8);
-}
-
-/**
- * DAILY
- */
-.daily-desc {
- color: #7f7f7f;
- font-size: 0.8em;
-}
-
-.daily-about a {
- color: #343434;
- text-decoration: none;
-}
-
-.daily-about a:hover {
- color: #7f7f7f;
-}
-
-.daily-about h3:before, .daily-about h3:after {
- display: block;
- content:"";
- background: linear-gradient(to right, #d5d4d4, #252525, #d5d4d4);
- height: 1px;
- width: 90%;
- margin: 10px auto;
-}
-
-.daily-entry {
- padding: 0 10px;
-}
-
-.daily-entry .daily-entry-title:after {
- display: block;
- content:"";
- background: linear-gradient(to right, #fff, #515151, #fff);
- height: 1px;
- width: 70%;
- margin: 5px auto;
-}
-
-.daily-entry .daily-entry-title {
- margin: 10px 0 0 0;
-}
-
-.daily-entry .daily-entry-title a {
- color: #000;
- text-decoration: none;
-}
-
-.daily-entry .daily-entry-description {
- padding: 5px 5px 0 5px;
- font-size: 0.9em;
- text-align: justify;
- word-wrap: break-word;
-}
-
-.daily-entry .daily-entry-tags {
- padding: 0 5px 5px 5px;
- font-size: 0.8em;
-}
-
-.daily-entry-thumbnail {
- float: left;
- margin: 15px 5px 5px 15px;
-}
-
-.daily-entry-description a {
- text-decoration: none;
- color: #1b926c;
-}
-
-.daily-entry-description a:hover {
- text-shadow: 1px 1px #ddd;
-}
-
-.daily-entry-description a:visited {
- color: #20b988;
-}
-
-/*
- * Fix empty bookmarklet name in Firefox
- */
-.pure-button {
- -moz-user-select: auto;
-}
-
-.tag-sort {
- margin-top: 30px;
- text-align: center;
-}
-
-.tag-sort a {
- display: inline-block;
- margin: 0 15px;
- color: white;
- text-decoration: none;
- font-weight: bold;
-}
-
-/**
- * Markdown
- */
-.markdown p {
- margin: 0 !important;
-}
-
-.markdown p + p {
- margin: 0.5em 0 0 0 !important;
-}
-
-.markdown *:first-child {
- margin-top: 0 !important;
-}
-
-.markdown *:last-child {
- margin-bottom: 5px !important;
-}
-
-/**
- * Pure Button
- */
-.pure-button-success,
-.pure-button-error,
-.pure-button-warning,
-.pure-button-primary,
-.pure-button-shaarli,
-.pure-button-secondary {
- color: white !important;
- border-radius: 4px;
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-}
-
-.pure-button-shaarli {
- background-color: #1B926C;
-}
diff --git a/tpl/default/daily.html b/tpl/default/daily.html
index 29d845d..816e5d0 100644
--- a/tpl/default/daily.html
+++ b/tpl/default/daily.html
@@ -69,9 +69,12 @@
{$link.title}
- {$thumb=thumbnail($value.url)}
- {if="$thumb!=false"}
- {$thumb}
+ {if="$thumbnails_enabled && !empty($link.thumbnail)"}
+
+
+
{/if}
{$link.formatedDescription}
{if="$link.tags"}
@@ -83,7 +86,7 @@
{/loop}
{/if}
-
{include="page.footer"}
+
diff --git a/tpl/default/dailyrss.html b/tpl/default/dailyrss.html
index b14a385..f589b06 100644
--- a/tpl/default/dailyrss.html
+++ b/tpl/default/dailyrss.html
@@ -8,7 +8,7 @@
{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}
{$value.url}
- {if="$value.thumbnail"}{$value.thumbnail}{/if}
+ {if="$value.thumbnail"}{/if}
{if="$value.description"}{$value.formatedDescription}{/if}
{/loop}
diff --git a/tpl/default/editlink.html b/tpl/default/editlink.html
index d03fd72..d8c5715 100644
--- a/tpl/default/editlink.html
+++ b/tpl/default/editlink.html
@@ -5,12 +5,11 @@
{include="page.header"}
-