]> 91.132.146.200 Git - bibliotheca-php.git/commitdiff
inital commit. Creating own repo to unclutter things.
authorBanana <mail@bananas-playground.net>
Wed, 30 Dec 2020 10:44:10 +0000 (11:44 +0100)
committerBanana <mail@bananas-playground.net>
Wed, 30 Dec 2020 10:44:10 +0000 (11:44 +0100)
90 files changed:
.gitignore [new file with mode: 0644]
README [new file with mode: 0644]
README.md [deleted file]
TODO [new file with mode: 0644]
VERSION [new file with mode: 0644]
documentation/bibliotheca.sql [new file with mode: 0644]
documentation/setup/bibliotheca.sql [new file with mode: 0644]
documentation/setup/install.txt [new file with mode: 0644]
documentation/usermanagement.txt [new file with mode: 0644]
sources/imdb.class.php.txt [new file with mode: 0644]
sources/moveinfos.txt [new file with mode: 0644]
sources/uikit-3.5.3.zip [new file with mode: 0644]
sources/version-names.txt [new file with mode: 0644]
webclient/api.php [new file with mode: 0644]
webclient/config/.gitignore [new file with mode: 0644]
webclient/config/database.php.default [new file with mode: 0644]
webclient/config/path.php.default [new file with mode: 0644]
webclient/config/system.php.default [new file with mode: 0644]
webclient/index.php [new file with mode: 0644]
webclient/lib/doomguy.class.php [new file with mode: 0644]
webclient/lib/gorenest.class.php [new file with mode: 0644]
webclient/lib/imdbwebparser.class.php [new file with mode: 0644]
webclient/lib/managecollectionfields.class.php [new file with mode: 0644]
webclient/lib/managecollections.class.php [new file with mode: 0644]
webclient/lib/manageentry.class.php [new file with mode: 0644]
webclient/lib/mancubus.class.php [new file with mode: 0644]
webclient/lib/possessed.class.php [new file with mode: 0644]
webclient/lib/spectre.class.php [new file with mode: 0644]
webclient/lib/summoner.class.php [new file with mode: 0644]
webclient/lib/tentacle.class.php [new file with mode: 0644]
webclient/lib/trite.class.php [new file with mode: 0644]
webclient/storage/.gitignore [new file with mode: 0644]
webclient/systemout/.gitignore [new file with mode: 0644]
webclient/view/default/auth/auth.html [new file with mode: 0644]
webclient/view/default/auth/auth.php [new file with mode: 0644]
webclient/view/default/collections/collections.html [new file with mode: 0644]
webclient/view/default/collections/collections.php [new file with mode: 0644]
webclient/view/default/dashboard/dashboard.html [new file with mode: 0644]
webclient/view/default/dashboard/dashboard.php [new file with mode: 0644]
webclient/view/default/entry/entry.html [new file with mode: 0644]
webclient/view/default/entry/entry.php [new file with mode: 0644]
webclient/view/default/entry/field-date.html [new file with mode: 0644]
webclient/view/default/entry/field-lookupmultiple.html [new file with mode: 0644]
webclient/view/default/entry/field-selection.html [new file with mode: 0644]
webclient/view/default/entry/field-text-title.html [new file with mode: 0644]
webclient/view/default/entry/field-text.html [new file with mode: 0644]
webclient/view/default/entry/field-text3-description.html [new file with mode: 0644]
webclient/view/default/entry/field-text3.html [new file with mode: 0644]
webclient/view/default/entry/field-textarea-content.html [new file with mode: 0644]
webclient/view/default/entry/field-textarea.html [new file with mode: 0644]
webclient/view/default/entry/field-unknown.html [new file with mode: 0644]
webclient/view/default/entry/field-upload-coverimage.html [new file with mode: 0644]
webclient/view/default/entry/field-upload.html [new file with mode: 0644]
webclient/view/default/entry/field-upload_multiple-attachment.html [new file with mode: 0644]
webclient/view/default/entry/field-upload_multiple.html [new file with mode: 0644]
webclient/view/default/entry/field-year.html [new file with mode: 0644]
webclient/view/default/main.php [new file with mode: 0644]
webclient/view/default/managecollectionfields/managecollectionfields.html [new file with mode: 0644]
webclient/view/default/managecollectionfields/managecollectionfields.php [new file with mode: 0644]
webclient/view/default/managecolletions/managecolletions.html [new file with mode: 0644]
webclient/view/default/managecolletions/managecolletions.php [new file with mode: 0644]
webclient/view/default/manageentry/field-lookupmultiple.html [new file with mode: 0644]
webclient/view/default/manageentry/field-selection.html [new file with mode: 0644]
webclient/view/default/manageentry/field-text.html [new file with mode: 0644]
webclient/view/default/manageentry/field-text3.html [new file with mode: 0644]
webclient/view/default/manageentry/field-textarea.html [new file with mode: 0644]
webclient/view/default/manageentry/field-unknown.html [new file with mode: 0644]
webclient/view/default/manageentry/field-upload.html [new file with mode: 0644]
webclient/view/default/manageentry/field-upload_multiple.html [new file with mode: 0644]
webclient/view/default/manageentry/field-year.html [new file with mode: 0644]
webclient/view/default/manageentry/manageentry.html [new file with mode: 0644]
webclient/view/default/manageentry/manageentry.php [new file with mode: 0644]
webclient/view/default/manageusers/manageusers.html [new file with mode: 0644]
webclient/view/default/manageusers/manageusers.php [new file with mode: 0644]
webclient/view/default/system/menu.php [new file with mode: 0644]
webclient/view/default/system/message.php [new file with mode: 0644]
webclient/view/default/system/pagination.html [new file with mode: 0644]
webclient/view/default/system/pagination_after.php [new file with mode: 0644]
webclient/view/default/system/pagination_before.php [new file with mode: 0644]
webclient/view/default/tags/tags.html [new file with mode: 0644]
webclient/view/default/tags/tags.php [new file with mode: 0644]
webclient/view/default/tool/tool-imdbweb.html [new file with mode: 0644]
webclient/view/default/tool/tool-imdbweb.php [new file with mode: 0644]
webclient/view/default/tool/tool.html [new file with mode: 0644]
webclient/view/default/tool/tool.php [new file with mode: 0644]
webclient/view/default/ui/css/style.css [new file with mode: 0644]
webclient/view/default/ui/css/uikit.min.css [new file with mode: 0644]
webclient/view/default/ui/js/suggest-tag.js [new file with mode: 0644]
webclient/view/default/ui/js/uikit-icons.min.js [new file with mode: 0644]
webclient/view/default/ui/js/uikit.min.js [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b6974b2
--- /dev/null
@@ -0,0 +1,6 @@
+.idea/
+.buildpath
+.project
+.settings/
+*.iml
+*.log
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..523821a
--- /dev/null
+++ b/README
@@ -0,0 +1,43 @@
+# Bibliotheca
+
+
+## Usage
+
+## Requirements
+
+* A Webserver (tested on Apache 2.4)
+* PHP 7+
+* MySQL 8+
+
+## Technical information
+This is build and tested on a linux based OS. Windows support not yet.
+
+### API
+api.php?QUERY_PARAMETERS
+
+collection=NUMBER
+    ID of a collection
+
+p=list
+    Get the latest 10 for given collection
+
+p=add&collection=NUMBER&authKey=API_AUTH_TOKEN
+    POST call to add a new entry to given collection.
+    See p=addInfo for the details which info is needed in the add call
+
+p=addInfo&collection=NUMBER
+    Describes how the data in the POST add call should be formated.
+    The JSON info in the data field, tells which fields are available and in which format the value
+    is accepted.
+    Expected is a curl call with an array as payload
+
+
+The result is json
+{
+    "message": "Message as string",
+    "status": INTEGER based on HTTP_STATUS CODE
+    "data": {}
+}
+
+## third party
+https://github.com/FabianBeiner/PHP-IMDB-Grabber with some modifications
diff --git a/README.md b/README.md
deleted file mode 100644 (file)
index ef25417..0000000
--- a/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# bibliotheca-php
-
-Collection management for your movies, music or books
\ No newline at end of file
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..f9b3001
--- /dev/null
+++ b/TODO
@@ -0,0 +1,15 @@
+User management: Adding secondary groups
+User management: Rights for a user and group. Used in user and group selections.
+Field management: Web interface
+Collection fields: final remove from entry table
+Management which fields should be displayed in dashboard
+Use try/catch for mysql stuff
+Better error handling and display while adding / update and delete
+better debug. When debug true, write into log file. -> see if(DEBUG)
+Mass edit of entries
+delete of a collection
+jdoc formatierung
+sort by filter for collection display
+UI
+- responsive and breakpoints
+Advanced search. More options and searchable fields
diff --git a/VERSION b/VERSION
new file mode 100644 (file)
index 0000000..592ef28
--- /dev/null
+++ b/VERSION
@@ -0,0 +1,9 @@
+0.2 - Vortex Rikers (tba)
+    * Games and movie collection as static files with Hugo (https://gohugo.io)
+    * Tool: Datacrow import into Bibilotheca database
+0.1 - Castle - (2019/09/31)
+       * First usable version
+       * Static collection with hugo (https://gohugo.io)
+       * Static collection design based on CSS/JS Uikit (https://getuikit.com)
+       * Tool: Datacrow (http://www.datacrow.net/) export can be imported into static files for hugo
+       * Tool: Datacrow import can create static md files based on a movie collection
diff --git a/documentation/bibliotheca.sql b/documentation/bibliotheca.sql
new file mode 100644 (file)
index 0000000..a6ff029
--- /dev/null
@@ -0,0 +1,384 @@
+-- phpMyAdmin SQL Dump
+-- version 4.9.6
+-- https://www.phpmyadmin.net/
+--
+-- Host: 127.0.0.1
+-- Generation Time: Dec 30, 2020 at 10:41 AM
+-- Server version: 8.0.22
+-- PHP Version: 7.4.13
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET AUTOCOMMIT = 0;
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `bibliotheca`
+--
+CREATE DATABASE IF NOT EXISTS `bibliotheca` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
+USE `bibliotheca`;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection`
+--
+
+DROP TABLE IF EXISTS `bib_collection`;
+CREATE TABLE `bib_collection` (
+  `id` int NOT NULL,
+  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `defaultSearchField` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int DEFAULT NULL,
+  `owner` int NOT NULL,
+  `group` int NOT NULL,
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_group`
+--
+
+DROP TABLE IF EXISTS `bib_group`;
+CREATE TABLE `bib_group` (
+  `id` int NOT NULL,
+  `name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `protected` tinyint(1) NOT NULL DEFAULT '0',
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int DEFAULT NULL,
+  `owner` int NOT NULL,
+  `group` int NOT NULL,
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_group`
+--
+
+INSERT INTO `bib_group` (`id`, `name`, `description`, `protected`, `created`, `modificationuser`, `owner`, `group`, `rights`) VALUES
+(1, 'Administration', 'Admin group', 1, '2020-05-31 21:25:29', 0, 1, 1, 'rwx------'),
+(2, 'Users', 'Default user group', 1, '2020-05-31 21:25:29', 0, 1, 1, 'rwxr--r--'),
+(3, 'Anonymous', 'Anonymous users', 1, '2020-05-31 21:25:29', 0, 1, 1, 'rwxr--r--');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_menu`
+--
+
+DROP TABLE IF EXISTS `bib_menu`;
+CREATE TABLE `bib_menu` (
+  `id` int UNSIGNED NOT NULL,
+  `text` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `action` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `icon` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `owner` int NOT NULL DEFAULT '0',
+  `group` int NOT NULL DEFAULT '0',
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `position` int NOT NULL DEFAULT '0',
+  `category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_menu`
+--
+
+INSERT INTO `bib_menu` (`id`, `text`, `action`, `icon`, `owner`, `group`, `rights`, `position`, `category`) VALUES
+(1, 'Dashboard', '', 'home', 1, 1, 'rw-r--r--', 0, 'show'),
+(2, 'Collections', 'collections', 'database', 1, 1, 'rw-r--r--', 1, 'show'),
+(3, 'Tags', 'tags', 'tag', 1, 1, 'rw-r--r--', 2, 'show'),
+(4, 'Add', 'manageentry', 'plus-circle', 1, 2, 'rw-rw----', 0, 'manage'),
+(6, 'Tags', 'managetags', 'tag', 1, 2, 'rw-rw----', 2, 'manage'),
+(7, 'Collections', 'managecolletions', 'database', 1, 2, 'rw-rw----', 3, 'manage'),
+(8, 'Users', 'manageusers', 'users', 1, 1, 'rw-------', 4, 'manage'),
+(9, 'Login', 'auth', '', 1, 1, 'rw-r--r--', 0, ''),
+(10, 'Collection fields', 'managecollectionfields', '', 1, 1, 'rw-------', 0, ''),
+(11, 'Entry', 'entry', '', 1, 1, 'rw-r--r--', 0, ''),
+(12, 'Search', 'search', '', 1, 1, 'rw-r--r--', 0, ''),
+(13, 'Edit', 'collections', 'pencil', 1, 2, 'rw-rw----', 1, 'manage'),
+(14, 'Tool', 'tool', '', 1, 1, 'rw-------', 0, '');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_sys_fields`
+--
+
+DROP TABLE IF EXISTS `bib_sys_fields`;
+CREATE TABLE `bib_sys_fields` (
+  `id` int NOT NULL,
+  `identifier` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `displayname` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `searchtype` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+  `createstring` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+  `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
+  `apiinfo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int DEFAULT NULL,
+  `owner` int NOT NULL,
+  `group` int NOT NULL,
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_sys_fields`
+--
+
+INSERT INTO `bib_sys_fields` (`id`, `identifier`, `displayname`, `type`, `searchtype`, `createstring`, `value`, `apiinfo`, `created`, `modificationuser`, `owner`, `group`, `rights`) VALUES
+(1, 'title', 'Title', 'text', 'text', '`title` varchar(128) NOT NULL', NULL, 'string 128', '2019-09-01 18:26:33', 0, 1, 1, 'rw-r--r--'),
+(2, 'description', 'Description', 'text3', 'text', '`description` varchar(255) NULL DEFAULT NULL', NULL, 'string 64', '2019-09-01 18:28:35', 0, 1, 1, 'rw-r--r--'),
+(3, 'content', 'Main content', 'textarea', 'text', 'content` text NULL DEFAULT NULL,', NULL, 'mysql text', '2019-09-01 18:28:35', 0, 1, 1, 'rw-r--r--'),
+(4, 'releasedate', 'Release date', 'date', 'text', '`releasedate` timestamp NULL DEFAULT NULL', NULL, 'mysql timestamp', '2019-09-01 19:01:39', 0, 1, 1, 'rw-r--r--'),
+(5, 'tag', 'Tag', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2019-09-01 19:11:18', 0, 1, 1, 'rw-r--r--'),
+(6, 'category', 'Category', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2019-09-01 19:11:18', 0, 1, 1, 'rw-r--r--'),
+(7, 'publisher', 'Publisher', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2019-09-01 19:17:51', 0, 1, 1, 'rw-r--r--'),
+(8, 'developer', 'Developer', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2019-09-01 19:17:51', 0, 1, 1, 'rw-r--r--'),
+(9, 'platform', 'Platform', 'selection', 'tag', '`platform` varchar(32) NULL DEFAULT NULL', 'PC,Xbox,Playstation,Nintendo,Nintendo Switch', 'One of PC,Xbox,Playstation,Nintendo,Nintendo Switch', '2019-09-01 19:18:33', 0, 1, 1, 'rw-r--r--'),
+(10, 'storage', 'Storage', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2019-09-01 19:18:33', 0, 1, 1, 'rw-r--r--'),
+(13, 'rating', 'Rating', 'selection', 'tag', '`rating` varchar(16) NULL DEFAULT NULL', '0/10,2/10,3/10,4/10,5/10,6/10,7/10,8/10,9/10,10/10', 'One of 0/10,2/10,3/10,4/10,5/10,6/10,7/10,8/10,9/10,10/10', '2019-09-01 19:25:35', 0, 1, 1, 'rw-r--r--'),
+(14, 'year', 'Year', 'year', 'tag', '`year` year NULL DEFAULT NULL', NULL, 'mysql year', '2019-09-01 19:30:11', 0, 1, 1, 'rw-r--r--'),
+(15, 'coverimage', 'Cover image', 'upload', NULL, NULL, NULL, 'One file in $_FILES[uploads] of post', '2019-09-01 19:48:44', 0, 1, 1, 'rw-r--r--'),
+(16, 'attachment', 'Attachments', 'upload_multiple', NULL, NULL, NULL, 'Multiple in $_FILES[uploads] of post', '2019-09-01 19:48:44', 0, 1, 1, 'rw-r--r--'),
+(17, 'os', 'Operating system and version', 'selection', 'tag', '`os` varchar(32) NULL DEFAULT NULL', 'Windows 10,Windows 95, Windows 99,Windows XP, Windows ME, Windows 2000,Windows Vista,Windows 8', 'One of Windows 10,Windows 95, Windows 99,Windows XP, Windows ME, Windows 2000,Windows Vista,Windows 8', '2019-09-01 19:55:13', 0, 1, 1, 'rw-r--r--'),
+(18, 'actors', 'Actors', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2020-07-26 07:12:48', NULL, 1, 1, 'rw-r--r--'),
+(19, 'countries', 'Countries', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2020-07-26 07:16:08', NULL, 1, 1, 'rw-r--r--'),
+(20, 'directors', 'Directors', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2020-07-26 07:17:59', NULL, 1, 1, 'rw-r--r--'),
+(21, 'genres', 'Genres', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2020-07-26 07:18:55', NULL, 1, 1, 'rw-r--r--'),
+(22, 'languages', 'Languages', 'lookupmultiple', 'tag', NULL, NULL, 'string 64', '2020-07-26 07:20:45', NULL, 1, 1, 'rw-r--r--'),
+(23, 'runtime', 'Runtime', 'text', 'text', '`runtime` varchar(128) NULL DEFAULT NULL', NULL, 'string 128', '2020-07-26 07:22:24', NULL, 1, 1, 'rw-r--r--'),
+(24, 'imdbrating', 'IMDB Rating', 'text', 'text', '`imdbrating` varchar(128) NULL DEFAULT NULL', NULL, 'string 128', '2020-12-27 10:00:33', 0, 1, 1, 'rw-r--r--'),
+(25, 'viewcount', 'View counter', 'text', 'text', '`viewcount` varchar(128) NULL DEFAULT NULL', NULL, 'string 128', '2020-12-27 10:41:10', 0, 1, 1, 'rw-r--r--');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_tool`
+--
+
+DROP TABLE IF EXISTS `bib_tool`;
+CREATE TABLE `bib_tool` (
+  `id` int NOT NULL,
+  `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `description` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `action` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `target` varchar(16) NOT NULL,
+  `owner` int NOT NULL,
+  `group` int NOT NULL,
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_tool`
+--
+
+INSERT INTO `bib_tool` (`id`, `name`, `description`, `action`, `target`, `owner`, `group`, `rights`) VALUES
+(1, 'IMDB web', 'Web parser', 'imdbweb', '_self', 1, 1, 'rw-r--r--');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_tool2collection`
+--
+
+DROP TABLE IF EXISTS `bib_tool2collection`;
+CREATE TABLE `bib_tool2collection` (
+  `fk_tool_id` int NOT NULL,
+  `fk_collection_id` int NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_user`
+--
+
+DROP TABLE IF EXISTS `bib_user`;
+CREATE TABLE `bib_user` (
+  `id` int NOT NULL,
+  `login` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `active` int NOT NULL DEFAULT '1',
+  `apiToken` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+  `apiTokenValidDate` timestamp NULL DEFAULT NULL,
+  `baseGroupId` int NOT NULL DEFAULT '0',
+  `protected` tinyint(1) NOT NULL DEFAULT '0',
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int DEFAULT NULL,
+  `owner` int NOT NULL,
+  `group` int NOT NULL,
+  `rights` char(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_user`
+--
+
+INSERT INTO `bib_user` (`id`, `login`, `password`, `name`, `active`, `apiToken`, `apiTokenValidDate`, `baseGroupId`, `protected`, `created`, `modificationuser`, `owner`, `group`, `rights`) VALUES
+(1, 'admin', '$2y$10$BdLVGaeiQc12smmNKf4rk.2Dj6ockECsSlpx1eO7RWN3RbX2gYrai', 'Administrator', 1, NULL, NULL, 1, 1, '2019-09-01 17:22:02', 0, 1, 1, 'rwxr-----'),
+(2, 'anonymoose', '', 'Anonymoose', 1, NULL, NULL, 3, 1, '2020-05-03 17:22:02', 0, 2, 3, 'rwxr--r--'),
+(4, 'banana', '$2y$10$9NtLpBt97bCQ22Qdz3HvjOyTXIlGBXPMaHOQytF64DnoxQJZG3xe.', 'Banana', 1, 'c435168733c58b82d455d776990ff425', '2020-11-23 14:43:55', 1, 0, '2020-05-30 18:23:01', 0, 4, 2, 'rwxr--r--');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_user2group`
+--
+
+DROP TABLE IF EXISTS `bib_user2group`;
+CREATE TABLE `bib_user2group` (
+  `fk_user_id` int NOT NULL DEFAULT '0',
+  `fk_group_id` int NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_user2group`
+--
+
+INSERT INTO `bib_user2group` (`fk_user_id`, `fk_group_id`) VALUES
+(1, 1),
+(2, 3),
+(4, 1);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_userSession`
+--
+
+DROP TABLE IF EXISTS `bib_userSession`;
+CREATE TABLE `bib_userSession` (
+  `fk_user_id` int NOT NULL,
+  `loginTime` datetime NOT NULL,
+  `area` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
+  `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `salt` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `bib_userSession`
+--
+
+INSERT INTO `bib_userSession` (`fk_user_id`, `loginTime`, `area`, `token`, `salt`) VALUES
+(4, '2020-12-30 10:49:31', 'bibliotheca-session', '81e5e56bfad6200d0f5a4812b9fbd976e68359fb', '03c4f30d');
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `bib_collection`
+--
+ALTER TABLE `bib_collection`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_group`
+--
+ALTER TABLE `bib_group`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_menu`
+--
+ALTER TABLE `bib_menu`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_sys_fields`
+--
+ALTER TABLE `bib_sys_fields`
+  ADD PRIMARY KEY (`id`) USING BTREE;
+
+--
+-- Indexes for table `bib_tool`
+--
+ALTER TABLE `bib_tool`
+  ADD PRIMARY KEY (`id`),
+  ADD UNIQUE KEY `action` (`action`);
+
+--
+-- Indexes for table `bib_tool2collection`
+--
+ALTER TABLE `bib_tool2collection`
+  ADD UNIQUE KEY `fk_collection_id` (`fk_collection_id`,`fk_tool_id`);
+
+--
+-- Indexes for table `bib_user`
+--
+ALTER TABLE `bib_user`
+  ADD PRIMARY KEY (`id`),
+  ADD UNIQUE KEY `login` (`login`);
+
+--
+-- Indexes for table `bib_user2group`
+--
+ALTER TABLE `bib_user2group`
+  ADD PRIMARY KEY (`fk_user_id`,`fk_group_id`);
+
+--
+-- Indexes for table `bib_userSession`
+--
+ALTER TABLE `bib_userSession`
+  ADD PRIMARY KEY (`area`);
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `bib_collection`
+--
+ALTER TABLE `bib_collection`
+  MODIFY `id` int NOT NULL AUTO_INCREMENT;
+
+--
+-- AUTO_INCREMENT for table `bib_group`
+--
+ALTER TABLE `bib_group`
+  MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
+
+--
+-- AUTO_INCREMENT for table `bib_menu`
+--
+ALTER TABLE `bib_menu`
+  MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=15;
+
+--
+-- AUTO_INCREMENT for table `bib_sys_fields`
+--
+ALTER TABLE `bib_sys_fields`
+  MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26;
+
+--
+-- AUTO_INCREMENT for table `bib_tool`
+--
+ALTER TABLE `bib_tool`
+  MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
+
+--
+-- AUTO_INCREMENT for table `bib_user`
+--
+ALTER TABLE `bib_user`
+  MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
diff --git a/documentation/setup/bibliotheca.sql b/documentation/setup/bibliotheca.sql
new file mode 100644 (file)
index 0000000..4567e83
--- /dev/null
@@ -0,0 +1,325 @@
+-- phpMyAdmin SQL Dump
+-- version 4.8.5
+-- https://www.phpmyadmin.net/
+--
+-- Host: 127.0.0.1
+-- Generation Time: Sep 01, 2019 at 08:27 PM
+-- Server version: 5.7.26-log
+-- PHP Version: 7.3.8
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET AUTOCOMMIT = 0;
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `bibliotheca`
+--
+CREATE DATABASE IF NOT EXISTS `bibliotheca` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
+USE `bibliotheca`;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection`
+--
+
+DROP TABLE IF EXISTS `bib_collection`;
+CREATE TABLE `bib_collection` (
+  `id` int(10) NOT NULL,
+  `name` varchar(64) COLLATE utf8mb4_bin NOT NULL,
+  `description` varchar(255) COLLATE utf8mb4_bin NOT NULL,
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int(11) NOT NULL,
+  `owner` int(10) NOT NULL,
+  `group` int(10) NOT NULL,
+  `rights` char(9) COLLATE utf8mb4_bin NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_collection`
+--
+
+INSERT INTO `bib_collection` (`id`, `name`, `description`, `created`, `modified`, `modificationuser`, `owner`, `group`, `rights`) VALUES
+(1, 'Movies', 'Movie collection', '2019-09-01 17:26:23', NULL, 0, 2, 2, 'rwxrw-r--'),
+(2, 'Games', 'Game collection', '2019-09-01 17:26:56', NULL, 0, 2, 2, 'rwxrw-r--');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection_entry_1`
+--
+
+DROP TABLE IF EXISTS `bib_collection_entry_1`;
+CREATE TABLE `bib_collection_entry_1` (
+  `id` int(10) NOT NULL,
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int(10) NOT NULL,
+  `title` varchar(128) COLLATE utf8mb4_bin NOT NULL,
+  `description` varchar(255) COLLATE utf8mb4_bin NOT NULL,
+  `content` text COLLATE utf8mb4_bin NOT NULL,
+  `releasedate` timestamp NULL DEFAULT NULL,
+  `year` year(4) DEFAULT NULL,
+  `image` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection_field_1`
+--
+
+DROP TABLE IF EXISTS `bib_collection_field_1`;
+CREATE TABLE `bib_collection_field_1` (
+  `id` int(11) NOT NULL,
+  `identifier` varchar(16) COLLATE utf8mb4_bin NOT NULL,
+  `displayname` varchar(128) COLLATE utf8mb4_bin NOT NULL,
+  `type` varchar(32) COLLATE utf8mb4_bin NOT NULL,
+  `position` int(10) DEFAULT NULL,
+  `searchable` tinyint(1) DEFAULT NULL,
+  `protected` tinyint(1) NOT NULL DEFAULT '0',
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int(10) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_collection_field_1`
+--
+
+INSERT INTO `bib_collection_field_1` (`id`, `identifier`, `displayname`, `type`, `position`, `searchable`, `protected`, `created`, `modified`, `modificationuser`) VALUES
+(1, 'title', 'Title', 'varchar', NULL, NULL, 1, '2019-09-01 18:26:33', '2019-09-01 18:53:00', 2),
+(2, 'description', 'Description', 'varchar', NULL, NULL, 1, '2019-09-01 18:28:35', '2019-09-01 18:53:04', 2),
+(3, 'content', 'Main content', 'text', NULL, NULL, 1, '2019-09-01 18:28:35', '2019-09-01 18:53:07', 2),
+(4, 'releasedate', 'Release date', 'date', NULL, NULL, 0, '2019-09-01 19:01:39', '2019-09-01 19:29:13', 2),
+(5, 'tag', 'Tag', 'lookupmultiple', NULL, NULL, 0, '2019-09-01 19:11:18', '2019-09-01 19:28:42', 2),
+(6, 'category', 'Category', 'lookupmultiple', NULL, NULL, 0, '2019-09-01 19:11:18', '2019-09-01 19:28:48', 2),
+(7, 'publisher', 'Publisher', 'lookupmultiple', NULL, NULL, 0, '2019-09-01 19:17:51', '2019-09-01 19:20:31', 2),
+(8, 'developer', 'Developer', 'lookupmultiple', NULL, NULL, 0, '2019-09-01 19:17:51', '2019-09-01 19:20:36', 2),
+(9, 'platform', 'Platform', 'lookup', NULL, NULL, 0, '2019-09-01 19:18:33', '2019-09-01 19:20:44', 2),
+(10, 'storage', 'Storage', 'lookup', NULL, NULL, 0, '2019-09-01 19:18:33', '2019-09-01 19:20:57', 2),
+(13, 'rating', 'Rating', 'lookup', NULL, NULL, 0, '2019-09-01 19:25:35', '2019-09-01 19:25:35', 2),
+(14, 'year', 'Year', 'year', NULL, NULL, 0, '2019-09-01 19:30:11', '2019-09-01 19:31:11', 2),
+(15, 'coverimage', 'Cover image', 'image', NULL, NULL, 0, '2019-09-01 19:48:44', '2019-09-01 19:48:44', 2),
+(16, 'attachment', 'Attachments', 'upload', NULL, NULL, 0, '2019-09-01 19:48:44', '2019-09-01 19:48:44', 2),
+(17, 'os', 'Operating system and version', 'lookupmultiple', NULL, NULL, 0, '2019-09-01 19:55:13', '2019-09-01 19:55:13', 2);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection_lookup2entry_1`
+--
+
+DROP TABLE IF EXISTS `bib_collection_lookup2entry_1`;
+CREATE TABLE `bib_collection_lookup2entry_1` (
+  `lookup` int(10) NOT NULL,
+  `entry` int(10) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_collection_lookup_1`
+--
+
+DROP TABLE IF EXISTS `bib_collection_lookup_1`;
+CREATE TABLE `bib_collection_lookup_1` (
+  `id` int(10) NOT NULL,
+  `name` varchar(32) COLLATE utf8mb4_bin NOT NULL,
+  `position` int(10) NOT NULL DEFAULT '0',
+  `field` int(10) NOT NULL,
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `modificationuser` int(10) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_collection_lookup_1`
+--
+
+INSERT INTO `bib_collection_lookup_1` (`id`, `name`, `position`, `field`, `created`, `modified`, `modificationuser`) VALUES
+(1, 'PC', 0, 9, '2019-09-01 19:53:27', '2019-09-01 19:53:27', 2),
+(2, 'Nintendo Switch', 0, 9, '2019-09-01 19:54:21', '2019-09-01 19:54:21', 2),
+(3, 'Windows 95', 0, 17, '2019-09-01 19:55:44', '2019-09-01 19:55:44', 2),
+(4, 'Windows 98', 0, 17, '2019-09-01 19:56:00', '2019-09-01 19:56:00', 2),
+(5, 'Windows ME', 0, 17, '2019-09-01 19:56:21', '2019-09-01 19:56:21', 2),
+(6, 'Windows 2000', 0, 17, '2019-09-01 19:56:21', '2019-09-01 19:56:21', 2),
+(7, 'Windows XP', 0, 17, '2019-09-01 19:56:44', '2019-09-01 19:56:44', 2),
+(8, 'Windows Vista', 0, 17, '2019-09-01 19:56:44', '2019-09-01 19:56:44', 2),
+(9, '1/10', 0, 13, '2019-09-01 19:58:23', '2019-09-01 19:58:23', 2),
+(10, '2/10', 0, 13, '2019-09-01 19:58:23', '2019-09-01 19:58:23', 2),
+(11, '3/10', 0, 13, '2019-09-01 19:58:40', '2019-09-01 19:58:40', 2),
+(12, '4/10', 0, 13, '2019-09-01 19:58:40', '2019-09-01 19:58:40', 2),
+(13, '5/10', 0, 13, '2019-09-01 19:58:56', '2019-09-01 19:58:56', 2),
+(14, '6/10', 0, 13, '2019-09-01 19:58:56', '2019-09-01 19:58:56', 2);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_group`
+--
+
+DROP TABLE IF EXISTS `bib_group`;
+CREATE TABLE `bib_group` (
+  `id` int(10) NOT NULL,
+  `name` varchar(16) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
+  `describtion` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
+  `active` tinyint(1) NOT NULL DEFAULT '1',
+  `protected` tinyint(1) NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_group`
+--
+
+INSERT INTO `bib_group` (`id`, `name`, `describtion`, `active`, `protected`) VALUES
+(1, 'Administration', 'Die Gruppe die alles darf.', 1, 1),
+(2, 'Benutzergruppe', 'Standard Benutzergruppe', 1, 1),
+(3, 'Gast', 'Die Gast Gruppe.', 1, 1),
+(8, 'Collection', 'Group to access the collection management', 1, 1);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_user`
+--
+
+DROP TABLE IF EXISTS `bib_user`;
+CREATE TABLE `bib_user` (
+  `id` int(10) NOT NULL,
+  `login` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
+  `password` varchar(40) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
+  `name` varchar(64) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
+  `active` int(10) NOT NULL DEFAULT '1',
+  `email` varchar(128) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
+  `baseGroupId` int(10) NOT NULL DEFAULT '0',
+  `protected` tinyint(1) NOT NULL DEFAULT '0',
+  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_user`
+--
+
+INSERT INTO `bib_user` (`id`, `login`, `password`, `name`, `active`, `email`, `baseGroupId`, `protected`, `created`) VALUES
+(1, 'admin', 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 'Banana', 1, 'mail@bananas-playground.net', 1, 1, '2019-09-01 17:22:02'),
+(2, 'bibuser', '', 'Mr. Gast', 1, 'test@test.com', 2, 1, '2019-09-01 17:22:02');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `bib_user2group`
+--
+
+DROP TABLE IF EXISTS `bib_user2group`;
+CREATE TABLE `bib_user2group` (
+  `fk_user_id` int(10) NOT NULL DEFAULT '0',
+  `fk_group_id` int(10) NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
+
+--
+-- Dumping data for table `bib_user2group`
+--
+
+INSERT INTO `bib_user2group` (`fk_user_id`, `fk_group_id`) VALUES
+(1, 1),
+(2, 2);
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `bib_collection`
+--
+ALTER TABLE `bib_collection`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_collection_entry_1`
+--
+ALTER TABLE `bib_collection_entry_1`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_collection_field_1`
+--
+ALTER TABLE `bib_collection_field_1`
+  ADD PRIMARY KEY (`id`) USING BTREE;
+
+--
+-- Indexes for table `bib_collection_lookup_1`
+--
+ALTER TABLE `bib_collection_lookup_1`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_group`
+--
+ALTER TABLE `bib_group`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_user`
+--
+ALTER TABLE `bib_user`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `bib_user2group`
+--
+ALTER TABLE `bib_user2group`
+  ADD PRIMARY KEY (`fk_user_id`,`fk_group_id`);
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `bib_collection`
+--
+ALTER TABLE `bib_collection`
+  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
+
+--
+-- AUTO_INCREMENT for table `bib_collection_entry_1`
+--
+ALTER TABLE `bib_collection_entry_1`
+  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT;
+
+--
+-- AUTO_INCREMENT for table `bib_collection_field_1`
+--
+ALTER TABLE `bib_collection_field_1`
+  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=18;
+
+--
+-- AUTO_INCREMENT for table `bib_collection_lookup_1`
+--
+ALTER TABLE `bib_collection_lookup_1`
+  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=15;
+
+--
+-- AUTO_INCREMENT for table `bib_group`
+--
+ALTER TABLE `bib_group`
+  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
+
+--
+-- AUTO_INCREMENT for table `bib_user`
+--
+ALTER TABLE `bib_user`
+  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
diff --git a/documentation/setup/install.txt b/documentation/setup/install.txt
new file mode 100644 (file)
index 0000000..2683cd0
--- /dev/null
@@ -0,0 +1 @@
+Default admin user pw: test
diff --git a/documentation/usermanagement.txt b/documentation/usermanagement.txt
new file mode 100644 (file)
index 0000000..4ef2c89
--- /dev/null
@@ -0,0 +1,21 @@
+Curently there is only a user management. Groups or default users can not be changed.
+
+Default users are:
+
+admin
+Should not be changed or removed.
+
+anonymoose
+The guest user. Should not be changed or removed.
+
+
+Default user groups are:
+
+Administration
+Default admin user group. Should not be changed or removed.
+
+Users
+Default user group. Should not be changed or removed.
+
+Anonymous
+Guest user group. Should not be changed or removed.
diff --git a/sources/imdb.class.php.txt b/sources/imdb.class.php.txt
new file mode 100644 (file)
index 0000000..981349b
--- /dev/null
@@ -0,0 +1,1758 @@
+<?php
+
+/**
+ * PHP IMDb.com Grabber
+ *
+ * This PHP library enables you to scrape data from IMDB.com.
+ *
+ *
+ * If you want to thank me for this library, please buy me something at Amazon
+ * (https://www.amazon.de/hz/wishlist/ls/8840JITISN9L/) or use
+ * https://www.paypal.me/FabianBeiner. Thank you! 🙌
+ *
+ * @author  Fabian Beiner <fb@fabianbeiner.de>
+ * @license https://opensource.org/licenses/MIT The MIT License
+ * @link    https://github.com/FabianBeiner/PHP-IMDB-Grabber/ GitHub Repository
+ * @version 6.1.7
+ */
+class IMDB
+{
+    /**
+     * Set this to true if you run into problems.
+     */
+    const IMDB_DEBUG = false;
+
+    /**
+     * Set the preferred language for the User Agent.
+     */
+    const IMDB_LANG = 'en-US,en;q=0.9';
+
+    /**
+     * Define the timeout for cURL requests.
+     */
+    const IMDB_TIMEOUT = 15;
+
+    /**
+     * These are the regular expressions used to extract the data.
+     * If you don’t know what you’re doing, you shouldn’t touch them.
+     */
+    const IMDB_AKA           = '~<td[^>]*>\s*Also\s*Known\s*As\s*</td>\s*<td>(.+)</td>~Uis';
+    const IMDB_ASPECT_RATIO  = '~<td[^>]*>Aspect\s*Ratio</td>\s*<td>(.+)</td>~Uis';
+    const IMDB_AWARDS        = '~<div\s*class="titlereference-overview-section">\s*Awards:(.+)</div>~Uis';
+    const IMDB_BUDGET        = '~<td[^>]*>Budget<\/td>\s*<td>\s*(.*)(?:\(estimated\))\s*<\/td>~Ui';
+    const IMDB_CAST          = '~<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="/name/([^/]*)/\?[^"]*"[^>]*>\s*<span.+>(.+)</span~Ui';
+    const IMDB_CAST_IMAGE    = '~(loadlate="(.*)"[^>]*><\/a>\s+<\/td>\s+)?<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="\/name\/([^/]*)\/\?[^"]*"[^>]*>\s*<span.+>(.+)<\/span+~Uis';
+    const IMDB_CERTIFICATION = '~<td[^>]*>\s*Certification\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_CHAR          = '~<td class="character">(?:\s+)<div>(.*)(?:\s+)(?: /| \(.*\)|<\/div>)~Ui';
+    const IMDB_COLOR         = '~<a href="\/search\/title\?colors=(?:.*)">(.*)<\/a>~Ui';
+    const IMDB_COMPANY       = '~href="[^"]*update=[t0-9]+:production_companies[^"]*">Edit</a>\s*</header>\s*<ul\s*class="simpleList">.+<a href="\/company\/(.*)\/">(.*)</a>~Ui';
+    const IMDB_COUNTRY       = '~<a href="/country/(\w+)">(.*)</a>~Ui';
+    const IMDB_CREATOR       = '~<div[^>]*>\s*(?:Creator|Creators)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
+    const IMDB_DIRECTOR      = '~<div[^>]*>\s*(?:Director|Directors)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
+    const IMDB_GENRE         = '~href="/genre/([a-zA-Z_-]*)/?">([a-zA-Z_ -]*)</a>~Ui';
+    const IMDB_GROSS         = '~pl-zebra-list__label">Cumulative Worldwide Gross<\/td>\s+<td>\s+(.*)\s+<~Uxsi';
+    const IMDB_ID            = '~((?:tt\d{6,})|(?:itle\?\d{6,}))~';
+    const IMDB_LANGUAGE      = '~<a href="\/language\/(\w+)">(.*)<\/a>~Ui';
+    const IMDB_LOCATION      = '~href="\/search\/title\?locations=(.*)">(.*)<\/a>~Ui';
+    const IMDB_LOCATIONS     = '~href="\/search\/title\?locations=[^>]*>\s?(.*)\s?<\/a>[^"]*<dd>\s?(.*)\s<\/dd>~Ui';
+    const IMDB_MPAA          = '~<li class="ipl-inline-list__item">(?:\s+)(TV-Y|TV-Y7|TV-G|TV-PG|TV-14|TV-MA|G|PG|PG-13|R|NC-17|NR|UR)(?:\s+)<\/li>~Ui';
+    const IMDB_NAME          = '~href="/name/(.+)/?(?:\?[^"]*)?"[^>]*>(.+)</a>~Ui';
+    const IMDB_DESCRIPTION   = '~<section class="titlereference-section-overview">\s+<div>(.*)</div>\s+<hr>~Ui';
+    const IMDB_NOT_FOUND     = '~<h1 class="findHeader">No results found for ~Ui';
+    const IMDB_PLOT          = '~<td[^>]*>\s*Plot\s*Summary\s*</td>\s*<td>\s*<p>(.+)</p>~Ui';
+    const IMDB_PLOT_KEYWORDS = '~<td[^>]*>Plot\s*Keywords</td>\s*<td>(.+)(?:<a\s*href="/title/[^>]*>[^<]*</a>\s*</li>\s*</ul>\s*)?</td>~Ui';
+    const IMDB_POSTER        = '~<link\s*rel=\'image_src\'\s*href="(.*)">~Ui';
+    const IMDB_RATING        = '~class="ipl-rating-star__rating">(.*)<~Ui';
+    const IMDB_RATING_COUNT  = '~class="ipl-rating-star__total-votes">\((.*)\)<~Ui';
+    const IMDB_RELEASE_DATE  = '~href="/title/[t0-9]*/releaseinfo">(.*)<~Ui';
+    const IMDB_RUNTIME       = '~<td[^>]*>\s*Runtime\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_SEARCH        = '~<td class="result_text"> <a href="\/title\/(tt\d{6,})\/(?:.*)"(?:\s*)>(?:.*)<\/a>~Ui';
+    const IMDB_SEASONS       = '~episodes\?season=(?:\d+)">(\d+)<~Ui';
+    const IMDB_SOUND_MIX     = '~<td[^>]*>\s*Sound\s*Mix\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_TAGLINE       = '~<td[^>]*>\s*Taglines\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_TITLE         = '~itemprop="name">(.*)(<\/h3>|<span)~Ui';
+    const IMDB_TITLE_ORIG    = '~</h3>(?:\s+)(.*)(?:\s+)<span class=\"titlereference-original-title-label~Ui';
+    const IMDB_TRAILER       = '~href="videoplayer/(vi[0-9]*)"~Ui';
+    const IMDB_URL           = '~https?://(?:.*\.|.*)imdb.com/(?:t|T)itle(?:\?|/)(..\d+)~i';
+    const IMDB_USER_REVIEW   = '~href="/title/[t0-9]*/reviews"[^>]*>([^<]*)\s*User~Ui';
+    const IMDB_VOTES         = '~"ipl-rating-star__total-votes">\s*\((.*)\)\s*<~Ui';
+    const IMDB_WRITER        = '~<div[^>]*>\s*(?:Writer|Writers)\s*:\s*<ul[^>]*>(.+)</ul>~Ui';
+    const IMDB_YEAR          = '~og:title\' content="(?:.*)\((?:.*)(\d{4})(?:.*)\)~Ui';
+
+    /**
+     * @var string The string returned, if nothing is found.
+     */
+    public static $sNotFound = 'n/A';
+
+    /**
+     * @var null|int The ID of the movie.
+     */
+    public $iId = null;
+
+    /**
+     * @var bool Is the content ready?
+     */
+    public $isReady = false;
+
+    /**
+     * @var string Char that separates multiple entries.
+     */
+    public $sSeparator = ' / ';
+
+    /**
+     * @var null|string The URL to the movie.
+     */
+    public $sUrl = null;
+
+    /**
+     * @var bool Return responses enclosed in array
+     */
+    public $bArrayOutput = false;
+
+    /**
+     * @var int Maximum cache time.
+     */
+    private $iCache = 1440;
+
+    /**
+     * @var null|string The root of the script.
+     */
+    private $sRoot = null;
+
+    /**
+     * @var null|string Holds the source.
+     */
+    private $sSource = null;
+
+    /**
+     * @var string What to search for?
+     */
+    private $sSearchFor = 'all';
+
+    /**
+     * @param string $sSearch    IMDb URL or movie title to search for.
+     * @param null   $iCache     Custom cache time in minutes.
+     * @param string $sSearchFor What to search for?
+     *
+     * @throws Exception
+     */
+    public function __construct($sSearch, $iCache = null, $sSearchFor = 'all')
+    {
+        $this->sRoot = dirname(__FILE__);
+        if ( ! is_writable($this->sRoot . '/posters') && ! mkdir($this->sRoot . '/posters')) {
+            throw new Exception('The directory “' . $this->sRoot . '/posters” isn’t writable.');
+        }
+        if ( ! is_writable($this->sRoot . '/cache') && ! mkdir($this->sRoot . '/cache')) {
+            throw new Exception('The directory “' . $this->sRoot . '/cache” isn’t writable.');
+        }
+        if ( ! is_writable($this->sRoot . '/cast') && ! mkdir($this->sRoot . '/cast')) {
+            throw new Exception('The directory “' . $this->sRoot . '/cast” isn’t writable.');
+        }
+        if ( ! function_exists('curl_init')) {
+            throw new Exception('You need to enable the PHP cURL extension.');
+        }
+        if (in_array(
+            $sSearchFor,
+            [
+                'movie',
+                'tv',
+                'episode',
+                'game',
+                'all',
+            ]
+        )) {
+            $this->sSearchFor = $sSearchFor;
+        }
+        if (true === self::IMDB_DEBUG) {
+            ini_set('display_errors', 1);
+            ini_set('display_startup_errors', 1);
+            error_reporting(-1);
+            echo '<pre><b>Running:</b> fetchUrl("' . $sSearch . '")</pre>';
+        }
+        if (null !== $iCache && (int) $iCache > 0) {
+            $this->iCache = (int) $iCache;
+        }
+        $this->fetchUrl($sSearch);
+    }
+
+    /**
+     * @param string $sSearch IMDb URL or movie title to search for.
+     *
+     * @return bool True on success, false on failure.
+     */
+    private function fetchUrl($sSearch)
+    {
+        $sSearch = trim($sSearch);
+
+        // Try to find a valid URL.
+        $sId = IMDBHelper::matchRegex($sSearch, self::IMDB_ID, 1);
+        if (false !== $sId) {
+            $this->iId  = preg_replace('~[\D]~', '', $sId);
+            $this->sUrl = 'https://www.imdb.com/title/tt' . $this->iId . '/reference';
+            $bSearch    = false;
+        } else {
+            switch (strtolower($this->sSearchFor)) {
+                case 'movie':
+                    $sParameters = '&s=tt&ttype=ft';
+                    break;
+                case 'tv':
+                    $sParameters = '&s=tt&ttype=tv';
+                    break;
+                case 'episode':
+                    $sParameters = '&s=tt&ttype=ep';
+                    break;
+                case 'game':
+                    $sParameters = '&s=tt&ttype=vg';
+                    break;
+                default:
+                    $sParameters = '&s=tt';
+            }
+
+            $this->sUrl = 'https://www.imdb.com/find?q=' . rawurlencode(str_replace(' ', '+', $sSearch)) . $sParameters;
+            $bSearch    = true;
+
+            // Was this search already performed and cached?
+            $sRedirectFile = $this->sRoot . '/cache/' . sha1($this->sUrl) . '.redir';
+            if (is_readable($sRedirectFile)) {
+                if (self::IMDB_DEBUG) {
+                    echo '<pre><b>Using redirect:</b> ' . basename($sRedirectFile) . '</pre>';
+                }
+                $sRedirect  = file_get_contents($sRedirectFile);
+                $this->sUrl = trim($sRedirect);
+                $this->iId  = preg_replace('~[\D]~', '', IMDBHelper::matchRegex($sRedirect, self::IMDB_ID, 1));
+                $bSearch    = false;
+            }
+        }
+
+        // Does a cache of this movie exist?
+        $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '.cache';
+        if (is_readable($sCacheFile)) {
+            $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+            if ($iDiff < $this->iCache) {
+                if (true === self::IMDB_DEBUG) {
+                    echo '<pre><b>Using cache:</b> ' . basename($sCacheFile) . '</pre>';
+                }
+                $this->sSource = file_get_contents($sCacheFile);
+                $this->isReady = true;
+
+                return true;
+            }
+        }
+
+        // Run cURL on the URL.
+        if (true === self::IMDB_DEBUG) {
+            echo '<pre><b>Running cURL:</b> ' . $this->sUrl . '</pre>';
+        }
+
+        $aCurlInfo = IMDBHelper::runCurl($this->sUrl);
+        $sSource   = $aCurlInfo['contents'];
+
+        if (false === $sSource) {
+            if (true === self::IMDB_DEBUG) {
+                echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+            }
+
+            return false;
+        }
+
+        // Was the movie found?
+        $sMatch = IMDBHelper::matchRegex($sSource, self::IMDB_SEARCH, 1);
+        if (false !== $sMatch) {
+            $sUrl = 'https://www.imdb.com/title/' . $sMatch . '/reference';
+            if (true === self::IMDB_DEBUG) {
+                echo '<pre><b>New redirect saved:</b> ' . basename($sRedirectFile) . ' => ' . $sUrl . '</pre>';
+            }
+            file_put_contents($sRedirectFile, $sUrl);
+            $this->sSource = null;
+            self::fetchUrl($sUrl);
+
+            return true;
+        }
+        $sMatch = IMDBHelper::matchRegex($sSource, self::IMDB_NOT_FOUND, 0);
+        if (false !== $sMatch) {
+            if (true === self::IMDB_DEBUG) {
+                echo '<pre><b>Movie not found:</b> ' . $sSearch . '</pre>';
+            }
+
+            return false;
+        }
+
+        $this->sSource = str_replace(
+            [
+                "\n",
+                "\r\n",
+                "\r",
+            ],
+            '',
+            $sSource
+        );
+        $this->isReady = true;
+
+        // Save cache.
+        if (false === $bSearch) {
+            if (true === self::IMDB_DEBUG) {
+                echo '<pre><b>Cache created:</b> ' . basename($sCacheFile) . '</pre>';
+            }
+            file_put_contents($sCacheFile, $this->sSource);
+        }
+
+        return true;
+    }
+
+    /**
+     * @return array All data.
+     */
+    public function getAll()
+    {
+        $aData = [];
+        foreach (get_class_methods(__CLASS__) as $method) {
+            if (substr($method, 0, 3) === 'get' && $method !== 'getAll' && $method !== 'getCastImages') {
+                $aData[$method] = [
+                    'name'  => ltrim($method, 'get'),
+                    'value' => $this->{$method}(),
+                ];
+            }
+        }
+        array_multisort($aData);
+
+        return $aData;
+    }
+
+    /**
+     * @return string “Also Known As” or $sNotFound.
+     */
+    public function getAka()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_AKA, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * Returns all local names
+     *
+     * @return string All local names.
+     */
+    public function getAkas()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            } else {
+                $fullAkas  = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
+                $aCurlInfo = IMDBHelper::runCurl($fullAkas);
+                $sSource   = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if (true === self::IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = IMDBHelper::matchRegex($sSource, "~<td>(.*?)<\/td>\s+<td>(.*?)<\/td>~");
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'title'   => IMDBHelper::cleanString($aReturned[2][$i]),
+                                'country' => IMDBHelper::cleanString($strName),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string “Aspect Ratio” or $sNotFound.
+     */
+    public function getAspectRatio()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_ASPECT_RATIO, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The awards of the movie or $sNotFound.
+     */
+    public function getAwards()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_AWARDS, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param int    $iLimit  How many cast members should be returned?
+     * @param bool   $bMore   Add … if there are more cast members than printed.
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked cast members or $sNotFound.
+     */
+    public function getCastAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_CAST);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return IMDBHelper::arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    self::$sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param int  $iLimit How many cast members should be returned?
+     * @param bool $bMore  Add … if there are more cast members than printed.
+     *
+     * @return string A list with cast members or $sNotFound.
+     */
+    public function getCast($iLimit = 0, $bMore = true)
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_CAST);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = IMDBHelper::cleanString($sName);
+                }
+
+                $bMore = (0 !== $iLimit && $bMore && (count($aMatch[2]) > $iLimit) ? '…' : '');
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return IMDBHelper::arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    self::$sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @param int    $iLimit    How many cast images should be returned?
+     * @param bool   $bMore     Add … if there are more cast members than printed.
+     * @param string $sSize     small, mid or big cast images
+     * @param bool   $bDownload Return URL or Download
+     *
+     * @return array Array with cast name as key, and image as value.
+     */
+    public function getCastImages($iLimit = 0, $bMore = true, $sSize = 'small', $bDownload = false)
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_CAST_IMAGE);
+            $aReturn = [];
+            if (count($aMatch[4])) {
+                foreach ($aMatch[4] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $sMatch = $aMatch[2][$i];
+
+                    if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                        $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
+                    } elseif ('mid' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                        $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@._V1_UX214_AL_.jpg';
+                    }
+
+                    if (false === $bDownload) {
+                        $sMatch = IMDBHelper::cleanString($sMatch);
+                    } else {
+                        $sLocal = IMDBHelper::saveImageCast($sMatch, $aMatch[3][$i]);
+                        if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                            $sMatch = $sLocal;
+                        } else {
+                            //the 'big' image isn't available, try the 'mid' one (vice versa)
+                            if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                                //trying the 'mid' one
+                                $sMatch = substr(
+                                        $aMatch[2][$i],
+                                        0,
+                                        strpos($aMatch[2][$i], '@._')
+                                    ) . '@._V1_UX214_AL_.jpg';
+                            } else {
+                                //trying the 'big' one
+                                $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
+                            }
+
+                            $sLocal = IMDBHelper::saveImageCast($sMatch, $aMatch[3][$i]);
+                            if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                                $sMatch = $sLocal;
+                            } else {
+                                $sMatch = IMDBHelper::cleanString($aMatch[2][$i]);
+                            }
+                        }
+                    }
+
+                    $aReturn[IMDBHelper::cleanString($aMatch[4][$i])] = $sMatch;
+                }
+
+                $bMore = (0 !== $iLimit && $bMore && (count($aMatch[4]) > $iLimit) ? '…' : '');
+
+                $bHaveMore = ($bMore && (count($aMatch[4]) > $iLimit));
+
+                $aReturn = array_replace(
+                    $aReturn,
+                    array_fill_keys(
+                        array_keys($aReturn, self::$sNotFound),
+                        'cast/not-found.jpg'
+                    )
+                );
+
+                return $aReturn;
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @param int    $iLimit  How many cast members should be returned?
+     * @param bool   $bMore   Add … if there are more cast members than
+     *                        printed.
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked cast members and their character or
+     *                $sNotFound.
+     */
+    public function getCastAndCharacterAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch     = IMDBHelper::matchRegex($this->sSource, self::IMDB_CAST);
+            $aMatchChar = IMDBHelper::matchRegex($this->sSource, self::IMDB_CHAR);
+            $aReturn    = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a> as ' . IMDBHelper::cleanString($aMatchChar[1][$i]);
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return IMDBHelper::arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    self::$sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @param int  $iLimit How many cast members should be returned?
+     * @param bool $bMore  Add … if there are more cast members than printed.
+     *
+     * @return string  A list with cast members and their character or
+     *                 $sNotFound.
+     */
+    public function getCastAndCharacter($iLimit = 0, $bMore = true)
+    {
+        if (true === $this->isReady) {
+            $aMatch     = IMDBHelper::matchRegex($this->sSource, self::IMDB_CAST);
+            $aMatchChar = IMDBHelper::matchRegex($this->sSource, self::IMDB_CHAR);
+            $aReturn    = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = IMDBHelper::cleanString($sName) . ' as ' . IMDBHelper::cleanString($aMatchChar[1][$i]);
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return IMDBHelper::arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    self::$sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string The certification of the movie or $sNotFound.
+     */
+    public function getCertification()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_CERTIFICATION, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string Color or $sNotFound.
+     */
+    public function getColor()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_COLOR, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The company producing the movie or $sNotFound.
+     */
+    public function getCompany()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCompanyAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string The linked company producing the movie or $sNotFound.
+     */
+    public function getCompanyAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_COMPANY);
+            if (isset($aMatch[2][0])) {
+                return '<a href="https://www.imdb.com/company/' . IMDBHelper::cleanString(
+                        $aMatch[1][0]
+                    ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                        $aMatch[2][0]
+                    ) . '</a>';
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with countries or $sNotFound.
+     */
+    public function getCountry()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCountryAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked countries or $sNotFound.
+     */
+    public function getCountryAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_COUNTRY);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/country/' . trim(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string A list with the creators or $sNotFound.
+     */
+    public function getCreator()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCreatorAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked creators or $sNotFound.
+     */
+    public function getCreatorAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_CREATOR, 1);
+            $aMatch  = IMDBHelper::matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string The description of the movie or $sNotFound.
+     */
+    public function getDescription()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_DESCRIPTION, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with the directors or $sNotFound.
+     */
+    public function getDirector()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getDirectorAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked directors or $sNotFound.
+     */
+    public function getDirectorAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_DIRECTOR, 1);
+            $aMatch  = IMDBHelper::matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string A list with the genres or $sNotFound.
+     */
+    public function getGenre()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getGenreAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked genres or $sNotFound.
+     */
+    public function getGenreAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_GENRE);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach (array_unique($aMatch[2]) as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/search/title?genres=' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string cumulative worldwide gross or $sNotFound.
+     */
+    public function getGross()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_GROSS, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with the languages or $sNotFound.
+     */
+    public function getLanguage()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getLanguageAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked languages or $sNotFound.
+     */
+    public function getLanguageAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_LANGUAGE);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/language/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string A list with the location or $sNotFound.
+     */
+    public function getLocation()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getLocationAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked location or $sNotFound.
+     */
+    public function getLocationAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_LOCATION);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/search/title?locations=' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * Returns all locations
+     *
+     * @return string location
+     * @return string specification
+     */
+    public function getLocations()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_locations.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            } else {
+                $fullLocations = sprintf('https://www.imdb.com/title/tt%s/locations', $this->iId);
+                $aCurlInfo     = IMDBHelper::runCurl($fullLocations);
+                $sSource       = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if (true === self::IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = IMDBHelper::matchRegex($sSource, self::IMDB_LOCATIONS);
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'location' => IMDBHelper::cleanString($strName),
+                            ];
+                        }
+                        if (strpos($aReturned[2][$i], '(') !== false) {
+                            $aReturn[] = [
+                                'specification' => IMDBHelper::cleanString($aReturned[2][$i]),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string The MPAA of the movie or $sNotFound.
+     */
+    public function getMpaa()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_MPAA, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with the plot keywords or $sNotFound.
+     */
+    public function getPlotKeywords()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_PLOT_KEYWORDS, 1);
+            if (false !== $sMatch) {
+                $aReturn = explode('|', IMDBHelper::cleanString($sMatch));
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @param int $iLimit The limit.
+     *
+     * @return string The plot of the movie or $sNotFound.
+     */
+    public function getPlot($iLimit = 0)
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_PLOT, 1);
+            if (false !== $sMatch) {
+                if ($iLimit !== 0) {
+                    return IMDBHelper::getShortText(IMDBHelper::cleanString($sMatch), $iLimit);
+                }
+
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sSize     Small, big, xxs, xs, s poster?
+     * @param bool   $bDownload Return URL to the poster or download it?
+     *
+     * @return bool|string Path to the poster.
+     */
+    public function getPoster($sSize = 'small', $bDownload = false)
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_POSTER, 1);
+            if (false !== $sMatch) {
+                if ('big' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@.jpg';
+                }
+                if ('xxs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY67_CR0,0,45,67_AL_.jpg';
+                }
+                if ('xs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY113_CR0,0,76,113_AL_.jpg';
+                }
+                if ('s' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UX182_CR0,0,182,268_AL_.jpg';
+                }
+                if (false === $bDownload) {
+                    return IMDBHelper::cleanString($sMatch);
+                } else {
+                    $sLocal = IMDBHelper::saveImage($sMatch, $this->iId);
+                    if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                        return $sLocal;
+                    } else {
+                        return $sMatch;
+                    }
+                }
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The rating of the movie or $sNotFound.
+     */
+    public function getRating()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_RATING, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The rating count of the movie or $sNotFound.
+     */
+    public function getRatingCount()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_RATING_COUNT, 1);
+            if (false !== $sMatch) {
+                return str_replace(',', '', IMDBHelper::cleanString($sMatch));
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * Release date doesn't contain all the information we need to create a media and
+     * we need this function that checks if users can vote target media (if can, it's released).
+     *
+     * @return  true If the media is released
+     */
+    public function isReleased()
+    {
+        $strReturn = $this->getReleaseDate();
+        if ($strReturn == self::$sNotFound || $strReturn == 'Not yet released') {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return string The release date of the movie or $sNotFound.
+     */
+    public function getReleaseDate()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_RELEASE_DATE, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * Returns all local names
+     *
+     * @return string country
+     * @return string release date
+     */
+    public function getReleaseDates()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            } else {
+                $fullAkas  = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
+                $aCurlInfo = IMDBHelper::runCurl($fullAkas);
+                $sSource   = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if (true === self::IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = IMDBHelper::matchRegex(
+                    $sSource,
+                    '~>(.*)<\/a><\/td>\s+<td class="release_date">(.*)<\/td>~'
+                );
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'country'     => IMDBHelper::cleanString($strName),
+                                'releasedate' => IMDBHelper::cleanString($aReturned[2][$i]),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string The runtime of the movie or $sNotFound.
+     */
+    public function getRuntime()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_RUNTIME, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with the seasons or $sNotFound.
+     */
+    public function getSeasons()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getSeasonsAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked seasons or $sNotFound.
+     */
+    public function getSeasonsAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_SEASONS);
+            $aReturn = [];
+            if (count($aMatch[1])) {
+                foreach (range(1, max($aMatch[1])) as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/title/tt' . $this->iId . '/episodes?season=' . $sName . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $sName . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound);
+    }
+
+    /**
+     * @return string The sound mix of the movie or $sNotFound.
+     */
+    public function getSoundMix()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_SOUND_MIX, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The tagline of the movie or $sNotFound.
+     */
+    public function getTagline()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_TAGLINE, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param bool $bForceLocal Try to return the original name of the movie.
+     *
+     * @return string The title of the movie or $sNotFound.
+     */
+    public function getTitle($bForceLocal = false)
+    {
+        if (true === $this->isReady) {
+            if (true === $bForceLocal) {
+                $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_TITLE_ORIG, 1);
+                if (false !== $sMatch && "" !== $sMatch) {
+                    return IMDBHelper::cleanString($sMatch);
+                }
+            }
+
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_TITLE, 1);
+            $sMatch = preg_replace('~\(\d{4}\)$~Ui', '', $sMatch);
+            if (false !== $sMatch && "" !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param bool $bEmbed Link to player directly?
+     *
+     * @return string The URL to the trailer of the movie or $sNotFound.
+     */
+    public function getTrailerAsUrl($bEmbed = false)
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_TRAILER, 1);
+            if (false !== $sMatch) {
+                $sUrl = 'https://www.imdb.com/video/imdb/' . $sMatch . '/' . ($bEmbed ? 'player' : '');
+
+                return IMDBHelper::cleanString($sUrl);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The IMDb URL.
+     */
+    public function getUrl()
+    {
+        if (true === $this->isReady) {
+            return IMDBHelper::cleanString(str_replace('reference', '', $this->sUrl));
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The user review of the movie or $sNotFound.
+     */
+    public function getUserReview()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_USER_REVIEW, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The votes of the movie or $sNotFound.
+     */
+    public function getVotes()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_VOTES, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string A list with the writers or $sNotFound.
+     */
+    public function getWriter()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getWriterAsUrl();
+            if (self::$sNotFound !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked writers or $sNotFound.
+     */
+    public function getWriterAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = IMDBHelper::matchRegex($this->sSource, self::IMDB_WRITER, 1);
+            $aMatch  = IMDBHelper::matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . IMDBHelper::cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . IMDBHelper::cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return IMDBHelper::arrayOutput($this->bArrayOutput, $this->sSeparator, self::$sNotFound, $aReturn);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The year of the movie or $sNotFound.
+     */
+    public function getYear()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_YEAR, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+
+    /**
+     * @return string The budget of the movie or $sNotFound.
+     */
+    public function getBudget()
+    {
+        if (true === $this->isReady) {
+            $sMatch = IMDBHelper::matchRegex($this->sSource, self::IMDB_BUDGET, 1);
+            if (false !== $sMatch) {
+                return IMDBHelper::cleanString($sMatch);
+            }
+        }
+
+        return self::$sNotFound;
+    }
+}
+
+class IMDBHelper extends IMDB
+{
+    /**
+     * Regular expression helper.
+     *
+     * @param string $sContent The content to search in.
+     * @param string $sPattern The regular expression.
+     * @param null   $iIndex   The index to return.
+     *
+     * @return bool   If no match was found.
+     * @return string If one match was found.
+     * @return array  If more than one match was found.
+     */
+    public static function matchRegex($sContent, $sPattern, $iIndex = null)
+    {
+        preg_match_all($sPattern, $sContent, $aMatches);
+        if ($aMatches === false) {
+            return false;
+        }
+        if ($iIndex !== null && is_int($iIndex)) {
+            if (isset($aMatches[$iIndex][0])) {
+                return $aMatches[$iIndex][0];
+            }
+
+            return false;
+        }
+
+        return $aMatches;
+    }
+
+    /**
+     * Preferred output in responses with multiple elements
+     *
+     * @param bool   $bArrayOutput Native array or string with separators.
+     * @param string $sSeparator   String separator.
+     * @param string $sNotFound    Not found text.
+     * @param array  $aReturn      Original input.
+     * @param bool   $bHaveMore    Have more elements indicator.
+     *
+     * @return string|array Multiple results separated by selected separator string, or enclosed into native array.
+     */
+    public static function arrayOutput($bArrayOutput, $sSeparator, $sNotFound, $aReturn = null, $bHaveMore = false)
+    {
+        if ($bArrayOutput) {
+            if ($aReturn == null || ! is_array($aReturn)) {
+                return [];
+            }
+
+            if ($bHaveMore) {
+                $aReturn[] = '…';
+            }
+
+            return $aReturn;
+        } else {
+            if ($aReturn == null || ! is_array($aReturn)) {
+                return $sNotFound;
+            }
+
+            foreach ($aReturn as $i => $value) {
+                if (is_array($value)) {
+                    $aReturn[$i] = implode($sSeparator, $value);
+                }
+            }
+
+            return implode($sSeparator, $aReturn) . (($bHaveMore) ? '…' : '');
+        }
+    }
+
+    /**
+     * @param string $sInput Input (eg. HTML).
+     *
+     * @return string Cleaned string.
+     */
+    public static function cleanString($sInput)
+    {
+        $aSearch  = [
+            'Full summary &raquo;',
+            'Full synopsis &raquo;',
+            'Add summary &raquo;',
+            'Add synopsis &raquo;',
+            'See more &raquo;',
+            'See why on IMDbPro.',
+            "\n",
+            "\r",
+        ];
+        $aReplace = [
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+        ];
+        $sInput   = str_replace('</li>', ' | ', $sInput);
+        $sInput   = strip_tags($sInput);
+        $sInput   = str_replace('&nbsp;', ' ', $sInput);
+        $sInput   = str_replace($aSearch, $aReplace, $sInput);
+        $sInput   = html_entity_decode($sInput, ENT_QUOTES | ENT_HTML5);
+        $sInput   = preg_replace('/\s+/', ' ', $sInput);
+        $sInput   = trim($sInput);
+        $sInput   = rtrim($sInput, ' |');
+
+        return ($sInput ? trim($sInput) : self::$sNotFound);
+    }
+
+    /**
+     * @param string $sText   The long text.
+     * @param int    $iLength The maximum length of the text.
+     *
+     * @return string The shortened text.
+     */
+    public static function getShortText($sText, $iLength = 100)
+    {
+        if (mb_strlen($sText) <= $iLength) {
+            return $sText;
+        }
+
+        list($sShort) = explode("\n", wordwrap($sText, $iLength - 1));
+
+        if (substr($sShort, -1) !== '.') {
+            return $sShort . '…';
+        }
+
+        return $sShort;
+    }
+
+    /**
+     * @param string $sUrl The URL to the image to download.
+     * @param int    $iId  The ID of the movie.
+     *
+     * @return string Local path.
+     */
+    public static function saveImage($sUrl, $iId)
+    {
+        if (preg_match('~title_addposter.jpg|imdb-share-logo.png~', $sUrl)) {
+            return 'posters/not-found.jpg';
+        }
+
+        $sFilename = dirname(__FILE__) . '/posters/' . $iId . '.jpg';
+        if (file_exists($sFilename)) {
+            return 'posters/' . $iId . '.jpg';
+        }
+
+        $aCurlInfo = self::runCurl($sUrl, true);
+        $sData     = $aCurlInfo['contents'];
+        if (false === $sData) {
+            return 'posters/not-found.jpg';
+        }
+
+        $oFile = fopen($sFilename, 'x');
+        fwrite($oFile, $sData);
+        fclose($oFile);
+
+        return 'posters/' . $iId . '.jpg';
+    }
+
+    /**
+     * @param string $sUrl      The URL to fetch.
+     * @param bool   $bDownload Download?
+     *
+     * @return bool|mixed Array on success, false on failure.
+     */
+    public static function runCurl($sUrl, $bDownload = false)
+    {
+        $oCurl = curl_init($sUrl);
+        curl_setopt_array(
+            $oCurl,
+            [
+                CURLOPT_BINARYTRANSFER => ($bDownload ? true : false),
+                CURLOPT_CONNECTTIMEOUT => self::IMDB_TIMEOUT,
+                CURLOPT_ENCODING       => '',
+                CURLOPT_FOLLOWLOCATION => 0,
+                CURLOPT_FRESH_CONNECT  => 0,
+                CURLOPT_HEADER         => ($bDownload ? false : true),
+                CURLOPT_HTTPHEADER     => [
+                    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+                    'Accept-Charset: utf-8, iso-8859-1;q=0.5',
+                    'Accept-Language: ' . self::IMDB_LANG,
+                ],
+                CURLOPT_REFERER        => 'https://www.imdb.com',
+                CURLOPT_RETURNTRANSFER => 1,
+                CURLOPT_SSL_VERIFYHOST => 0,
+                CURLOPT_SSL_VERIFYPEER => 0,
+                CURLOPT_TIMEOUT        => self::IMDB_TIMEOUT,
+                CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',
+                CURLOPT_VERBOSE        => 0,
+            ]
+        );
+        $sOutput   = curl_exec($oCurl);
+        $aCurlInfo = curl_getinfo($oCurl);
+        curl_close($oCurl);
+        $aCurlInfo['contents'] = $sOutput;
+
+        if (200 !== $aCurlInfo['http_code'] && 302 !== $aCurlInfo['http_code']) {
+            if (true === self::IMDB_DEBUG) {
+                echo '<pre><b>cURL returned wrong HTTP code “' . $aCurlInfo['http_code'] . '”, aborting.</b></pre>';
+            }
+
+            return false;
+        }
+
+        return $aCurlInfo;
+    }
+
+    /**
+     * @param string $sUrl The URL to the image to download.
+     * @param int    $cId  The cast ID of the actor.
+     *
+     * @return string Local path.
+     */
+    public static function saveImageCast($sUrl, $cId)
+    {
+        if ( ! preg_match('~http~', $sUrl)) {
+            return 'cast/not-found.jpg';
+        }
+
+        $sFilename = dirname(__FILE__) . '/cast/' . $cId . '.jpg';
+        if (file_exists($sFilename)) {
+            return 'cast/' . $cId . '.jpg';
+        }
+
+        $aCurlInfo = self::runCurl($sUrl, true);
+        $sData     = $aCurlInfo['contents'];
+        if (false === $sData) {
+            return 'cast/not-found.jpg';
+        }
+
+        $oFile = fopen($sFilename, 'x');
+        fwrite($oFile, $sData);
+        fclose($oFile);
+
+        return 'cast/' . $cId . '.jpg';
+    }
+}
diff --git a/sources/moveinfos.txt b/sources/moveinfos.txt
new file mode 100644 (file)
index 0000000..37e86f0
--- /dev/null
@@ -0,0 +1 @@
+https://www.imdb.com/interfaces/
diff --git a/sources/uikit-3.5.3.zip b/sources/uikit-3.5.3.zip
new file mode 100644 (file)
index 0000000..6858fd0
Binary files /dev/null and b/sources/uikit-3.5.3.zip differ
diff --git a/sources/version-names.txt b/sources/version-names.txt
new file mode 100644 (file)
index 0000000..ff3c3ba
--- /dev/null
@@ -0,0 +1,40 @@
+Castle (Intro movie): Unreal
+Vortex Rikers: Vortex2
+NyLeve's Falls: NyLeve
+Rrajigar Mine: Dig
+Depths Of Rrajigar: Dug
+Sacred Passage: Passage
+Chizra - Nali Water God: Chizra
+The Ceremonial Chambers: Ceremony
+Dark Arena: Dark
+Harobed Village: Harobed
+Terraniux Underground: TerraLift
+Terraniux: Terraniux
+Noork's Elbow: Noork
+Temple Of Vandora: Ruins
+The Trench: Trench
+ISV-KRAN deck 4: IsvKran4
+ISV-KRAN decks 3 & 2: IsvKran32
+ISVDECK1: IsvDeck1
+Spire Village: SpireVillage
+The Sunspire: TheSunspire
+Gateway To Na Pali: SkyCaves
+Na Pali Haven: SkyTown
+Outpost 3J: SkyBase
+Velora Pass: VeloraEnd
+Bluff Eversmoking: Bluff
+Dasa Mountain Pass: DasaPass
+Cellars At Dasa Pass: DasaCellars
+Serpent Canyon: NaliBoat
+Nali Castle: NaliC
+Demonlord's Lair: NaliLord
+Demon Crater: DCrater
+MotherShip Basement: ExtremeBeg
+MotherShip Lab: ExtremeLab
+MotherShip Core: ExtremeCore
+Skaarj Generator: ExtremeGen
+Illumination: ExtremeDGen
+The Darkening: ExtremeDark
+The Source Antechamber: ExtremeEnd
+The Source: QueenEnd
+Ending Sequence (movie): Endgame 
\ No newline at end of file
diff --git a/webclient/api.php b/webclient/api.php
new file mode 100644 (file)
index 0000000..8610ab1
--- /dev/null
@@ -0,0 +1,229 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define('DEBUG',false);
+
+require_once './config/path.php';
+require_once './config/system.php';
+require_once './config/database.php';
+
+# static helper class
+require_once 'lib/summoner.class.php';
+# general includes
+require_once 'lib/doomguy.class.php';
+require_once 'lib/spectre.class.php';
+require_once 'lib/mancubus.class.php';
+require_once 'lib/manageentry.class.php';
+require_once 'lib/trite.class.php';
+
+## main vars
+# database object
+$DB = false;
+$Spectre = false;
+
+## DB connection
+$DB = new mysqli(DB_HOST, DB_USERNAME,DB_PASSWORD, DB_NAME);
+$driver = new mysqli_driver();
+$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
+if ($DB->connect_errno) exit('Can not connect to MySQL Server');
+$DB->set_charset("utf8mb4");
+$DB->query("SET collation_connection = 'utf8mb4_0900_ai_ci'");
+
+# user Object
+$Doomguy = new Doomguy($DB);
+# API object
+$Spectre = new Spectre($DB, $Doomguy);
+
+$_requestMode = "default";
+if(isset($_GET['p']) && !empty($_GET['p'])) {
+    $_requestMode = trim($_GET['p']);
+    $_requestMode = Summoner::validate($_requestMode,'nospace') ? $_requestMode : "default";
+
+    if(!$Spectre->allowedRequests($_requestMode)) $_requestMode = "default";
+}
+$_authKey = false;
+if(isset($_GET['authKey']) && !empty($_GET['authKey'])) {
+    $_authKey = trim($_GET['authKey']);
+    $_authKey = Summoner::validate($_authKey,'nospace') ? $_authKey : false;
+}
+
+$_apiResult = array(
+    'message' => 'Nothing to see here.',
+    'status' => 200,
+    'data' => array()
+);
+switch ($_requestMode) {
+    case 'list':
+        # get the latest 10 entris for given collection
+        $_msg = 'Missing parameter with value: collection';
+        $_status = 404;
+        $_data = array();
+
+        $_collection = false;
+        if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+            $_collection = trim($_GET['collection']);
+            $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+        }
+
+        if(!empty($_collection)) {
+            $_msg = 'Invalid collection.';
+            $Mancubus = new Mancubus($DB,$Doomguy);
+            $Trite = new Trite($DB,$Doomguy);
+            $collectionInfo = $Trite->load($_collection);
+
+            $Mancubus->setCollection($Trite->param('id'));
+            $Mancubus->setQueryOptions(array('limit' => 10));
+
+            $entries = $Mancubus->getEntries();
+            if(!empty($entries)) {
+                $_msg = 'Latest entries for collection: '.$collectionInfo['name'];
+                $_status = 200;
+                $_data = $entries;
+            }
+        }
+
+        $_apiResult = array(
+            'message' => $_msg,
+            'status' => $_status,
+            'data' => $_data
+        );
+    break;
+
+    case 'add':
+        # add a single new entry to given collection
+        # authenticated by api token
+        $_msg = 'Missing parameter with value: collection';
+        $_status = 400;
+        $_data = array();
+
+        $Doomguy->authByApiToken($_authKey);
+        if(!$Doomguy->isSignedIn()) {
+            $_apiResult = array(
+                'message' => "Missing API token.",
+                'status' => 401,
+                'data' => $_data
+            );
+            break;
+        }
+
+        $_collection = false;
+        if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+            $_collection = trim($_GET['collection']);
+            $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+        }
+
+        if(!empty($_collection)) {
+            $_msg = 'Invalid POST data.';
+
+            $Mancubus = new Mancubus($DB,$Doomguy);
+            $ManangeEntry = new Manageentry($DB,$Doomguy);
+
+            $ManangeEntry->setCollection($_collection);
+            $editFields = $ManangeEntry->getEditFields();
+
+            if(!empty($_POST) && !empty($editFields)) {
+                $fdata = $_POST;
+                if(!empty($_FILES)) {
+                    $fupload = $Spectre->prepareFilesArray($_FILES);
+                }
+
+                $_owner = $Doomguy->param('id');
+                $_group = $Doomguy->param('baseGroupId');
+                $_rights = 'rwxrwxr--';
+
+                foreach ($editFields as $fieldId=>$fieldData) {
+                    if(isset($fupload['name'][$fieldData['identifier']])) {
+                        $fieldData['uploadData'] = $fupload;
+                        $_fieldsToSave[$fieldData['identifier']] = $fieldData;
+                    }
+                    elseif(isset($fdata[$fieldData['identifier']])) {
+                        $_value = trim($fdata[$fieldData['identifier']]);
+                        if(!empty($_value)) {
+                            $fieldData['valueToSave'] = trim($fdata[$fieldData['identifier']]);
+
+                            $_fieldsToSave[$fieldData['identifier']] = $fieldData;
+                        }
+                    }
+                }
+
+                // special case. Title field should be always available.
+                if(!empty($_fieldsToSave) && isset($_fieldsToSave['title'])) {
+                    $do = $ManangeEntry->create($_fieldsToSave, $_owner, $_group, $_rights);
+                    if(!empty($do)) {
+                        $_msg = 'Added entry: '.$_fieldsToSave['title']['valueToSave'];
+                        $_status = 200;
+                        $_data = array();
+                    }
+                }
+            }
+        }
+
+        $_apiResult = array(
+            'message' => $_msg,
+            'status' => $_status,
+            'data' => $_data
+        );
+    break;
+
+    case 'addInfo':
+        # return information about the given collection to create an ad call.
+        $_msg = 'Missing parameter with value: collection';
+        $_status = 404;
+        $_data = array();
+
+        $_collection = false;
+        if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+            $_collection = trim($_GET['collection']);
+            $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+        }
+
+        if(!empty($_collection)) {
+            $_msg = 'Invalid collection.';
+            $Mancubus = new Mancubus($DB,$Doomguy);
+            $Trite = new Trite($DB,$Doomguy);
+            $collectionInfo = $Trite->load($_collection);
+
+            $Mancubus->setCollection($Trite->param('id'));
+
+            // just get one entry fpr given collection and then build the
+            // json information about adding structure
+            $entryStructure = $Mancubus->getEntryStructure();
+            $structure = $Spectre->buildAddStructure($entryStructure['fields']);
+
+            if(!empty($structure)) {
+                $_msg = 'API POST and FILES data information for collection: '.$collectionInfo['name'];
+                $_status = 200;
+                $_data = $structure;
+            }
+        }
+
+        $_apiResult = array(
+            'message' => $_msg,
+            'status' => $_status,
+            'data' => $_data
+        );
+    break;
+
+    case 'default':
+    default:
+        // do nothing
+}
+
+# header information
+http_response_code($_apiResult['status']);
+header('Content-type: application/json; charset=UTF-8');
+echo json_encode($_apiResult);
diff --git a/webclient/config/.gitignore b/webclient/config/.gitignore
new file mode 100644 (file)
index 0000000..cde8069
--- /dev/null
@@ -0,0 +1 @@
+*.php
diff --git a/webclient/config/database.php.default b/webclient/config/database.php.default
new file mode 100644 (file)
index 0000000..450bcfd
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# database config
+define('DB_HOST','127.0.0.1');
+define('DB_USERNAME','user');
+define('DB_PASSWORD','test');
+define('DB_NAME','bibliotheca');
+define('DB_PREFIX','bib'); # a _ is added automatically as seperation
diff --git a/webclient/config/path.php.default b/webclient/config/path.php.default
new file mode 100644 (file)
index 0000000..cd41577
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# path settings
+define('PATH_ABSOLUTE','/home/banana/code/bibliotheca/webclient');
+define('PATH_SYSTEMOUT',PATH_ABSOLUTE.'/systemout');
+define('PATH_STORAGE',PATH_ABSOLUTE.'/storage');
+define('PATH_WEB_STORAGE','storage');
diff --git a/webclient/config/system.php.default b/webclient/config/system.php.default
new file mode 100644 (file)
index 0000000..1acc399
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+mb_http_output('UTF-8');
+mb_internal_encoding('UTF-8');
+ini_set('error_reporting',-1); // E_ALL & E_STRICT
+
+## check request
+$_urlToParse = filter_var($_SERVER['QUERY_STRING'],FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
+if(!empty($_urlToParse)) {
+    # see http://de2.php.net/manual/en/regexp.reference.unicode.php
+    if(preg_match('/[\p{C}\p{M}\p{Sc}\p{Sk}\p{So}\p{Zl}\p{Zp}]/u',$_urlToParse) === 1) {
+        die('Malformed request. Make sure you know what you are doing.');
+    }
+}
+
+## set the error reporting
+ini_set('log_errors',true);
+ini_set('error_log',PATH_SYSTEMOUT.'/error.log');
+if(DEBUG === true) {
+    ini_set('display_errors',true);
+}
+else {
+    ini_set('display_errors',false);
+}
+
+# time settings
+date_default_timezone_set('Europe/Berlin');
+
+# theme support
+# fallback support to default
+define('UI_THEME', 'default');
+
+# session
+define('SESSION_LIFETIME', 43200); // 8 hours
+define('SESSION_NAME', "bibliotheca-session");
+define('SESSION_SAVE_PATH', PATH_SYSTEMOUT.'/session');
+
+# usersettings
+define('USER_DEFAULT_RIGHTS_STRING','rwxrwx---');
+define('ADMIN_GROUP_ID','1');
+define('ANON_USER_ID','2');
+define('ANON_GROUP_ID','3');
+
+# view options
+define('RESULTS_PER_PAGE',24);
diff --git a/webclient/index.php b/webclient/index.php
new file mode 100644 (file)
index 0000000..01164a6
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define('DEBUG',true);
+
+require_once './config/path.php';
+require_once './config/system.php';
+require_once './config/database.php';
+
+# static helper class
+require_once 'lib/summoner.class.php';
+# general includes
+require_once 'lib/doomguy.class.php';
+require_once 'lib/gorenest.class.php';
+
+
+## main vars
+# database object
+$DB = false;
+# the template data as an array
+# and some defaults
+$TemplateData = array();
+$TemplateData['pagination'] = array();
+$TemplateData['searchAction'] = 'index.php';
+# the view
+$View = Summoner::themefile('dashboard/dashboard.html', UI_THEME);
+# the script
+$ViewScript = Summoner::themefile('dashboard/dashboard.php', UI_THEME);
+# the messages
+$ViewMessage = Summoner::themefile('system/message.php',UI_THEME);
+# the menu
+$ViewMenu = Summoner::themefile('system/menu.php',UI_THEME);
+# the pagination
+$ViewPagination = Summoner::themefile('system/pagination.html',UI_THEME);
+
+## DB connection
+$DB = new mysqli(DB_HOST, DB_USERNAME,DB_PASSWORD, DB_NAME);
+$driver = new mysqli_driver();
+$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
+if ($DB->connect_errno) exit('Can not connect to MySQL Server');
+$DB->set_charset("utf8mb4");
+$DB->query("SET collation_connection = 'utf8mb4_0900_ai_ci'");
+
+# user Object
+$Doomguy = new Doomguy($DB);
+# menu Object
+$Gorenest = new GoreNest($DB,$Doomguy);
+
+$_requestMode = false;
+if(isset($_GET['p']) && !empty($_GET['p'])) {
+    $_requestMode = trim($_GET['p']);
+    $_requestMode = Summoner::validate($_requestMode,'nospace') ? $_requestMode : "dashboard";
+
+    $_validPages = $Gorenest->allowedPageRequests();
+    $_validPages["dashboard"] = "dashboard";
+    if(!isset($_validPages[$_requestMode])) $_requestMode = "dashboard";
+
+    $ViewScript = Summoner::themefile($_requestMode.'/'.$_requestMode.'.php', UI_THEME);
+    $View = Summoner::themefile($_requestMode.'/'.$_requestMode.'.html', UI_THEME);
+}
+
+# now inlcude the script
+# this sets information into $Data and can overwrite $View
+if(!empty($ViewScript)) {
+    require_once $ViewScript;
+}
+
+if(!empty($TemplateData['refresh'])) {
+    header("Location: ".$TemplateData['refresh']);
+}
+
+# header information
+header('Content-type: text/html; charset=UTF-8');
+
+## now inlcude the main view
+require_once Summoner::themefile('main.php', UI_THEME);
+
+$DB->close();
diff --git a/webclient/lib/doomguy.class.php b/webclient/lib/doomguy.class.php
new file mode 100644 (file)
index 0000000..1d20d91
--- /dev/null
@@ -0,0 +1,475 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * User object
+ * access rights and information about the current logged in user
+ */
+class Doomguy {
+
+    /**
+     * the global DB object
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * if the user is logged in or not
+     * @var boolean
+     */
+    protected $isSignedIn = false;
+
+    /**
+     * the data from the current user
+     * @var array
+     */
+    protected $userData = false;
+
+    /**
+     * the user ID from user management or default
+     * @var Int
+     */
+    protected $userID = 0;
+
+    /**
+     * the rights string defined the mysql query !
+     * the syntax is for mysql only
+     *
+     * @var array
+     */
+    protected $_rightsArray = array(
+        'user' => array(
+            'read' => 'r________',
+            'write' => 'rw_______',
+            'delete' => 'rwx______'
+        ),
+        'group' => array(
+            'read' => '___r_____',
+            'write' => '___rw____',
+            'delete' => '___rwx___'
+        ),
+        'world' => array(
+            'read' => '______r__',
+            'write' => '______rw_',
+            'delete' => '______rwx'
+        )
+    );
+
+    public function __construct($db) {
+        $this->_DB = $db;
+
+        if($this->_checkSession() === true) {
+            $this->isSignedIn = true;
+            $this->_loadUser();
+        }
+        else {
+            # anonymoose ;-)
+            $this->userID = ANON_USER_ID;
+            $this->_loadUser();
+        }
+    }
+
+    /**
+     * get the value of the specified param from the user data array
+     * @param string $param
+     * @return bool|mixed
+     */
+    public function param($param) {
+        $ret = false;
+
+        $param = trim($param);
+
+        if(!empty($param) && isset($this->userData[$param])) {
+            $ret = $this->userData[$param];
+        }
+
+        return $ret;
+    }
+
+    /**
+     * return the isSignedIn status.
+     * @return boolean
+     */
+    public function isSignedIn() {
+        return $this->isSignedIn;
+    }
+
+    /**
+     * get the data from the userSession table
+     * @param string $param
+     * @return bool
+     */
+    public function getSessionInfo($param) {
+        $ret = false;
+
+        $query = $this->_DB->query("SELECT `".$param."`
+                                                                       FROM `".DB_PREFIX."_userSession`
+                                                                       WHERE `fk_user_id` = '".$this->_DB->real_escape_string($this->userID)."'");
+        if($query !== false && $query->num_rows > 0) {
+            $result = $query->fetch_assoc();
+            $ret = $result[$param];
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Log out the current loaded user
+     * @return boolean
+     */
+    public function logOut () {
+        $ret = false;
+
+        if($this->_checkAgainstSessionTable() === true) {
+            $this->_destroySession();
+            $ret = true;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * check if the loaded user is in this group
+     * if the user is in ADMIN_GROUP_ID, the he is automatically "in" every group
+     * @param int $groupID
+     * @return bool
+     */
+    public function isInGroup($groupID) {
+        $ret = false;
+
+        if($this->userData['isRoot'] === true) {
+            $ret = true;
+        }
+        elseif(in_array($groupID, array_keys($this->userData['group']))) {
+            $ret = true;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * authenticate the user. Create session and db entries
+     * @param string $username
+     * @param string $password
+     * @return boolean
+     */
+    public function authenticate($username,$password) {
+        $ret = false;
+
+        if(!empty($username) && !empty($password)) {
+            $do = $this->_checkAgainstUserTable($username);
+            if($do === true) {
+                # valid user now load the user data and compare password etc.
+                $this->_loadUser();
+                if(password_verify($password,$this->userData['password'])) {
+                    # everything ok
+
+                    # create the session info
+                    $tokenInfo = $this->_createToken();
+                    $_SESSION[SESSION_NAME]['bibliothecatoken'] = $tokenInfo['token'];
+
+                    $this->_DB->query("INSERT INTO `".DB_PREFIX."_userSession`
+                                                               SET `token` = '".$this->_DB->real_escape_string($tokenInfo['token'])."',
+                                                               `loginTime` = NOW(),
+                                                               `area` = '".$this->_DB->real_escape_string(SESSION_NAME)."',
+                                                               `fk_user_id` = '".$this->_DB->real_escape_string($this->userID)."',
+                                                   `salt` = '".$this->_DB->real_escape_string($tokenInfo['salt'])."'
+                                                               ON DUPLICATE KEY UPDATE
+                                                      `token` = '".$this->_DB->real_escape_string($tokenInfo['token'])."',
+                                                      `salt` = '".$this->_DB->real_escape_string($tokenInfo['salt'])."',
+                                                                  `loginTime` = NOW()");
+
+                    # do some actions
+                    $this->_loginActions();
+
+                    $ret = true;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Use the user identified by apitoken
+     * @param $token string
+     */
+    public function authByApiToken($token) {
+        if(!empty($token)) {
+            $queryStr = "SELECT `id`
+                                               FROM `".DB_PREFIX."_user`
+                                               WHERE `apiToken` = '".$this->_DB->real_escape_string($token)."'
+                                               AND `apiTokenValidDate` > NOW()";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                $result = $query->fetch_assoc();
+                $this->userID = $result['id'];
+                $this->isSignedIn = true;
+                $this->_loadUser();
+                $this->_loginActions();
+            }
+        }
+    }
+
+    /**
+     * create the sql string for rights sql
+     *
+     * @param string $mode
+     * @param bool $tableName
+     * @return string $str
+     * @throws Exception
+     */
+    public function getSQLRightsString($mode = "read", $tableName=false) {
+        $prefix = '';
+        if(!empty($tableName)) {
+            $prefix = "`".$tableName."`.";
+        }
+        if(isset($this->_rightsArray['user'][$mode]) && isset($this->_rightsArray['group'][$mode]) && isset($this->_rightsArray['world'][$mode])) {
+            $uid = $this->userID;
+            $gids = implode("','", array_keys($this->userData['groups']));
+
+            if($this->userData['isRoot'] === true) {
+                $str = "( ($prefix`rights` LIKE '".$this->_rightsArray['user'][$mode]."') ";
+                $str .= "OR ($prefix`rights` LIKE '".$this->_rightsArray['group'][$mode]."') ";
+                $str .= "OR ($prefix`rights` LIKE '".$this->_rightsArray['world'][$mode]."') )";
+            }
+            else {
+                $str = "( ($prefix`owner` = ".$uid." AND $prefix`rights` LIKE '".$this->_rightsArray['user'][$mode]."') ";
+                $str .= "OR ($prefix`group` IN ('".$gids."') AND $prefix`rights` LIKE '".$this->_rightsArray['group'][$mode]."') ";
+                $str .= "OR ($prefix`rights` LIKE '".$this->_rightsArray['world'][$mode]."') )";
+            }
+        }
+        else {
+            throw new Exception("Site User: invalid rights string.");
+        }
+
+        return $str;
+    }
+
+    /**
+     * check if we can use session
+     * we only use session if we can use cookies with the session
+     * THIS DOES NOT CHECK IF THE USER HAS COOKIES ACTIVATED !
+     */
+    protected function _checkSession() {
+
+        if(ini_set('session.use_only_cookies',true) === false ||
+            ini_set('session.cookie_httponly',true) === false ||
+            ini_set('session.use_cookies',true) === false) {
+
+            return false;
+        }
+
+
+        $garbage_timeout = SESSION_LIFETIME + 300;
+        ini_set('session.gc_maxlifetime', $garbage_timeout);
+        # the % rate how often the session.gc is run
+        # http://de.php.net/manual/en/session.configuration.php#ini.session.gc-probability
+        ini_set('session.gc_probability',10); // 100 = everytime = 100%
+
+        session_save_path(SESSION_SAVE_PATH);
+        session_set_cookie_params(SESSION_LIFETIME);
+        session_name(SESSION_NAME);
+        session_start();
+        # produce problems
+        # multiple request at once will confuse the script and loose session information
+        #session_regenerate_id(true);
+
+        if(isset($_SESSION[SESSION_NAME]['bibliothecatoken']) && !empty($_SESSION[SESSION_NAME]['bibliothecatoken'])) {
+            return $this->_checkAgainstSessionTable();
+        }
+
+        return false;
+    }
+
+    /**
+     * we have session data available. Now check if those data is valid
+     */
+    protected function _checkAgainstSessionTable() {
+        $ret = false;
+
+        $timeframe = date("Y-m-d H:i:s",time()-SESSION_LIFETIME);
+
+        $queryStr = "SELECT s.fk_user_id, s.salt, s.token FROM `".DB_PREFIX."_userSession` AS s
+                       INNER JOIN `".DB_PREFIX."_user` AS u ON s.fk_user_id = u.id
+                       WHERE s.token = '".$this->_DB->real_escape_string($_SESSION[SESSION_NAME]['bibliothecatoken'])."'
+                   AND s.salt <> ''
+                       AND s.loginTime >= '".$timeframe."'";
+        $query = $this->_DB->query($queryStr);
+
+        if($query !== false && $query->num_rows > 0) {
+            # existing session info
+            $result = $query->fetch_assoc();
+
+            # valide the token
+            $_check = $this->_createToken($result['salt']);
+            if(!empty($_check) && $result['token'] === $_check['token']) {
+                $this->userID = $result['fk_user_id'];
+
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * check if the given username is set in user table
+     * if so load the user data
+     * @param string $u
+     * @return boolean
+     */
+    protected function _checkAgainstUserTable($u) {
+        $ret = false;
+
+        if(!empty($u)) {
+            $query = $this->_DB->query("SELECT `id`
+                                       FROM `".DB_PREFIX."_user`
+                                       WHERE `login` = '". $this->_DB->real_escape_string($u)."'
+                                       AND `active` = '1'");
+            if($query !== false && $query->num_rows > 0) {
+                $result = $query->fetch_assoc();
+                $this->userID = $result['id'];
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * if we have to run some at login
+     */
+    protected function _loginActions() {
+        # @todo:
+        # garbage collection for error files
+
+        # clean old sessions on session table
+        $timeframe = date("Y-m-d H:i:s",time()-SESSION_LIFETIME);
+        $query = $this->_DB->query("DELETE FROM `".DB_PREFIX."_userSession`
+                               WHERE `loginTime` <= '".$timeframe."'");
+    }
+
+    /**
+     * load the user and groups
+     */
+    protected function _loadUser() {
+        if(!empty($this->userID)) {
+            $queryStr = "SELECT `id`, `baseGroupId`,`protected`,`password`,`login`
+                                               FROM `".DB_PREFIX."_user`
+                                               WHERE `id` = '".$this->_DB->real_escape_string($this->userID)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                $result = $query->fetch_assoc();
+                $this->userData = $result;
+            }
+
+            # now the groups
+            $queryStr = "SELECT g.name AS groupName,
+                                       g.description AS groupDescription,
+                                       g.id AS groupId
+                                       FROM `".DB_PREFIX."_user2group` AS u2g,
+                                               `".DB_PREFIX."_group` AS g
+                                       WHERE u2g.fk_user_id = '".$this->_DB->real_escape_string($this->userID)."'
+                                       AND u2g.fk_group_id = g.id";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $this->userData['groups'][$result['groupId']] = array(
+                        'groupName' => $result['groupName'],
+                        'groupDescription' => $result['groupDescription']
+                    );
+                }
+            }
+
+            $this->userData['isRoot'] = false;
+            $grIds = array_keys($this->userData['groups']);
+            if(in_array(ADMIN_GROUP_ID,$grIds)) {
+                $this->userData['isRoot'] = true;
+            }
+        }
+    }
+
+    /**
+     * destroy and remove the current session from SESSION and session table
+     * @return boolean
+     */
+    protected function _destroySession() {
+        $timeframe = date("Y-m-d H:i:s",time()-SESSION_LIFETIME);
+        $query = $this->_DB->query("DELETE FROM `".DB_PREFIX."_userSession`
+                               WHERE `fk_user_id` = '".$this->_DB->real_escape_string($this->userID)."'
+                               OR `loginTime` <= '".$timeframe."'");
+
+        unset($_SESSION);
+        unset($_COOKIE);
+        session_destroy();
+
+        return true;
+    }
+
+    /**
+     * create the usertoken based on the HEADER information:
+     * HTTP_USER_AGENT, REMOTE_ADDR, HTTP_ACCEPT, HTTP_ACCEPT_LANGUAGE
+     * HTTP_ACCEPT_ENCODING, HTTP_VIA
+     * and a salt
+     *
+     * @param bool $salt
+     * @return bool
+     */
+    protected function _createToken($salt=false) {
+        $ret = false;
+
+        $defaultStr = "unknown";
+
+        if(!isset($_SERVER['HTTP_USER_AGENT'])) $_SERVER['HTTP_USER_AGENT'] = $defaultStr;
+        if(!isset($_SERVER['REMOTE_ADDR'])) $_SERVER['REMOTE_ADDR'] = $defaultStr;
+        if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $defaultStr;
+        if(!isset($_SERVER['HTTP_VIA'])) $_SERVER['HTTP_VIA'] = $defaultStr;
+        if(!isset($_SERVER['HTTP_DNT'])) $_SERVER['HTTP_DNT'] = $defaultStr;
+
+        // cli info
+        if(!isset($_SERVER['PATH'])) $_SERVER['PATH'] = $defaultStr;
+        if(!isset($_SERVER['SHELL'])) $_SERVER['SHELL'] = $defaultStr;
+        if(!isset($_SERVER['SESSION_MANAGER'])) $_SERVER['SESSION_MANAGER'] = $defaultStr;
+        if(!isset($_SERVER['USER'])) $_SERVER['USER'] = $defaultStr;
+
+        $finalString = $_SERVER['HTTP_USER_AGENT']
+            .$_SERVER['REMOTE_ADDR']
+            .$_SERVER['HTTP_ACCEPT_LANGUAGE']
+            .$_SERVER['HTTP_DNT']
+            .$_SERVER['HTTP_VIA']
+            .$_SERVER['PATH']
+            .$_SERVER['SHELL']
+            .$_SERVER['SESSION_MANAGER']
+            .$_SERVER['USER'];
+
+        # check how often we have unknown in it
+        # the more the less secure...
+        $_count = substr_count($finalString, $defaultStr);
+        if($_count < 5) {
+            if(empty($salt)) {
+                # 8 chars
+                $salt = bin2hex(openssl_random_pseudo_bytes(4));
+            }
+            $ret['token'] = sha1($finalString.$salt);
+            $ret['salt'] = $salt;
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/gorenest.class.php b/webclient/lib/gorenest.class.php
new file mode 100644 (file)
index 0000000..cfd5cd8
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * the menu class. Provides the menu based on user
+ */
+class GoreNest {
+
+    /**
+     * the global DB object
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * the current loaded user
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * the already loaded menu information
+     * to avoid multiple calls to the DB
+     * @var array
+     */
+    private $_menuData = array();
+
+    /**
+     * GoreNest constructor.
+     * @param $db
+     * @param $user
+     */
+    public function __construct($db, $user) {
+        $this->_DB = $db;
+        $this->_User = $user;
+    }
+
+    /**
+     * Get the menu data for given area and category.
+     * This shows only entries which have a category set.
+     * No category can be used for hidden entries.
+     *
+     * @param $category
+     * @param bool $reload
+     * @return array
+     */
+    public function get($category,$reload=false) {
+
+        if(empty($category)) return false;
+
+        if(empty($reload) && isset($this->_menuData[$category])) {
+            return $this->_menuData[$category];
+        }
+
+        # reset the menu
+        $this->_menuData[$category] = array();
+
+        $queryStr = "SELECT id, text, action, icon, category
+                                       FROM `".DB_PREFIX."_menu`
+                                       WHERE ".$this->_User->getSQLRightsString()."
+                                               AND `category` = '".$this->_DB->real_escape_string($category)."'
+                        ORDER BY position";
+        $query  = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $this->_menuData[$result['category']][$result['id']] = $result;
+            }
+        }
+
+        return $this->_menuData[$category];
+    }
+
+    /**
+     * Allowed page requests based on the menu entries and user
+     * @return array
+     */
+    public function allowedPageRequests() {
+        $ret = array();
+        $queryStr = "SELECT id, action
+                                       FROM `".DB_PREFIX."_menu`
+                                       WHERE ".$this->_User->getSQLRightsString()."";
+        $query  = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['action']] = $result['action'];
+            }
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/imdbwebparser.class.php b/webclient/lib/imdbwebparser.class.php
new file mode 100644 (file)
index 0000000..38ea398
--- /dev/null
@@ -0,0 +1,1808 @@
+<?php
+/**
+ * PHP IMDb.com Grabber
+ *
+ * This PHP library enables you to scrape data from IMDB.com.
+ *
+ *
+ * If you want to thank me for this library, please buy me something at Amazon
+ * (https://www.amazon.de/hz/wishlist/ls/8840JITISN9L/) or use
+ * https://www.paypal.me/FabianBeiner. Thank you!
+ *
+ * @author  Fabian Beiner <fb@fabianbeiner.de>
+ * @license https://opensource.org/licenses/MIT The MIT License
+ * @link    https://github.com/FabianBeiner/PHP-IMDB-Grabber/ GitHub Repository
+ * @version 6.1.7
+ *
+ *
+ * Functionality is the same but modified heavily to remove the does-not-make-sense static helper
+ * wich was not static since it depended on the IMDB class. Also some could not be extended or overwritten
+ *
+ */
+class IMDB
+{
+    /**
+     * Set this to true if you run into problems.
+     */
+    private $IMDB_DEBUG = false;
+
+    /**
+     * Set the preferred language for the User Agent.
+     */
+    private $IMDB_LANG = 'en-US,en;q=0.9';
+
+    /**
+     * Define the timeout for cURL requests.
+     */
+    private $IMDB_TIMEOUT = 15;
+
+    /**
+     * These are the regular expressions used to extract the data.
+     * If you don’t know what you’re doing, you shouldn’t touch them.
+     */
+    const IMDB_AKA           = '~<td[^>]*>\s*Also\s*Known\s*As\s*</td>\s*<td>(.+)</td>~Uis';
+    const IMDB_ASPECT_RATIO  = '~<td[^>]*>Aspect\s*Ratio</td>\s*<td>(.+)</td>~Uis';
+    const IMDB_AWARDS        = '~<div\s*class="titlereference-overview-section">\s*Awards:(.+)</div>~Uis';
+    const IMDB_BUDGET        = '~<td[^>]*>Budget<\/td>\s*<td>\s*(.*)(?:\(estimated\))\s*<\/td>~Ui';
+    const IMDB_CAST          = '~<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="/name/([^/]*)/\?[^"]*"[^>]*>\s*<span.+>(.+)</span~Ui';
+    const IMDB_CAST_IMAGE    = '~(loadlate="(.*)"[^>]*><\/a>\s+<\/td>\s+)?<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="\/name\/([^/]*)\/\?[^"]*"[^>]*>\s*<span.+>(.+)<\/span+~Uis';
+    const IMDB_CERTIFICATION = '~<td[^>]*>\s*Certification\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_CHAR          = '~<td class="character">(?:\s+)<div>(.*)(?:\s+)(?: /| \(.*\)|<\/div>)~Ui';
+    const IMDB_COLOR         = '~<a href="\/search\/title\?colors=(?:.*)">(.*)<\/a>~Ui';
+    const IMDB_COMPANY       = '~href="[^"]*update=[t0-9]+:production_companies[^"]*">Edit</a>\s*</header>\s*<ul\s*class="simpleList">.+<a href="\/company\/(.*)\/">(.*)</a>~Ui';
+    const IMDB_COUNTRY       = '~<a href="/country/(\w+)">(.*)</a>~Ui';
+    const IMDB_CREATOR       = '~<div[^>]*>\s*(?:Creator|Creators)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
+    const IMDB_DIRECTOR      = '~<div[^>]*>\s*(?:Director|Directors)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
+    const IMDB_GENRE         = '~href="/genre/([a-zA-Z_-]*)/?">([a-zA-Z_ -]*)</a>~Ui';
+    const IMDB_GROSS         = '~pl-zebra-list__label">Cumulative Worldwide Gross<\/td>\s+<td>\s+(.*)\s+<~Uxsi';
+    const IMDB_ID            = '~((?:tt\d{6,})|(?:itle\?\d{6,}))~';
+    const IMDB_LANGUAGE      = '~<a href="\/language\/(\w+)">(.*)<\/a>~Ui';
+    const IMDB_LOCATION      = '~href="\/search\/title\?locations=(.*)">(.*)<\/a>~Ui';
+    const IMDB_LOCATIONS     = '~href="\/search\/title\?locations=[^>]*>\s?(.*)\s?<\/a>[^"]*<dd>\s?(.*)\s<\/dd>~Ui';
+    const IMDB_MPAA          = '~<li class="ipl-inline-list__item">(?:\s+)(TV-Y|TV-Y7|TV-G|TV-PG|TV-14|TV-MA|G|PG|PG-13|R|NC-17|NR|UR)(?:\s+)<\/li>~Ui';
+    const IMDB_NAME          = '~href="/name/(.+)/?(?:\?[^"]*)?"[^>]*>(.+)</a>~Ui';
+    const IMDB_DESCRIPTION   = '~<section class="titlereference-section-overview">\s+<div>(.*)</div>\s+<hr>~Ui';
+    const IMDB_NOT_FOUND     = '~<h1 class="findHeader">No results found for ~Ui';
+    const IMDB_PLOT          = '~<td[^>]*>\s*Plot\s*Summary\s*</td>\s*<td>\s*<p>(.+)</p>~Ui';
+    const IMDB_PLOT_KEYWORDS = '~<td[^>]*>Plot\s*Keywords</td>\s*<td>(.+)(?:<a\s*href="/title/[^>]*>[^<]*</a>\s*</li>\s*</ul>\s*)?</td>~Ui';
+    const IMDB_POSTER        = '~<link\s*rel=\'image_src\'\s*href="(.*)">~Ui';
+    const IMDB_RATING        = '~class="ipl-rating-star__rating">(.*)<~Ui';
+    const IMDB_RATING_COUNT  = '~class="ipl-rating-star__total-votes">\((.*)\)<~Ui';
+    const IMDB_RELEASE_DATE  = '~href="/title/[t0-9]*/releaseinfo">(.*)<~Ui';
+    const IMDB_RUNTIME       = '~<td[^>]*>\s*Runtime\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_SEARCH        = '~<td class="result_text"> <a href="\/title\/(tt\d{6,})\/(?:.*)"(?:\s*)>(?:.*)<\/a>~Ui';
+    const IMDB_SEASONS       = '~episodes\?season=(?:\d+)">(\d+)<~Ui';
+    const IMDB_SOUND_MIX     = '~<td[^>]*>\s*Sound\s*Mix\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_TAGLINE       = '~<td[^>]*>\s*Taglines\s*</td>\s*<td>(.+)</td>~Ui';
+    const IMDB_TITLE         = '~itemprop="name">(.*)(<\/h3>|<span)~Ui';
+    const IMDB_TITLE_ORIG    = '~</h3>(?:\s+)(.*)(?:\s+)<span class=\"titlereference-original-title-label~Ui';
+    const IMDB_TRAILER       = '~href="videoplayer/(vi[0-9]*)"~Ui';
+    const IMDB_URL           = '~https?://(?:.*\.|.*)imdb.com/(?:t|T)itle(?:\?|/)(..\d+)~i';
+    const IMDB_USER_REVIEW   = '~href="/title/[t0-9]*/reviews"[^>]*>([^<]*)\s*User~Ui';
+    const IMDB_VOTES         = '~"ipl-rating-star__total-votes">\s*\((.*)\)\s*<~Ui';
+    const IMDB_WRITER        = '~<div[^>]*>\s*(?:Writer|Writers)\s*:\s*<ul[^>]*>(.+)</ul>~Ui';
+    const IMDB_YEAR          = '~og:title\' content="(?:.*)\((?:.*)(\d{4})(?:.*)\)~Ui';
+
+    /**
+     * @var string The string returned, if nothing is found.
+     */
+    public $sNotFound = 'n/A';
+
+    /**
+     * @var null|int The ID of the movie.
+     */
+    public $iId = null;
+
+    /**
+     * @var bool Is the content ready?
+     */
+    public $isReady = false;
+
+    /**
+     * @var string Char that separates multiple entries.
+     */
+    public $sSeparator = ' / ';
+
+    /**
+     * @var null|string The URL to the movie.
+     */
+    public $sUrl = null;
+
+    /**
+     * @var bool Return responses enclosed in array
+     */
+    public $bArrayOutput = false;
+
+    /**
+     * @var int Maximum cache time.
+     */
+    private $iCache = 1440;
+
+    /**
+     * @var null|string The root of the script.
+     */
+    private $sRoot = null;
+
+    /**
+     * @var null|string Holds the source.
+     */
+    private $sSource = null;
+
+    /**
+     * @var string What to search for?
+     */
+    private $sSearchFor = 'all';
+
+    /**
+     * IMDB constructor. Can now set some options
+     *
+     * @param $options array with the following options
+     *      int iCache Custom cache time in minutes.
+     *      string sSearchFor What type to search for?
+     *      string storage Where to store data. Absolute path
+     *      boolean debug Show depubg messages or not
+     */
+    public function __construct($options) {
+
+        if(isset($options['debug']) && !empty($options['debug'])) {
+            $this->IMDB_DEBUG = true;
+        }
+
+        if(isset($options['iCache']) && !empty($options['iCache'])) $this->iCache = (int) $options['iCache'];
+
+        $this->sRoot = dirname(__FILE__);
+        if(isset($options['storage']) && !empty($options['storage'])) {
+            $this->sRoot = $options['storage'];
+        }
+
+        if(isset($options['sSearchFor']) && !empty($options['sSearchFor'])) {
+            if (in_array(
+                $options['sSearchFor'],
+                [
+                    'movie',
+                    'tv',
+                    'episode',
+                    'game',
+                    'all',
+                ]
+            )) {
+                $this->sSearchFor = $options['sSearchFor'];
+            }
+        }
+    }
+
+
+    /**
+     * @param $sSearch
+     * @throws Exception
+     */
+    public function search($sSearch) {
+
+        $sSearch = trim($sSearch);
+        if(empty($sSearch)) {
+            throw new Exception('Missing search term');
+        }
+
+        if ( ! is_writable($this->sRoot . '/posters') && ! mkdir($this->sRoot . '/posters')) {
+            throw new Exception('The directory “' . $this->sRoot . '/posters” isn’t writable.');
+        }
+        if ( ! is_writable($this->sRoot . '/cache') && ! mkdir($this->sRoot . '/cache')) {
+            throw new Exception('The directory “' . $this->sRoot . '/cache” isn’t writable.');
+        }
+        if ( ! is_writable($this->sRoot . '/cast') && ! mkdir($this->sRoot . '/cast')) {
+            throw new Exception('The directory “' . $this->sRoot . '/cast” isn’t writable.');
+        }
+
+        if ( ! function_exists('curl_init')) {
+            throw new Exception('You need to enable the PHP cURL extension.');
+        }
+
+        $this->fetchUrl($sSearch);
+    }
+
+    /**
+     * @param string $sSearch IMDb URL or movie title to search for.
+     *
+     * @return bool True on success, false on failure.
+     */
+    private function fetchUrl($sSearch)
+    {
+
+
+        if ($this->IMDB_DEBUG) {
+            echo '<pre><b>Running:</b> fetchUrl("' . $sSearch . '")</pre>';
+        }
+
+        // Try to find a valid URL.
+        $sId = $this->matchRegex($sSearch, self::IMDB_ID, 1);
+        if (false !== $sId) {
+            $this->iId  = preg_replace('~[\D]~', '', $sId);
+            $this->sUrl = 'https://www.imdb.com/title/tt' . $this->iId . '/reference';
+            $bSearch    = false;
+        } else {
+            switch (strtolower($this->sSearchFor)) {
+                case 'movie':
+                    $sParameters = '&s=tt&ttype=ft';
+                    break;
+                case 'tv':
+                    $sParameters = '&s=tt&ttype=tv';
+                    break;
+                case 'episode':
+                    $sParameters = '&s=tt&ttype=ep';
+                    break;
+                case 'game':
+                    $sParameters = '&s=tt&ttype=vg';
+                    break;
+                default:
+                    $sParameters = '&s=tt';
+            }
+
+            $this->sUrl = 'https://www.imdb.com/find?q=' . rawurlencode(str_replace(' ', '+', $sSearch)) . $sParameters;
+            $bSearch    = true;
+
+            // Was this search already performed and cached?
+            $sRedirectFile = $this->sRoot . '/cache/' . sha1($this->sUrl) . '.redir';
+            if (is_readable($sRedirectFile)) {
+                if ($this->IMDB_DEBUG) {
+                    echo '<pre><b>Using redirect:</b> ' . basename($sRedirectFile) . '</pre>';
+                }
+                $sRedirect  = file_get_contents($sRedirectFile);
+                $this->sUrl = trim($sRedirect);
+                $this->iId  = preg_replace('~[\D]~', '', $this->matchRegex($sRedirect, self::IMDB_ID, 1));
+                $bSearch    = false;
+            }
+        }
+
+        // Does a cache of this movie exist?
+        $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '.cache';
+        if (is_readable($sCacheFile)) {
+            $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+            if ($iDiff < $this->iCache) {
+                if ($this->IMDB_DEBUG) {
+                    echo '<pre><b>Using cache:</b> ' . basename($sCacheFile) . '</pre>';
+                }
+                $this->sSource = file_get_contents($sCacheFile);
+                $this->isReady = true;
+
+                return true;
+            }
+        }
+
+        // Run cURL on the URL.
+        if ($this->IMDB_DEBUG) {
+            echo '<pre><b>Running cURL:</b> ' . $this->sUrl . '</pre>';
+        }
+
+        $aCurlInfo = $this->runCurl($this->sUrl);
+        $sSource   = $aCurlInfo['contents'];
+
+        if (false === $sSource) {
+            if ($this->IMDB_DEBUG) {
+                echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+            }
+
+            return false;
+        }
+
+        // Was the movie found?
+        $sMatch = $this->matchRegex($sSource, self::IMDB_SEARCH, 1);
+        if (false !== $sMatch) {
+            $sUrl = 'https://www.imdb.com/title/' . $sMatch . '/reference';
+            if ($this->IMDB_DEBUG) {
+                echo '<pre><b>New redirect saved:</b> ' . basename($sRedirectFile) . ' => ' . $sUrl . '</pre>';
+            }
+            file_put_contents($sRedirectFile, $sUrl);
+            $this->sSource = null;
+            $this->fetchUrl($sUrl);
+
+            return true;
+        }
+        $sMatch = $this->matchRegex($sSource, self::IMDB_NOT_FOUND, 0);
+        if (false !== $sMatch) {
+            if ($this->IMDB_DEBUG) {
+                echo '<pre><b>Movie not found:</b> ' . $sSearch . '</pre>';
+            }
+
+            return false;
+        }
+
+        $this->sSource = str_replace(
+            [
+                "\n",
+                "\r\n",
+                "\r",
+            ],
+            '',
+            $sSource
+        );
+        $this->isReady = true;
+
+        // Save cache.
+        if (false === $bSearch) {
+            if ($this->IMDB_DEBUG) {
+                echo '<pre><b>Cache created:</b> ' . basename($sCacheFile) . '</pre>';
+            }
+            file_put_contents($sCacheFile, $this->sSource);
+        }
+
+        return true;
+    }
+
+    /**
+     * @return array All data.
+     */
+    public function getAll()
+    {
+        $aData = [];
+        foreach (get_class_methods(__CLASS__) as $method) {
+            if (substr($method, 0, 3) === 'get' && $method !== 'getAll' && $method !== 'getCastImages') {
+                $aData[$method] = [
+                    'name'  => ltrim($method, 'get'),
+                    'value' => $this->{$method}(),
+                ];
+            }
+        }
+        array_multisort($aData);
+
+        return $aData;
+    }
+
+    /**
+     * @return string “Also Known As” or $sNotFound.
+     */
+    public function getAka()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_AKA, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * Returns all local names
+     *
+     * @return string All local names.
+     */
+    public function getAkas()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            } else {
+                $fullAkas  = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
+                $aCurlInfo = $this->runCurl($fullAkas);
+                $sSource   = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if ($this->IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = $this->matchRegex($sSource, "~<td>(.*?)<\/td>\s+<td>(.*?)<\/td>~");
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'title'   => $this->cleanString($aReturned[2][$i]),
+                                'country' => $this->cleanString($strName),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string “Aspect Ratio” or $sNotFound.
+     */
+    public function getAspectRatio()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_ASPECT_RATIO, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The awards of the movie or $sNotFound
+     */
+    public function getAwards()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_AWARDS, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param int    $iLimit  How many cast members should be returned?
+     * @param bool   $bMore   Add … if there are more cast members than printed.
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked cast members or $sNotFound.
+     */
+    public function getCastAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_CAST);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return $this->arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    $this->sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param int  $iLimit How many cast members should be returned?
+     * @param bool $bMore  Add … if there are more cast members than printed.
+     *
+     * @return string A list with cast members or $sNotFound.
+     */
+    public function getCast($iLimit = 0, $bMore = true)
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_CAST);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = $this->cleanString($sName);
+                }
+
+                $bMore = (0 !== $iLimit && $bMore && (count($aMatch[2]) > $iLimit) ? '…' : '');
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return $this->arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    $this->sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @param int    $iLimit    How many cast images should be returned?
+     * @param bool   $bMore     Add … if there are more cast members than printed.
+     * @param string $sSize     small, mid or big cast images
+     * @param bool   $bDownload Return URL or Download
+     *
+     * @return array Array with cast name as key, and image as value.
+     */
+    public function getCastImages($iLimit = 0, $bMore = true, $sSize = 'small', $bDownload = false)
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_CAST_IMAGE);
+            $aReturn = [];
+            if (count($aMatch[4])) {
+                foreach ($aMatch[4] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $sMatch = $aMatch[2][$i];
+
+                    if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                        $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
+                    } elseif ('mid' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                        $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@._V1_UX214_AL_.jpg';
+                    }
+
+                    if (false === $bDownload) {
+                        $sMatch = $this->cleanString($sMatch);
+                    } else {
+                        $sLocal = $this->saveImageCast($sMatch, $aMatch[3][$i]);
+                        if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                            $sMatch = $sLocal;
+                        } else {
+                            //the 'big' image isn't available, try the 'mid' one (vice versa)
+                            if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
+                                //trying the 'mid' one
+                                $sMatch = substr(
+                                        $aMatch[2][$i],
+                                        0,
+                                        strpos($aMatch[2][$i], '@._')
+                                    ) . '@._V1_UX214_AL_.jpg';
+                            } else {
+                                //trying the 'big' one
+                                $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
+                            }
+
+                            $sLocal = $this->saveImageCast($sMatch, $aMatch[3][$i]);
+                            if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                                $sMatch = $sLocal;
+                            } else {
+                                $sMatch = $this->cleanString($aMatch[2][$i]);
+                            }
+                        }
+                    }
+
+                    $aReturn[$this->cleanString($aMatch[4][$i])] = $sMatch;
+                }
+
+                $bMore = (0 !== $iLimit && $bMore && (count($aMatch[4]) > $iLimit) ? '…' : '');
+
+                $bHaveMore = ($bMore && (count($aMatch[4]) > $iLimit));
+
+                $aReturn = array_replace(
+                    $aReturn,
+                    array_fill_keys(
+                        array_keys($aReturn, $this->sNotFound),
+                        'cast/not-found.jpg'
+                    )
+                );
+
+                return $aReturn;
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @param int    $iLimit  How many cast members should be returned?
+     * @param bool   $bMore   Add … if there are more cast members than
+     *                        printed.
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked cast members and their character or
+     *                $sNotFound.
+     */
+    public function getCastAndCharacterAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch     = $this->matchRegex($this->sSource, self::IMDB_CAST);
+            $aMatchChar = $this->matchRegex($this->sSource, self::IMDB_CHAR);
+            $aReturn    = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a> as ' . $this->cleanString($aMatchChar[1][$i]);
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return $this->arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    $this->sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @param int  $iLimit How many cast members should be returned?
+     * @param bool $bMore  Add … if there are more cast members than printed.
+     *
+     * @return string  A list with cast members and their character or
+     *                 $sNotFound.
+     */
+    public function getCastAndCharacter($iLimit = 0, $bMore = true)
+    {
+        if (true === $this->isReady) {
+            $aMatch     = $this->matchRegex($this->sSource, self::IMDB_CAST);
+            $aMatchChar = $this->matchRegex($this->sSource, self::IMDB_CHAR);
+            $aReturn    = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    if (0 !== $iLimit && $i >= $iLimit) {
+                        break;
+                    }
+                    $aReturn[] = $this->cleanString($sName) . ' as ' . $this->cleanString($aMatchChar[1][$i]);
+                }
+
+                $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
+
+                return $this->arrayOutput(
+                    $this->bArrayOutput,
+                    $this->sSeparator,
+                    $this->sNotFound,
+                    $aReturn,
+                    $bHaveMore
+                );
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string The certification of the movie or $sNotFound.
+     */
+    public function getCertification()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_CERTIFICATION, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string Color or $sNotFound.
+     */
+    public function getColor()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_COLOR, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The company producing the movie or $sNotFound.
+     */
+    public function getCompany()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCompanyAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string The linked company producing the movie or $sNotFound.
+     */
+    public function getCompanyAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch = $this->matchRegex($this->sSource, self::IMDB_COMPANY);
+            if (isset($aMatch[2][0])) {
+                return '<a href="https://www.imdb.com/company/' . $this->cleanString(
+                        $aMatch[1][0]
+                    ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                        $aMatch[2][0]
+                    ) . '</a>';
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with countries or $sNotFound.
+     */
+    public function getCountry()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCountryAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with linked countries or $sNotFound.
+     */
+    public function getCountryAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_COUNTRY);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/country/' . trim(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string A list with the creators or $sNotFound.
+     */
+    public function getCreator()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getCreatorAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked creators or $sNotFound.
+     */
+    public function getCreatorAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = $this->matchRegex($this->sSource, self::IMDB_CREATOR, 1);
+            $aMatch  = $this->matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string The description of the movie or $sNotFound.
+     */
+    public function getDescription()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_DESCRIPTION, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with the directors or $sNotFound.
+     */
+    public function getDirector()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getDirectorAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked directors or $sNotFound.
+     */
+    public function getDirectorAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = $this->matchRegex($this->sSource, self::IMDB_DIRECTOR, 1);
+            $aMatch  = $this->matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string A list with the genres or $sNotFound.
+     */
+    public function getGenre()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getGenreAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked genres or $sNotFound.
+     */
+    public function getGenreAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_GENRE);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach (array_unique($aMatch[2]) as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/search/title?genres=' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string cumulative worldwide gross or $sNotFound.
+     */
+    public function getGross()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_GROSS, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with the languages or $sNotFound.
+     */
+    public function getLanguage()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getLanguageAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked languages or $sNotFound.
+     */
+    public function getLanguageAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_LANGUAGE);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/language/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string A list with the location or $sNotFound.
+     */
+    public function getLocation()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getLocationAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked location or $sNotFound.
+     */
+    public function getLocationAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_LOCATION);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/search/title?locations=' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * Returns all locations
+     *
+     * @return string location
+     * @return string specification
+     */
+    public function getLocations()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_locations.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            } else {
+                $fullLocations = sprintf('https://www.imdb.com/title/tt%s/locations', $this->iId);
+                $aCurlInfo     = $this->runCurl($fullLocations);
+                $sSource       = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if ($this->IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = $this->matchRegex($sSource, self::IMDB_LOCATIONS);
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'location' => $this->cleanString($strName),
+                            ];
+                        }
+                        if (strpos($aReturned[2][$i], '(') !== false) {
+                            $aReturn[] = [
+                                'specification' => $this->cleanString($aReturned[2][$i]),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string The MPAA of the movie or $sNotFound.
+     */
+    public function getMpaa()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_MPAA, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with the plot keywords or $sNotFound.
+     */
+    public function getPlotKeywords()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_PLOT_KEYWORDS, 1);
+            if (false !== $sMatch) {
+                $aReturn = explode('|', $this->cleanString($sMatch));
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @param int $iLimit The limit.
+     *
+     * @return string The plot of the movie or $sNotFound.
+     */
+    public function getPlot($iLimit = 0)
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_PLOT, 1);
+            if (false !== $sMatch) {
+                if ($iLimit !== 0) {
+                    return $this->shortText($this->cleanString($sMatch), $iLimit);
+                }
+
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sSize     Small, big, xxs, xs, s poster?
+     * @param bool   $bDownload Return URL to the poster or download it?
+     *
+     * @return bool|string Path to the poster.
+     */
+    public function getPoster($sSize = 'small', $bDownload = false)
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_POSTER, 1);
+            if (false !== $sMatch) {
+                if ('big' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@.jpg';
+                }
+                if ('xxs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY67_CR0,0,45,67_AL_.jpg';
+                }
+                if ('xs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY113_CR0,0,76,113_AL_.jpg';
+                }
+                if ('s' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
+                    $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UX182_CR0,0,182,268_AL_.jpg';
+                }
+                if (false === $bDownload) {
+                    return $this->cleanString($sMatch);
+                } else {
+                    $sLocal = $this->saveImage($sMatch, $this->iId);
+                    if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
+                        return $sLocal;
+                    } else {
+                        return $sMatch;
+                    }
+                }
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The rating of the movie or $sNotFound.
+     */
+    public function getRating()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_RATING, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The rating count of the movie or $sNotFound.
+     */
+    public function getRatingCount()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_RATING_COUNT, 1);
+            if (false !== $sMatch) {
+                return str_replace(',', '', $this->cleanString($sMatch));
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * Release date doesn't contain all the information we need to create a media and
+     * we need this function that checks if users can vote target media (if can, it's released).
+     *
+     * @return  true If the media is released
+     */
+    public function isReleased()
+    {
+        $strReturn = $this->getReleaseDate();
+        if ($strReturn == $this->sNotFound || $strReturn == 'Not yet released') {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return string The release date of the movie or $sNotFound.
+     */
+    public function getReleaseDate()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_RELEASE_DATE, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * Returns all local names
+     *
+     * @return string country
+     * @return string release date
+     */
+    public function getReleaseDates()
+    {
+        if (true === $this->isReady) {
+            // Does a cache of this movie exist?
+            $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
+            $bUseCache  = false;
+
+            if (is_readable($sCacheFile)) {
+                $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
+                if ($iDiff < $this->iCache || false) {
+                    $bUseCache = true;
+                }
+            }
+
+            if ($bUseCache) {
+                $aRawReturn = file_get_contents($sCacheFile);
+                $aReturn    = unserialize($aRawReturn);
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            } else {
+                $fullAkas  = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
+                $aCurlInfo = $this->runCurl($fullAkas);
+                $sSource   = $aCurlInfo['contents'];
+
+                if (false === $sSource) {
+                    if ($this->IMDB_DEBUG) {
+                        echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
+                    }
+
+                    return false;
+                }
+
+                $aReturned = $this->matchRegex(
+                    $sSource,
+                    '~>(.*)<\/a><\/td>\s+<td class="release_date">(.*)<\/td>~'
+                );
+
+                if ($aReturned) {
+                    $aReturn = [];
+                    foreach ($aReturned[1] as $i => $strName) {
+                        if (strpos($strName, '(') === false) {
+                            $aReturn[] = [
+                                'country'     => $this->cleanString($strName),
+                                'releasedate' => $this->cleanString($aReturned[2][$i]),
+                            ];
+                        }
+                    }
+
+                    file_put_contents($sCacheFile, serialize($aReturn));
+
+                    return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+                }
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string The runtime of the movie or $sNotFound.
+     */
+    public function getRuntime()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_RUNTIME, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with the seasons or $sNotFound.
+     */
+    public function getSeasons()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getSeasonsAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked seasons or $sNotFound.
+     */
+    public function getSeasonsAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $aMatch  = $this->matchRegex($this->sSource, self::IMDB_SEASONS);
+            $aReturn = [];
+            if (count($aMatch[1])) {
+                foreach (range(1, max($aMatch[1])) as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/title/tt' . $this->iId . '/episodes?season=' . $sName . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $sName . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
+    }
+
+    /**
+     * @return string The sound mix of the movie or $sNotFound.
+     */
+    public function getSoundMix()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_SOUND_MIX, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The tagline of the movie or $sNotFound.
+     */
+    public function getTagline()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_TAGLINE, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param bool $bForceLocal Try to return the original name of the movie.
+     *
+     * @return string The title of the movie or $sNotFound.
+     */
+    public function getTitle($bForceLocal = false)
+    {
+        if (true === $this->isReady) {
+            if (true === $bForceLocal) {
+                $sMatch = $this->matchRegex($this->sSource, self::IMDB_TITLE_ORIG, 1);
+                if (false !== $sMatch && "" !== $sMatch) {
+                    return $this->cleanString($sMatch);
+                }
+            }
+
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_TITLE, 1);
+            $sMatch = preg_replace('~\(\d{4}\)$~Ui', '', $sMatch);
+            if (false !== $sMatch && "" !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param bool $bEmbed Link to player directly?
+     *
+     * @return string The URL to the trailer of the movie or $sNotFound.
+     */
+    public function getTrailerAsUrl($bEmbed = false)
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_TRAILER, 1);
+            if (false !== $sMatch) {
+                $sUrl = 'https://www.imdb.com/video/imdb/' . $sMatch . '/' . ($bEmbed ? 'player' : '');
+
+                return $this->cleanString($sUrl);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The IMDb URL.
+     */
+    public function getUrl()
+    {
+        if (true === $this->isReady) {
+            return $this->cleanString(str_replace('reference', '', $this->sUrl));
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The user review of the movie or $sNotFound.
+     */
+    public function getUserReview()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_USER_REVIEW, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The votes of the movie or $sNotFound.
+     */
+    public function getVotes()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_VOTES, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string A list with the writers or $sNotFound.
+     */
+    public function getWriter()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->getWriterAsUrl();
+            if ($this->sNotFound !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @param string $sTarget Add a target to the links?
+     *
+     * @return string A list with the linked writers or $sNotFound.
+     */
+    public function getWriterAsUrl($sTarget = '')
+    {
+        if (true === $this->isReady) {
+            $sMatch  = $this->matchRegex($this->sSource, self::IMDB_WRITER, 1);
+            $aMatch  = $this->matchRegex($sMatch, self::IMDB_NAME);
+            $aReturn = [];
+            if (count($aMatch[2])) {
+                foreach ($aMatch[2] as $i => $sName) {
+                    $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
+                            $aMatch[1][$i]
+                        ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
+                            $sName
+                        ) . '</a>';
+                }
+
+                return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The year of the movie or $sNotFound.
+     */
+    public function getYear()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_YEAR, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+    /**
+     * @return string The budget of the movie or $sNotFound.
+     */
+    public function getBudget()
+    {
+        if (true === $this->isReady) {
+            $sMatch = $this->matchRegex($this->sSource, self::IMDB_BUDGET, 1);
+            if (false !== $sMatch) {
+                return $this->cleanString($sMatch);
+            }
+        }
+
+        return $this->sNotFound;
+    }
+
+
+    /**
+     * Regular expression helper.
+     *
+     * @param string $sContent The content to search in.
+     * @param string $sPattern The regular expression.
+     * @param null   $iIndex   The index to return.
+     *
+     * @return bool   If no match was found.
+     * @return string If one match was found.
+     * @return array  If more than one match was found.
+     */
+    private function matchRegex($sContent, $sPattern, $iIndex = null)
+    {
+        preg_match_all($sPattern, $sContent, $aMatches);
+        if ($aMatches === false) {
+            return false;
+        }
+        if ($iIndex !== null && is_int($iIndex)) {
+            if (isset($aMatches[$iIndex][0])) {
+                return $aMatches[$iIndex][0];
+            }
+
+            return false;
+        }
+
+        return $aMatches;
+    }
+
+    /**
+     * Preferred output in responses with multiple elements
+     *
+     * @param bool   $bArrayOutput Native array or string with separators.
+     * @param string $sSeparator   String separator.
+     * @param string $sNotFound    Not found text.
+     * @param array  $aReturn      Original input.
+     * @param bool   $bHaveMore    Have more elements indicator.
+     *
+     * @return string|array Multiple results separated by selected separator string, or enclosed into native array.
+     */
+    private function arrayOutput($bArrayOutput, $sSeparator, $sNotFound, $aReturn = null, $bHaveMore = false)
+    {
+        if ($bArrayOutput) {
+            if ($aReturn == null || ! is_array($aReturn)) {
+                return [];
+            }
+
+            if ($bHaveMore) {
+                $aReturn[] = '…';
+            }
+
+            return $aReturn;
+        } else {
+            if ($aReturn == null || ! is_array($aReturn)) {
+                return $sNotFound;
+            }
+
+            foreach ($aReturn as $i => $value) {
+                if (is_array($value)) {
+                    $aReturn[$i] = implode($sSeparator, $value);
+                }
+            }
+
+            return implode($sSeparator, $aReturn) . (($bHaveMore) ? '…' : '');
+        }
+    }
+
+    /**
+     * @param string $sInput Input (eg. HTML).
+     *
+     * @return string Cleaned string.
+     */
+    private function cleanString($sInput)
+    {
+        $aSearch  = [
+            'Full summary &raquo;',
+            'Full synopsis &raquo;',
+            'Add summary &raquo;',
+            'Add synopsis &raquo;',
+            'See more &raquo;',
+            'See why on IMDbPro.',
+            "\n",
+            "\r",
+        ];
+        $aReplace = [
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+            '',
+        ];
+        $sInput   = str_replace('</li>', ' | ', $sInput);
+        $sInput   = strip_tags($sInput);
+        $sInput   = str_replace('&nbsp;', ' ', $sInput);
+        $sInput   = str_replace($aSearch, $aReplace, $sInput);
+        $sInput   = html_entity_decode($sInput, ENT_QUOTES | ENT_HTML5);
+        $sInput   = preg_replace('/\s+/', ' ', $sInput);
+        $sInput   = trim($sInput);
+        $sInput   = rtrim($sInput, ' |');
+
+        return ($sInput ? trim($sInput) : $this->sNotFound);
+    }
+
+    /**
+     * @param string $sText   The long text.
+     * @param int    $iLength The maximum length of the text.
+     *
+     * @return string The shortened text.
+     */
+    private function shortText($sText, $iLength = 100)
+    {
+        if (mb_strlen($sText) <= $iLength) {
+            return $sText;
+        }
+
+        list($sShort) = explode("\n", wordwrap($sText, $iLength - 1));
+
+        if (substr($sShort, -1) !== '.') {
+            return $sShort . '…';
+        }
+
+        return $sShort;
+    }
+
+    /**
+     * @param string $sUrl The URL to the image to download.
+     * @param int    $iId  The ID of the movie.
+     *
+     * @return string Local path.
+     */
+    private function saveImage($sUrl, $iId)
+    {
+        if (preg_match('~title_addposter.jpg|imdb-share-logo.png~', $sUrl)) {
+            return 'posters/not-found.jpg';
+        }
+
+        $sFilename = $this->sRoot . '/posters/' . $iId . '.jpg';
+        if (file_exists($sFilename)) {
+            return 'posters/' . $iId . '.jpg';
+        }
+
+        $aCurlInfo = $this->runCurl($sUrl, true);
+        $sData     = $aCurlInfo['contents'];
+        if (false === $sData) {
+            return 'posters/not-found.jpg';
+        }
+
+        $oFile = fopen($sFilename, 'x');
+        fwrite($oFile, $sData);
+        fclose($oFile);
+
+        return 'posters/' . $iId . '.jpg';
+    }
+
+    /**
+     * @param string $sUrl      The URL to fetch.
+     * @param bool   $bDownload Download?
+     *
+     * @return bool|mixed Array on success, false on failure.
+     */
+    private function runCurl($sUrl, $bDownload = false)
+    {
+        $oCurl = curl_init($sUrl);
+        curl_setopt_array(
+            $oCurl,
+            [
+                CURLOPT_BINARYTRANSFER => ($bDownload ? true : false),
+                CURLOPT_CONNECTTIMEOUT => $this->IMDB_TIMEOUT,
+                CURLOPT_ENCODING       => '',
+                CURLOPT_FOLLOWLOCATION => 0,
+                CURLOPT_FRESH_CONNECT  => 0,
+                CURLOPT_HEADER         => ($bDownload ? false : true),
+                CURLOPT_HTTPHEADER     => [
+                    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+                    'Accept-Charset: utf-8, iso-8859-1;q=0.5',
+                    'Accept-Language: ' . $this->IMDB_LANG,
+                ],
+                CURLOPT_REFERER        => 'https://www.imdb.com',
+                CURLOPT_RETURNTRANSFER => 1,
+                CURLOPT_SSL_VERIFYHOST => 0,
+                CURLOPT_SSL_VERIFYPEER => 0,
+                CURLOPT_TIMEOUT        => $this->IMDB_TIMEOUT,
+                CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',
+                CURLOPT_VERBOSE        => 0,
+            ]
+        );
+        $sOutput   = curl_exec($oCurl);
+        $aCurlInfo = curl_getinfo($oCurl);
+        curl_close($oCurl);
+        $aCurlInfo['contents'] = $sOutput;
+
+        if (200 !== $aCurlInfo['http_code'] && 302 !== $aCurlInfo['http_code']) {
+            if ($this->IMDB_DEBUG) {
+                echo '<pre><b>cURL returned wrong HTTP code “' . $aCurlInfo['http_code'] . '”, aborting.</b></pre>';
+            }
+
+            return false;
+        }
+
+        return $aCurlInfo;
+    }
+
+    /**
+     * @param string $sUrl The URL to the image to download.
+     * @param int    $cId  The cast ID of the actor.
+     *
+     * @return string Local path.
+     */
+    private function saveImageCast($sUrl, $cId)
+    {
+        if ( ! preg_match('~http~', $sUrl)) {
+            return 'cast/not-found.jpg';
+        }
+
+        $sFilename = $this->sRoot . '/cast/' . $cId . '.jpg';
+        if (file_exists($sFilename)) {
+            return 'cast/' . $cId . '.jpg';
+        }
+
+        $aCurlInfo = $this->runCurl($sUrl, true);
+        $sData     = $aCurlInfo['contents'];
+        if (false === $sData) {
+            return 'cast/not-found.jpg';
+        }
+
+        $oFile = fopen($sFilename, 'x');
+        fwrite($oFile, $sData);
+        fclose($oFile);
+
+        return 'cast/' . $cId . '.jpg';
+    }
+
+    /**
+     * Makes strings with $this->sSeparator as separator result in an array
+     *
+     * @param $string
+     * @return array|string
+     */
+    public function slashStringAsArray($string) {
+        $ret = $string;
+
+        if(strstr($string, $this->sSeparator)) {
+            $ret = array();
+            $_t = explode($this->sSeparator, $string);
+            foreach ($_t as $v) {
+                $v = trim($v);
+                if(!empty($v)) {
+                    $ret[] = $v;
+                }
+            }
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/managecollectionfields.class.php b/webclient/lib/managecollectionfields.class.php
new file mode 100644 (file)
index 0000000..af19d83
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class ManageCollectionFields to manage fields from a existing collection
+ */
+class ManageCollectionFields {
+
+    /**
+     * The database object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * The collection we are working with
+     *
+     * @var integer
+     */
+    private $_collectionId;
+
+    /**
+     * Which db cols should not be removed
+     *
+     * @var array
+     */
+    private $_protectedDBCols = array(
+        'id','created','modified','modificationuser','owner','group','rights'
+    );
+
+    /**
+     * Store existing fileds info for runtime
+     *
+     * @var array
+     */
+    private $_cacheExistingSysFields = array();
+
+    /**
+     * ManageCollections constructor
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+    }
+
+    /**
+     * The id from the collection we are working with
+     *
+     * @param $id integer
+     */
+    public function setCollection($id) {
+        if(!empty($id)) {
+            $this->_collectionId = $id;
+        }
+    }
+
+    /**
+     * Get available fields based on user
+     *
+     * @return array
+     * @todo No rights implemented yet. Maybe not needed. Management done by hand directly on DB
+     */
+    public function getAvailableFields() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `identifier`, `displayname`, `type`,
+                        `createstring`, `value`
+                    FROM `".DB_PREFIX."_sys_fields`
+                    ORDER BY `displayname`";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['id']] = $result;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Simple comma seperated number string
+     *
+     * @param $string string
+     * @return bool
+     */
+    public function validateFieldSortString($string) {
+        $ret = false;
+
+        $_t = str_replace(",","",$string);
+        if(Summoner::validate($_t, 'digit')) {
+            $ret = true;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * $fieldsSortString have to valided already
+     *
+     * @todo remove non existing ones from table
+     *
+     * @param $fieldsSortString string
+     * @return bool
+     */
+    public function updateFields($fieldsSortString) {
+        $ret = false;
+        $ids = array();
+
+        $fieldsSortString = trim($fieldsSortString, ", ");
+        if(strstr($fieldsSortString, ",")) {
+            $ids = explode(",", $fieldsSortString);
+        }
+        else {
+            $ids[] = $fieldsSortString;
+        }
+
+        if(!empty($ids)) {
+            $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+            $queryStr1 = "DELETE FROM `".DB_PREFIX."_collection_fields_".$this->_collectionId."`
+                        WHERE `fk_field_id` NOT IN (".implode(",",$ids).")";
+            $q1 = $this->_DB->query($queryStr1);
+            if($q1 !== false) {
+                // https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
+                $queryStr = "INSERT INTO `".DB_PREFIX."_collection_fields_".$this->_collectionId."` (`fk_field_id`,`sort`) VALUES ";
+                foreach ($ids as $k => $v) {
+                    $queryStr .= "($v,$k),";
+                }
+                $queryStr = trim($queryStr, ",");
+                $queryStr .= " AS newEntry(fid,s) ON DUPLICATE KEY UPDATE `sort`=s";
+
+                $q2 = $this->_DB->query($queryStr);
+                if($q2 !== false) {
+                    $_newColumns = $this->_getSQLForCollectionColumns($ids);
+                    $alterQuery = false;
+                    if(!empty($_newColumns)) {
+                        $alterString = "ALTER TABLE `".DB_PREFIX."_collection_entry_".$this->_collectionId."`";
+                        foreach($_newColumns as $k=>$v) {
+                            $alterString .= " ADD ".$v['createstring'].",";
+                        }
+                        $alterString = trim($alterString, ",");
+                        $alterQuery = $this->_DB->query($alterString);
+                    }
+                    if(!empty($_newColumns) && $alterQuery == false) {
+                        $this->_DB->rollback();
+                        error_log('ERROR Failed to update entry table: '.var_export($alterString, true));
+                    }
+                    else {
+                        $this->_DB->commit();
+                        $ret = true;
+                    }
+                }
+                else {
+                    $this->_DB->rollback();
+                    error_log('ERROR Failed to update collection fields: '.var_export($queryStr1, true));
+                    error_log('ERROR Failed to update collection fields: '.var_export($queryStr, true));
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get the fields for currently loaded collection.
+     *
+     * @param bool $refresh True to reload from DB
+     * @return array
+     */
+    public function getExistingFields($refresh=false) {
+        if($refresh === false && !empty($this->_cacheExistingSysFields)) {
+            return $this->_cacheExistingSysFields;
+        }
+
+        $queryStr = "SELECT `cf`.`fk_field_id` AS id, `sf`.`type`, `sf`.`displayname`, `sf`.`identifier`
+                        FROM `".DB_PREFIX."_collection_fields_".$this->_collectionId."` AS cf
+                        LEFT JOIN `".DB_PREFIX."_sys_fields` AS sf ON `cf`.`fk_field_id` = `sf`.`id`
+                        ORDER BY `cf`.`sort`";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $this->_cacheExistingSysFields[$result['id']] = $result;
+            }
+        }
+
+        return $this->_cacheExistingSysFields;
+    }
+
+    /**
+     * Get the column names from current collection entry table
+     *
+     * @return array
+     */
+    private function _getExistingCollectionColumns() {
+        $ret = array();
+
+        $queryStr = "SHOW COLUMNS FROM `".DB_PREFIX."_collection_entry_".$this->_collectionId."`";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                if(!in_array($result['Field'], $this->_protectedDBCols, true)) {
+                    $ret[$result['Field']] = $result['Field'];
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get the required SQL information from given field ids
+     * to create columns in entry table.
+     *
+     * @param $columnIds array sort=>fk_field_id
+     * @return array
+     */
+    private function _getSQLForCollectionColumns($columnIds) {
+        $_fields = array();
+        // enrich with information
+        $_sysFields = $this->getAvailableFields();
+        $_existingDBColumns = $this->_getExistingCollectionColumns();
+        if(!empty($columnIds)) {
+            foreach($columnIds as $sort=>$fieldId) {
+                if(isset($_sysFields[$fieldId])) {
+                    $_fd = $_sysFields[$fieldId];
+                    if(isset($_existingDBColumns[$_fd['identifier']])) continue;
+                    if(empty($_fd['createstring'])) continue;
+                    $_fields[$fieldId] = $_fd;
+                }
+            }
+        }
+        return $_fields;
+    }
+}
diff --git a/webclient/lib/managecollections.class.php b/webclient/lib/managecollections.class.php
new file mode 100644 (file)
index 0000000..fc6104d
--- /dev/null
@@ -0,0 +1,489 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class ManageCollections to manage collections
+ */
+class ManageCollections {
+       /**
+        * The database object
+     *
+        * @var object
+        */
+       private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+       private $_User;
+
+    /**
+     * ManageCollections constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+               $this->_DB = $databaseConnectionObject;
+               $this->_User = $userObj;
+       }
+
+    /**
+     * Load collection info from table. Checks user rights
+     *
+     * @param $id
+     * @param string $ritghsMode
+     * @return array
+     */
+       public function getCollection($id,$ritghsMode="read") {
+        $ret = array();
+
+        if (Summoner::validate($id, 'digit')) {
+            $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`
+                    FROM `".DB_PREFIX."_collection` AS c
+                    WHERE ".$this->_User->getSQLRightsString($ritghsMode, "c")."
+                    AND `c`.`id` = '".$this->_DB->real_escape_string($id)."'";
+            try {
+                $query = $this->_DB->query($queryStr);
+                if ($query !== false && $query->num_rows > 0) {
+                    $ret = $query->fetch_assoc();
+                }
+            }
+            catch (Exception $e) {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get all available collections for display based on current user
+     *
+     * @return array
+     */
+       public function getCollections() {
+        $ret = array();
+
+        $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`,
+                    `c`.`owner`, `c`.`group`, `c`.`rights`, 
+                    `u`.`name` AS username, `g`.`name` AS groupname
+                    FROM `".DB_PREFIX."_collection` AS c
+                    LEFT JOIN `".DB_PREFIX."_user` AS u ON `c`.`owner` = `u`.`id`
+                    LEFT JOIN `".DB_PREFIX."_group` AS g ON `c`.`group` = `g`.`id`
+                    WHERE ".$this->_User->getSQLRightsString("read", "c")."
+                    ORDER BY `c`.`name`";
+        try {
+            $query = $this->_DB->query($queryStr);
+
+            if ($query !== false && $query->num_rows > 0) {
+                while (($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+        catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Retrieve the groups for selection based on user rights
+     *
+     * @return array
+     */
+    public function getGroupsForSelection() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `name`, `description` 
+                    FROM `".DB_PREFIX."_group` 
+                    WHERE ".$this->_User->getSQLRightsString()."
+                    ORDER BY `name`";
+        try {
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+        catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Fetch all available users for selection based on current user rights
+     *
+     * @return array
+     */
+    public function getUsersForSelection() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `name`, `login`
+                        FROM `".DB_PREFIX."_user`
+                        WHERE ".$this->_User->getSQLRightsString()."";
+        try {
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+        catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Fetch all availbale tools based on current user rights
+     *
+     * @return array
+     */
+    public function getToolsForSelection() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `name`, `description`
+                        FROM `".DB_PREFIX."_tool`
+                        WHERE ".$this->_User->getSQLRightsString()."";
+        try {
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+        catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Create new collection entry in collection table. Provide valid data
+     * only $name will be checked again
+     *
+     * @param array $data
+     * @return bool
+     */
+    public function createCollection($data) {
+        $ret = false;
+
+        if(!empty($data['name']) === true
+            && $this->_validNewCollectionName($data['name']) === true
+        ) {
+            $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+            try {
+                $queryStr = "INSERT INTO `".DB_PREFIX."_collection`
+                            SET `name` = '".$this->_DB->real_escape_string($data['name'])."',
+                                `description` = '".$this->_DB->real_escape_string($data['description'])."',
+                                `owner` = '".$this->_DB->real_escape_string($data['owner'])."',
+                                `group` = '".$this->_DB->real_escape_string($data['group'])."',
+                                `rights` = '".$this->_DB->real_escape_string($data['rights'])."',
+                                `defaultSearchField` = '".$this->_DB->real_escape_string($data['defaultSearchField'])."'";
+                $this->_DB->query($queryStr);
+                $newId = $this->_DB->insert_id;
+
+
+                $queryEntry2lookup = "CREATE TABLE `".DB_PREFIX."_collection_entry2lookup_".$newId."` (
+                                        `fk_field` int NOT NULL,
+                                        `fk_entry` int NOT NULL,
+                                        `value` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+                                        FULLTEXT KEY `value` (`value`)
+                                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci";
+                $this->_DB->query($queryEntry2lookup);
+
+                $queryCollectionFields = "CREATE TABLE `".DB_PREFIX."_collection_fields_".$newId."` (
+                                         `fk_field_id` int NOT NULL,
+                                         `sort` int NOT NULL,
+                                         UNIQUE KEY `fk_field_id` (`fk_field_id`),
+                                         KEY `sort` (`sort`)
+                                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci";
+                $this->_DB->query($queryCollectionFields);
+
+                $queryCollectionEntry = "CREATE TABLE `".DB_PREFIX."_collection_entry_".$newId."` (
+                                         `id` int NOT NULL AUTO_INCREMENT,
+                                         `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+                                         `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                                         `modificationuser` int NOT NULL,
+                                         `owner` int NOT NULL,
+                                         `group` int NOT NULL,
+                                         `rights` char(9) COLLATE utf8mb4_bin NOT NULL,
+                                         PRIMARY KEY (`id`)
+                                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci";
+                $this->_DB->query($queryCollectionEntry);
+
+                $this->_updateToolRelation($newId,$data['tool']);
+
+                $this->_DB->commit();
+                $ret = true;
+            }
+            catch (Exception $e) {
+                if(DEBUG) var_dump($e->getMessage());
+                error_log('ERROR Failed to create entry: '.var_export($e->getMessage(),true));
+                $this->_DB->rollback();
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load the information from collection table for given $id
+     *
+     * @param string $id Number
+     * @return array
+     */
+    public function getEditData($id) {
+        $ret = array();
+
+        if (Summoner::validate($id, 'digit')) {
+            $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`,
+                    `c`.`owner`, `c`.`group`, `c`.`rights`, `c`.`defaultSearchField`,
+                    `u`.`name` AS username, `g`.`name` AS groupname
+                    FROM `".DB_PREFIX."_collection` AS c
+                    LEFT JOIN `".DB_PREFIX."_user` AS u ON `c`.`owner` = `u`.`id`
+                    LEFT JOIN `".DB_PREFIX."_group` AS g ON `c`.`group` = `g`.`id`
+                    WHERE ".$this->_User->getSQLRightsString("read", "c")."
+                    AND `c`.`id` = '".$this->_DB->real_escape_string($id)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                $ret = $query->fetch_assoc();
+                $ret['rights'] = Summoner::prepareRightsArray($ret['rights']);
+                $ret['tool'] = $this->getAvailableTools($id);
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Update collection with given data identified by given id
+     * See method for the fields
+     *
+     * @param array $data
+     * @return bool
+     */
+    public function updateCollection($data) {
+        $ret = false;
+
+        if(DEBUG) error_log("[DEBUG] ".__METHOD__."  data: ".var_export($data,true));
+
+        if(!empty($data['name']) === true
+            && $this->_validUpdateCollectionName($data['name'], $data['id']) === true
+            && Summoner::validate($data['id'], 'digit')
+        ) {
+            $queryStr = "UPDATE `".DB_PREFIX."_collection`
+                        SET `name` = '".$this->_DB->real_escape_string($data['name'])."',
+                            `description` = '".$this->_DB->real_escape_string($data['description'])."',
+                            `owner` = '".$this->_DB->real_escape_string($data['owner'])."',
+                            `group` = '".$this->_DB->real_escape_string($data['group'])."',
+                            `rights` = '".$this->_DB->real_escape_string($data['rights'])."',
+                            `defaultSearchField` = '".$this->_DB->real_escape_string($data['defaultSearchField'])."'
+                        WHERE `id` = '".$this->_DB->real_escape_string($data['id'])."'";
+            try {
+                $this->_DB->query($queryStr);
+                $this->_updateToolRelation($data['id'],$data['tool']);
+                $ret = true;
+            }
+            catch (Exception $e) {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql catch: ".$e->getMessage());
+            }
+
+            // update the search field if it is a field from the collection entry table
+            // and add the index. The lookup table has already a fulltext index on value
+            $queryCheck = "SHOW COLUMNS FROM `".DB_PREFIX."_collection_entry_".$data['id']."` 
+                                LIKE '".$this->_DB->real_escape_string($data['defaultSearchField'])."'";
+            $queryStr = "CREATE FULLTEXT INDEX ".$this->_DB->real_escape_string($data['defaultSearchField'])."
+                        ON `".DB_PREFIX."_collection_entry_".$data['id']."`
+                            (`".$this->_DB->real_escape_string($data['defaultSearchField'])."`)";
+            try {
+                $query = $this->_DB->query($queryCheck);
+                if($query !== false && $query->num_rows > 0) {
+                    $this->_DB->query($queryStr);
+                    // altering or adding an index while data exists
+                    // ignores the collation (?)
+                    // optimize does a recreation and the column collation
+                    // is considered
+                    $this->_DB->query("OPTIMIZE TABLE `".DB_PREFIX."_collection_entry_".$data['id']."`");
+                }
+            } catch (Exception $e) {
+                if($e->getCode() == "1061") {
+                    // duplicate key
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql query: ".$e->getMessage());
+                }
+                else {
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql query: ".$queryCheck);
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql query: ".$queryStr);
+                    error_log("[ERROR] ".__METHOD__."  mysql query: ".$e->getMessage());
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Delete collection identified by given id
+     *
+     * @param $id string Number
+     * @return bool
+     */
+    public function deleteCollection($id) {
+        $ret = false;
+
+        // @todo Implement list deletion
+        // what to do with the entries?
+        exit('No implemented yet.');
+
+        if(!empty($id) && Summoner::validate($id, 'digit')) {
+            $queryStr = "DELETE FROM `".DB_PREFIX."_collection`
+                            WHERE `id` = '".$this->_DB->real_escape_string($id)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false) {
+
+                var_dump("Implement list deletion");
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load the tools configured to the given collection
+     *
+     * @param $id
+     * @return array
+     */
+    public function getAvailableTools($id) {
+        $ret = array();
+
+        $queryStr = "SELECT `t`.`id`, `t`.`name`, `t`.`description`, `t`.`action`, `t`.`target`
+                    FROM `".DB_PREFIX."_tool2collection` AS t2c
+                    LEFT JOIN `".DB_PREFIX."_tool` AS t ON t2c.fk_collection_id = t.id
+                    WHERE t2c.fk_collection_id = '".$this->_DB->real_escape_string($id)."'";
+        try {
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+        catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql catch: ".$e->getMessage());
+        }
+
+        return  $ret;
+    }
+
+    /**
+     * Check if given name can be used as a new one
+     *
+     * @param $name string
+     * @return bool
+     */
+    private function _validNewCollectionName($name) {
+        $ret = false;
+        if (Summoner::validate($name, 'nospace')) {
+            $queryStr = "SELECT `id` FROM `".DB_PREFIX."_collection`
+                                WHERE `name` = '".$this->_DB->real_escape_string($name)."'";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows < 1) {
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Check if given name can be used as a new name for id
+     *
+     * @param $name string
+     * @param $id string Number
+     * @return bool
+     */
+    private function _validUpdateCollectionName($name, $id) {
+        $ret = false;
+
+        if (Summoner::validate($name, 'nospace')
+            && Summoner::validate($id,'digit')
+        ) {
+            $queryStr = "SELECT `id` FROM `".DB_PREFIX."_collection`
+                                WHERE `name` = '".$this->_DB->real_escape_string($name)."'
+                                AND `id` != '".$this->_DB->real_escape_string($id)."'";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows < 1) {
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Update the given colletion ($id) with the given tool array
+     *
+     * @param $id
+     * @param $tool
+     * @return bool
+     */
+    private function _updateToolRelation($id,$tool) {
+        $ret = false;
+
+        $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+        try {
+            $this->_DB->query("DELETE FROM `".DB_PREFIX."_tool2collection`
+                                WHERE `fk_collection_id` = '".$this->_DB->real_escape_string($id)."'");
+            if(!empty($tool)) {
+                foreach($tool as $k=>$v) {
+                    if(!empty($v)) {
+                        $this->_DB->query("INSERT IGNORE INTO `".DB_PREFIX."_tool2collection`
+                                            SET `fk_tool_id` = '".$this->_DB->real_escape_string($v)."',
+                                                `fk_collection_id` = '".$this->_DB->real_escape_string($id)."'");
+                    }
+                }
+            }
+            $this->_DB->commit();
+            $ret = true;
+        } catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql catch: ".$e->getMessage());
+            $this->_DB->rollback();
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/manageentry.class.php b/webclient/lib/manageentry.class.php
new file mode 100644 (file)
index 0000000..ef14375
--- /dev/null
@@ -0,0 +1,689 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Manageentry {
+    /**
+     * The database object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * Currently loaded collection to manage entries from
+     *
+     * @var string Number
+     */
+    private $_collectionId;
+
+    /**
+     * Placeholder in query strings for inserted DB id
+     *
+     * @var string
+     */
+    private $_replaceEntryString = 'REPLACE_ENTERY';
+
+    /**
+     * ManageCollections constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+    }
+
+    /**
+     * Set the collection to manage entries from
+     *
+     * @param $collectionId
+     */
+    public function setCollection($collectionId) {
+        if(!empty($collectionId)) {
+            $this->_collectionId = $collectionId;
+        }
+    }
+
+    /**
+     * Load the fields for the loaded collection
+     * Also load additional data based on fieldtype and _loadField_ method
+     *
+     * @return array
+     */
+    public function getEditFields() {
+        $ret = array();
+
+        if(!empty($this->_collectionId)) {
+            $queryStr = "SELECT `cf`.`fk_field_id` AS id, `sf`.`type`, `sf`.`displayname`, `sf`.`identifier`,
+                            `sf`.`value`
+                        FROM `".DB_PREFIX."_collection_fields_".$this->_DB->real_escape_string($this->_collectionId)."` AS cf
+                        LEFT JOIN `".DB_PREFIX."_sys_fields` AS sf ON `cf`.`fk_field_id` = `sf`.`id`
+                        ORDER BY `cf`.`sort`";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $_mn = '_loadField_'.$result['type'];
+                    if(method_exists($this, $_mn)) {
+                        $result = $this->$_mn($result);
+                    }
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load required data for edit. Uses some functions from Mancubus but has
+     * different data layout. Checks write edit too
+     *
+     * @param $entryId
+     * @return array
+     */
+    public function getEditData($entryId) {
+        $ret = array();
+
+        if(!empty($this->_collectionId) && !empty($entryId)) {
+            $queryStr = "SELECT * 
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_DB->real_escape_string($this->_collectionId)."` 
+                        WHERE ".$this->_User->getSQLRightsString("write")."
+                        AND `id` = '".$this->_DB->real_escape_string($entryId)."'";
+            $query = $this->_DB->query($queryStr);
+
+            if($query !== false && $query->num_rows > 0) {
+                $_entryFields = $this->getEditFields();
+
+                if(($result = $query->fetch_assoc()) != false) {
+                    $ret = $this->_mergeEntryWithFields($result, $_entryFields);
+                    $ret['_canDelete'] = $this->_canDelete($entryId);
+                }
+
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Create an entry with given data
+     *
+     * @param array $data
+     * @param number $owner
+     * @param number $group
+     * @param string $rights
+     * @param mixed $update Either false for no update or the ID to update
+     * @return mixed
+     */
+    public function create($data, $owner, $group, $rights, $update=false) {
+        $ret = false;
+
+        if(DEBUG) error_log("[DEBUG] ".__METHOD__." data: ".var_export($data,true));
+
+        //@todo there is no setting for individual rights available yet
+        if(!empty($data) && !empty($owner) && !empty($group) && !empty($rights)) {
+
+            // create the queryData array
+            // init is the entry in the table. Needed for after stuff
+            // after returns query and upload which then calls the extra methods
+            $queryData['init'] = array();
+            $queryData['after'] = array();
+            foreach ($data as $i=>$d) {
+                $_mn = '_saveField_'.$d['type'];
+                if(method_exists($this, $_mn)) {
+                    $queryData = $this->$_mn($d, $queryData);
+                }
+                else {
+                    if(DEBUG)error_log("[DEBUG] ".__METHOD__." Missing query function for: ".var_export($d, true));
+                }
+            }
+
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." queryData: ".var_export($queryData,true));
+
+            if(!empty($queryData['init'])) {
+                $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+                try {
+                    $queryStr = "INSERT INTO `".DB_PREFIX."_collection_entry_".$this->_collectionId."`";
+                    if($update !== false && is_numeric($update)) {
+                        $queryStr = "UPDATE `".DB_PREFIX."_collection_entry_".$this->_collectionId."`";
+                    }
+                    $queryStr .= " SET
+                                `modificationuser` = '".$this->_DB->real_escape_string($owner)."',
+                                `owner` = '".$this->_DB->real_escape_string($owner)."',
+                                `group` = '".$this->_DB->real_escape_string($group)."',
+                                `rights`= '".$this->_DB->real_escape_string($rights)."',";
+                    $queryStr .= implode(", ",$queryData['init']);
+                    if($update !== false && is_numeric($update)) {
+                        $queryStr .= " WHERE `id` = '".$this->_DB->real_escape_string($update)."'";
+                    }
+
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__." init queryStr: ".var_export($queryStr,true));
+
+                    $this->_DB->query($queryStr);
+
+                    if($update !== false && is_numeric($update)) {
+                        $newId = $update;
+                    }
+                    else {
+                        $newId = $this->_DB->insert_id;
+                    }
+
+                    if(!empty($newId)) {
+                        if(!empty($queryData['after']) && isset($queryData['after']['query'])) {
+                            foreach ($queryData['after']['query'] as $q) {
+                                $this->_runAfter_query($q, $newId);
+                            }
+                        }
+
+                        if(!empty($queryData['after']) && isset($queryData['after']['upload'])) {
+                            foreach ($queryData['after']['upload'] as $q) {
+                                $this->_runAfter_upload($q, $newId);
+                            }
+                        }
+
+                        $this->_DB->commit();
+                        $ret = $newId;
+                    }
+                    else {
+                        $this->_DB->rollback();
+                    }
+                } catch (Exception $e) {
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql catch: ".$e->getMessage());
+                    $this->_DB->rollback();
+                }
+            }
+            else {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." empty init in: ".var_export($queryData,true));
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Delete given entryId from currently loaded collection
+     * Checks userrights too.
+     *
+     * @param $entryId
+     * @return bool
+     */
+    public function delete($entryId) {
+        $ret = false;
+
+        if(!empty($entryId) && !empty($this->_collectionId)) {
+
+            if ($this->_canDelete($entryId)) {
+
+                $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+                try {
+                    // remove assets
+                    $_path = PATH_STORAGE.'/'.$this->_collectionId.'/'.$entryId;
+                    if(is_dir($_path) && is_readable($_path)) {
+                        if(DEBUG) error_log("[DEBUG] ".__METHOD__."  remove assets :".$_path);
+                        $rmDir = Summoner::recursive_remove_directory($_path);
+                        if($rmDir === false) {
+                            throw new Exception("Failed to delete path: ".$_path);
+                        }
+                    }
+
+                    // delete data from lookup fields
+                    $queryStr = "DELETE 
+                        FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."`
+                        WHERE `fk_entry` = '".$this->_DB->real_escape_string($entryId)."'";
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__." remove lookup queryStr: ".var_export($queryStr,true));
+                    $this->_DB->query($queryStr);
+
+                    // delete entry
+                    $queryStr = "DELETE
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_collectionId."`
+                        WHERE `id` = '".$this->_DB->real_escape_string($entryId)."'
+                            AND " . $this->_User->getSQLRightsString("delete") . "";
+                    $this->_DB->query($queryStr);
+
+                    $this->_DB->commit();
+                    $ret = true;
+                } catch (Exception $e) {
+                    if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql catch: ".$e->getMessage());
+                    $this->_DB->rollback();
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Validates that current use can write the given Entry
+     *
+     * @param $entryId
+     * @return bool
+     */
+    public function canEditEntry($entryId) {
+        $ret = false;
+
+        if(!empty($entryId) && !empty($this->_collectionId)) {
+
+            $queryStr = "SELECT `id`
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_collectionId."`
+                        WHERE `id` = '".$this->_DB->real_escape_string($entryId)."'
+                            AND " . $this->_User->getSQLRightsString("write") . "";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows > 0) {
+                if (($result = $query->fetch_assoc()) != false) {
+                    $ret = true;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Check if given entryid can be deleted from current collection
+     * and user
+     *
+     * @param $entryId
+     * @return bool
+     */
+    private function _canDelete($entryId) {
+        $ret = false;
+
+        if(!empty($entryId) && !empty($this->_collectionId)) {
+
+            $queryStr = "SELECT `id`
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_collectionId."`
+                        WHERE `id` = '".$this->_DB->real_escape_string($entryId)."'
+                            AND " . $this->_User->getSQLRightsString("delete") . "";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows > 0) {
+                if (($result = $query->fetch_assoc()) != false) {
+                    $ret = true;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Merge the loaded entryData with the to look up entryFields data
+     * In this case only the fields which have a _loadFieldValue_ method
+     * are loaded. More is not needed here.
+     *
+     * @param $entryData array
+     * @param $entryFields array
+     * @return array
+     */
+    private function _mergeEntryWithFields($entryData, $entryFields) {
+        if(!empty($entryFields)) {
+            foreach($entryFields as $f) {
+                $_mnValue = '_loadFieldValue_'.$f['type'];
+
+                if(!isset($entryData[$f['identifier']]) && method_exists($this, $_mnValue) && isset($entryData['id']) ) {
+                    $entryData[$f['identifier']] = $this->$_mnValue($entryData['id'], $f);
+                }
+            }
+        }
+        return $entryData;
+    }
+
+    /**
+     * Load the values for given $entryId for $fieldData
+     * lookup function for field type lookupmultiple
+     *
+     * @see Mancubus
+     * @param Number $entryId
+     * @param array $fieldData
+     * @return array
+     */
+    private function _loadFieldValue_lookupmultiple($entryId, $fieldData) {
+        $ret = array();
+
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+            $queryStr = "SELECT `value` 
+                        FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."`
+                        WHERE `fk_field` = '".$this->_DB->real_escape_string($fieldData['id'])."'
+                            AND `fk_entry` = '".$this->_DB->real_escape_string($entryId)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[] = $result['value'];
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get the single upload file from storage location
+     * lookup function for field type upload
+     *
+     * @see Mancubus
+     * @param $entryId
+     * @param $fieldData
+     * @return string
+     */
+    private function _loadFieldValue_upload($entryId, $fieldData) {
+        $ret = "";
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+
+            $uploadedFile = glob(PATH_STORAGE.'/'.$this->_collectionId.'/'.$entryId.'/'.$fieldData['identifier'].'-*');
+            if(!empty($uploadedFile)) {
+                foreach ($uploadedFile as $f) {
+                    $ret = basename($f);
+                    break;
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Get the multiple upload files from storage location
+     * lookup function for field type upload_multiple
+     *
+     * @see Mancubus
+     * @param $entryId
+     * @param $fieldData
+     * @return array
+     */
+    private function _loadFieldValue_upload_multiple($entryId, $fieldData) {
+        $ret = array();
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+
+            $uploadedFile = glob(PATH_STORAGE.'/'.$this->_collectionId.'/'.$entryId.'/'.$fieldData['identifier'].'-*');
+            if(!empty($uploadedFile)) {
+                foreach ($uploadedFile as $f) {
+                    $ret[] = basename($f);
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Provide the options for a selection field by processing the $data['value']
+     * since the values are stored in the entry DB as a list
+     *
+     * @param $data array
+     * @return array
+     */
+    private function _loadField_selection($data) {
+        if(!empty($data) && isset($data['value']) && !empty($data['value'])) {
+            if(strstr($data['value'], ",")) {
+                $data['options'] = explode(",", $data['value']);
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Load suggestions based on the existing data for this field
+     *
+     * @param $data array Field data
+     * @return array
+     */
+    private function _loadField_lookupmultiple($data) {
+        if(!empty($data) && isset($data['id']) && !empty($data['id'])) {
+            $queryStr = "SELECT DISTINCT(`value`) 
+                        FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."`
+                        WHERE `fk_field` = '".$this->_DB->real_escape_string($data['id'])."'";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows > 0) {
+                while (($result = $query->fetch_assoc()) != false) {
+                    $data['suggestion'][] = $result['value'];
+                }
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Create part of the insert statement for field type text
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_text($data, $queryData) {
+        $queryData['init'][] = "`".$data['identifier']."` = '".$this->_DB->real_escape_string($data['valueToSave'])."'";
+        return $queryData;
+    }
+
+    /**
+     * Create part of the insert statement for field type text3
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_text3($data, $queryData) {
+        return $this->_saveField_text($data, $queryData);
+    }
+
+    /**
+     * Create part of the insert statement for field type textarea
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_textarea($data, $queryData) {
+        return $this->_saveField_text($data, $queryData);
+    }
+
+    /**
+     * Create part of the insert statement for field type selection
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_selection($data, $queryData) {
+        return $this->_saveField_text($data, $queryData);
+    }
+    /**
+     * Create part of the insert statement for field type year
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_year($data, $queryData) {
+        return $this->_saveField_text($data, $queryData);
+    }
+
+    /**
+     * Create part of the insert statement for field type lookupmultiple
+     *
+     * @param $data array Field data
+     * @param $queryData array Query data array
+     * @return array
+     */
+    private function _saveField_lookupmultiple($data, $queryData) {
+        $_d = trim($data['valueToSave']);
+        $_d = trim($_d, ",");
+
+        // first clean since the new data is everything
+        $queryData['after']['query'][] = "DELETE FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_collectionId."`
+                                        WHERE `fk_field` = '".$this->_DB->real_escape_string($data['id'])."'
+                                            AND `fk_entry` = '".$this->_replaceEntryString."'";
+        if(!empty($_d)) {
+            $_process = array($_d);
+            if (strstr($data['valueToSave'], ",")) {
+                $_process = explode(",", $data['valueToSave']);
+            }
+            foreach ($_process as $p) {
+                $queryData['after']['query'][] = "INSERT IGNORE INTO `".DB_PREFIX."_collection_entry2lookup_".$this->_collectionId."`
+                                SET `fk_field` = '".$this->_DB->real_escape_string($data['id'])."',
+                                    `fk_entry` = '".$this->_replaceEntryString."',
+                                    `value` = '".$this->_DB->real_escape_string($p)."'";
+            }
+        }
+
+        return $queryData;
+    }
+
+    /**
+     * Single upload field
+     *
+     * @param $data array The data from _FILES
+     * @param $queryData array
+     * @return array
+     */
+    private function _saveField_upload($data, $queryData) {
+        $_up = $data['uploadData'];
+
+        // delete the single upload
+        // this way the after query method is triggered without any upload
+        if(isset($data['deleteData'])) {
+            $queryData['after']['upload'][] = array(
+                'identifier' => $data['identifier'],
+                'multiple' => false,
+                'deleteData' => $data['deleteData']
+            );
+        }
+
+        if($_up['error'][$data['identifier']] === 0) {
+            $_ext = pathinfo($_up['name'][$data['identifier']],PATHINFO_EXTENSION);
+            $newFilename = sha1($_up['name'][$data['identifier']]).".".$_ext;
+
+            $queryData['after']['upload'][] = array(
+                'identifier' => $data['identifier'],
+                'name' => $newFilename,
+                'tmp_name' => $_up['tmp_name'][$data['identifier']],
+                'multiple' => false
+            );
+        }
+        return $queryData;
+    }
+
+    /**
+     * Multiple upload field
+     *
+     * @param $data array The data from _FILES
+     * @param $queryData array
+     * @return array
+     */
+    private function _saveField_upload_multiple($data, $queryData) {
+        $_up = $data['uploadData'];
+
+        if(isset($data['deleteData'])) {
+            $queryData['after']['upload'][] = array(
+                'identifier' => $data['identifier'],
+                'multiple' => true,
+                'deleteData' => $data['deleteData']
+            );
+        }
+
+        foreach ($_up['error'][$data['identifier']] as $k=>$v) {
+            if($v === 0) {
+                $_ext = pathinfo($_up['name'][$data['identifier']][$k],PATHINFO_EXTENSION);
+                $newFilename = sha1($_up['name'][$data['identifier']][$k]).".".$_ext;
+
+                $queryData['after']['upload'][] = array(
+                    'identifier' => $data['identifier'],
+                    'name' => $newFilename,
+                    'tmp_name' => $_up['tmp_name'][$data['identifier']][$k],
+                    'multiple' => true
+                );
+            }
+        }
+
+        return $queryData;
+    }
+
+    /**
+     * runs the query and throws query execption if false
+     *
+     * @param $queryString
+     * @param $insertId
+     */
+    private function _runAfter_query($queryString, $insertId) {
+        if(!empty($queryString) && !empty($insertId)) {
+            // replace only once to avoid replacing actual data
+            $queryStr = Summoner::replaceOnce($queryString,$this->_replaceEntryString, $insertId);
+            $this->_DB->query($queryStr);
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." queryStr: ".var_export($queryStr,true));
+        }
+    }
+
+    /**
+     * Move uploaded into right directory
+     * If single upload (multiple=false) then remove all the files for this type field first. Works the same
+     * if you want to remove the upload via edit
+     *
+     * Also removes the defined uploads from multiple upload field
+     *
+     * @param $uploadData
+     * @param $insertId
+     * @throws Exception
+     */
+    private function _runAfter_upload($uploadData, $insertId) {
+        if(!empty($uploadData) && !empty($insertId)) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." uploadata: ".var_export($uploadData,true));
+            $_path = PATH_STORAGE.'/'.$this->_collectionId.'/'.$insertId;
+            if(!is_dir($_path)) {
+                if(!mkdir($_path, 0777, true)) {
+                    throw new Exception("Failed to create storage path: ".$_path);
+                }
+            }
+
+            if($uploadData['multiple'] === false) {
+                // single upload. Delete existing first.
+                // also triggered if the single needs to be deleted
+                $_existingFiles = glob($_path.'/'.$uploadData['identifier'].'-*');
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." remove single existing: ".var_export($_existingFiles,true));
+                if(!empty($_existingFiles)) {
+                    foreach ($_existingFiles as $f) {
+                        unlink($f);
+                    }
+                    clearstatcache();
+                }
+            }
+
+            if($uploadData['multiple'] === true && isset($uploadData['deleteData'])) {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." remove multiple existing: ".var_export($uploadData['deleteData'],true));
+                foreach ($uploadData['deleteData'] as $k=>$v) {
+                    $_file = $_path.'/'.$v;
+                    if(file_exists($_file)) {
+                        unlink($_file);
+                    }
+                    clearstatcache();
+                }
+            }
+
+            if(isset($uploadData['tmp_name']) && isset($uploadData['name'])) {
+                if(!move_uploaded_file($uploadData['tmp_name'],$_path.'/'.$uploadData['identifier'].'-'.$uploadData['name'])) {
+                    throw new Exception("Can not move file to: ".$_path.'/'.$uploadData['identifier'].'-'.$uploadData['name']);
+                }
+            }
+        }
+    }
+}
diff --git a/webclient/lib/mancubus.class.php b/webclient/lib/mancubus.class.php
new file mode 100644 (file)
index 0000000..1d1682e
--- /dev/null
@@ -0,0 +1,626 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class Mancubus everything to show an entry
+ */
+class Mancubus {
+    /**
+     * The database object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * Currently loaded collection to work with
+     *
+     * @var number
+     */
+    private $_collectionId;
+
+    /**
+     * Options for db queries
+     *  'limit' => int,
+     *  'offset' => int,
+     *  'orderby' => string,
+     *  'sortDirection' => ASC|DESC
+     *
+     * @var array
+     */
+    private $_queryOptions;
+
+    /**
+     * Mancubus constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+
+        $this->_setDefaults();
+    }
+
+    /**
+     * Set the to work with collection id
+     *
+     * @param $collectionId Number
+     */
+    public function setCollection($collectionId) {
+        if(!empty($collectionId)) {
+            $this->_collectionId = $collectionId;
+        }
+    }
+
+    /**
+     * Set the following options which can be used in DB queries
+     * array(
+     *  'limit' => RESULTS_PER_PAGE,
+     *  'offset' => (RESULTS_PER_PAGE * ($_curPage-1)),
+     *  'orderby' => $_sort,
+     *  'sortDirection' => $_sortDirection
+     * );
+     *
+     * @param array $options
+     */
+    public function setQueryOptions($options) {
+
+        if(!isset($options['limit'])) $options['limit'] = 5;
+        if(!isset($options['offset'])) $options['offset'] = false;
+        if(!isset($options['sort'])) $options['sort'] = false;
+        if(!isset($options['sortDirection'])) $options['sortDirection'] = false;
+
+        $this->_queryOptions = $options;
+    }
+    
+    /**
+     * Get all available collections for display based on current user
+     *
+     * @param int $selections Number of selections
+     * @param int $entries Number of entries
+     * @param string $search Search string to search for
+     * @return array
+     */
+    public function getLatest($selections, $entries, $search='') {
+        $ret = array();
+
+        $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`,
+                    `c`.`owner`, `c`.`group`, `c`.`rights`, 
+                    `u`.`name` AS username, `g`.`name` AS groupname
+                    FROM `".DB_PREFIX."_collection` AS c
+                    LEFT JOIN `".DB_PREFIX."_user` AS u ON `c`.`owner` = `u`.`id`
+                    LEFT JOIN `".DB_PREFIX."_group` AS g ON `c`.`group` = `g`.`id`
+                    WHERE ".$this->_User->getSQLRightsString("read", "c")."
+                    ORDER BY `c`.`name`
+                    LIMIT $selections";
+        $query = $this->_DB->query($queryStr);
+
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $_mObj = new Mancubus($this->_DB,$this->_User);
+                $_mObj->setCollection($result['id']);
+                $_mObj->setQueryOptions(array('limit' => $entries));
+
+                if(!empty($search)) {
+                    require_once 'lib/trite.class.php';
+                    $_colObj = new Trite($this->_DB,$this->_User);
+                    $_colObj->load($result['id']);
+
+                    $result['entries'] = $_mObj->getEntries($_colObj->param('defaultSearchField'),$search,true);
+                }
+                else {
+                    $result['entries'] = $_mObj->getEntries();
+                }
+                $ret[$result['id']] = $result;
+                unset($_mObj);
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get entries for loaded collection limited by search in
+     * given colName and colValue
+     *
+     * @param string $colName Table col to search
+     * @param string $colValue Value to search in col
+     * @param bool $fulltext If col has a fulltext index use it.
+     * @return array
+     */
+    public function getEntries($colName='', $colValue='',$fulltext=false) {
+        $ret = array();
+
+        if(!empty($this->_collectionId)) {
+            // split since part of it is used later
+            $querySelect = "SELECT *";
+            $queryFrom = " FROM `".DB_PREFIX."_collection_entry_".$this->_DB->real_escape_string($this->_collectionId)."` AS t";
+            $queryWhere = " WHERE ".$this->_User->getSQLRightsString("read", "t")."";
+
+            if(!empty($colName) && !empty($colValue)) {
+                if($fulltext === true) {
+                    $queryWhere .= " AND MATCH (`t`.`".$this->_DB->real_escape_string($colName)."`) 
+                        AGAINST ('".$this->_DB->real_escape_string($colValue)."' IN BOOLEAN MODE)";
+                }
+                else {
+                    $queryWhere .= " AND `t`.`" . $this->_DB->real_escape_string($colName) . "` = '" . $this->_DB->real_escape_string($colValue) . "'";
+                }
+            }
+
+            $queryOrder = " ORDER BY";
+            if(!empty($this->_queryOptions['sort'])) {
+                $queryOrder .= ' t.'.$this->_queryOptions['sort'];
+            }
+            else {
+                $queryOrder .= " t.created";
+            }
+            if(!empty($this->_queryOptions['sortDirection'])) {
+                $queryOrder .= ' '.$this->_queryOptions['sortDirection'];
+            }
+            else {
+                $queryOrder .= " DESC";
+            }
+
+            $queryLimit = '';
+            if(!empty($this->_queryOptions['limit'])) {
+                $queryLimit .= " LIMIT ".$this->_queryOptions['limit'];
+                # offset can be 0
+                if($this->_queryOptions['offset'] !== false) {
+                    $queryLimit .= " OFFSET ".$this->_queryOptions['offset'];
+                }
+            }
+
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__."  data: ".$querySelect.$queryFrom.$queryWhere.$queryOrder.$queryLimit);
+
+            $query = $this->_DB->query($querySelect.$queryFrom.$queryWhere.$queryOrder.$queryLimit);
+
+            if($query !== false && $query->num_rows > 0) {
+                $_entryFields = $this->_getEntryFields();
+
+                while(($result = $query->fetch_assoc()) != false) {
+                    $result = $this->_mergeEntryWithFields($result, $_entryFields);
+
+                    $ret['results'][$result['id']] = $result;
+                }
+
+                $query = $this->_DB->query("SELECT COUNT(t.id) AS amount ".$queryFrom.$queryWhere);
+                $result = $query->fetch_assoc();
+                $ret['amount'] = $result['amount'];
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Retrive all the data needed to display the entry for given entryId
+     * @param $entryId
+     * @return array|mixed
+     */
+    public function getEntry($entryId) {
+        $ret = array();
+
+        if(!empty($this->_collectionId) && !empty($entryId)) {
+            $queryStr = "SELECT * 
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_DB->real_escape_string($this->_collectionId)."` 
+                        WHERE ".$this->_User->getSQLRightsString("read")."
+                        AND `id` = '".$this->_DB->real_escape_string($entryId)."'";
+            $query = $this->_DB->query($queryStr);
+
+            if($query !== false && $query->num_rows > 0) {
+                $_entryFields = $this->_getEntryFields();
+
+                if(($result = $query->fetch_assoc()) != false) {
+                    $ret = $this->_mergeEntryWithFields($result, $_entryFields);
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get entries for loaded collection by looking for the given value in given field
+     *
+     * @param Number $fieldId ID of the field to search in
+     * @param String $fieldValue Value of the field
+     * @return array
+     */
+    public function getEntriesByFieldValue($fieldId, $fieldValue) {
+        $ret = array();
+
+        $fieldData = array();
+        $queryStr = "SELECT `identifier`, `type` FROM `".DB_PREFIX."_sys_fields`
+                        WHERE `id` = '".$this->_DB->real_escape_string($fieldId)."'";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            if(($result = $query->fetch_assoc()) != false) {
+                $fieldData = $result;
+            }
+        }
+
+        if(empty($fieldData)) return $ret;
+
+        if($fieldData['type'] !== "lookupmultiple") {
+            return $this->getEntries($fieldData['identifier'], $fieldValue);
+        }
+
+        $querySelect = "SELECT `fk_entry`";
+        $queryFrom = " FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."` AS t";
+        $queryWhere = " WHERE t.fk_field = '".$this->_DB->real_escape_string($fieldId)."'
+                    AND t.value = '".$this->_DB->real_escape_string($fieldValue)."'";
+
+        $queryOrder = " ORDER BY";
+        if(!empty($this->_queryOptions['sort'])) {
+            $queryOrder .= ' t.'.$this->_queryOptions['sort'];
+        }
+        else {
+            $queryOrder .= " t.value";
+        }
+        if(!empty($this->_queryOptions['sortDirection'])) {
+            $queryOrder .= ' '.$this->_queryOptions['sortDirection'];
+        }
+        else {
+            $queryOrder .= " DESC";
+        }
+
+        $queryLimit = '';
+        if(!empty($this->_queryOptions['limit'])) {
+            $queryLimit .= " LIMIT ".$this->_queryOptions['limit'];
+            # offset can be 0
+            if($this->_queryOptions['offset'] !== false) {
+                $queryLimit .= " OFFSET ".$this->_queryOptions['offset'];
+            }
+        }
+
+        $query = $this->_DB->query($querySelect.$queryFrom.$queryWhere.$queryOrder.$queryLimit);
+
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $_r = $this->getEntry($result['fk_entry']);
+                $ret['results'][$_r['id']] = $_r;
+            }
+
+            $query = $this->_DB->query("SELECT COUNT(t.value) AS amount ".$queryFrom.$queryWhere);
+            $result = $query->fetch_assoc();
+            $ret['amount'] = $result['amount'];
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get tags for loaded collection. Provide earch term to use match against db search
+     *
+     * @todo Replace with trite class
+     *
+     * @param mixed $search Search term
+     * @return array
+     */
+    public function getTags($search=false) {
+        $ret = array();
+
+        if(!empty($this->_collectionId)) {
+            $queryStr = "SELECT `cf`.`fk_field_id` AS id, `sf`.`type`, `sf`.`displayname`, `sf`.`identifier`
+                        FROM `".DB_PREFIX."_collection_fields_".$this->_DB->real_escape_string($this->_collectionId)."` AS cf
+                        LEFT JOIN `".DB_PREFIX."_sys_fields` AS sf ON `cf`.`fk_field_id` = `sf`.`id`
+                        WHERE `sf`.`searchtype` = 'tag' 
+                        ORDER BY `sf`.`displayname`";
+
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                    $ret[$result['id']]['entries'] = array();
+
+                    $_mn = '_loadTagDistinct_'.$result['type'];
+                    if(method_exists($this, $_mn)) {
+                        $ret[$result['id']]['entries'] = $this->$_mn($result,$search);
+                    }
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Return the storage info for loaded collection
+     * Used by API
+     * @return array|mixed
+     */
+    public function getEntryStructure() {
+        $ret = array();
+
+        $_entryFields = $this->_getEntryFields();
+        $ret = $this->_mergeEntryWithFields($ret, $_entryFields);
+
+        return $ret;
+    }
+
+    /**
+     * Load the fields from the loaded collection
+     * @return array
+     */
+    private function _getEntryFields() {
+        $ret = array();
+
+        if(!empty($this->_collectionId)) {
+            $queryStr = "SELECT `cf`.`fk_field_id` AS id, `sf`.`type`, `sf`.`displayname`, `sf`.`identifier`,
+                                `sf`.`value` AS preValue, `sf`.`apiinfo` 
+                        FROM `".DB_PREFIX."_collection_fields_".$this->_DB->real_escape_string($this->_collectionId)."` AS cf
+                        LEFT JOIN `".DB_PREFIX."_sys_fields` AS sf ON `cf`.`fk_field_id` = `sf`.`id`
+                        ORDER BY `cf`.`sort`";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[$result['id']] = $result;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Merge the loaded information from collection_entry with the given
+     * configured fields
+     * @param array $entryData Loaded entry
+     * @param array $entryFields Loaded fields
+     * @return mixed
+     */
+    private function _mergeEntryWithFields($entryData, $entryFields) {
+        if(!empty($entryFields)) {
+            foreach($entryFields as $f) {
+                $_mnValue = '_loadFieldValue_'.$f['type'];
+
+                if(isset($entryData[$f['identifier']])) {
+                    $f['value'] = $entryData[$f['identifier']];
+                    unset($entryData[$f['identifier']]);
+                } elseif(method_exists($this, $_mnValue) && isset($entryData['id'])) {
+                    $f['value'] = $this->$_mnValue($entryData['id'], $f);
+                }
+
+                $_mnSelectionValue = '_loadFieldSelection_'.$f['type'];
+                if(method_exists($this, $_mnSelectionValue) && isset($f['preValue'])) {
+                    $f['preValue'] = $this->$_mnSelectionValue($f['preValue']);
+                }
+
+                $entryData['fields'][$f['identifier']] = $f;
+            }
+        }
+        return $entryData;
+    }
+
+    /**
+     * Load the values for given $entryId for $fieldData
+     * lookup function for field type lookupmultiple
+     * @param Numer $entryId
+     * @param array $fieldData
+     * @return array
+     */
+    private function _loadFieldValue_lookupmultiple($entryId, $fieldData) {
+        $ret = array();
+
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+            $queryStr = "SELECT `value` 
+                        FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."`
+                        WHERE `fk_field` = '".$this->_DB->real_escape_string($fieldData['id'])."'
+                            AND `fk_entry` = '".$this->_DB->real_escape_string($entryId)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                while(($result = $query->fetch_assoc()) != false) {
+                    $ret[] = $result['value'];
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get the single upload file from storage location
+     * lookup function for field type upload
+     * @param $entryId
+     * @param $fieldData
+     * @return string
+     */
+    private function _loadFieldValue_upload($entryId, $fieldData) {
+        $ret = "";
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+
+            $uploadedFile = glob(PATH_STORAGE.'/'.$this->_collectionId.'/'.$entryId.'/'.$fieldData['identifier'].'-*');
+            if(!empty($uploadedFile)) {
+                foreach ($uploadedFile as $f) {
+                    $ret = basename($f);
+                    break;
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Get the multiple upload files from storage location
+     * lookup function for field type upload_multiple
+     * @param $entryId
+     * @param $fieldData
+     * @return array
+     */
+    private function _loadFieldValue_upload_multiple($entryId, $fieldData) {
+        $ret = array();
+        if(!empty($entryId) && !empty($fieldData) && !empty($this->_collectionId)) {
+
+            $uploadedFile = glob(PATH_STORAGE.'/'.$this->_collectionId.'/'.$entryId.'/'.$fieldData['identifier'].'-*');
+            if(!empty($uploadedFile)) {
+                foreach ($uploadedFile as $f) {
+                    $ret[] = basename($f);
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Load and prepare the value for a selection field
+     *
+     * @param $data string
+     * @return array
+     */
+    private function _loadFieldSelection_selection($data) {
+        $ret = array();
+
+        if(is_string($data)) {
+            if(strstr($data, ',')) {
+                $ret = explode(',',$data);
+            }
+            else {
+                $ret[] = $data;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load the selection as tag.
+     * Search is a 1:1 match
+     *
+     * @param array $fieldData The sys field data
+     * @param mixed $search Searchterm
+     * @return array
+     */
+    private function _loadTagDistinct_selection($fieldData,$search=false) {
+        return $this->_loadColAsTagFromEntryTable($fieldData['identifier'],$search);
+    }
+
+    /**
+     * Load the data for lookupmultiple field. Provide field id and optional searchterm.
+     * Uses currently loaded collection
+     *
+     * @param array $fieldData The field data to use
+     * @param mixed $search Searchterm to run a match against DB search
+     * @return array
+     */
+    private function _loadTagDistinct_lookupmultiple($fieldData,$search=false) {
+        $ret = array();
+
+        if(!empty($fieldData) && !empty($this->_collectionId)) {
+            $queryStr = "SELECT DISTINCT(`value`) 
+                        FROM `".DB_PREFIX."_collection_entry2lookup_".$this->_DB->real_escape_string($this->_collectionId)."`
+                        WHERE `fk_field` = '".$this->_DB->real_escape_string($fieldData['id'])."'";
+            if(!empty($search)) {
+                $queryStr .= " AND MATCH (`value`) AGAINST ('" . $this->_DB->real_escape_string($search) . "' IN BOOLEAN MODE)";
+            }
+
+            try {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+
+                $query = $this->_DB->query($queryStr);
+                if ($query !== false && $query->num_rows > 0) {
+                    while (($result = $query->fetch_assoc()) != false) {
+                        $ret[] = $result['value'];
+                    }
+                }
+            }
+            catch (Exception $e) {
+                error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load the data from lookupmultiple field. In this case $fieldata is overwritten
+     * and year is used.
+     *
+     * @param array $fieldData
+     * @param bool $search
+     * @return array
+     */
+    private function _loadTagDistinct_year($fieldData,$search=false) {
+        return $this->_loadColAsTagFromEntryTable("year",$search);
+    }
+
+    /**
+     * Get the distinct data from a col and optionaml search term
+     *
+     * @param $colname
+     * @param $search
+     * @return array
+     */
+    private function _loadColAsTagFromEntryTable($colname,$search) {
+        $ret = array();
+
+        if(!empty($colname) && !empty($this->_collectionId)) {
+            if(!empty($search)) {
+                $queryStr = "SELECT `".$this->_DB->real_escape_string($colname)."` 
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_DB->real_escape_string($this->_collectionId)."`";
+                $queryStr .= " WHERE `".$colname."` = '".$this->_DB->real_escape_string($search)."'";
+            }
+            else {
+                $queryStr = "SELECT DISTINCT(`".$this->_DB->real_escape_string($colname)."`) 
+                        FROM `".DB_PREFIX."_collection_entry_".$this->_DB->real_escape_string($this->_collectionId)."`";
+            }
+
+            $queryStr .= " ORDER BY `".$this->_DB->real_escape_string($colname)."` DESC";
+
+            try {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+
+                $query = $this->_DB->query($queryStr);
+                if($query !== false && $query->num_rows > 0) {
+                    while(($result = $query->fetch_assoc()) != false) {
+                        if(!empty($result[$colname])) {
+                            $ret[] = $result[$colname];
+                        }
+                    }
+                }
+            }
+            catch (Exception $e) {
+                error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+            }
+        }
+
+
+        return $ret;
+    }
+
+    /**
+     * set some defaults by init of the class
+     */
+    private function _setDefaults() {
+        // default query options
+        $options['limit'] = 5;
+        $options['offset'] = false;
+        $options['sort'] = false;
+        $options['sortDirection'] = false;
+        $this->setQueryOptions($options);
+    }
+}
diff --git a/webclient/lib/possessed.class.php b/webclient/lib/possessed.class.php
new file mode 100644 (file)
index 0000000..0be12c8
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class Possessed
+ * User management
+ * There is no group management yet. It uses the defined groups
+ * from the initial setup. Don't change em, could break something.
+ *
+ * passwords used here: password_hash("somePassword", PASSWORD_DEFAULT);
+ *
+ */
+class Possessed {
+    /**
+     * the global DB object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    public function __construct($db) {
+        $this->_DB = $db;
+    }
+
+    /**
+     * Retrieve the groups for selection
+     *
+     * @return array
+     */
+    public function getGroups() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `name`, `description` FROM `".DB_PREFIX."_group` ORDER BY `name`";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['id']] = $result;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Fetch all available users for management
+     *
+     * @return array
+     */
+    public function getUsers() {
+        $ret = array();
+
+        $queryStr = "SELECT `id`, `login`, `name`, `active`, `baseGroupId`, `protected`, `created`
+                        FROM `".DB_PREFIX."_user`";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['id']] = $result;
+                $ret[$result['id']]['groups'] = $this->_loadUserGroupInfo($result['id']);
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Create or update a user and set the required user releations
+     *
+     * @param $username string
+     * @param $login string
+     * @param $password string
+     * @param $group string Number
+     * @param bool $active
+     * @return bool
+     */
+    public function createUser($username, $login, $password, $group, $active=false) {
+        $ret = false;
+
+        if(!empty($login) === true
+            && $this->_validNewLogin($login) == true
+            && $this->_validUsergroup($group) == true
+            &&(!empty($password))
+        ) {
+            if ($active === true) {
+                $active = "1";
+            } else {
+                $active = "0";
+            }
+            $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+            $_password = password_hash($password, PASSWORD_DEFAULT);
+
+            $queryStr = "INSERT INTO `".DB_PREFIX . "_user`
+                        SET `name` = '".$this->_DB->real_escape_string($username)."',
+                            `login` = '".$this->_DB->real_escape_string($login)."',
+                            `password` = '".$this->_DB->real_escape_string($_password)."',
+                            `active` = '".$this->_DB->real_escape_string($active)."',
+                            `baseGroupId` = '".$this->_DB->real_escape_string($group)."',
+                            `rights` = 'rwxr--r--',
+                            `owner` = 0,
+                            `group` = '".$this->_DB->real_escape_string($group)."'";
+            $query = $this->_DB->query($queryStr);
+
+            if ($query !== false) {
+                $_userid = $this->_DB->insert_id;
+                $this->_DB->query("UPDATE `".DB_PREFIX . "_user`
+                                    SET `owner` = '".$this->_DB->real_escape_string($_userid)."'
+                                    WHERE `id` = '".$this->_DB->real_escape_string($_userid)."'");
+                $_setGroupRelation = $this->_setGroupReleation($_userid,$group);
+                if($_setGroupRelation !== false) {
+                    $this->_DB->commit();
+                    $ret = true;
+                }
+                $this->_DB->rollback();
+                error_log('ERROR Failed to insert user releation: '.var_export($queryStr, true));
+            } else {
+                $this->_DB->rollback();
+                error_log('ERROR Failed to insert user: '.var_export($queryStr, true));
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Update given user id with given data
+     *
+     * @param $id
+     * @param $username
+     * @param $login
+     * @param $password
+     * @param $group
+     * @param bool $active
+     * @param bool $refreshApiToken
+     * @return bool
+     */
+    public function updateUser($id, $username, $login, $password, $group, $active=false, $refreshApiToken=false) {
+        $ret = false;
+
+        if(!empty($login) === true
+            && $this->_validUpdateLogin($login,$id) == true
+            && $this->_validUsergroup($group) == true
+            && !empty($id)
+        ) {
+            if ($active === true) {
+                $active = "1";
+            } else {
+                $active = "0";
+            }
+
+            $_password = password_hash($password, PASSWORD_DEFAULT);
+
+            $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+            $queryStr = "UPDATE `".DB_PREFIX . "_user`
+                        SET `name` = '".$this->_DB->real_escape_string($username)."',
+                            `login` = '".$this->_DB->real_escape_string($login)."',
+                            `active` = '".$this->_DB->real_escape_string($active)."',
+                            `baseGroupId` = '".$this->_DB->real_escape_string($group)."'";
+            if(Summoner::validate($password,'text')) {
+                $queryStr .= ", `password` = '".$this->_DB->real_escape_string($_password)."'";
+            }
+            if($refreshApiToken === true) {
+                $queryStr .= ", `apiToken` = '".md5(base64_encode(openssl_random_pseudo_bytes(30)))."'";
+                $queryStr .= ", `apiTokenValidDate` = CURRENT_TIMESTAMP() + INTERVAL 1 DAY";
+            }
+            $queryStr .= " WHERE `id` = '".$this->_DB->real_escape_string($id)."'
+                        AND `protected` = '0'";
+            $query = $this->_DB->query($queryStr);
+
+            if ($query !== false) {
+                $_setGroupRelation = $this->_setGroupReleation($id,$group, true);
+                if($_setGroupRelation !== false) {
+                    $this->_DB->commit();
+                    $ret = true;
+                }
+                $this->_DB->rollback();
+                error_log('ERROR Failed to insert user releation: '.var_export($queryStr, true));
+            } else {
+                $this->_DB->rollback();
+                error_log('ERROR Failed to insert user: '.var_export($queryStr, true));
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load the userinformation and groups for given id
+     *
+     * @param $userId string Number
+     * @return array
+     */
+    public function getEditData($userId) {
+        $ret = array();
+
+        if(Summoner::validate($userId,'digit')) {
+            $queryStr = "SELECT `id`, `login`, `name`, `active`, `baseGroupId`, `created`,`apiToken`,`apiTokenValidDate`
+                        FROM `".DB_PREFIX."_user`
+                        WHERE `protected` = '0'
+                        AND `id` = '".$this->_DB->real_escape_string($userId)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows == 1) {
+                $ret = $query->fetch_assoc();
+                $ret['groups'] = $this->_loadUserGroupInfo($userId);
+            }
+
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Delete user by given user id
+     *
+     * @param $id string Number
+     * @return bool
+     */
+    public function deleteUser($id) {
+        $ret = false;
+
+        if(!empty($id)) {
+            $this->_DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
+
+            $d1 = $this->_DB->query("DELETE FROM `".DB_PREFIX."_user` 
+                WHERE `id` = '".$this->_DB->real_escape_string($id)."'
+                AND `protected` = '0'");
+            $d2 = $this->_DB->query("DELETE FROM `".DB_PREFIX."_user2group` WHERE `fk_user_id` = '".$this->_DB->real_escape_string($id)."'");
+            $d3 = $this->_DB->query("DELETE FROM `".DB_PREFIX."_userSession` WHERE `fk_user_id` = '".$this->_DB->real_escape_string($id)."'");
+
+            if($d1 !== false && $d2 !== false && $d3 !== false) {
+                $this->_DB->commit();
+                $ret = true;
+            }
+            else {
+                $this->_DB->rollback();
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Check if given login can be used as a new one
+     *
+     * @param string $login
+     * @return bool
+     */
+    private function _validNewLogin($login) {
+        $ret = false;
+        if (Summoner::validate($login, 'nospace')) {
+            $queryStr = "SELECT `id` FROM `".DB_PREFIX."_user`
+                                WHERE `login` = '".$this->_DB->real_escape_string($login)."'";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows < 1) {
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Check if given $login can be used as a new login for given id
+     *
+     * @param string $login
+     * @param string $id Number
+     * @return bool
+     */
+    private function _validUpdateLogin($login,$id) {
+        $ret = false;
+        if (Summoner::validate($login, 'nospace')) {
+            $queryStr = "SELECT `id` FROM `" . DB_PREFIX . "_user`
+                                WHERE `login` = '".$this->_DB->real_escape_string($login)."'
+                                AND `id` != '".$this->_DB->real_escape_string($id)."'";
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows < 1) {
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * check if given group id is present
+     *
+     * @param string $groupId Number
+     * @return bool
+     */
+    private function _validUsergroup($groupId) {
+        $ret = false;
+
+        if(Summoner::validate($groupId,'digit')) {
+            $queryStr = "SELECT `id` FROM `".DB_PREFIX."_group`
+                        WHERE `id` = '".$this->_DB->real_escape_string($groupId)."'";
+            $query = $this->_DB->query($queryStr);
+            if($query !== false && $query->num_rows > 0) {
+                $ret = true;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Set user to group releation in database.
+     * clean will delete all existing ones for given userid first.
+     *
+     * @param string $userid Number
+     * @param string $groupid Number
+     * @param bool $clean
+     * @return bool
+     */
+    private function _setGroupReleation($userid, $groupid, $clean=false) {
+        $ret = false;
+
+        if(Summoner::validate($userid,'digit')
+            && Summoner::validate($groupid,'digit')) {
+
+            if($clean === true) {
+                $this->_DB->query("DELETE FROM `".DB_PREFIX."_user2group`
+                    WHERE `fk_user_id` = '".$this->_DB->real_escape_string($userid)."'");
+            }
+
+            $queryStr = "INSERT IGNORE INTO `".DB_PREFIX."_user2group`
+                            SET `fk_user_id` = '".$this->_DB->real_escape_string($userid)."',
+                                `fk_group_id` = '".$this->_DB->real_escape_string($groupid)."'";
+            $ret = $this->_DB->query($queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Load all the groups the user is in and the information of them
+     * 
+     * @param $userId string Number
+     * @return array
+     */
+    private function _loadUserGroupInfo($userId) {
+        $ret = array();
+
+        $queryStr = "SELECT g.name AS groupName,
+                                       g.description AS groupDescription,
+                                       g.id AS groupId
+                                       FROM `".DB_PREFIX."_user2group` AS u2g,
+                                               `".DB_PREFIX."_group` AS g
+                                       WHERE u2g.fk_user_id = '".$this->_DB->real_escape_string($userId)."'
+                                       AND u2g.fk_group_id = g.id";
+        $query = $this->_DB->query($queryStr);
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['groupId']] = array(
+                    'groupName' => $result['groupName'],
+                    'groupDescription' => $result['groupDescription']
+                );
+            }
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/spectre.class.php b/webclient/lib/spectre.class.php
new file mode 100644 (file)
index 0000000..ced903f
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class Spectre
+ * API for Bibliotheca
+ */
+class Spectre {
+    /**
+     * the global DB object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    private $_allowedRequests = array('default','list','add','addInfo');
+
+    /**
+     * Spectre constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+    }
+
+    /**
+     * Validate given request string
+     *
+     * @param $request string
+     * @return bool
+     */
+    public function allowedRequests($request) {
+        $ret = false;
+
+        if(in_array($request, $this->_allowedRequests)) {
+            $ret = true;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * With given data build the structure to create a add post
+     * request
+     *
+     * @param $data
+     * @return array
+     */
+    public function buildAddStructure($data) {
+        $ret = array();
+
+        if(!empty($data) && is_array($data)) {
+            foreach($data as $k=>$v) {
+                $ret[$k] = array('input' => $v['apiinfo']);
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * rewrite the data from curl into the format the
+     * POST via web frontend creates
+     * "The problem occurs when you have a form that uses both single file and HTML array feature."
+     * 
+     * @param $data
+     * @return array
+     */
+    public function prepareFilesArray($data) {
+        $ret = array();
+
+        if(!empty($data)) {
+            foreach($data as $fieldName=>$fdata) {
+                foreach($fdata as $k=>$v) {
+                    $ret[$k][$fieldName] = $v;
+                }
+
+            }
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/summoner.class.php b/webclient/lib/summoner.class.php
new file mode 100644 (file)
index 0000000..15ccefd
--- /dev/null
@@ -0,0 +1,685 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * a static helper class
+ */
+class Summoner {
+
+    /**
+     * Return path to given theme file with fallback to default theme
+     *
+     * @param string $file relative path from THEME/
+     * @param string $theme Theme name
+     * @param string $defaultTheme Default theme name can be overwritten
+     * @return boolean|string False of nothing is found
+     */
+    static function themefile($file, $theme, $defaultTheme='default') {
+        $ret = false;
+
+        if(file_exists('view/'.$theme.'/'.$file)) {
+            $ret = 'view/'.$theme.'/'.$file;
+        }
+        elseif (file_exists('view/'.$defaultTheme.'/'.$file)) {
+            $ret = 'view/'.$defaultTheme.'/'.$file;
+        }
+
+        return $ret;
+    }
+
+       /**
+        * validate the given string with the given type. Optional check the string
+        * length
+        *
+        * @param string $input The string to check
+        * @param string $mode How the string should be checked
+        * @param mixed $limit If int given the string is checked for length
+        *
+        * @see http://de.php.net/manual/en/regexp.reference.unicode.php
+        * http://www.sql-und-xml.de/unicode-database/#pc
+        *
+        * the pattern replaces all that is allowed. the correct result after
+        * the replace should be empty, otherwise are there chars which are not
+        * allowed
+        *
+        * @return bool
+        */
+       static function validate($input,$mode='text',$limit=false) {
+               // check if we have input
+               $input = trim($input);
+
+               if($input == "") return false;
+
+               $ret = false;
+
+               switch ($mode) {
+                       case 'mail':
+                           if(filter_var($input,FILTER_VALIDATE_EMAIL) === $input) {
+                               return true;
+                           }
+                else {
+                    return false;
+                           }
+                       break;
+
+                       case 'rights':
+                               return self::isRightsString($input);
+                       break;
+
+                       case 'url':
+                               if(filter_var($input,FILTER_VALIDATE_URL) === $input) {
+                                       return true;
+                               }
+                               else {
+                                       return false;
+                               }
+                       break;
+
+                       case 'nospace':
+                               // text without any whitespace and special chars
+                               $pattern = '/[\p{L}\p{N}]/u';
+                       break;
+
+                       case 'nospaceP':
+                               // text without any whitespace and special chars
+                               // but with Punctuation other
+                               # http://www.sql-und-xml.de/unicode-database/po.html
+                               $pattern = '/[\p{L}\p{N}\p{Po}\-]/u';
+                       break;
+
+                       case 'digit':
+                               // only numbers and digit
+                               // warning with negative numbers...
+                               $pattern = '/[\p{N}\-]/';
+                       break;
+
+                       case 'pageTitle':
+                               // text with whitespace and without special chars
+                               // but with Punctuation
+                               $pattern = '/[\p{L}\p{N}\p{Po}\p{Z}\s-]/u';
+                       break;
+
+                       # strange. the \p{M} is needed.. don't know why..
+                       case 'filename':
+                               $pattern = '/[\p{L}\p{N}\p{M}\-_\.\p{Zs}]/u';
+                       break;
+
+                       case 'text':
+                       default:
+                               $pattern = '/[\p{L}\p{N}\p{P}\p{S}\p{Z}\p{M}\s]/u';
+               }
+
+               $value = preg_replace($pattern, '', $input);
+
+               #if($input === $value) {
+               if($value === "") {
+                       $ret = true;
+               }
+
+               if(!empty($limit)) {
+                       # isset starts with 0
+                       if(isset($input[$limit])) {
+                               # too long
+                               $ret = false;
+                       }
+               }
+
+               return $ret;
+       }
+
+       /**
+        * return if the given string is utf8
+        * http://php.net/manual/en/function.mb-detect-encoding.php
+        *
+        * @param string $string
+        * @return number
+        */
+       static function is_utf8 ( $string ) {
+          // From http://w3.org/International/questions/qa-forms-utf-8.html
+          return preg_match('%^(?:
+                [\x09\x0A\x0D\x20-\x7E]            # ASCII
+              | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+              |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+              | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+              |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+              |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+              | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+              |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+          )*$%xs', $string);
+       }
+
+       /**
+        * check if the given string is a rights string.
+        * @param string $string
+        * @return boolean
+        */
+       static function isRightsString($string) {
+               $ret = false;
+
+               $string = trim($string);
+               if(empty($string)) return false;
+               if(isset($string[9])) return false;
+
+               $check = str_replace("r", "", $string);
+               $check = str_replace("w", "", $check);
+               $check = str_replace("x", "", $check);
+               $check = str_replace("-", "", $check);
+
+               if(empty($check)) {
+                       $ret = true;
+               }
+
+               return $ret;
+       }
+
+       /**
+        * creates the rights string from the given rights array
+        * check what options are set and set the missing ones to -
+        *
+        * then create the rights string
+        * IMPORTANT: keep the order otherwise the rights will be messed up
+        *
+        * @param $rightsArr array
+        * @return mixed
+        */
+       static function prepareRightsString($rightsArr) {
+               $rsArr = array();
+               $ret = false;
+
+               if(!empty($rightsArr)) {
+                       // we need a complete type list
+                       // since we can get an "incomplete" array
+                       // if the user hasnt the rights for a specific type
+                       if(!isset($rightsArr['user'])) {
+                               $rightsArr['user'] = "";
+                       }
+                       if(!isset($rightsArr['group'])) {
+                               $rightsArr['group'] = "";
+                       }
+                       if(!isset($rightsArr['other'])) {
+                               $rightsArr['other'] = "";
+                       }
+
+                       // create the rights information
+                       foreach ($rightsArr as $type=>$data) {
+                               if(!empty($data['read']) && $data['read'] == "1") {
+                                       $rsArr[$type]['read'] = "r";
+                               }
+                               else {
+                                       $rsArr[$type]['read'] = "-";
+                               }
+
+                               if(!empty($data['write']) && $data['write'] == "1") {
+                                       $rsArr[$type]['write'] = "w";
+                               }
+                               else {
+                                       $rsArr[$type]['write'] = "-";
+                               }
+
+                               if(!empty($data['delete']) && $data['delete'] == "1") {
+                                       $rsArr[$type]['delete'] = "x";
+                               }
+                               else {
+                                       $rsArr[$type]['delete'] = "-";
+                               }
+                       }
+
+                       $rString = $rsArr['user']['read'].$rsArr['user']['write'].$rsArr['user']['delete'];
+                       $rString .= $rsArr['group']['read'].$rsArr['group']['write'].$rsArr['group']['delete'];
+                       $rString .= $rsArr['other']['read'].$rsArr['other']['write'].$rsArr['other']['delete'];
+
+                       if(strlen($rString) != 9) {
+                               $ret = false;
+                               // invalid rights string !!
+                       }
+                       else {
+                               $ret = $rString;
+                       }
+               }
+
+               return $ret;
+       }
+
+    /**
+     * Creates from given rights string the rights array
+     * @param $rightsString
+     * @return array
+     */
+       static function prepareRightsArray($rightsString) {
+           $ret = array();
+
+           if(self::isRightsString($rightsString) === true) {
+            $ret['user']['read'] = '-';
+            $ret['user']['write'] = '-';
+            $ret['user']['delete'] = '-';
+            if($rightsString[0] === 'r') $ret['user']['read'] = 'r';
+            if($rightsString[1] === 'w') $ret['user']['write'] = 'w';
+            if($rightsString[2] === 'x') $ret['user']['delete'] = 'x';
+
+            $ret['group']['read'] = '-';
+            $ret['group']['write'] = '-';
+            $ret['group']['delete'] = '-';
+            if($rightsString[3] === 'r') $ret['group']['read'] = 'r';
+            if($rightsString[4] === 'w') $ret['group']['write'] = 'w';
+            if($rightsString[5] === 'x') $ret['group']['delete'] = 'x';
+
+            $ret['other']['read'] = '-';
+            $ret['other']['write'] = '-';
+            $ret['other']['delete'] = '-';
+            if($rightsString[6] === 'r') $ret['other']['read'] = 'r';
+            if($rightsString[7] === 'w') $ret['other']['write'] = 'w';
+            if($rightsString[8] === 'x') $ret['other']['delete'] = 'x';
+        }
+
+           return $ret;
+    }
+
+       /**
+        * get the mime type for given file
+        * uses either mime_content_type or finfo
+        * @param string $file The absolute path to the file
+        * @return mixed|string
+        */
+       static function getMimeType($file) {
+               $mime = 'application/octet-stream'; # default
+
+               if(function_exists('mime_content_type') !== true) {
+                       $mime = mime_content_type($file);
+               }
+               elseif(function_exists('finfo_open') === true) {
+            # provide empty magic file, system default file will be used
+            $finfo = finfo_open(FILEINFO_MIME_TYPE,null);
+            if($finfo) {
+                $mime = finfo_file($finfo, $file);
+                finfo_close($finfo);
+            }
+
+                       # the mime info returns sometimes "application/x-gzip; charset=binary"
+                       # but wee need the part before the ;
+                       if(strstr($mime,';')) {
+                               $tmp = explode(";",$mime);
+                               $mime = $tmp[0];
+                       }
+               }
+
+               return $mime;
+       }
+
+       /**
+        * use the mimeType string to return the string to be used as an icon identifier
+        * eg. application/pdf => pdf
+        * @param string $mime
+        * @return string $ret
+        */
+       static function mimeToIcon($mime) {
+               $ret = 'unknown';
+
+               if(!empty($mime) && strstr($mime,'/') !== false) {
+                       $tmp = explode('/', $mime);
+                       $ret = $tmp[1];
+               }
+               elseif($mime === "directory") {
+                       $ret = "dir";
+               }
+
+               return $ret;
+       }
+
+       /**
+        * read a dir and return the entries as an array
+        * with full path to the files
+        * @param string $directory The absolute path to the directory
+        * @param array $ignore An Array with strings to ignored
+        * @param boolean $recursive If we run a recursive scan or not
+        * @return array
+        */
+       static function readDir($directory,$ignore=array(),$recursive=false) {
+               $files = array();
+
+               $dh = opendir($directory);
+               while(false !== ($file = readdir($dh))) {
+                       if($file[0] ==".") continue;
+                       if(!empty($ignore)) {
+                               foreach ($ignore as $ig)  {
+                               if(strstr($file,$ig)) continue 2;
+                       }
+               }
+
+               if(is_file($directory."/".$file)) {
+                   array_push($files, $directory."/".$file);
+               }
+               elseif($recursive === true) {
+                       array_push($files, $directory."/".$file);
+                   $files = array_merge($files, self::readDir($directory."/".$file,$ignore, $recursive));
+               }
+                       elseif(is_dir($directory."/".$file)) {
+                               array_push($files, $directory."/".$file);
+                       }
+               }
+               closedir($dh);
+
+               return $files;
+       }
+
+       /**
+        * delete and/or empty a diretory
+        *
+        * $empty = true => empty the diretory but do not delete it
+        *
+        * @param string $directory
+        * @param boolean $empty
+        * @param mixed $fTime If not false remove files older then this value in sec.
+        * @return boolean
+        */
+       static function recursive_remove_directory($directory, $empty=false,$fTime=false) {
+               // if the path has a slash at the end we remove it here
+               if(substr($directory,-1) == '/') {
+                       $directory = substr($directory,0,-1);
+               }
+
+               // if the path is not valid or is not a directory ...
+               if(!file_exists($directory) || !is_dir($directory)) {
+                       // ... we return false and exit the function
+                       return false;
+
+               // ... if the path is not readable
+               }elseif(!is_readable($directory)) {
+                       // ... we return false and exit the function
+                       return false;
+
+               // ... else if the path is readable
+               }
+               else {
+                       // we open the directory
+                       $handle = opendir($directory);
+
+                       // and scan through the items inside
+                       while (false !== ($item = readdir($handle))) {
+                               // if the filepointer is not the current directory
+                               // or the parent directory
+                               //if($item != '.' && $item != '..' && $item != '.svn') {
+                               if($item[0] != '.') {
+                                       // we build the new path to delete
+                                       $path = $directory.'/'.$item;
+
+                                       // if the new path is a directory
+                                       if(is_dir($path)) {
+                                          // we call this function with the new path
+                                               self::recursive_remove_directory($path);
+
+                                       // if the new path is a file
+                                       }
+                                       else {
+                                               // we remove the file
+                                               if($fTime !== false && is_int($fTime)) {
+                                                       // check filemtime
+                                                       $ft = filemtime($path);
+                                                       $offset = time()-$fTime;
+                                                       if($ft <= $offset) {
+                                                               unlink($path);
+                                                       }
+                                               }
+                                               else {
+                                                       unlink($path);
+                                               }
+                                       }
+                               }
+                       }
+                       // close the directory
+                       closedir($handle);
+
+                       // if the option to empty is not set to true
+                       if($empty == false) {
+                               // try to delete the now empty directory
+                               if(!rmdir($directory)) {
+                                       // return false if not possible
+                                       return false;
+                               }
+                       }
+                       // return success
+                       return true;
+               }
+       }
+
+    /**
+     * execute a curl call to the fiven $url
+     * @param string $url The request url
+     * @param int $port
+     * @return bool|string
+     */
+       static function curlCall($url,$port=80) {
+               $ret = false;
+
+               $ch = curl_init();
+
+               curl_setopt($ch, CURLOPT_URL, $url);
+               curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+               curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
+               curl_setopt($ch, CURLOPT_TIMEOUT, 30);
+               curl_setopt($ch, CURLOPT_PORT, $port);
+
+               $do = curl_exec($ch);
+               if(is_string($do) === true) {
+                       $ret = $do;
+               }
+               else {
+                       $ret = false;
+               }
+
+               curl_close($ch);
+
+               return $ret;
+       }
+
+       /**
+        * check if a string strts with a given string
+        *
+        * @param string $haystack
+        * @param string $needle
+        * @return boolean
+        */
+       static function startsWith($haystack, $needle) {
+               $length = strlen($needle);
+               return (substr($haystack, 0, $length) === $needle);
+       }
+
+       /**
+        * check if a string ends with a given string
+        *
+        * @param string $haystack
+        * @param string $needle
+        * @return boolean
+        */
+       static function endsWith($haystack, $needle) {
+               $length = strlen($needle);
+               if ($length == 0) {
+                       return true;
+               }
+
+               return (substr($haystack, -$length) === $needle);
+       }
+
+       /**
+        * http://de1.php.net/manual/en/function.getimagesize.php
+        * http://php.net/manual/en/function.imagecreatefromjpeg.php
+        *
+        * @param string $file The absolute path to the image file
+        * @param number $width
+        * @param number $height
+        * @return boolean
+        */
+       static function createThumbnail($file,$width=ADMIN_THUMBNAIL_DEFAULT_WIDTH,$height=ADMIN_THUMBNAIL_DEFAULT_HEIGHT) {
+               $ret = false;
+
+               if(!is_file($file)) return false;
+               # check if this is a support file type to create a thumbnail
+               $mimeType = self::getMimeType($file);
+               if(!strstr(ADMIN_THUMBNAIL_SUPPORTED_FILE_TYPES, $mimeType)) return false;
+
+               // Get new dimensions
+               $imageinfo = getimagesize($file);
+
+               if(empty($imageinfo)) return false;
+
+               $thumbnailName = $file.ADMIN_THUMBNAIL_IDENTIFIER.".".$height."x".$width;
+
+               $width_orig = $imageinfo[0];
+               $height_orig = $imageinfo[1];
+               $ratio_orig = $width_orig/$height_orig;
+
+               if ($width/$height > $ratio_orig) {
+                       $width = $height*$ratio_orig;
+               } else {
+                       $height = $width/$ratio_orig;
+               }
+
+               $im = false;
+
+               // Resample
+               $image_p = imagecreatetruecolor($width, $height);
+
+               switch ($imageinfo[2]) {
+                       case IMAGETYPE_GIF:
+                               $im = imageCreateFromGif($file);
+                               imagecopyresampled($image_p, $im, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
+                               imagegif($image_p, $thumbnailName);
+                       break;
+
+                       case IMAGETYPE_JPEG:
+                               $im = imageCreateFromJpeg($file);
+                               imagecopyresampled($image_p, $im, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
+                               // save
+                               $do = imagejpeg($image_p, $thumbnailName, 70);
+                       break;
+
+                       case IMAGETYPE_PNG:
+                               $im = imageCreateFromPng($file);
+                               imagecopyresampled($image_p, $im, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
+                               imagepng($image_p, $thumbnailName, 5);
+                       break;
+               }
+
+               imagedestroy($im);
+               imagedestroy($image_p);
+
+               if(file_exists($thumbnailName)) {
+                       $ret = true;
+               }
+
+               return $ret;
+       }
+
+       /**
+        * fix the filesystem filenames. Remove whitespace and ...
+        * @param array $filenames File or folder list
+        * @return array
+        */
+       static function fixAssetFilenames($filenames) {
+               $ret = $filenames;
+
+               foreach($filenames as $k=>$file) {
+                       if(file_exists($file)) {
+                               if(strstr($file, " ")) {
+                                       # we do not allow any whitespace in a filename
+                                       $newFilename = str_replace(" ", "-", $file);
+                                       rename($file, $newFilename);
+                                       $filenames[$k] = $newFilename;
+                               }
+                       }
+               }
+
+               return $filenames;
+       }
+
+       /**
+        * simulate the Null coalescing operator in php5
+        *
+        * this only works with arrays and checking if the key is there and echo/return it.
+        *
+        * http://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op
+        *
+        * @param $array
+        * @param $key
+        * @return bool|mixed
+        */
+       static function ifset($array,$key) {
+           return isset($array[$key]) ? $array[$key] : false;
+       }
+
+       /**
+        * based on self::ifset check also the value
+     *
+        * @param $array
+        * @param $key
+        * @param $value
+        * @return bool
+        */
+       static function ifsetValue($array,$key,$value) {
+               if(self::ifset($array,$key)) {
+                       return $array[$key] == $value;
+               }
+               return false;
+       }
+
+    /**
+     * Replace in $heystack the $needle with $replace only once
+     *
+     * @param $haystack string
+     * @param $needle string
+     * @param $replace string
+     * @return string
+     */
+       static function replaceOnce($haystack, $needle, $replace) {
+        $newstring = $haystack;
+        $pos = strpos($haystack, $needle);
+        if ($pos !== false) {
+            $newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
+        }
+        return $newstring;
+    }
+
+    /**
+     * http_build_query with modify array
+     * modify will add: key AND value not empty
+     * modify will remove: only key with no value
+     *
+     * @param $array
+     * @param array $modify
+     * @return string
+     */
+    static function createFromParameterLinkQuery($array,$modify=array()) {
+        $ret = '';
+
+        if(!empty($modify)) {
+            foreach($modify as $k=>$v) {
+                if(empty($v)) {
+                    unset($array[$k]);
+                }
+                else {
+                    $array[$k] = $v;
+                }
+            }
+        }
+
+        if(!empty($array)) {
+            $ret = http_build_query($array);
+        }
+
+        return $ret;
+    }
+}
diff --git a/webclient/lib/tentacle.class.php b/webclient/lib/tentacle.class.php
new file mode 100644 (file)
index 0000000..398d220
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class Tentacle
+ * Tools management
+ */
+class Tentacle {
+    /**
+     * the global DB object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * Tentacle constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+    }
+
+    /**
+     * Validate if given action is a valid tool and if the user has access
+     *
+     * @param $identifier
+     * @return bool
+     */
+    public function validate($identifier) {
+        $ret = false;
+
+        $queryStr = "SELECT `name`,`description`,`action`
+                    FROM `".DB_PREFIX."_tool`  
+                    WHERE ".$this->_User->getSQLRightsString("read")."
+                    AND `action` = '".$this->_DB->real_escape_string($identifier)."'";
+        try {
+            $query = $this->_DB->query($queryStr);
+            if ($query !== false && $query->num_rows > 0) {
+                $ret = $query->fetch_assoc();
+            }
+
+        } catch (Exception $e) {
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql catch: ".$e->getMessage());
+            if(DEBUG) error_log("[DEBUG] ".__METHOD__." mysql query: ".$queryStr);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Default creation info based on current user
+     *
+     * @return array
+     */
+    public function getDefaultCreationInfo() {
+        return array(
+            'id' => $this->_User->param('id'),
+            'group' => $this->_User->param('baseGroupId'),
+            'rights' => 'rwxrwxr--'
+        );
+    }
+}
diff --git a/webclient/lib/trite.class.php b/webclient/lib/trite.class.php
new file mode 100644 (file)
index 0000000..22a0e83
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class Trite
+ *
+ * Everything related for using a collection.
+ * For manage collection use Managecollection class
+ *
+ */
+class Trite {
+    /**
+     * The database object
+     *
+     * @var object
+     */
+    private $_DB;
+
+    /**
+     * The user object to query with
+     *
+     * @var object
+     */
+    private $_User;
+
+    /**
+     * Currently loaded collection to work with
+     *
+     * @var number
+     */
+    private $_id;
+
+    /**
+     * Current loaded collection data as an array
+     *
+     * @var array
+     */
+    private $_collectionData;
+
+    /**
+     * Options for db queries
+     *  'limit' => int,
+     *  'offset' => int,
+     *  'orderby' => string,
+     *  'sortDirection' => ASC|DESC
+     *
+     * @var array
+     */
+    private $_queryOptions;
+
+    /**
+     * Trite constructor.
+     *
+     * @param $databaseConnectionObject
+     * @param $userObj
+     */
+    public function __construct($databaseConnectionObject, $userObj) {
+        $this->_DB = $databaseConnectionObject;
+        $this->_User = $userObj;
+
+        $this->_setDefaults();
+    }
+
+    /**
+     * Set the following options which can be used in DB queries
+     * array(
+     *  'limit' => RESULTS_PER_PAGE,
+     *  'offset' => (RESULTS_PER_PAGE * ($_curPage-1)),
+     *  'orderby' => $_sort,
+     *  'sortDirection' => $_sortDirection
+     * );
+     * @param array $options
+     */
+    public function setQueryOptions($options) {
+
+        if(!isset($options['limit'])) $options['limit'] = 5;
+        if(!isset($options['offset'])) $options['offset'] = false;
+        if(!isset($options['sort'])) $options['sort'] = false;
+        if(!isset($options['sortDirection'])) $options['sortDirection'] = false;
+
+        $this->_queryOptions = $options;
+    }
+
+    /**
+     * Get information to display for current collection
+     * based on current user and given rights
+     *
+     * @param int $id The collection ID to load
+     * @param string $right The rights mode. read, write or delete
+     * @return array
+     */
+    public function load($id,$right="read") {
+        $this->_collectionData = array();
+
+        if(!empty($id) && Summoner::validate($id, 'digit')) {
+
+            $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`,
+                    `c`.`owner`, `c`.`group`, `c`.`rights`, `c`.`defaultSearchField`,
+                    `u`.`name` AS username, `g`.`name` AS groupname
+                    FROM `".DB_PREFIX."_collection` AS c
+                    LEFT JOIN `".DB_PREFIX."_user` AS u ON `c`.`owner` = `u`.`id`
+                    LEFT JOIN `".DB_PREFIX."_group` AS g ON `c`.`group` = `g`.`id`
+                    WHERE ".$this->_User->getSQLRightsString($right, "c")."
+                    AND `c`.`id` = '".$this->_DB->real_escape_string($id)."'";
+            try {
+                $query = $this->_DB->query($queryStr);
+                if ($query !== false && $query->num_rows > 0) {
+                    $this->_collectionData = $query->fetch_assoc();
+                    $this->_id = $this->_collectionData['id'];
+                }
+            } catch (Exception $e) {
+                if(DEBUG) error_log("[DEBUG] ".__METHOD__."  mysql query: ".$queryStr);
+                error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+            }
+        }
+
+        return $this->_collectionData;
+    }
+
+    /**
+     * get the value of the specified param from the collection data array
+     *
+     * @param string $param
+     * @return bool|mixed
+     */
+    public function param($param) {
+        $ret = false;
+
+        $param = trim($param);
+
+        if(!empty($param) && isset($this->_collectionData[$param])) {
+            $ret = $this->_collectionData[$param];
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Get all available collections for display based on current user
+     * and read mode
+     *
+     * @return array
+     */
+    public function getCollections() {
+        $ret = array();
+
+        $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`
+                    FROM `".DB_PREFIX."_collection` AS c
+                    LEFT JOIN `".DB_PREFIX."_user` AS u ON `c`.`owner` = `u`.`id`
+                    LEFT JOIN `".DB_PREFIX."_group` AS g ON `c`.`group` = `g`.`id`
+                    WHERE ".$this->_User->getSQLRightsString("read", "c")."
+                    ORDER BY `c`.`name`";
+        $query = $this->_DB->query($queryStr);
+
+        if($query !== false && $query->num_rows > 0) {
+            while(($result = $query->fetch_assoc()) != false) {
+                $ret[$result['id']] = $result;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * set some defaults by init of the class
+     */
+    private function _setDefaults() {
+        // default query options
+        $options['limit'] = 5;
+        $options['offset'] = false;
+        $options['sort'] = false;
+        $options['sortDirection'] = false;
+        $this->setQueryOptions($options);
+    }
+}
diff --git a/webclient/storage/.gitignore b/webclient/storage/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/webclient/systemout/.gitignore b/webclient/systemout/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/webclient/view/default/auth/auth.html b/webclient/view/default/auth/auth.html
new file mode 100644 (file)
index 0000000..625e0f6
--- /dev/null
@@ -0,0 +1,31 @@
+<?php if($Doomguy->isSignedIn() === true) { ?>
+<h3 class="uk-h3">Logout</h3>
+<a class="uk-button uk-button-primary" href="index.php?p=auth&m=logout">
+    Logout
+    <span uk-icon="icon: sign-out"></span>
+</a>
+<?php } else { ?>
+<h3 class="uk-h3">Login</h3>
+<div class="uk-flex uk-flex-wrap uk-flex-wrap-around">
+    <form class="uk-form-horizontal uk-margin-small" method="post">
+        <div class="uk-margin">
+            <label class="uk-form-label" for="username">Username</label>
+            <div class="uk-form-controls">
+                <input class="uk-input" id="username" type="text" autocomplete="off" name="fdata[login]">
+            </div>
+        </div>
+        <div class="uk-margin">
+            <label class="uk-form-label" for="password">Password</label>
+            <div class="uk-form-controls">
+                <input class="uk-input" id="password" type="password" autocomplete="off" name="fdata[password]">
+            </div>
+        </div>
+        <div class="uk-margin">
+            <button class="uk-button uk-button-primary" type="submit" name="submitForm">
+                Login
+                <span class="uk-icon" uk-icon="icon: sign-in"></span>
+            </button>
+        </div>
+    </form>
+</div>
+<?php } ?>
diff --git a/webclient/view/default/auth/auth.php b/webclient/view/default/auth/auth.php
new file mode 100644 (file)
index 0000000..4747933
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// passwords used here: password_hash("somePassword", PASSWORD_DEFAULT);
+
+if(isset($_GET['m']) && !empty($_GET['m'])) {
+    if($_GET['m'] == "logout") {
+        $Doomguy->logOut();
+        $TemplateData['refresh'] = 'index.php';
+    }
+}
+elseif(isset($_POST['submitForm'])) {
+    $fdata = $_POST['fdata'];
+    if(!empty($fdata)) {
+        $_username = trim($fdata['login']);
+        $_password = trim($fdata['password']);
+
+        if(!empty($_username) && !empty($_password)) {
+            if(Summoner::validate($_username,'text') === true && Summoner::validate($_password,'text') === true) {
+                $do = $Doomguy->authenticate($_username, $_password);
+                if($do === true) {
+                    $TemplateData['refresh'] = 'index.php';
+                }
+                else {
+                    $TemplateData['message']['content'] = "Invalid username or password.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+            else {
+                $TemplateData['message']['content'] = "Please provide valid e-Mail and password.";
+                $TemplateData['message']['status'] = "error";
+            }
+        }
+    }
+}
diff --git a/webclient/view/default/collections/collections.html b/webclient/view/default/collections/collections.html
new file mode 100644 (file)
index 0000000..73ec71c
--- /dev/null
@@ -0,0 +1,55 @@
+<h3 class="uk-h3"><?php echo Summoner::ifset($TemplateData['loadedCollection'], 'name'); ?></h3>
+
+<?php if(!empty($TemplateData['search'])) { ?>
+<div uk-alert id="searchNotice">
+    <button class="uk-alert-close" type="button" uk-close></button>
+    <p>Display result for: <b><?php echo $TemplateData['search']; ?></b></p>
+</div>
+<script type="text/javascript">
+    UIkit.util.on('#searchNotice', 'hide', function () {
+        window.location.href="index.php?p=collections&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>";
+    });
+</script>
+<?php } ?>
+
+<?php if(!empty($TemplateData['entries'])) { ?>
+<div class="uk-grid-small uk-grid-match" uk-grid>
+    <?php foreach($TemplateData['entries']['results'] as $entryK=>$entry) { ?>
+    <div class="uk-width-1-4@s uk-width-1-6@l">
+        <div class="uk-card uk-card-default uk-card-small">
+            <div class="uk-card-media-top">
+                <?php if(Summoner::ifset($entry['fields'], 'coverimage')) { ?>
+                <img src="<?php echo $TemplateData['storagePath'].'/'.$entryK.'/'.$entry['fields']['coverimage']['value']; ?>"
+                     alt="<?php echo $entry['fields']['coverimage']['displayname']; ?>">
+
+                <?php } ?>
+            </div>
+            <div class="uk-card-body uk-visible@l">
+                <?php if(Summoner::ifset($entry['fields'], 'title')) { ?>
+                <h3 class="uk-card-title"><?php echo $entry['fields']['title']['value']; ?></h3>
+                <?php } ?>
+
+                <?php if(Summoner::ifset($entry['fields'], 'description')) { ?>
+                <p><?php echo $entry['fields']['description']['value']; ?></p>
+                <?php } ?>
+            </div>
+            <div class="uk-card-footer">
+                <a href="<?php echo $TemplateData['entryLinkPrefix']; ?>&id=<?php echo $entryK; ?>" class="uk-button uk-button-text">View</a>
+            </div>
+        </div>
+    </div>
+    <?php } ?>
+</div>
+<?php } elseif(!empty($TemplateData['collections'])) { ?>
+<h3 class="uk-h3">Collection overview</h3>
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-2-3@m uk-width-1-2@xl">
+        <dl class="uk-description-list uk-description-list-divider">
+            <?php foreach($TemplateData['collections'] as $k=>$v) { ?>
+            <dt><a href="index.php?p=collections&collection=<?php echo $k; ?>"><?php echo $v['name']; ?></a></dt>
+            <dd><?php echo $v['description']; ?></dd>
+            <?php } ?>
+        </dl>
+    </div>
+</div>
+<?php } ?>
diff --git a/webclient/view/default/collections/collections.php b/webclient/view/default/collections/collections.php
new file mode 100644 (file)
index 0000000..b29698a
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/mancubus.class.php';
+$Mancubus = new Mancubus($DB,$Doomguy);
+require_once 'lib/trite.class.php';
+$Trite = new Trite($DB,$Doomguy);
+
+$_collection = false;
+if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+    $_collection = trim($_GET['collection']);
+    $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+}
+
+// field id to search within
+$_fid = false;
+if(isset($_GET['fid']) && !empty($_GET['fid'])) {
+    $_fid = trim($_GET['fid']);
+    $_fid = Summoner::validate($_fid,'digit') ? $_fid : false;
+}
+
+// field value to look up
+$_fv = false;
+if(isset($_GET['fv']) && !empty($_GET['fv'])) {
+    $_fv = trim($_GET['fv']);
+    $_fv = Summoner::validate($_fv,'text') ? $_fv : false;
+}
+
+$_search = false;
+if(isset($_POST['navSearch'])) {
+    $_search = trim($_POST['navSearch']);
+    $_search = Summoner::validate($_search,'text') ? $_search :  false;
+}
+
+require_once(Summoner::themefile('system/pagination_before.php',UI_THEME));
+
+$TemplateData['loadedCollection'] = array();
+$TemplateData['storagePath'] = '';
+$TemplateData['entries'] = array();
+$TemplateData['collections'] = array();
+$TemplateData['search'] = false;
+// needed for pagination link building
+$TemplateData['pagination']['currentGetParameters']['p'] = 'collections';
+$TemplateData['pagination']['currentGetParameters']['collection'] = $_collection;
+
+if(!empty($_collection)) {
+    $TemplateData['loadedCollection'] = $Trite->load($_collection);
+    if(!empty($TemplateData['loadedCollection'])) {
+        $Mancubus->setCollection($Trite->param('id'));
+        $Mancubus->setQueryOptions($_queryOptions); // this comes from pagination_before!
+        $TemplateData['storagePath'] = PATH_WEB_STORAGE . '/' . $_collection;
+        $TemplateData['entryLinkPrefix'] = "index.php?p=entry&collection=".$_collection;
+        $TemplateData['searchAction'] = 'index.php?p=collections&collection='.$_collection;
+
+        if (!empty($_fv) && !empty($_fid)) {
+            $TemplateData['entries'] = $Mancubus->getEntriesByFieldValue($_fid, $_fv);
+            $TemplateData['search'] = $_fv;
+
+            $TemplateData['pagination']['currentGetParameters']['fid'] = $_fid;
+            $TemplateData['pagination']['currentGetParameters']['fv'] = $_fv;
+        } else {
+            $TemplateData['entries'] = $Mancubus->getEntries($Trite->param('defaultSearchField'),$_search,true);
+            if (!empty($_search)) {
+                $TemplateData['search'] = $_search;
+            }
+        }
+    }
+    else {
+        $TemplateData['message']['content'] = "Can not load given collection.";
+        $TemplateData['message']['status'] = "error";
+    }
+}
+else {
+    $TemplateData['collections'] = $Trite->getCollections();
+}
+
+require_once(Summoner::themefile('system/pagination_after.php',UI_THEME));
diff --git a/webclient/view/default/dashboard/dashboard.html b/webclient/view/default/dashboard/dashboard.html
new file mode 100644 (file)
index 0000000..6ad47e0
--- /dev/null
@@ -0,0 +1,54 @@
+<?php if(!empty($TemplateData['search'])) { ?>
+<div uk-alert id="searchNotice">
+    <button class="uk-alert-close" type="button" uk-close></button>
+    <p>Display result for: <b><?php echo $TemplateData['search']; ?></b></p>
+</div>
+<script type="text/javascript">
+    UIkit.util.on('#searchNotice', 'hide', function () {
+        window.location.href="index.php";
+    });
+</script>
+<?php } ?>
+
+<div class="uk-grid-divider uk-child-width-expand@s" uk-grid>
+<?php foreach($TemplateData['latest'] as $k=>$v) { ?>
+    <div>
+        <a href="index.php?p=collections&collection=<?php echo $k; ?>"><?php echo $v['name']; ?></a><br  />
+        <?php echo $v['description']; ?>
+
+        <?php
+        if(isset($v['entries']['results'])) {
+            foreach($v['entries']['results'] as $entryK=>$entry) { ?>
+
+        <div class="uk-card uk-card-default uk-grid-collapse uk-child-width-1-2@s uk-margin" uk-grid>
+            <div class="uk-card-media-left uk-cover-container">
+                <?php if(Summoner::ifset($entry['fields'], 'coverimage')) { ?>
+                <img src="<?php echo PATH_WEB_STORAGE.'/'.$k.'/'.$entryK.'/'.$entry['fields']['coverimage']['value']; ?>"
+                     alt="<?php echo $entry['fields']['coverimage']['displayname']; ?>" uk-cover>
+                <canvas width="600" height="400"></canvas>
+                <?php } ?>
+            </div>
+            <div>
+                <div class="uk-card-body">
+                    <?php if(Summoner::ifset($entry['fields'], 'title')) { ?>
+                    <h3 class="uk-card-title"><?php echo $entry['fields']['title']['value']; ?></h3>
+                    <?php } ?>
+
+                    <?php if(Summoner::ifset($entry['fields'], 'description')) { ?>
+                    <p><?php echo $entry['fields']['description']['value']; ?></p>
+                    <?php } ?>
+                </div>
+                <div class="uk-card-footer">
+                    <a href="index.php?p=entry&collection=<?php echo $k ?>&id=<?php echo $entryK; ?>" class="uk-button uk-button-text">View</a>
+                </div>
+            </div>
+        </div>
+
+        <?php
+            }
+        }
+        ?>
+
+    </div>
+<?php } ?>
+</div>
diff --git a/webclient/view/default/dashboard/dashboard.php b/webclient/view/default/dashboard/dashboard.php
new file mode 100644 (file)
index 0000000..a4a843f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/mancubus.class.php';
+$Mancubus = new Mancubus($DB,$Doomguy);
+
+$TemplateData['search'] = false;
+$TemplateData['searchAction'] = 'index.php';
+
+$_search = false;
+if(isset($_POST['navSearch'])) {
+    $_search = trim($_POST['navSearch']);
+    $_search = Summoner::validate($_search,'text') ? $_search :  false;
+}
+
+$TemplateData['latest'] = $Mancubus->getLatest(5,5,$_search);
+if (!empty($_search)) {
+    $TemplateData['search'] = $_search;
+}
diff --git a/webclient/view/default/entry/entry.html b/webclient/view/default/entry/entry.html
new file mode 100644 (file)
index 0000000..4c83cc1
--- /dev/null
@@ -0,0 +1,55 @@
+<h3 class="uk-h3"><a href="index.php?p=collections&collection=<?php echo Summoner::ifset($TemplateData['loadedCollection'], 'id'); ?>"><?php echo Summoner::ifset($TemplateData['loadedCollection'], 'name'); ?></a></h3>
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-1-2@l">
+        <article class="uk-article">
+            <?php if($TemplateData['showEdit'] === true) { ?>
+            <p class="uk-article-meta"><a href="index.php?p=manageentry&collection=<?php echo Summoner::ifset($TemplateData['loadedCollection'], 'id'); ?>&id=<?php echo $TemplateData['entry']['id']; ?>">EDIT</a></p>
+            <?php
+            }
+
+            if(isset($TemplateData['entry']['fields'])) {
+                foreach($TemplateData['entry']['fields'] as $field) {
+
+                    if($field['identifier'] == "coverimage") continue;
+                    if($field['identifier'] == "attachment") continue;
+
+                    $_fieldViewSpecial = Summoner::themefile('entry/field-'.$field['type'].'-'.$field['identifier'].'.html', UI_THEME);
+                    $_fieldView = Summoner::themefile('entry/field-'.$field['type'].'.html', UI_THEME);
+                    if(file_exists($_fieldViewSpecial)) {
+                        require $_fieldViewSpecial;
+                    }
+                    elseif(file_exists($_fieldView)) {
+                        require $_fieldView;
+                    }
+                    else {
+                        require $TemplateData['fieldViewDefault'];
+                    }
+                }
+            }
+            ?>
+
+        </article>
+    </div>
+    <div class="uk-width-1-2@l">
+        <?php
+        if(isset($TemplateData['entry']['fields'])) {
+            foreach($TemplateData['entry']['fields'] as $field) {
+                if($field['identifier'] == "coverimage" || $field['identifier'] == "attachment") {
+
+                    $_fieldViewSpecial = Summoner::themefile('entry/field-'.$field['type'].'-'.$field['identifier'].'.html', UI_THEME);
+                    $_fieldView = Summoner::themefile('entry/field-'.$field['type'].'.html', UI_THEME);
+                    if(file_exists($_fieldViewSpecial)) {
+                        require $_fieldViewSpecial;
+                    }
+                    elseif(file_exists($_fieldView)) {
+                        require $_fieldView;
+                    }
+                    else {
+                        require $TemplateData['fieldViewDefault'];
+                    }
+                }
+            }
+        }
+        ?>
+    </div>
+</div>
diff --git a/webclient/view/default/entry/entry.php b/webclient/view/default/entry/entry.php
new file mode 100644 (file)
index 0000000..a554905
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/mancubus.class.php';
+$Mancubus = new Mancubus($DB,$Doomguy);
+require_once 'lib/manageentry.class.php';
+$ManageEntry = new Manageentry($DB,$Doomguy);
+require_once 'lib/trite.class.php';
+$Trite = new Trite($DB,$Doomguy);
+
+$_collection = false;
+if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+    $_collection = trim($_GET['collection']);
+    $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+$TemplateData['fieldViewDefault'] = Summoner::themefile('entry/field-unknown.html', UI_THEME);
+$TemplateData['entry'] = array();
+$TemplateData['loadedCollection'] = array();
+$TemplateData['storagePath'] = '';
+$TemplateData['showEdit'] = false;
+
+if(!empty($_collection) && !empty($_id)) {
+    $TemplateData['loadedCollection'] = $Trite->load($_collection);
+    if(!empty($TemplateData['loadedCollection'])) {
+        $Mancubus->setCollection($Trite->param('id'));
+        $TemplateData['entry'] = $Mancubus->getEntry($_id);
+        $TemplateData['storagePath'] = PATH_WEB_STORAGE . '/' . $Trite->param('id') . '/' . $_id;
+        $TemplateData['searchAction'] = 'index.php?p=collections&collection=' . $Trite->param('id');
+
+        $ManageEntry->setCollection($Trite->param('id'));
+        $TemplateData['showEdit'] = $ManageEntry->canEditEntry($_id);
+    }
+    else {
+        $TemplateData['message']['content'] = 'Can not load given collection.';
+        $TemplateData['message']['status'] = 'error';
+    }
+}
+else {
+    $TemplateData['message']['status'] = 'error';
+    $TemplateData['message']['content'] = 'Missing required query parameters.';
+}
diff --git a/webclient/view/default/entry/field-date.html b/webclient/view/default/entry/field-date.html
new file mode 100644 (file)
index 0000000..61f0e48
--- /dev/null
@@ -0,0 +1,4 @@
+<p data-field-name="date" data-field-id="<?php echo $field['identifier']; ?>">
+    <span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+    <a href="index.php?p=collections&collection='.$TemplateData['loadedCollection']['id'].'&fid='.$field['id'].'&fv='.urlencode(Summoner::ifset($field, 'value')).'"><?php echo Summoner::ifset($field, 'value'); ?></a>
+</p>
diff --git a/webclient/view/default/entry/field-lookupmultiple.html b/webclient/view/default/entry/field-lookupmultiple.html
new file mode 100644 (file)
index 0000000..47d42e0
--- /dev/null
@@ -0,0 +1,8 @@
+<p data-field-name="lookupmultiple" data-field-id="<?php echo $field['identifier']; ?>">
+    <span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+    <?php
+    foreach($field['value'] as $_fv) {
+        echo '<a href="index.php?p=collections&collection='.$TemplateData['loadedCollection']['id'].'&fid='.$field['id'].'&fv='.urlencode($_fv).'">'.$_fv.'</a>, ';
+    }
+    ?>
+</p>
diff --git a/webclient/view/default/entry/field-selection.html b/webclient/view/default/entry/field-selection.html
new file mode 100644 (file)
index 0000000..2872380
--- /dev/null
@@ -0,0 +1,4 @@
+<p data-field-name="selection" data-field-id="<?php echo $field['identifier']; ?>">
+    <span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+    <a href="index.php?p=collections&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>&fid=<?php echo $field['id']; ?>&fv=<?php echo urlencode(Summoner::ifset($field, 'value')); ?>"><?php echo Summoner::ifset($field, 'value'); ?></a>
+</p>
diff --git a/webclient/view/default/entry/field-text-title.html b/webclient/view/default/entry/field-text-title.html
new file mode 100644 (file)
index 0000000..216fac6
--- /dev/null
@@ -0,0 +1 @@
+<h1 class="uk-article-title" data-field-name="text-title" data-field-id="<?php echo $field['identifier']; ?>"><?php echo Summoner::ifset($field, 'value'); ?></h1>
diff --git a/webclient/view/default/entry/field-text.html b/webclient/view/default/entry/field-text.html
new file mode 100644 (file)
index 0000000..9f76b0e
--- /dev/null
@@ -0,0 +1 @@
+<p data-field-name="text" data-field-id="<?php echo $field['identifier']; ?>"><span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span> <?php echo Summoner::ifset($field, 'value'); ?></p>
diff --git a/webclient/view/default/entry/field-text3-description.html b/webclient/view/default/entry/field-text3-description.html
new file mode 100644 (file)
index 0000000..065ab0f
--- /dev/null
@@ -0,0 +1 @@
+<p data-field-name="text3-description" class="uk-text-lead" data-field-id="<?php echo $field['identifier']; ?>"><?php echo Summoner::ifset($field, 'value'); ?></p>
diff --git a/webclient/view/default/entry/field-text3.html b/webclient/view/default/entry/field-text3.html
new file mode 100644 (file)
index 0000000..c663afb
--- /dev/null
@@ -0,0 +1 @@
+<p data-field-name="text3" data-field-id="<?php echo $field['identifier']; ?>"><span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span> <?php echo Summoner::ifset($field, 'value'); ?></p>
diff --git a/webclient/view/default/entry/field-textarea-content.html b/webclient/view/default/entry/field-textarea-content.html
new file mode 100644 (file)
index 0000000..6e5e340
--- /dev/null
@@ -0,0 +1 @@
+<p data-field-name="textarea-content" data-field-id="<?php echo $field['identifier']; ?>" class="uk-dropcap"><?php echo Summoner::ifset($field, 'value'); ?></p>
diff --git a/webclient/view/default/entry/field-textarea.html b/webclient/view/default/entry/field-textarea.html
new file mode 100644 (file)
index 0000000..7cd22c2
--- /dev/null
@@ -0,0 +1 @@
+<p data-field-name="textarea" data-field-id="<?php echo $field['identifier']; ?>"><span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span> <?php echo Summoner::ifset($field, 'value'); ?></p>
diff --git a/webclient/view/default/entry/field-unknown.html b/webclient/view/default/entry/field-unknown.html
new file mode 100644 (file)
index 0000000..fa3ba54
--- /dev/null
@@ -0,0 +1 @@
+<p>Missing template for: <?php echo $field['identifier']; ?></p>
diff --git a/webclient/view/default/entry/field-upload-coverimage.html b/webclient/view/default/entry/field-upload-coverimage.html
new file mode 100644 (file)
index 0000000..8e78315
--- /dev/null
@@ -0,0 +1,6 @@
+<div class="uk-margin" data-field-name="upload-coverimage">
+    <img src="<?php echo $TemplateData['storagePath'].'/'.Summoner::ifset($field, 'value'); ?>"
+         title="<?php echo Summoner::ifset($field, 'value'); ?>"
+         width=""
+    />
+</div>
diff --git a/webclient/view/default/entry/field-upload.html b/webclient/view/default/entry/field-upload.html
new file mode 100644 (file)
index 0000000..5acb876
--- /dev/null
@@ -0,0 +1,3 @@
+<p data-field-name="upload" data-field-id="<?php echo $field['identifier']; ?>"><span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+    <a href="<?php echo $TemplateData['storagePath'].'/'.Summoner::ifset($field, 'value'); ?>" target="_blank"><?php echo Summoner::ifset($field, 'value'); ?></a>
+</p>
diff --git a/webclient/view/default/entry/field-upload_multiple-attachment.html b/webclient/view/default/entry/field-upload_multiple-attachment.html
new file mode 100644 (file)
index 0000000..6145c89
--- /dev/null
@@ -0,0 +1,9 @@
+<div data-field-name="upload_multiple-attachment" class="uk-child-width-1-3@m" uk-grid uk-lightbox="animation: fade">
+    <?php foreach ($field['value'] as $_uEntry) { ?>
+    <div>
+        <a class="uk-inline" href="<?php echo $TemplateData['storagePath'].'/'.$_uEntry; ?>" data-caption="<?php echo $_uEntry; ?>">
+            <img src="<?php echo $TemplateData['storagePath'].'/'.$_uEntry; ?>" alt="<?php echo $_uEntry; ?>">
+        </a>
+    </div>
+    <?php } ?>
+</div>
diff --git a/webclient/view/default/entry/field-upload_multiple.html b/webclient/view/default/entry/field-upload_multiple.html
new file mode 100644 (file)
index 0000000..955ccfd
--- /dev/null
@@ -0,0 +1,8 @@
+<p data-field-name="upload_multiple" data-field-id="<?php echo $field['identifier']; ?>"><span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+<ul class="uk-list uk-list-collapse uk-list-disc">
+    <?php foreach ($field['value'] as $_uEntry) { ?>
+    <li><a href="<?php echo $TemplateData['storagePath'].'/'.$_uEntry; ?>" target="_blank"><?php echo $_uEntry; ?></a></li>
+    <?php } ?>
+</ul>
+</p>
+
diff --git a/webclient/view/default/entry/field-year.html b/webclient/view/default/entry/field-year.html
new file mode 100644 (file)
index 0000000..7f04a91
--- /dev/null
@@ -0,0 +1,4 @@
+<p data-field-name="year" data-field-id="<?php echo $field['identifier']; ?>">
+    <span class="uk-text-muted"><?php echo $field['displayname']; ?>:</span>
+    <a href="index.php?p=collections&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>&fid=<?php echo $field['id']; ?>&fv=<?php echo urlencode(Summoner::ifset($field, 'value')); ?>"><?php echo Summoner::ifset($field, 'value'); ?></a>
+</p>
diff --git a/webclient/view/default/main.php b/webclient/view/default/main.php
new file mode 100644 (file)
index 0000000..ff5fec7
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+
+       <link type="text/css" rel="stylesheet" href="view/default/ui/css/uikit.min.css"  media="screen,projection"/>
+       <link type="text/css" rel="stylesheet" href="view/default/ui/css/style.css"  media="screen,projection"/>
+    <script type="text/javascript" src="view/default/ui/js/uikit.min.js"></script>
+    <script type="text/javascript" src="view/default/ui/js/uikit-icons.min.js"></script>
+
+       <meta name="author" content="https://www.bananas-playground.net/projekt/bibliotheca" />
+       <title>Bibliotheca</title>
+</head>
+<body>
+    <header>
+       <?php require_once $ViewMenu; ?>
+    </header>
+
+    <main>
+        <div class="uk-container uk-container-expand uk-margin-top">
+            <?php require_once $ViewMessage; ?>
+            <?php require_once $ViewPagination; ?>
+            <?php require_once $View; ?>
+        </div>
+       </main>
+
+    <footer>
+        <div class="uk-container uk-container-expand">
+            <p>&nbsp;</p>
+        </div>
+    </footer>
+</body>
+</html>
diff --git a/webclient/view/default/managecollectionfields/managecollectionfields.html b/webclient/view/default/managecollectionfields/managecollectionfields.html
new file mode 100644 (file)
index 0000000..ddc23b0
--- /dev/null
@@ -0,0 +1,60 @@
+<h3 class="uk-h3">Manage your fields for: <?php echo $TemplateData['editData']['name']; ?></h3>
+
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-1-2">
+        <h4 class="uk-h4">Add or remove a field</h4>
+        <p>
+            Just use drag and drop below to add, remove or order your fields.<br />
+            <span class="" uk-icon="icon: warning"></span> Removing a field will remove
+            the stored data from the collection.<br />
+            <span class="" uk-icon="icon: warning"></span> Make sure at least the <b>title</b>
+            field is available.
+        </p>
+        <div id="collectionFields" uk-sortable="group: sortable-group">
+            <?php foreach($TemplateData['existingFields'] as $k=>$v) { ?>
+            <div data-field-id="<?php echo $k; ?>">
+                <span class="uk-sortable-handle uk-margin-small-right" uk-icon="icon: table"></span>
+                <?php echo $v['displayname']; ?> (<?php echo $v['type']; ?>)
+            </div>
+            <?php } ?>
+        </div>
+
+        <form class="uk-form-horizontal uk-margin-small" method="post" onsubmit="return saveOrderAndSubmit()">
+            <input type="hidden" name="fdata[fieldSortString]" id="fieldSort"
+               value="<?php echo Summoner::ifset($TemplateData['editData'], 'fieldSortString'); ?>">
+            <div class="uk-margin">
+                <button class="uk-button uk-button-primary" type="submit" name="submitForm">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+    <div class="uk-width-1-2">
+        <h4 class="uk-h4">Available fields</h4>
+        <div uk-sortable="group: sortable-group">
+            <?php foreach($TemplateData['availableFields'] as $k=>$v) { ?>
+            <div data-field-id="<?php echo $k; ?>">
+                <span class="uk-sortable-handle uk-margin-small-right" uk-icon="icon: table"></span>
+                <?php echo $v['displayname']; ?> (<?php echo $v['type']; ?>)
+            </div>
+            <?php } ?>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    function saveOrderAndSubmit() {
+        let list = document.getElementById("collectionFields");
+        let fieldSort = document.getElementById("fieldSort");
+        let sortString = '';
+        if(list && list.children.length > 0 && fieldSort) {
+            let fields = Array.from(list.children);
+            fields.forEach(function(item, index) {
+                sortString += item.getAttribute("data-field-id")+",";
+            });
+            fieldSort.value = sortString;
+            return true;
+        }
+        return false;
+    }
+</script>
diff --git a/webclient/view/default/managecollectionfields/managecollectionfields.php b/webclient/view/default/managecollectionfields/managecollectionfields.php
new file mode 100644 (file)
index 0000000..536f372
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * manage the fields from a existing collection
+ */
+
+require_once 'lib/managecollections.class.php';
+$ManangeCollections = new ManageCollections($DB,$Doomguy);
+require_once 'lib/managecollectionfields.class.php';
+$ManangeCollectionFields = new ManageCollectionFields($DB,$Doomguy);
+$TemplateData['availableFields'] = $ManangeCollectionFields->getAvailableFields();
+$TemplateData['existingFields'] = array();
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+if(!empty($_id)) {
+    $TemplateData['editData'] = $ManangeCollections->getEditData($_id);
+    $ManangeCollectionFields->setCollection($_id);
+    $TemplateData['existingFields'] = $ManangeCollectionFields->getExistingFields();
+    // reduce the selection for only the new ones
+    if(!empty($TemplateData['existingFields'])) {
+        foreach ($TemplateData['existingFields'] as $k=>$v) {
+            unset($TemplateData['availableFields'][$k]);
+        }
+    }
+
+    // if loading failed redirect to overview
+    if(!isset($TemplateData['editData']['name'])) {
+        $TemplateData['refresh'] = 'index.php?p=managecolletions';
+    }
+}
+
+if(isset($_POST['submitForm'])) {
+    $fdata = $_POST['fdata'];
+    if (!empty($fdata)) {
+        $_fieldSortString = trim($fdata['fieldSortString']);
+        if($ManangeCollectionFields->validateFieldSortString($_fieldSortString)) {
+            $do = $ManangeCollectionFields->updateFields($_fieldSortString);
+            if ($do === true) {
+                $TemplateData['refresh'] = 'index.php?p=managecollectionfields&id='.$_id;
+            } else {
+                $TemplateData['message']['content'] = "Fields could not be updated.";
+                $TemplateData['message']['status'] = "error";
+            }
+        }
+        else {
+            $TemplateData['message']['content'] = "Please provide valid fields.";
+            $TemplateData['message']['status'] = "error";
+        }
+    }
+}
diff --git a/webclient/view/default/managecolletions/managecolletions.html b/webclient/view/default/managecolletions/managecolletions.html
new file mode 100644 (file)
index 0000000..486957f
--- /dev/null
@@ -0,0 +1,166 @@
+<h3 class="uk-h3">Manage your collections</h3>
+
+<div class="uk-grid-small uk-grid-row-small" uk-grid>
+       <div class="uk-width-1-2">
+               <h4 class="uk-h4">Add or modify a collection</h4>
+               <form class="uk-form-horizontal uk-margin-small" method="post">
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="name">Name</label>
+                               <div class="uk-form-controls">
+                                       <input class="uk-input" id="name" type="text" autocomplete="off" name="fdata[name]"
+                                               placeholder="Unique name. No special chars."
+                                               value="<?php echo Summoner::ifset($TemplateData['editData'], 'name'); ?>">
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="description">Description</label>
+                               <div class="uk-form-controls">
+                                       <input class="uk-input" id="description" type="text" autocomplete="off" name="fdata[description]"
+                                                  value="<?php echo Summoner::ifset($TemplateData['editData'], 'description'); ?>">
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="owner">Owner</label>
+                               <div class="uk-form-controls">
+                                       <select class="uk-select" id="owner" name="fdata[owner]">
+                                               <option value="">Please select</option>
+                                               <?php foreach($TemplateData['ownerSelection'] as $k=>$v) { ?>
+                                               <option value="<?php echo $k; ?>"
+                                               <?php if(Summoner::ifsetValue($TemplateData['editData'], 'owner',$k)) echo 'selected'; ?>
+                                               ><?php echo $v['login']; ?> (<?php echo $v['name']; ?>)</option>
+                                               <?php } ?>
+                                       </select>
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="group">Group</label>
+                               <div class="uk-form-controls">
+                                       <select class="uk-select" id="group" name="fdata[group]">
+                                               <option value="">Please select</option>
+                                               <?php foreach($TemplateData['groupSelection'] as $k=>$v) { ?>
+                                               <option value="<?php echo $k; ?>"
+                                                       <?php if(Summoner::ifsetValue($TemplateData['editData'], 'group',$k)) echo 'selected'; ?>
+                                               ><?php echo $v['name']; ?> (<?php echo $v['description']; ?>)</option>
+                                               <?php } ?>
+                                       </select>
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <div class="uk-form-label">Rights</div>
+                               <div class="uk-form-controls uk-form-controls-text">
+                                       <table class="uk-table uk-table-small">
+                                               <tr>
+                                                       <th>User</th>
+                                                       <th>Group</th>
+                                                       <th>Other</th>
+                                               </tr>
+                                               <tr>
+                                                       <td>
+                                                               <label>r:<input class="uk-checkbox" type="checkbox" name="fdata[rights][user][read]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['user'], 'read', 'r')) echo "checked"; ?>></label>
+                                                               <label>w:<input class="uk-checkbox" type="checkbox" name="fdata[rights][user][write]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['user'], 'write', 'w')) echo "checked"; ?>></label>
+                                                               <label>x:<input class="uk-checkbox" type="checkbox" name="fdata[rights][user][delete]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['user'], 'delete', 'x')) echo "checked"; ?>></label>
+                                                       </td>
+                                                       <td>
+                                                               <label>r:<input class="uk-checkbox" type="checkbox" name="fdata[rights][group][read]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['group'], 'read', 'r')) echo "checked"; ?>></label>
+                                                               <label>w:<input class="uk-checkbox" type="checkbox" name="fdata[rights][group][write]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['group'], 'write', 'w')) echo "checked"; ?>></label>
+                                                               <label>x:<input class="uk-checkbox" type="checkbox" name="fdata[rights][group][delete]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['group'], 'delete', 'x')) echo "checked"; ?>></label>
+                                                       </td>
+                                                       <td>
+                                                               <label>r:<input class="uk-checkbox" type="checkbox" name="fdata[rights][other][read]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['other'], 'read', 'r')) echo "checked"; ?>></label>
+                                                               <label>w:<input class="uk-checkbox" type="checkbox" name="fdata[rights][other][write]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['other'], 'write', 'w')) echo "checked"; ?>></label>
+                                                               <label>x:<input class="uk-checkbox" type="checkbox" name="fdata[rights][other][delete]" value="1"
+                                                                       <?php if(Summoner::ifsetValue($TemplateData['editData']['rights']['other'], 'delete', 'x')) echo "checked"; ?>></label>
+                                                       </td>
+                                               </tr>
+                                       </table>
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="tool">Tools</label>
+                               <div class="uk-form-controls">
+                                       <select class="uk-select" id="tool" name="fdata[tool][]" multiple="multiple" size="5">
+                                               <option value="">None</option>
+                                               <?php foreach($TemplateData['toolSelection'] as $k=>$v) { ?>
+                                               <option value="<?php echo $k; ?>"
+                                               <?php if(Summoner::ifset($TemplateData['editData']['tool'],$k)) echo 'selected'; ?>
+                                               ><?php echo $v['name']; ?> (<?php echo $v['description']; ?>)</option>
+                                               <?php } ?>
+                                       </select>
+                               </div>
+                       </div>
+                       <?php if(Summoner::ifset($TemplateData['editData'], 'name')) { ?>
+                       <div class="uk-margin">
+                               <div class="uk-form-label">Delete <span uk-icon="warning"></span></div>
+                               <div class="uk-form-controls uk-form-controls-text">
+                                       <label>
+                                               <input class="uk-checkbox" type="checkbox" name="fdata[doDelete]" value="1">
+                                               Warning: this will delete ALL the data in this collection!
+                                       </label>
+                               </div>
+                       </div>
+                       <?php } ?>
+                       <div class="uk-margin">
+                               <label class="uk-form-label" for="defaultSearchField">Default global search field</label>
+                               <div class="uk-form-controls">
+                                       <select class="uk-select" id="defaultSearchField" name="fdata[defaultSearchField]">
+                                               <option value="">Please select</option>
+                                               <?php foreach($TemplateData['existingFields'] as $k=>$v) { ?>
+                                               <option value="<?php echo $v['identifier']; ?>"
+                                               <?php if(Summoner::ifsetValue($TemplateData['editData'], 'defaultSearchField', $v['identifier'])) echo 'selected'; ?>
+                                               ><?php echo $v['displayname']; ?> (<?php echo $v['type']; ?>)</option>
+                                               <?php } ?>
+                                       </select>
+                                       <small>The field is used in the global search.
+                                       <span class="" uk-icon="icon: warning"></span> Altering the default search field results in
+                                       a DB reindex. This could take some time, depending on the amount of data.</small>
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <button class="uk-button uk-button-primary" type="submit" name="submitForm">
+                                       Save
+                               </button>
+                       </div>
+               </form>
+       </div>
+       <div class="uk-width-1-2">
+               <h4 class="uk-h4">Available collections</h4>
+               <table class="uk-table">
+                       <thead>
+                       <tr>
+                               <th>Name</th>
+                               <th>Description</th>
+                               <th>Ownership</th>
+                               <th></th>
+                       </tr>
+                       </thead>
+                       <tbody>
+                       <?php foreach($TemplateData['existingCollections'] as $k=>$v) { ?>
+                       <tr>
+                               <td>
+                                       <?php echo $v['name']; ?><br/>
+                                       <small><?php echo $v['created']; ?></small>
+                               </td>
+                               <td><?php echo $v['description']; ?></td>
+                               <td>
+                                       <span uk-icon="user"></span> <?php echo $v['username']; ?><br />
+                                       <span uk-icon="users"></span> <?php echo $v['groupname']; ?><br />
+                                       <span uk-icon="lock"></span> <?php echo $v['rights']; ?>
+                               </td>
+                               <td>
+                                       <a href="index.php?p=managecolletions&m=edit&id=<?php echo $k; ?>" uk-icon="pencil"></a>
+                                       <a href="index.php?p=managecollectionfields&id=<?php echo $k; ?>" uk-icon="list"></a>
+                               </td>
+                       </tr>
+                       <?php } ?>
+                       </tbody>
+               </table>
+       </div>
+</div>
diff --git a/webclient/view/default/managecolletions/managecolletions.php b/webclient/view/default/managecolletions/managecolletions.php
new file mode 100644 (file)
index 0000000..14d126d
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/managecollections.class.php';
+$ManangeCollections = new ManageCollections($DB,$Doomguy);
+require_once 'lib/managecollectionfields.class.php';
+$ManangeCollectionFields = new ManageCollectionFields($DB,$Doomguy);
+
+$TemplateData['existingCollections'] = $ManangeCollections->getCollections();
+$TemplateData['ownerSelection'] = $ManangeCollections->getUsersForSelection();
+$TemplateData['groupSelection'] = $ManangeCollections->getGroupsForSelection();
+$TemplateData['toolSelection'] = $ManangeCollections->getToolsForSelection();
+// default rights
+$TemplateData['editData']['rights'] = Summoner::prepareRightsArray('rwxr--r--');
+// tool needs to be preset
+$TemplateData['editData']['tool'] = array();
+$TemplateData['existingFields'] = array();
+
+// @todo providing the id is enough
+$_editMode = false;
+if(isset($_GET['m']) && !empty($_GET['m'])) {
+    if($_GET['m'] == "edit") {
+        $_editMode = true;
+    }
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+if($_editMode === true && !empty($_id)) {
+    $TemplateData['editData'] = $ManangeCollections->getEditData($_id);
+    $ManangeCollectionFields->setCollection($_id);
+    $TemplateData['existingFields'] = $ManangeCollectionFields->getExistingFields();
+    if(!isset($TemplateData['editData']['name'])) {
+        $TemplateData['refresh'] = 'index.php?p=managecolletions';
+    }
+}
+
+$_saveData = array();
+if(isset($_POST['submitForm'])) {
+    $fdata = $_POST['fdata'];
+    if (!empty($fdata)) {
+        $_saveData['name'] = trim($fdata['name']);
+        $_saveData['description'] = trim($fdata['description']);
+        $_saveData['owner'] = trim($fdata['owner']);
+        $_saveData['group'] = trim($fdata['group']);
+        $_saveData['rights'] = Summoner::prepareRightsString($fdata['rights']);
+        $_saveData['defaultSearchField'] = trim($fdata['defaultSearchField']);
+        $_saveData['id'] = $_id;
+
+        $_saveData['tool'] = array();
+        if(isset($fdata['tool'])) {
+            $_saveData['tool'] = $fdata['tool'];
+        }
+
+        if(!empty($TemplateData['editData']['name'])) { // EDIT
+            if(isset($fdata['doDelete'])) {
+                $do = $ManangeCollections->deleteCollection($_id);
+                if ($do === true) {
+                    $TemplateData['refresh'] = 'index.php?p=managecolletions';
+                } else {
+                    $TemplateData['message']['content'] = "Collection could not be deleted.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+            else {
+                if (Summoner::validate($_saveData['name'], 'nospace') === true
+                    && isset($TemplateData['groupSelection'][$_saveData['group']])
+                    && isset($TemplateData['ownerSelection'][$_saveData['owner']])
+                ) {
+                    $do = $ManangeCollections->updateCollection($_saveData);
+                    if ($do === true) {
+                        $TemplateData['refresh'] = 'index.php?p=managecolletions';
+                    } else {
+                        $TemplateData['message']['content'] = "Collection could not be updated.";
+                        $TemplateData['message']['status'] = "error";
+                    }
+                } else {
+                    $TemplateData['message']['content'] = "Provide name, owner, group and valid rights.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+        }
+        else { // ADD
+            if (!empty($_saveData['name']) && !empty($_saveData['owner']) && !empty($_saveData['group']) && !empty($_saveData['rights'])) {
+                if (Summoner::validate($_saveData['name'], 'nospace') === true
+                    && isset($TemplateData['groupSelection'][$_saveData['group']])
+                    && isset($TemplateData['ownerSelection'][$_saveData['owner']])
+                ) {
+                    $do = $ManangeCollections->createCollection($_saveData);
+                    if ($do === true) {
+                        $TemplateData['refresh'] = 'index.php?p=managecolletions';
+                    } else {
+                        $TemplateData['message']['content'] = "Collection could not be created.";
+                        $TemplateData['message']['status'] = "error";
+                    }
+                } else {
+                    $TemplateData['message']['content'] = "Provide name, owner, group and valid rights.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+        }
+
+    }
+}
diff --git a/webclient/view/default/manageentry/field-lookupmultiple.html b/webclient/view/default/manageentry/field-lookupmultiple.html
new file mode 100644 (file)
index 0000000..cb885e2
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+$existingFieldValue = array();
+if(Summoner::ifset($TemplateData['editData'], $field['identifier'])) {
+    $existingFieldValue = $TemplateData['editData'][$field['identifier']];
+}
+?>
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>-input"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <div class="input-multiple-listbox" id="<?php echo $field['identifier']; ?>-listbox">
+        <?php
+        if(!empty($existingFieldValue)) {
+            foreach($existingFieldValue as $ev) { ?>
+
+            <div class="input-multiple-template" id="<?php echo $field['identifier']; ?>-<?php echo $ev; ?>">
+                <a onclick="removeTag('<?php echo $ev; ?>','<?php echo $field['identifier']; ?>')" title="click to remove"><span class="uk-label"><?php echo $ev; ?></span></a>
+            </div>
+
+        <?php
+            }
+        }
+        ?>
+        </div>
+        <input class="uk-input" id="<?php echo $field['identifier']; ?>-input" type="text" autocomplete="off"
+            name="<?php echo $field['identifier']; ?>-input"
+            list="<?php echo $field['identifier']; ?>-datalist"
+            onkeypress="addTag(event,'<?php echo $field['identifier']; ?>')"
+            placeholder="Write and press enter."
+        >
+    </div>
+</div>
+
+<datalist id="<?php echo $field['identifier']; ?>-datalist">
+    <?php
+        if(isset($field['suggestion'])) {
+            foreach($field['suggestion'] as $t) {
+    ?>
+    <option value="<?php echo $t; ?>"><?php echo $t; ?></option>
+    <?php
+            }
+        }
+    ?>
+</datalist>
+
+<input type="hidden" name="fdata[<?php echo $field['identifier']; ?>]" id="<?php echo $field['identifier']; ?>-save" value="<?php echo implode(',',$existingFieldValue); ?>" />
+
+<div class="input-multiple-template" id="<?php echo $field['identifier']; ?>-template" style="display: none;">
+    <a onclick="removeTag('','<?php echo $field['identifier']; ?>')" title="click to remove"><span class="uk-label"></span></a>
+</div>
diff --git a/webclient/view/default/manageentry/field-selection.html b/webclient/view/default/manageentry/field-selection.html
new file mode 100644 (file)
index 0000000..6dafc78
--- /dev/null
@@ -0,0 +1,13 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <select class="uk-select" id="<?php echo $field['identifier']; ?>" name="fdata[<?php echo $field['identifier']; ?>]">
+            <option value="">Please select</option>
+            <?php foreach($field['options'] as $k=>$v) { ?>
+            <option value="<?php echo $v; ?>"
+                <?php if(Summoner::ifsetValue($TemplateData['editData'], $field['identifier'],$v)) echo 'selected'; ?>
+            ><?php echo $v; ?></option>
+            <?php } ?>
+        </select>
+    </div>
+</div>
diff --git a/webclient/view/default/manageentry/field-text.html b/webclient/view/default/manageentry/field-text.html
new file mode 100644 (file)
index 0000000..a6c5c41
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <input class="uk-input" id="<?php echo $field['identifier']; ?>" type="text" autocomplete="off"
+           name="fdata[<?php echo $field['identifier']; ?>]"
+           value="<?php echo Summoner::ifset($TemplateData['editData'], $field['identifier']); ?>"
+        >
+    </div>
+</div>
diff --git a/webclient/view/default/manageentry/field-text3.html b/webclient/view/default/manageentry/field-text3.html
new file mode 100644 (file)
index 0000000..974b0da
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <textarea class="uk-textarea" autocomplete="off"
+                  id="<?php echo $field['identifier']; ?>" rows="3"
+                  name="fdata[<?php echo $field['identifier']; ?>]"><?php echo Summoner::ifset($TemplateData['editData'], $field['identifier']); ?></textarea>
+    </div>
+</div>
+
diff --git a/webclient/view/default/manageentry/field-textarea.html b/webclient/view/default/manageentry/field-textarea.html
new file mode 100644 (file)
index 0000000..0e20fdb
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <textarea class="uk-textarea" autocomplete="off"
+            id="<?php echo $field['identifier']; ?>" rows="6"
+            name="fdata[<?php echo $field['identifier']; ?>]"><?php echo Summoner::ifset($TemplateData['editData'], $field['identifier']); ?></textarea>
+    </div>
+</div>
+
diff --git a/webclient/view/default/manageentry/field-unknown.html b/webclient/view/default/manageentry/field-unknown.html
new file mode 100644 (file)
index 0000000..a1cdcbf
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="uk-margin">
+    Missing template for: <?php echo $field['identifier']; ?>
+</div>
diff --git a/webclient/view/default/manageentry/field-upload.html b/webclient/view/default/manageentry/field-upload.html
new file mode 100644 (file)
index 0000000..152a325
--- /dev/null
@@ -0,0 +1,17 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <input type="file" id="<?php echo $field['identifier']; ?>" multiple="false"
+           name="fdata[<?php echo $field['identifier']; ?>]"
+        >
+        <?php if(Summoner::ifset($TemplateData['editData'], $field['identifier'])) { ?>
+        <div uk-lightbox>
+            <?php echo '<a href="'.$TemplateData['storagePath'].'/'.Summoner::ifset($TemplateData['editData'], $field['identifier']).'">'.Summoner::ifset($TemplateData['editData'], $field['identifier']).'</a>'; ?>
+            <input type="checkbox" value="<?php echo Summoner::ifset($TemplateData['editData'], $field['identifier']); ?>"
+                   name="fdata[<?php echo $field['identifier']; ?>_delete]"
+                   title="Delete"
+            />
+        </div>
+        <?php } ?>
+    </div>
+</div>
diff --git a/webclient/view/default/manageentry/field-upload_multiple.html b/webclient/view/default/manageentry/field-upload_multiple.html
new file mode 100644 (file)
index 0000000..52e64d2
--- /dev/null
@@ -0,0 +1,24 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <input type="file" id="<?php echo $field['identifier']; ?>" multiple="true"
+            name="fdata[<?php echo $field['identifier']; ?>][]"
+        >
+        <div uk-lightbox>
+        <?php
+        if(isset($TemplateData['editData']) && !empty($TemplateData['editData'][$field['identifier']])) {
+            foreach($TemplateData['editData'][$field['identifier']] as $e) {
+        ?>
+            <a target="_blank" href="<?php echo $TemplateData['storagePath'].'/'.$e; ?>"><?php echo $e; ?></a>
+            <input type="checkbox" value="<?php echo $e; ?>"
+                   name="fdata[<?php echo $field['identifier']; ?>_delete][]"
+                   title="Delete"
+            />
+            <br>
+        <?php
+            }
+        }
+        ?>
+        </div>
+    </div>
+</div>
diff --git a/webclient/view/default/manageentry/field-year.html b/webclient/view/default/manageentry/field-year.html
new file mode 100644 (file)
index 0000000..75b687e
--- /dev/null
@@ -0,0 +1,10 @@
+<div class="uk-margin">
+    <label class="uk-form-label" for="<?php echo $field['identifier']; ?>"><?php echo $field['displayname']; ?></label>
+    <div class="uk-form-controls">
+        <input class="uk-input" id="<?php echo $field['identifier']; ?>" type="number" autocomplete="off"
+            placeholder="YYYY" min="0000" max="9999"
+            name="fdata[<?php echo $field['identifier']; ?>]"
+            value="<?php echo Summoner::ifset($TemplateData['editData'], $field['identifier']); ?>"
+        >
+    </div>
+</div>
diff --git a/webclient/view/default/manageentry/manageentry.html b/webclient/view/default/manageentry/manageentry.html
new file mode 100644 (file)
index 0000000..96fc698
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+if(!empty($TemplateData['editFields'])) {
+       $_entry = '';
+       if(!empty($TemplateData['editData'])) {
+               $_entry = $TemplateData['editData']['id'];
+?>
+               <h3 class="uk-h3">Update an entry in: <?php echo $TemplateData['loadedCollection']['name']; ?></h3>
+               <p><a href="index.php?p=entry&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>&id=<?php echo $_entry; ?>">View entry</a></p>
+<?php } else { ?>
+               <h3 class="uk-h3">Add an entry to: <?php echo $TemplateData['loadedCollection']['name']; ?></h3>
+<?php } ?>
+<div class="uk-grid-small uk-grid-row-small" uk-grid>
+       <div class="uk-width-2-3">
+               <form class="uk-form-horizontal uk-margin-small" method="post" enctype="multipart/form-data">
+
+                       <?php
+                       foreach($TemplateData['editFields'] as $field) {
+                               $_editFieldView = Summoner::themefile('manageentry/field-'.$field['type'].'.html', UI_THEME);
+                               if(file_exists($_editFieldView)) {
+                                       require $_editFieldView;
+                               }
+                               else {
+                                       require $TemplateData['_editFieldViewDefault'];
+                               }
+                       }
+
+                       if(!empty($TemplateData['editData']['_canDelete'])) {
+                       ?>
+
+                       <div class="uk-margin">
+                               <div class="uk-form-label">Delete <span uk-icon="warning"></span></div>
+                               <div class="uk-form-controls uk-form-controls-text">
+                                       <label>
+                                               <input class="uk-checkbox" type="checkbox" name="fdata[doDelete]" value="1">
+                                       </label>
+                               </div>
+                       </div>
+
+                       <?php } ?>
+
+                       <div class="uk-margin">
+                               <button class="uk-button uk-button-primary" type="submit" name="submitForm">
+                                       Save
+                               </button>
+                       </div>
+               </form>
+       </div>
+       <div>
+               <?php if(!empty($TemplateData['availableTools'])) { ?>
+               <h4>Available tools</h4>
+               <ul>
+               <?php foreach($TemplateData['availableTools'] as $tool) { ?>
+                       <li><a href="index.php?p=tool&t=<?php echo $tool['action']; ?>&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>&id=<?php echo $_entry; ?>"
+                                  target="<?php echo $tool['target']; ?>"><?php echo $tool['name']; ?> (<?php echo $tool['description']; ?>)</a></li>
+               <?php } ?>
+               </ul>
+               <?php } ?>
+       </div>
+</div>
+<script type="text/javascript" src="view/default/ui/js/suggest-tag.js"></script>
+<?php } else { ?>
+<h3 class="uk-h3">Add an entry to your collection</h3>
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+       <div class="uk-width-1-2">
+               <h4 class="uk-h4">Please select a collection first:</h4>
+               <dl class="uk-description-list uk-description-list-divider">
+                       <?php foreach($TemplateData['existingCollections'] as $k=>$v) { ?>
+                       <dt><a href="index.php?p=manageentry&collection=<?php echo $k; ?>"><?php echo $v['name']; ?></a></dt>
+                       <dd><?php echo $v['description']; ?></dd>
+                       <?php } ?>
+               </dl>
+       </div>
+</div>
+<?php } ?>
diff --git a/webclient/view/default/manageentry/manageentry.php b/webclient/view/default/manageentry/manageentry.php
new file mode 100644 (file)
index 0000000..5cbb984
--- /dev/null
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/managecollections.class.php';
+$ManangeCollections = new ManageCollections($DB,$Doomguy);
+require_once 'lib/manageentry.class.php';
+$ManangeEntry = new Manageentry($DB,$Doomguy);
+
+$TemplateData['editFields'] = array();
+$TemplateData['editData'] = array();
+$TemplateData['loadedCollection'] = '';
+$TemplateData['storagePath'] = '';
+
+$TemplateData['existingCollections'] = $ManangeCollections->getCollections();
+$TemplateData['_editFieldViewDefault'] = Summoner::themefile('manageentry/field-unknown.html', UI_THEME);
+
+$_collection = false;
+if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+    $_collection = trim($_GET['collection']);
+    $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+if(!empty($_collection)) {
+    $setCollection = $ManangeCollections->getCollection($_collection, "write");
+
+    if(!empty($setCollection)) {
+        $ManangeEntry->setCollection($_collection);
+        $TemplateData['loadedCollection'] = $setCollection;
+
+        $TemplateData['editFields'] = $ManangeEntry->getEditFields();
+        $TemplateData['availableTools'] = $ManangeCollections->getAvailableTools($_collection);
+
+        if(!empty($_id)) {
+            $TemplateData['storagePath'] = PATH_WEB_STORAGE . '/' . $_collection . '/' . $_id;
+
+            // prefill template data. Used also later to check if on edit mode
+            $TemplateData['editData'] = $ManangeEntry->getEditData($_id);
+            // special case. Title field should be always available.
+            if(!isset($TemplateData['editData']['title'])) {
+                $TemplateData['message']['content'] = "Entry has no value in title field.";
+                $TemplateData['message']['status'] = "error";
+            }
+        }
+
+        if(isset($_POST['submitForm'])) {
+            $fdata = $_POST['fdata'];
+            $fupload = array('name' => ''); // match $_FILES
+            if(!empty($_FILES) && isset($_FILES['fdata'])) {
+                $fupload = $_FILES['fdata'];
+            }
+            $_fieldsToSave = array();
+            if (!empty($fdata)) {
+                // @todo there is no setting for individual rights available yet
+                $_owner = $Doomguy->param('id');
+                $_group = $Doomguy->param('baseGroupId');
+                $_rights = 'rwxrwxr--';
+
+                foreach ($TemplateData['editFields'] as $fieldId=>$fieldData) {
+                    if(isset($fdata[$fieldData['identifier']])) {
+                        $_value = trim($fdata[$fieldData['identifier']]);
+                        $fieldData['valueToSave'] = trim($fdata[$fieldData['identifier']]);
+                        $_fieldsToSave[$fieldData['identifier']] = $fieldData;
+                    } elseif(isset($fupload['name'][$fieldData['identifier']])) {
+                        if(isset($fdata[$fieldData['identifier']."_delete"])) {
+                            $fieldData['deleteData'] = $fdata[$fieldData['identifier']."_delete"];
+                        }
+                        // special case upload
+                        // $_FILES data is combinend
+                        $fieldData['uploadData'] = $fupload;
+
+                        $_fieldsToSave[$fieldData['identifier']] = $fieldData;
+                    }
+                }
+
+                // special case. Title field should be always available.
+                if(!empty($TemplateData['editData']['title'])) { // EDIT
+                    if(isset($fdata['doDelete'])) {
+                        $do = $ManangeEntry->delete($_id);
+                        if ($do === true) {
+                            $TemplateData['refresh'] = 'index.php?p=collections&collection='.$_collection;
+                        } else {
+                            $TemplateData['message']['content'] = "Entry could not be removed.";
+                            $TemplateData['message']['status'] = "error";
+                        }
+                    } elseif (!empty($_fieldsToSave) && isset($_fieldsToSave['title'])) {
+                        $do = $ManangeEntry->create($_fieldsToSave, $_owner, $_group, $_rights, $_id);
+                        if ($do !== 0) {
+                            $TemplateData['refresh'] = 'index.php?p=manageentry&collection='.$_collection.'&id='.$_id;
+                        } else {
+                            $TemplateData['message']['content'] = "Entry could not be updated.";
+                            $TemplateData['message']['status'] = "error";
+                        }
+                    }
+                }
+                else { // ADD
+                    // special case. Title field should be always available.
+                    if (!empty($_fieldsToSave) && isset($_fieldsToSave['title'])) {
+                        $do = $ManangeEntry->create($_fieldsToSave, $_owner, $_group, $_rights);
+                        if (!empty($do)) {
+                            $TemplateData['message']['content'] = "New entry: <a href='index.php?p=manageentry&collection=".$_collection."&id=".$do."'>".$do."</a>";
+                            $TemplateData['message']['status'] = "success";
+                        } else {
+                            // use editData to display given data
+                            $TemplateData['editData'] = $fdata;
+                            $TemplateData['message']['content'] = "Entry could not be added.";
+                            $TemplateData['message']['status'] = "error";
+                        }
+                    } else {
+                        // use editData to display given data
+                        $TemplateData['editData'] = $fdata;
+                        $TemplateData['message']['content'] = "Provide at least 'Title'.";
+                        $TemplateData['message']['status'] = "error";
+                    }
+                }
+            }
+        }
+    }
+    else {
+        $TemplateData['message']['content'] = "Collection could not be loaded.";
+        $TemplateData['message']['status'] = "error";
+    }
+}
diff --git a/webclient/view/default/manageusers/manageusers.html b/webclient/view/default/manageusers/manageusers.html
new file mode 100644 (file)
index 0000000..4dc33d2
--- /dev/null
@@ -0,0 +1,125 @@
+<h3 class="uk-h3">User management</h3>
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-1-2">
+        <h4 class="uk-h4">Add or modify a user</h4>
+        <form class="uk-form-horizontal uk-margin-small" method="post">
+            <div class="uk-margin">
+                <label class="uk-form-label" for="username">Username</label>
+                <div class="uk-form-controls">
+                    <input class="uk-input" id="username" type="text" autocomplete="off" name="fdata[username]"
+                        value="<?php echo Summoner::ifset($TemplateData['editData'], 'name'); ?>">
+                </div>
+            </div>
+            <div class="uk-margin">
+                <label class="uk-form-label" for="login">Login</label>
+                <div class="uk-form-controls">
+                    <input class="uk-input" id="login" type="text" autocomplete="off" name="fdata[login]"
+                        value="<?php echo Summoner::ifset($TemplateData['editData'], 'login'); ?>">
+                </div>
+            </div>
+            <div class="uk-margin">
+                <label class="uk-form-label" for="password">Password</label>
+                <div class="uk-form-controls">
+                    <input class="uk-input" id="password" type="password" autocomplete="off" name="fdata[password]">
+                </div>
+            </div>
+            <div class="uk-margin">
+                <label class="uk-form-label" for="group">Main group</label>
+                <div class="uk-form-controls">
+                    <select class="uk-select" id="group" name="fdata[group]">
+                        <option value="">Please select</option>
+                        <?php foreach($TemplateData['existingGroups'] as $k=>$v) { ?>
+                        <option value="<?php echo $k; ?>"
+                            <?php if(Summoner::ifsetValue($TemplateData['editData'], 'baseGroupId',$k)) echo 'selected'; ?>
+                            ><?php echo $v['name']; ?> (<?php echo $v['description']; ?>)</option>
+                        <?php } ?>
+                    </select>
+                </div>
+            </div>
+            <div class="uk-margin">
+                <label class="uk-form-label" for="group">Additional groups</label>
+                <div class="uk-form-controls">
+                    <select class="uk-select" id="additionalgroups" name="fdata[additionalgroups]">
+                        <option value="">To be done</option>
+                    </select>
+                </div>
+            </div>
+            <div class="uk-margin">
+                <div class="uk-form-label">Can login</div>
+                <div class="uk-form-controls uk-form-controls-text">
+                    <label>
+                        <input class="uk-checkbox" type="checkbox" name="fdata[active]" value="1"
+                            <?php if(Summoner::ifset($TemplateData['editData'], 'active')) echo "checked"; ?>>
+                    </label>
+                </div>
+            </div>
+            <?php if(Summoner::ifset($TemplateData['editData'], 'name')) { ?>
+            <div class="uk-margin">
+                <div class="uk-form-label">Delete <span uk-icon="warning"></span></div>
+                <div class="uk-form-controls uk-form-controls-text">
+                    <label>
+                        <input class="uk-checkbox" type="checkbox" name="fdata[doDelete]" value="1">
+                    </label>
+                </div>
+            </div>
+            <div class="uk-margin">
+                <div class="uk-form-label">Create API Token</div>
+                <div class="uk-form-controls uk-form-controls-text">
+                    <label>
+                        <input class="uk-checkbox" type="checkbox" name="fdata[refreshApiToken]" value="1"><br />
+                        Valid until: <?php echo Summoner::ifset($TemplateData['editData'], 'apiTokenValidDate'); ?><br />
+                        <?php echo Summoner::ifset($TemplateData['editData'], 'apiToken'); ?>
+                    </label>
+                </div>
+            </div>
+            <?php } ?>
+            <div class="uk-margin">
+                <button class="uk-button uk-button-primary" type="submit" name="submitForm">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+    <div class="uk-width-1-2">
+        <h4 class="uk-h4">Available users</h4>
+        <table class="uk-table">
+            <thead>
+                <tr>
+                    <th>Login</th>
+                    <th>Username</th>
+                    <th>Group(s)</th>
+                    <th>Status</th>
+                    <th></th>
+                </tr>
+            </thead>
+            <tbody>
+            <?php foreach($TemplateData['existingUsers'] as $k=>$v) { ?>
+                <tr>
+                    <td>
+                        <?php echo $v['login']; ?><br/>
+                        <small><?php echo $v['created']; ?></small>
+                    </td>
+                    <td><?php echo $v['name']; ?></td>
+                    <td>
+                        <ul class="uk-list uk-list-disc uk-list-collapse">
+                        <?php foreach($v['groups'] as $gk=>$gv) { ?>
+                            <li class="<?php if($gk == $v['baseGroupId']) echo 'uk-text-emphasis'; ?>">
+                                <?php echo $gv['groupName']; ?>
+                            </li>
+                        <?php } ?>
+                        </ul>
+                    </td>
+                    <td><?php echo $v['active']; ?></td>
+                    <td>
+                        <?php if($v['protected'] == "0") { ?>
+                        <a href="index.php?p=manageusers&m=edit&id=<?php echo $k; ?>" uk-icon="pencil"></a>
+                        <?php } ?>
+                    </td>
+                </tr>
+            <?php } ?>
+            </tbody>
+        </table>
+
+
+    </div>
+</div>
diff --git a/webclient/view/default/manageusers/manageusers.php b/webclient/view/default/manageusers/manageusers.php
new file mode 100644 (file)
index 0000000..a7e1b89
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+require_once 'lib/possessed.class.php';
+$Possessed = new Possessed($DB);
+$TemplateData['existingGroups'] = $Possessed->getGroups();
+$TemplateData['existingUsers'] = $Possessed->getUsers();
+$TemplateData['editData'] = false;
+
+$_editMode = false;
+if(isset($_GET['m']) && !empty($_GET['m'])) {
+    if($_GET['m'] == "edit") {
+        $_editMode = true;
+    }
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+if($_editMode === true && !empty($_id)) {
+    $TemplateData['editData'] = $Possessed->getEditData($_id);
+    if(!isset($TemplateData['editData']['name'])) {
+        $TemplateData['refresh'] = 'index.php?p=manageusers';
+    }
+}
+
+
+if(isset($_POST['submitForm'])) {
+    $fdata = $_POST['fdata'];
+    if(!empty($fdata)) {
+
+        $_login = trim($fdata['login']);
+        $_group = trim($fdata['group']);
+        $_username = trim($fdata['username']);
+        $_password = trim($fdata['password']);
+        $_active = false;
+        if (isset($fdata['active'])) {
+            $_active = true;
+        }
+
+        if(!empty($TemplateData['editData'])) {
+            if(isset($fdata['doDelete'])) {
+                $do = $Possessed->deleteUser($_id);
+                if ($do === true) {
+                    $TemplateData['refresh'] = 'index.php?p=manageusers';
+                } else {
+                    $TemplateData['message']['content'] = "User could not be deleted.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+            elseif (!empty($_username) && !empty($_group) && !empty($_login)) {
+                if (Summoner::validate($_username, 'text') === true
+                    && Summoner::validate($_login, 'nospace') === true
+                    && isset($TemplateData['existingGroups'][$_group])
+                ) {
+                    $refreshApi = false;
+                    if(isset($fdata['refreshApiToken'])) {
+                        $refreshApi = true;
+                    }
+                    $do = $Possessed->updateUser($_id, $_username, $_login, $_password, $_group, $_active, $refreshApi);
+                    if ($do === true) {
+                        $TemplateData['refresh'] = 'index.php?p=manageusers';
+                    } else {
+                        $TemplateData['message']['content'] = "User could not be updated.";
+                        $TemplateData['message']['status'] = "error";
+                    }
+                } else {
+                    $TemplateData['message']['content'] = "Provide username, login and a valid user group.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+        }
+        else { // adding mode
+            if (!empty($_username) && !empty($_password) && !empty($_group) && !empty($_login)) {
+                if (Summoner::validate($_username, 'text') === true
+                    && Summoner::validate($_password, 'text') === true
+                    && Summoner::validate($_login, 'nospace') === true
+                    && isset($TemplateData['existingGroups'][$_group])
+                ) {
+                    $do = $Possessed->createUser($_username, $_login, $_password, $_group, $_active);
+                    if ($do === true) {
+                        $TemplateData['refresh'] = 'index.php?p=manageusers';
+                    } else {
+                        $TemplateData['message']['content'] = "User could not be created.";
+                        $TemplateData['message']['status'] = "error";
+                    }
+                } else {
+                    $TemplateData['message']['content'] = "Provide username, login, password and a valid user group.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            }
+        }
+    }
+}
diff --git a/webclient/view/default/system/menu.php b/webclient/view/default/system/menu.php
new file mode 100644 (file)
index 0000000..53bab8c
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+$_menuShow = $Gorenest->get('show');
+$_menuManage = $Gorenest->get('manage');
+?>
+<nav class="uk-navbar-container" uk-navbar>
+    <div class="uk-navbar-left">
+        <ul class="uk-navbar-nav">
+            <li class="uk-parent">
+                <a href="">Show</a>
+                <div class="uk-navbar-dropdown">
+                    <ul class="uk-nav uk-navbar-dropdown-nav">
+                        <?php foreach($_menuShow as $entry) { ?>
+                            <li>
+                                <a href="index.php?p=<?php echo $entry['action']; ?>">
+                                    <span class="uk-icon uk-margin-small-right" uk-icon="icon: <?php echo $entry['icon']; ?>"></span>
+                                    <?php echo $entry['text']; ?>
+                                </a>
+                            </li>
+                        <?php } ?>
+                    </ul>
+                </div>
+            </li>
+            <?php if(!empty($_menuManage)) { ?>
+            <li class="uk-parent">
+                <a href="">Manage</a>
+                <div class="uk-navbar-dropdown">
+                    <ul class="uk-nav uk-navbar-dropdown-nav">
+                        <?php foreach($_menuManage as $entry) { ?>
+                            <li>
+                                <a href="index.php?p=<?php echo $entry['action']; ?>">
+                                    <span class="uk-icon uk-margin-small-right" uk-icon="icon: <?php echo $entry['icon']; ?>"></span>
+                                    <?php echo $entry['text']; ?>
+                                </a>
+                            </li>
+                        <?php } ?>
+                    </ul>
+                </div>
+            </li>
+            <?php } ?>
+            <li>
+                <a href="index.php?p=auth">
+                    <?php if($Doomguy->isSignedIn() === true) { echo "Logout"; } else { echo "Login"; } ?>
+                </a>
+            </li>
+        </ul>
+    </div>
+    <div class="uk-navbar-right">
+        <div>
+            <a class="uk-navbar-toggle" uk-search-icon href="#"></a>
+            <div class="uk-drop" uk-drop="mode: click; pos: left-center; offset: 0">
+                <form class="uk-search uk-search-navbar uk-width-1-1" method="post" action="<?php echo $TemplateData['searchAction']; ?>">
+                    <input class="uk-search-input" type="search" placeholder="Search..." name="navSearch" autofocus>
+                </form>
+            </div>
+        </div>
+    </div>
+</nav>
diff --git a/webclient/view/default/system/message.php b/webclient/view/default/system/message.php
new file mode 100644 (file)
index 0000000..fc8e008
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+if(isset($TemplateData['message']['content'])) {
+    $cssClass = 'primary';
+    if(isset($TemplateData['message']['status'])) {
+        switch($TemplateData['message']['status']) {
+            case 'error':
+                $cssClass = 'danger';
+            break;
+            case 'warning':
+                $cssClass = 'warning';
+            break;
+            case 'success':
+                $cssClass = 'success';
+            break;
+
+            case 'info':
+            default:
+
+        }
+    }
+?>
+<div class="uk-alert-<?php echo $cssClass; ?>" uk-alert>
+    <p><?php echo $TemplateData['message']['content']; ?></p>
+</div>
+<?php } ?>
diff --git a/webclient/view/default/system/pagination.html b/webclient/view/default/system/pagination.html
new file mode 100644 (file)
index 0000000..5fdafa4
--- /dev/null
@@ -0,0 +1,36 @@
+<?php if(!empty($TemplateData['pagination']) && $TemplateData['pagination']['pages'] > 1) { ?>
+<ul class="uk-pagination" uk-margin>
+    <?php
+    if($TemplateData['pagination']['curPage'] > 1) {
+    echo '<li><a href="index.php?'.Summoner::createFromParameterLinkQuery($TemplateData['pagination']['currentGetParameters'],array('page'=>($TemplateData['pagination']['curPage']-1))).'">
+        <span uk-pagination-previous></span></a></li>';
+    }
+
+    $ellipsisShown = 0;
+    for($i=1;$i<=$TemplateData['pagination']['pages'];$i++) {
+        $active = '';
+        if($i == $TemplateData['pagination']['curPage']) $active = 'uk-active';
+
+        if(in_array($i,$TemplateData['pagination']['visibleRange'])) {
+            echo '<li class="'.$active.'"><a href="index.php?'.Summoner::createFromParameterLinkQuery($TemplateData['pagination']['currentGetParameters'],array('page'=>$i)).'"
+                title="Goto page '.$i.'">'.$i.'</a></li>';
+        }
+        else {
+            if($i < $TemplateData['pagination']['currentRangeStart'] && $ellipsisShown == 0) {
+                echo '<li class="uk-disabled"><span>&hellip;</span></li>';
+                $ellipsisShown = 1;
+            }
+            if($i > $TemplateData['pagination']['currentRangeEnd'] && ($ellipsisShown == 0 || $ellipsisShown == 1)) {
+                echo '<li class="uk-disabled"><span>&hellip;</span></li>';
+                $ellipsisShown = 2;
+            }
+        }
+    }
+
+    if($TemplateData['pagination']['curPage'] < $TemplateData['pagination']['pages']) {
+    echo '<li><a href="index.php?'.Summoner::createFromParameterLinkQuery($TemplateData['pagination']['currentGetParameters'],array('page'=>($TemplateData['pagination']['curPage']+1))).'">
+        <span uk-pagination-next></span></a></li>';
+    }
+    ?>
+</ul>
+<?php } ?>
diff --git a/webclient/view/default/system/pagination_after.php b/webclient/view/default/system/pagination_after.php
new file mode 100644 (file)
index 0000000..48a106b
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * split pagination building in two parts to make it includeable
+ * - pagination_before
+ *   this one sets the defaults and checks for requestparams
+ * - pagination_after
+ *   this one gets the results from the queries and builds the required infos for the pagination view
+ */
+
+// this is comes from pagination_before
+// $TemplateData['pagination']
+
+if(!empty($TemplateData['entries']['amount'])) {
+    $TemplateData['pagination']['pages'] = ceil($TemplateData['entries']['amount'] / RESULTS_PER_PAGE);
+    $TemplateData['pagination']['curPage'] = $_curPage;
+
+    $TemplateData['pagination']['currentGetParameters']['page'] = $_curPage;
+}
+
+if($TemplateData['pagination']['pages'] > 11) {
+    # first pages
+    $TemplateData['pagination']['visibleRange'] = range(1,3);
+    # last pages
+    foreach(range($TemplateData['pagination']['pages']-2, $TemplateData['pagination']['pages']) as $e) {
+        array_push($TemplateData['pagination']['visibleRange'], $e);
+    }
+    # pages before and after current page
+    $cRange = range($TemplateData['pagination']['curPage']-1, $TemplateData['pagination']['curPage']+1);
+    foreach($cRange as $e) {
+        array_push($TemplateData['pagination']['visibleRange'], $e);
+    }
+    $TemplateData['pagination']['currentRangeStart'] = array_shift($cRange);
+    $TemplateData['pagination']['currentRangeEnd'] = array_pop($cRange);
+}
+else {
+    $TemplateData['pagination']['visibleRange'] = range(1,$TemplateData['pagination']['pages']);
+}
diff --git a/webclient/view/default/system/pagination_before.php b/webclient/view/default/system/pagination_before.php
new file mode 100644 (file)
index 0000000..ac24626
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * split pagination building in two parts to make it includeable
+ * - pagination_before
+ *   this one sets the defaults and checks for requestparams
+ * - pagination_after
+ *   this one gets the results from the queries and builds the required infos for the pagination view
+ */
+
+$TemplateData['pagination'] = array('pages' => 0);
+
+$_curPage = 1;
+if(isset($_GET['page']) && !empty($_GET['page'])) {
+    $_curPage = trim($_GET['page']);
+    $_curPage = Summoner::validate($_curPage,'digit') ? $_curPage : 1;
+}
+$_sort = false;
+if(isset($_GET['s']) && !empty($_GET['s'])) {
+    $_sort = trim($_GET['s']);
+    $_sort = Summoner::validate($_sort,'nospace') ? $_sort : false;
+}
+
+$_sortDirection = false;
+if(isset($_GET['sd']) && !empty($_GET['sd'])) {
+    $_sortDirection = trim($_GET['sd']);
+    $_sortDirection = Summoner::validate($_sortDirection,'nospace') ? $_sortDirection : false;
+}
+
+$_queryOptions = array(
+    'limit' => RESULTS_PER_PAGE,
+    'offset' => (RESULTS_PER_PAGE * ($_curPage-1)),
+    'orderby' => $_sort,
+    'sortDirection' => $_sortDirection
+);
diff --git a/webclient/view/default/tags/tags.html b/webclient/view/default/tags/tags.html
new file mode 100644 (file)
index 0000000..16f10c1
--- /dev/null
@@ -0,0 +1,37 @@
+<div class="uk-grid-small uk-grid-row-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-1-2@l">
+    <?php if(!empty($TemplateData['tags'])) { ?>
+        <h3 class="uk-h3">Selectable tags for: <?php echo Summoner::ifset($TemplateData['loadedCollection'], 'name'); ?></h3>
+
+        <?php if(!empty($TemplateData['search'])) { ?>
+        <div uk-alert id="searchNotice">
+            <button class="uk-alert-close" type="button" uk-close></button>
+            <p>Display result for: <b><?php echo $TemplateData['search']; ?></b></p>
+        </div>
+        <script type="text/javascript">
+            UIkit.util.on('#searchNotice', 'hide', function () {
+                window.location.href="index.php?p=tags&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>";
+            });
+        </script>
+        <?php } ?>
+
+        <?php foreach($TemplateData['tags'] as $k=>$v) { ?>
+        <h4 class="uk-heading-line"><span><a uk-toggle="target: #toggle-<?php echo $k; ?>"><?php echo $v['displayname']; ?></a></span></h4>
+        <div id="toggle-<?php echo $k; ?>">
+            <?php foreach($v['entries'] as $ek=>$ev) { ?>
+            <a href="index.php?p=collections&collection=<?php echo $TemplateData['loadedCollection']['id']; ?>&fid=<?php echo $k; ?>&fv=<?php echo urlencode($ev); ?>"><?php echo $ev; ?></a>,
+            <?php } ?>
+        </div>
+        <?php } ?>
+
+    <?php } elseif(!empty($TemplateData['collections'])) { ?>
+        <h3 class="uk-h3">Please select a collection first</h3>
+        <dl class="uk-description-list uk-description-list-divider">
+            <?php foreach($TemplateData['collections'] as $k=>$v) { ?>
+            <dt><a href="index.php?p=tags&collection=<?php echo $k; ?>"><?php echo $v['name']; ?></a></dt>
+            <dd><?php echo $v['description']; ?></dd>
+            <?php } ?>
+        </dl>
+    <?php } ?>
+    </div>
+</div>
diff --git a/webclient/view/default/tags/tags.php b/webclient/view/default/tags/tags.php
new file mode 100644 (file)
index 0000000..ecda30d
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/mancubus.class.php';
+$Mancubus = new Mancubus($DB,$Doomguy);
+require_once 'lib/trite.class.php';
+$Trite = new Trite($DB,$Doomguy);
+
+$_collection = false;
+if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+    $_collection = trim($_GET['collection']);
+    $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+$TemplateData['loadedCollection'] = array();
+$TemplateData['tags'] = array();
+$TemplateData['search'] = false;
+
+$_search = false;
+if(isset($_POST['navSearch'])) {
+    $_search = trim($_POST['navSearch']);
+    $_search = Summoner::validate($_search,'text') ? $_search :  false;
+}
+
+
+if(!empty($_collection)) {
+    $TemplateData['loadedCollection'] = $Trite->load($_collection);
+    if(!empty($TemplateData['loadedCollection'])) {
+        $TemplateData['searchAction'] = 'index.php?p=tags&collection='.$Trite->param('id');
+        $Mancubus->setCollection($Trite->param('id'));
+        $TemplateData['tags'] = $Mancubus->getTags($_search);
+        if(!empty($_search)) {
+            $TemplateData['search'] = $_search;
+        }
+    }
+    else {
+        $TemplateData['message']['content'] = "Can not load given collection.";
+        $TemplateData['message']['status'] = "error";
+    }
+}
+else {
+    $TemplateData['collections'] = $Trite->getCollections();
+}
diff --git a/webclient/view/default/tool/tool-imdbweb.html b/webclient/view/default/tool/tool-imdbweb.html
new file mode 100644 (file)
index 0000000..cdc541b
--- /dev/null
@@ -0,0 +1,56 @@
+<p><b>Limitations</b></p>
+<p>Picture: Use URL to manually save and upload.</p>
+<p>Rating: Works only if the rating matches 1:1.</p>
+<p>Data will be overwritten</p>
+
+<form class="uk-form-horizontal uk-margin-small" method="post" enctype="multipart/form-data">
+    <div class="uk-margin">
+        <label class="uk-form-label" for="search">Search</label>
+        <div class="uk-form-controls">
+            <input class="uk-input" id="search" type="text" autocomplete="off"
+                   name="fdata[search]"
+                   value="<?php echo Summoner::ifset($TemplateData['editEntry'], 'title'); ?>"
+            >
+        </div>
+        <div class="uk-margin">
+            <button class="uk-button uk-button-primary" type="submit" name="submitFormSearch">
+                Search
+            </button>
+        </div>
+    </div>
+</form>
+
+<?php if($TemplateData['showMatchingForm']) { ?>
+<form class="uk-form-horizontal uk-margin-small uk-grid-small" method="post" enctype="multipart/form-data" uk-grid>
+    <input type="hidden" name="fdata[imdbId]" value="<?php echo $TemplateData['movieImdbId']; ?>">
+    <?php
+    if(!empty($TemplateData['movieData'])) {
+        foreach($TemplateData['movieData'] as $k=>$v) {
+    ?>
+
+    <div class="uk-width-1-2@s uk-overflow-hidden">
+        <p>
+            <b><?php echo $v['name']; ?></b><br />
+            <?php echo $v['value']; ?>
+        </p>
+    </div>
+    <div class="uk-width-1-2@s">
+        <select class="uk-select" name="fdata[into][<?php echo $k; ?>]">
+            <option value="">None</option>
+            <?php echo $TemplateData['saveToSelection']; ?>
+        </select>
+    </div>
+
+    <?php
+        }
+    }
+    ?>
+
+    <div class="uk-margin">
+        <button class="uk-button uk-button-primary" type="submit" name="submitFormSave">
+            Save
+        </button>
+    </div>
+
+</form>
+<?php } ?>
diff --git a/webclient/view/default/tool/tool-imdbweb.php b/webclient/view/default/tool/tool-imdbweb.php
new file mode 100644 (file)
index 0000000..d04cd58
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * this is the special file for a tool.
+ * Requirements and more information come from the main tool.php file
+ */
+
+require_once 'lib/imdbwebparser.class.php';
+
+$IMDB = new IMDB(array(
+    'sSearchFor' => 'movie',
+    'storage' => PATH_SYSTEMOUT,
+    'debug' => false
+));
+
+
+$TemplateData['movieData'] = array();
+$TemplateData['saveToSelection'] = '';
+$TemplateData['showMatchingForm'] = false;
+
+// prepare fields to save into selection
+// create one time and then reuse it
+$collectionFields = $ManangeCollectionsFields->getExistingFields();
+if(!empty($collectionFields)) {
+    foreach ($collectionFields as $k=>$v) {
+        $TemplateData['saveToSelection'] .= "<option value='".$k."'>".$v['displayname']."</option>\n";
+    }
+}
+
+if(isset($_POST['submitFormSearch'])) {
+    $fdata = $_POST['fdata'];
+    if (!empty($fdata)) {
+        $search = trim($fdata['search']);
+        $search = Summoner::validate($search) ? $search : false;
+
+        if(!empty($search)) {
+            try {
+                $IMDB->search($search);
+            }
+            catch (Exception $e) {
+                if(DEBUG) error_log("[DEBUG] imdb search catch: ".$e->getMessage());
+            }
+
+            if ($IMDB->isReady) {
+                $TemplateData['movieData'] = $IMDB->getAll();
+                $TemplateData['movieImdbId'] = "tt".$IMDB->iId; // this is the IMDB id you can search for
+                $TemplateData['showMatchingForm'] = true;
+            } else {
+                $TemplateData['message']['content'] = "Nothing found.";
+                $TemplateData['message']['status'] = "error";
+            }
+        }
+        else {
+            $TemplateData['message']['content'] = "Invalid search term";
+            $TemplateData['message']['status'] = "error";
+        }
+    }
+}
+
+if(isset($_POST['submitFormSave'])) {
+    $fdata = $_POST['fdata'];
+    if (!empty($fdata)) {
+        $_imdbId = $fdata['imdbId'];
+        $_imdbId = Summoner::validate($_imdbId,'nospace') ? $_imdbId : false;
+
+        if(!empty($_imdbId)) {
+            try {
+                $IMDB->search($_imdbId);
+            }
+            catch (Exception $e) {
+                if(DEBUG) error_log("[DEBUG] imdb search catch: ".$e->getMessage());
+            }
+
+            if ($IMDB->isReady) {
+                $TemplateData['movieImdbId'] = $_imdbId;
+                $_movieData = $IMDB->getAll();
+
+                // build data array based on submit
+                // see creation log for structure
+                $_data = array();
+                foreach($fdata['into'] as $k=>$v) {
+                    if(!empty($v)) {
+                        $_t = $IMDB->$k();
+
+                        // multiple selections format for field type lookup_multiple
+                        if(strstr($_t, $IMDB->sSeparator)) {
+                            $_t = str_replace($IMDB->sSeparator,",", $_t);
+                        }
+
+                        if(isset($collectionFields[$v])) {
+                            $_data[$v] = $collectionFields[$v];
+                            $_data[$v]['valueToSave'] = $_t;
+                        }
+                    }
+                }
+
+                $_r = $Tools->getDefaultCreationInfo();
+                if(!empty($TemplateData['editEntry'])) {
+                    // update existing one
+                    $do = $Manageentry->create($_data,
+                        $_r['id'],
+                        $_r['group'],
+                        $_r['rights'],
+                        $TemplateData['editEntry']['id']
+                    );
+                    $TemplateData['message']['content'] = "Date saved successfully";
+                }
+                else {
+                    // create into loaded collection
+                    $do = $Manageentry->create($_data,
+                        $_r['id'],
+                        $_r['group'],
+                        $_r['rights']
+                    );
+                    $TemplateData['message']['content'] = "Date saved successfully: 
+                        <a href='index.php?p=manageentry&collection=".$collection['id']."&id=".$do."'>Here</a>";
+                }
+
+                if(!empty($do)) {
+                    $TemplateData['message']['status'] = "success";
+                }
+                else {
+                    $TemplateData['message']['content'] = "Data could not be saved. See logs for more.";
+                    $TemplateData['message']['status'] = "error";
+                }
+            } else {
+                $TemplateData['message']['content'] = "Nothing found.";
+                $TemplateData['message']['status'] = "error";
+            }
+        }
+        else {
+            $TemplateData['message']['content'] = "IMDB search result information lost.";
+            $TemplateData['message']['status'] = "error";
+        }
+    }
+}
+
diff --git a/webclient/view/default/tool/tool.html b/webclient/view/default/tool/tool.html
new file mode 100644 (file)
index 0000000..8cf10d4
--- /dev/null
@@ -0,0 +1,12 @@
+<h3 class="uk-h3">Using <?php echo $TemplateData['tool']['name']; ?> with collection: <?php echo $TemplateData['collection']['name']; ?></h3>
+<?php if(!empty($TemplateData['editEntry'])) { ?>
+<h4><span uk-icon="arrow-left"></span>
+    <a href="index.php?p=manageentry&collection=<?php echo $TemplateData['collection']['id']; ?>&id=<?php echo $TemplateData['editEntry']['id']; ?>"><?php echo Summoner::ifset($TemplateData['editEntry'], 'title'); ?></a>
+</h4>
+<?php } ?>
+
+<div class="uk-grid-small uk-grid-row-small" uk-grid>
+    <div class="uk-width-1-2">
+        <?php if(!empty($TemplateData['tool']['viewFile'])) { require_once $TemplateData['tool']['viewFile']; } ?>
+    </div>
+</div>
diff --git a/webclient/view/default/tool/tool.php b/webclient/view/default/tool/tool.php
new file mode 100644 (file)
index 0000000..9f5e6f5
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Bibliotheca webclient
+ *
+ * Copyright 2018-2020 Johannes Keßler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once 'lib/tentacle.class.php';
+$Tools = new Tentacle($DB,$Doomguy);
+require_once 'lib/managecollections.class.php';
+$ManangeCollections = new ManageCollections($DB,$Doomguy);
+require_once 'lib/managecollectionfields.class.php';
+$ManangeCollectionsFields = new ManageCollectionFields($DB, $Doomguy);
+require_once  'lib/manageentry.class.php';
+$Manageentry = new Manageentry($DB,$Doomguy);
+
+$TemplateData['tool'] = array();
+$TemplateData['tool']['viewFile'] = '';
+$TemplateData['collection'] = array();
+$TemplateData['editEntry'] = array();
+
+$_collection = false;
+if(isset($_GET['collection']) && !empty($_GET['collection'])) {
+    $_collection = trim($_GET['collection']);
+    $_collection = Summoner::validate($_collection,'digit') ? $_collection : false;
+}
+
+$_id = false;
+if(isset($_GET['id']) && !empty($_GET['id'])) {
+    $_id = trim($_GET['id']);
+    $_id = Summoner::validate($_id,'digit') ? $_id : false;
+}
+
+$_t = false;
+if(isset($_GET['t']) && !empty($_GET['t'])) {
+    $_t = trim($_GET['t']);
+    $_t = Summoner::validate($_t,'nospace') ? $_t : false;
+}
+
+if(!empty($_collection) && !empty($_t)) {
+    $collection = $ManangeCollections->getCollection($_collection,"write");
+    $toolInfo = $Tools->validate($_t);
+
+    if(!empty($collection) && !empty($toolInfo)) {
+        $TemplateData['tool'] = $toolInfo;
+        $TemplateData['collection'] = $collection;
+
+        $ManangeCollectionsFields->setCollection($_collection);
+        $Manageentry->setCollection($_collection);
+
+        if(!empty($_id)) {
+            $TemplateData['editEntry'] = $Manageentry->getEditData($_id);
+        }
+
+        $_toolFile = Summoner::themefile('tool/tool-'.$toolInfo['action'].'.php', UI_THEME);
+        $_toolViewFile = Summoner::themefile('tool/tool-'.$toolInfo['action'].'.html', UI_THEME);
+        if(file_exists($_toolFile) && file_exists($_toolViewFile)) {
+            require_once $_toolFile;
+            $TemplateData['tool']['viewFile'] = $_toolViewFile;
+        }
+        else {
+            $TemplateData['tool']['viewFile'] = '';
+            $TemplateData['message']['content'] = "Required tool files can not be found.";
+            $TemplateData['message']['status'] = "error";
+        }
+    }
+    else {
+        $TemplateData['message']['content'] = "Collection nor tool could not be loaded.";
+        $TemplateData['message']['status'] = "error";
+    }
+}
+
diff --git a/webclient/view/default/ui/css/style.css b/webclient/view/default/ui/css/style.css
new file mode 100644 (file)
index 0000000..e71cb60
--- /dev/null
@@ -0,0 +1,13 @@
+.uk-label {
+    text-transform: none;
+}
+
+.input-multiple-listbox {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+}
+
+.input-multiple-template {
+    margin: 1px;
+}
diff --git a/webclient/view/default/ui/css/uikit.min.css b/webclient/view/default/ui/css/uikit.min.css
new file mode 100644 (file)
index 0000000..447f064
--- /dev/null
@@ -0,0 +1 @@
+/*! UIkit 3.5.3 | https://www.getuikit.com | (c) 2014 - 2020 YOOtheme | MIT License */html{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:16px;font-weight:400;line-height:1.5;-webkit-text-size-adjust:100%;background:#fff;color:#666}body{margin:0}a:active,a:hover{outline:0}.uk-link,a{color:#1e87f0;text-decoration:none;cursor:pointer}.uk-link-toggle:focus .uk-link,.uk-link-toggle:hover .uk-link,.uk-link:hover,a:hover{color:#0f6ecd;text-decoration:underline}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration-style:dotted}b,strong{font-weight:bolder}:not(pre)>code,:not(pre)>kbd,:not(pre)>samp{font-family:Consolas,monaco,monospace;font-size:.875rem;color:#f0506e;white-space:nowrap;padding:2px 6px;background:#f8f8f8}em{color:#f0506e}ins{background:#ffd;color:#666;text-decoration:none}mark{background:#ffd;color:#666}q{font-style:italic}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}audio,canvas,iframe,img,svg,video{vertical-align:middle}canvas,img,video{max-width:100%;height:auto;box-sizing:border-box}@supports (display:block){svg{max-width:100%;height:auto;box-sizing:border-box}}svg:not(:root){overflow:hidden}img:not([src]){min-width:1px;visibility:hidden}iframe{border:0}address,dl,fieldset,figure,ol,p,pre,ul{margin:0 0 20px 0}*+address,*+dl,*+fieldset,*+figure,*+ol,*+p,*+pre,*+ul{margin-top:20px}.uk-h1,.uk-h2,.uk-h3,.uk-h4,.uk-h5,.uk-h6,.uk-heading-2xlarge,.uk-heading-large,.uk-heading-medium,.uk-heading-small,.uk-heading-xlarge,h1,h2,h3,h4,h5,h6{margin:0 0 20px 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-weight:400;color:#333;text-transform:none}*+.uk-h1,*+.uk-h2,*+.uk-h3,*+.uk-h4,*+.uk-h5,*+.uk-h6,*+.uk-heading-2xlarge,*+.uk-heading-large,*+.uk-heading-medium,*+.uk-heading-small,*+.uk-heading-xlarge,*+h1,*+h2,*+h3,*+h4,*+h5,*+h6{margin-top:40px}.uk-h1,h1{font-size:2.23125rem;line-height:1.2}.uk-h2,h2{font-size:1.7rem;line-height:1.3}.uk-h3,h3{font-size:1.5rem;line-height:1.4}.uk-h4,h4{font-size:1.25rem;line-height:1.4}.uk-h5,h5{font-size:16px;line-height:1.4}.uk-h6,h6{font-size:.875rem;line-height:1.4}@media (min-width:960px){.uk-h1,h1{font-size:2.625rem}.uk-h2,h2{font-size:2rem}}ol,ul{padding-left:30px}ol>li>ol,ol>li>ul,ul>li>ol,ul>li>ul{margin:0}dt{font-weight:700}dd{margin-left:0}.uk-hr,hr{overflow:visible;text-align:inherit;margin:0 0 20px 0;border:0;border-top:1px solid #e5e5e5}*+.uk-hr,*+hr{margin-top:20px}address{font-style:normal}blockquote{margin:0 0 20px 0;font-size:1.25rem;line-height:1.5;font-style:italic;color:#333}*+blockquote{margin-top:20px}blockquote p:last-of-type{margin-bottom:0}blockquote footer{margin-top:10px;font-size:.875rem;line-height:1.5;color:#666}blockquote footer::before{content:"— "}pre{font:.875rem/1.5 Consolas,monaco,monospace;color:#666;-moz-tab-size:4;tab-size:4;overflow:auto;padding:10px;border:1px solid #e5e5e5;border-radius:3px;background:#fff}pre code{font-family:Consolas,monaco,monospace}::selection{background:#39f;color:#fff;text-shadow:none}details,main{display:block}summary{display:list-item}template{display:none}.uk-breakpoint-s::before{content:'640px'}.uk-breakpoint-m::before{content:'960px'}.uk-breakpoint-l::before{content:'1200px'}.uk-breakpoint-xl::before{content:'1600px'}:root{--uk-breakpoint-s:640px;--uk-breakpoint-m:960px;--uk-breakpoint-l:1200px;--uk-breakpoint-xl:1600px}.uk-link-muted a,a.uk-link-muted{color:#999}.uk-link-muted a:hover,.uk-link-toggle:focus .uk-link-muted,.uk-link-toggle:hover .uk-link-muted,a.uk-link-muted:hover{color:#666}.uk-link-text a,a.uk-link-text{color:inherit}.uk-link-text a:hover,.uk-link-toggle:focus .uk-link-text,.uk-link-toggle:hover .uk-link-text,a.uk-link-text:hover{color:#999}.uk-link-heading a,a.uk-link-heading{color:inherit}.uk-link-heading a:hover,.uk-link-toggle:focus .uk-link-heading,.uk-link-toggle:hover .uk-link-heading,a.uk-link-heading:hover{color:#1e87f0;text-decoration:none}.uk-link-reset a,a.uk-link-reset{color:inherit!important;text-decoration:none!important}.uk-link-toggle{color:inherit!important;text-decoration:none!important}.uk-link-toggle:focus{outline:0}.uk-heading-small{font-size:2.6rem;line-height:1.2}.uk-heading-medium{font-size:2.8875rem;line-height:1.1}.uk-heading-large{font-size:3.4rem;line-height:1.1}.uk-heading-xlarge{font-size:4rem;line-height:1}.uk-heading-2xlarge{font-size:6rem;line-height:1}@media (min-width:960px){.uk-heading-small{font-size:3.25rem}.uk-heading-medium{font-size:3.5rem}.uk-heading-large{font-size:4rem}.uk-heading-xlarge{font-size:6rem}.uk-heading-2xlarge{font-size:8rem}}@media (min-width:1200px){.uk-heading-medium{font-size:4rem}.uk-heading-large{font-size:6rem}.uk-heading-xlarge{font-size:8rem}.uk-heading-2xlarge{font-size:11rem}}.uk-heading-divider{padding-bottom:calc(5px + .1em);border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-bullet{position:relative}.uk-heading-bullet::before{content:"";display:inline-block;position:relative;top:calc(-.1 * 1em);vertical-align:middle;height:calc(4px + .7em);margin-right:calc(5px + .2em);border-left:calc(5px + .1em) solid #e5e5e5}.uk-heading-line{overflow:hidden}.uk-heading-line>*{display:inline-block;position:relative}.uk-heading-line>::after,.uk-heading-line>::before{content:"";position:absolute;top:calc(50% - ((.2px + .05em)/ 2));width:2000px;border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-line>::before{right:100%;margin-right:calc(5px + .3em)}.uk-heading-line>::after{left:100%;margin-left:calc(5px + .3em)}[class*=uk-divider]{border:none;margin-bottom:20px}*+[class*=uk-divider]{margin-top:20px}.uk-divider-icon{position:relative;height:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22%23e5e5e5%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:50% 50%}.uk-divider-icon::after,.uk-divider-icon::before{content:"";position:absolute;top:50%;max-width:calc(50% - (50px / 2));border-bottom:1px solid #e5e5e5}.uk-divider-icon::before{right:calc(50% + (50px / 2));width:100%}.uk-divider-icon::after{left:calc(50% + (50px / 2));width:100%}.uk-divider-small{line-height:0}.uk-divider-small::after{content:"";display:inline-block;width:100px;max-width:100%;border-top:1px solid #e5e5e5;vertical-align:top}.uk-divider-vertical{width:1px;height:100px;margin-left:auto;margin-right:auto;border-left:1px solid #e5e5e5}.uk-list{padding:0;list-style:none}.uk-list>li>:last-child{margin-bottom:0}.uk-list>li:nth-child(n+2),.uk-list>li>ul{margin-top:10px}.uk-list-circle,.uk-list-decimal,.uk-list-disc,.uk-list-hyphen,.uk-list-square{padding-left:30px}.uk-list-disc{list-style-type:disc}.uk-list-circle{list-style-type:circle}.uk-list-square{list-style-type:square}.uk-list-decimal{list-style-type:decimal}.uk-list-hyphen{list-style-type:'–  '}.uk-list-muted li::marker{color:#999!important}.uk-list-emphasis li::marker{color:#333!important}.uk-list-primary li::marker{color:#1e87f0!important}.uk-list-secondary li::marker{color:#222!important}.uk-list-bullet>li{position:relative;padding-left:30px}.uk-list-bullet>li::before{content:"";position:absolute;top:0;left:0;width:1.5em;height:1.5em;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-list-divider>li:nth-child(n+2){margin-top:10px;padding-top:10px;border-top:1px solid #e5e5e5}.uk-list-striped>li{padding:10px 10px}.uk-list-striped>li:nth-of-type(odd){border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-list-striped>li:nth-of-type(odd){background:#f8f8f8}.uk-list-striped>li:nth-child(n+2){margin-top:0}.uk-list-large>li:nth-child(n+2),.uk-list-large>li>ul{margin-top:20px}.uk-list-collapse>li:nth-child(n+2),.uk-list-collapse>li>ul{margin-top:0}.uk-list-large.uk-list-divider>li:nth-child(n+2){margin-top:20px;padding-top:20px}.uk-list-collapse.uk-list-divider>li:nth-child(n+2){margin-top:0;padding-top:0}.uk-list-large.uk-list-striped>li{padding:20px 10px}.uk-list-collapse.uk-list-striped>li{padding-top:0;padding-bottom:0}.uk-list-collapse.uk-list-striped>li:nth-child(n+2),.uk-list-large.uk-list-striped>li:nth-child(n+2){margin-top:0}.uk-description-list>dt{color:#333;font-size:.875rem;font-weight:400;text-transform:uppercase}.uk-description-list>dt:nth-child(n+2){margin-top:20px}.uk-description-list-divider>dt:nth-child(n+2){margin-top:20px;padding-top:20px;border-top:1px solid #e5e5e5}.uk-table{border-collapse:collapse;border-spacing:0;width:100%;margin-bottom:20px}*+.uk-table{margin-top:20px}.uk-table th{padding:16px 12px;text-align:left;vertical-align:bottom;font-size:.875rem;font-weight:400;color:#999;text-transform:uppercase}.uk-table td{padding:16px 12px;vertical-align:top}.uk-table td>:last-child{margin-bottom:0}.uk-table tfoot{font-size:.875rem}.uk-table caption{font-size:.875rem;text-align:left;color:#999}.uk-table-middle,.uk-table-middle td{vertical-align:middle!important}.uk-table-divider>:first-child>tr:not(:first-child),.uk-table-divider>:not(:first-child)>tr,.uk-table-divider>tr:not(:first-child){border-top:1px solid #e5e5e5}.uk-table-striped tbody tr:nth-of-type(odd),.uk-table-striped>tr:nth-of-type(odd){background:#f8f8f8;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-table-hover tbody tr:hover,.uk-table-hover>tr:hover{background:#ffd}.uk-table tbody tr.uk-active,.uk-table>tr.uk-active{background:#ffd}.uk-table-small td,.uk-table-small th{padding:10px 12px}.uk-table-large td,.uk-table-large th{padding:22px 12px}.uk-table-justify td:first-child,.uk-table-justify th:first-child{padding-left:0}.uk-table-justify td:last-child,.uk-table-justify th:last-child{padding-right:0}.uk-table-shrink{width:1px}.uk-table-expand{min-width:150px}.uk-table-link{padding:0!important}.uk-table-link>a{display:block;padding:16px 12px}.uk-table-small .uk-table-link>a{padding:10px 12px}@media (max-width:959px){.uk-table-responsive,.uk-table-responsive tbody,.uk-table-responsive td,.uk-table-responsive th,.uk-table-responsive tr{display:block}.uk-table-responsive thead{display:none}.uk-table-responsive td,.uk-table-responsive th{width:auto!important;max-width:none!important;min-width:0!important;overflow:visible!important;white-space:normal!important}.uk-table-responsive .uk-table-link:not(:first-child)>a,.uk-table-responsive td:not(:first-child):not(.uk-table-link),.uk-table-responsive th:not(:first-child):not(.uk-table-link){padding-top:5px!important}.uk-table-responsive .uk-table-link:not(:last-child)>a,.uk-table-responsive td:not(:last-child):not(.uk-table-link),.uk-table-responsive th:not(:last-child):not(.uk-table-link){padding-bottom:5px!important}.uk-table-justify.uk-table-responsive td,.uk-table-justify.uk-table-responsive th{padding-left:0;padding-right:0}}.uk-table tbody tr{transition:background-color .1s linear}.uk-icon{margin:0;border:none;border-radius:0;overflow:visible;font:inherit;color:inherit;text-transform:none;padding:0;background-color:transparent;display:inline-block;fill:currentcolor;line-height:0}button.uk-icon:not(:disabled){cursor:pointer}.uk-icon::-moz-focus-inner{border:0;padding:0}.uk-icon:not(.uk-preserve) [fill*='#']:not(.uk-preserve){fill:currentcolor}.uk-icon:not(.uk-preserve) [stroke*='#']:not(.uk-preserve){stroke:currentcolor}.uk-icon>*{transform:translate(0,0)}.uk-icon-image{width:20px;height:20px;background-position:50% 50%;background-repeat:no-repeat;background-size:contain;vertical-align:middle}.uk-icon-link{color:#999}.uk-icon-link:focus,.uk-icon-link:hover{color:#666;outline:0}.uk-active>.uk-icon-link,.uk-icon-link:active{color:#595959}.uk-icon-button{box-sizing:border-box;width:36px;height:36px;border-radius:500px;background:#f8f8f8;color:#999;vertical-align:middle;display:inline-flex;justify-content:center;align-items:center;transition:.1s ease-in-out;transition-property:color,background-color}.uk-icon-button:focus,.uk-icon-button:hover{background-color:#ebebeb;color:#666;outline:0}.uk-active>.uk-icon-button,.uk-icon-button:active{background-color:#dfdfdf;color:#666}.uk-range{box-sizing:border-box;margin:0;vertical-align:middle;max-width:100%;width:100%;-webkit-appearance:none;background:0 0;padding:0}.uk-range:focus{outline:0}.uk-range::-moz-focus-outer{border:none}.uk-range::-ms-track{height:15px;background:0 0;border-color:transparent;color:transparent}.uk-range:not(:disabled)::-webkit-slider-thumb{cursor:pointer}.uk-range:not(:disabled)::-moz-range-thumb{cursor:pointer}.uk-range:not(:disabled)::-ms-thumb{cursor:pointer}.uk-range::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-7px;height:15px;width:15px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-range::-moz-range-thumb{border:none;height:15px;width:15px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-range::-ms-thumb{margin-top:0}.uk-range::-ms-thumb{border:none;height:15px;width:15px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-range::-ms-tooltip{display:none}.uk-range::-webkit-slider-runnable-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:active::-webkit-slider-runnable-track,.uk-range:focus::-webkit-slider-runnable-track{background:#d2d2d2}.uk-range::-moz-range-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:focus::-moz-range-track{background:#d2d2d2}.uk-range::-ms-fill-lower,.uk-range::-ms-fill-upper{height:3px;background:#ebebeb;border-radius:500px}.uk-range:focus::-ms-fill-lower,.uk-range:focus::-ms-fill-upper{background:#d2d2d2}.uk-checkbox,.uk-input,.uk-radio,.uk-select,.uk-textarea{box-sizing:border-box;margin:0;border-radius:0;font:inherit}.uk-input{overflow:visible}.uk-select{text-transform:none}.uk-select optgroup{font:inherit;font-weight:700}.uk-textarea{overflow:auto}.uk-input[type=search]::-webkit-search-cancel-button,.uk-input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.uk-input[type=number]::-webkit-inner-spin-button,.uk-input[type=number]::-webkit-outer-spin-button{height:auto}.uk-input::-moz-placeholder,.uk-textarea::-moz-placeholder{opacity:1}.uk-checkbox:not(:disabled),.uk-radio:not(:disabled){cursor:pointer}.uk-fieldset{border:none;margin:0;padding:0}.uk-input,.uk-textarea{-webkit-appearance:none}.uk-input,.uk-select,.uk-textarea{max-width:100%;width:100%;border:0 none;padding:0 10px;background:#fff;color:#666;border:1px solid #e5e5e5;transition:.2s ease-in-out;transition-property:color,background-color,border}.uk-input,.uk-select:not([multiple]):not([size]){height:40px;vertical-align:middle;display:inline-block}.uk-input:not(input),.uk-select:not(select){line-height:38px}.uk-select[multiple],.uk-select[size],.uk-textarea{padding-top:4px;padding-bottom:4px;vertical-align:top}.uk-input:focus,.uk-select:focus,.uk-textarea:focus{outline:0;background-color:#fff;color:#666;border-color:#1e87f0}.uk-input:disabled,.uk-select:disabled,.uk-textarea:disabled{background-color:#f8f8f8;color:#999;border-color:#e5e5e5}.uk-input::-ms-input-placeholder{color:#999!important}.uk-input::placeholder{color:#999}.uk-textarea::-ms-input-placeholder{color:#999!important}.uk-textarea::placeholder{color:#999}.uk-form-small{font-size:.875rem}.uk-form-small:not(textarea):not([multiple]):not([size]){height:30px;padding-left:8px;padding-right:8px}.uk-form-small:not(select):not(input):not(textarea){line-height:28px}.uk-form-large{font-size:1.25rem}.uk-form-large:not(textarea):not([multiple]):not([size]){height:55px;padding-left:12px;padding-right:12px}.uk-form-large:not(select):not(input):not(textarea){line-height:53px}.uk-form-danger,.uk-form-danger:focus{color:#f0506e;border-color:#f0506e}.uk-form-success,.uk-form-success:focus{color:#32d296;border-color:#32d296}.uk-form-blank{background:0 0;border-color:transparent}.uk-form-blank:focus{border-color:#e5e5e5;border-style:dashed}input.uk-form-width-xsmall{width:50px}select.uk-form-width-xsmall{width:75px}.uk-form-width-small{width:130px}.uk-form-width-medium{width:200px}.uk-form-width-large{width:500px}.uk-select:not([multiple]):not([size]){-webkit-appearance:none;-moz-appearance:none;padding-right:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:100% 50%}.uk-select:not([multiple]):not([size])::-ms-expand{display:none}.uk-select:not([multiple]):not([size]) option{color:#444}.uk-select:not([multiple]):not([size]):disabled{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]{padding-right:20px;background-repeat:no-repeat;background-position:100% 50%}.uk-input[list]:focus,.uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]::-webkit-calendar-picker-indicator{display:none}.uk-checkbox,.uk-radio{display:inline-block;height:16px;width:16px;overflow:hidden;margin-top:-4px;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;border:1px solid #ccc;transition:.2s ease-in-out;transition-property:background-color,border}.uk-radio{border-radius:50%}.uk-checkbox:focus,.uk-radio:focus{outline:0;border-color:#1e87f0}.uk-checkbox:checked,.uk-checkbox:indeterminate,.uk-radio:checked{background-color:#1e87f0;border-color:transparent}.uk-checkbox:checked:focus,.uk-checkbox:indeterminate:focus,.uk-radio:checked:focus{background-color:#0e6dcd}.uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23fff%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23fff%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23fff%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled,.uk-radio:disabled{background-color:#f8f8f8;border-color:#e5e5e5}.uk-radio:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23999%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:disabled:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23999%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-legend{width:100%;color:inherit;padding:0;font-size:1.5rem;line-height:1.4}.uk-form-custom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-form-custom input[type=file],.uk-form-custom select{position:absolute;top:0;z-index:1;width:100%;height:100%;left:0;-webkit-appearance:none;opacity:0;cursor:pointer}.uk-form-custom input[type=file]{font-size:500px;overflow:hidden}.uk-form-label{color:#333;font-size:.875rem}.uk-form-stacked .uk-form-label{display:block;margin-bottom:5px}@media (max-width:959px){.uk-form-horizontal .uk-form-label{display:block;margin-bottom:5px}}@media (min-width:960px){.uk-form-horizontal .uk-form-label{width:200px;margin-top:7px;float:left}.uk-form-horizontal .uk-form-controls{margin-left:215px}.uk-form-horizontal .uk-form-controls-text{padding-top:7px}}.uk-form-icon{position:absolute;top:0;bottom:0;left:0;width:40px;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-form-icon:hover{color:#666}.uk-form-icon:not(a):not(button):not(input){pointer-events:none}.uk-form-icon:not(.uk-form-icon-flip)~.uk-input{padding-left:40px!important}.uk-form-icon-flip{right:0;left:auto}.uk-form-icon-flip~.uk-input{padding-right:40px!important}.uk-button{margin:0;border:none;overflow:visible;font:inherit;color:inherit;text-transform:none;-webkit-appearance:none;border-radius:0;display:inline-block;box-sizing:border-box;padding:0 30px;vertical-align:middle;font-size:.875rem;line-height:38px;text-align:center;text-decoration:none;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color,border-color}.uk-button:not(:disabled){cursor:pointer}.uk-button::-moz-focus-inner{border:0;padding:0}.uk-button:hover{text-decoration:none}.uk-button:focus{outline:0}.uk-button-default{background-color:transparent;color:#333;border:1px solid #e5e5e5}.uk-button-default:focus,.uk-button-default:hover{background-color:transparent;color:#333;border-color:#b2b2b2}.uk-button-default.uk-active,.uk-button-default:active{background-color:transparent;color:#333;border-color:#999}.uk-button-primary{background-color:#1e87f0;color:#fff;border:1px solid transparent}.uk-button-primary:focus,.uk-button-primary:hover{background-color:#0f7ae5;color:#fff}.uk-button-primary.uk-active,.uk-button-primary:active{background-color:#0e6dcd;color:#fff}.uk-button-secondary{background-color:#222;color:#fff;border:1px solid transparent}.uk-button-secondary:focus,.uk-button-secondary:hover{background-color:#151515;color:#fff}.uk-button-secondary.uk-active,.uk-button-secondary:active{background-color:#080808;color:#fff}.uk-button-danger{background-color:#f0506e;color:#fff;border:1px solid transparent}.uk-button-danger:focus,.uk-button-danger:hover{background-color:#ee395b;color:#fff}.uk-button-danger.uk-active,.uk-button-danger:active{background-color:#ec2147;color:#fff}.uk-button-danger:disabled,.uk-button-default:disabled,.uk-button-primary:disabled,.uk-button-secondary:disabled{background-color:transparent;color:#999;border-color:#e5e5e5}.uk-button-small{padding:0 15px;line-height:28px;font-size:.875rem}.uk-button-large{padding:0 40px;line-height:53px;font-size:.875rem}.uk-button-text{padding:0;line-height:1.5;background:0 0;color:#333;position:relative}.uk-button-text::before{content:"";position:absolute;bottom:0;left:0;right:100%;border-bottom:1px solid #333;transition:right .3s ease-out}.uk-button-text:focus,.uk-button-text:hover{color:#333}.uk-button-text:focus::before,.uk-button-text:hover::before{right:0}.uk-button-text:disabled{color:#999}.uk-button-text:disabled::before{display:none}.uk-button-link{padding:0;line-height:1.5;background:0 0;color:#1e87f0}.uk-button-link:focus,.uk-button-link:hover{color:#0f6ecd;text-decoration:underline}.uk-button-link:disabled{color:#999;text-decoration:none}.uk-button-group{display:inline-flex;vertical-align:middle;position:relative}.uk-button-group>.uk-button:nth-child(n+2),.uk-button-group>div:nth-child(n+2) .uk-button{margin-left:-1px}.uk-button-group .uk-button.uk-active,.uk-button-group .uk-button:active,.uk-button-group .uk-button:focus,.uk-button-group .uk-button:hover{position:relative;z-index:1}.uk-section{display:flow-root;box-sizing:border-box;padding-top:40px;padding-bottom:40px}@media (min-width:960px){.uk-section{padding-top:70px;padding-bottom:70px}}.uk-section>:last-child{margin-bottom:0}.uk-section-xsmall{padding-top:20px;padding-bottom:20px}.uk-section-small{padding-top:40px;padding-bottom:40px}.uk-section-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-section-large{padding-top:140px;padding-bottom:140px}}.uk-section-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-section-xlarge{padding-top:210px;padding-bottom:210px}}.uk-section-default{background:#fff}.uk-section-muted{background:#f8f8f8}.uk-section-primary{background:#1e87f0}.uk-section-secondary{background:#222}.uk-container{display:flow-root;box-sizing:content-box;max-width:1200px;margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px}@media (min-width:640px){.uk-container{padding-left:30px;padding-right:30px}}@media (min-width:960px){.uk-container{padding-left:40px;padding-right:40px}}.uk-container>:last-child{margin-bottom:0}.uk-container .uk-container{padding-left:0;padding-right:0}.uk-container-xsmall{max-width:750px}.uk-container-small{max-width:900px}.uk-container-large{max-width:1400px}.uk-container-xlarge{max-width:1600px}.uk-container-expand{max-width:none}.uk-container-expand-left{margin-left:0}.uk-container-expand-right{margin-right:0}@media (min-width:640px){.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 30px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 30px)}}@media (min-width:960px){.uk-container-expand-left,.uk-container-expand-right{max-width:calc(50% + (1200px / 2) - 40px)}.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 40px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 40px)}.uk-container-expand-left.uk-container-large,.uk-container-expand-right.uk-container-large{max-width:calc(50% + (1400px / 2) - 40px)}.uk-container-expand-left.uk-container-xlarge,.uk-container-expand-right.uk-container-xlarge{max-width:calc(50% + (1600px / 2) - 40px)}}.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 15px)}.uk-container-item-padding-remove-left{margin-left:-15px}.uk-container-item-padding-remove-right{margin-right:-15px}@media (min-width:640px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 30px)}.uk-container-item-padding-remove-left{margin-left:-30px}.uk-container-item-padding-remove-right{margin-right:-30px}}@media (min-width:960px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 40px)}.uk-container-item-padding-remove-left{margin-left:-40px}.uk-container-item-padding-remove-right{margin-right:-40px}}.uk-grid{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none}.uk-grid>*{margin:0}.uk-grid>*>:last-child{margin-bottom:0}.uk-grid{margin-left:-30px}.uk-grid>*{padding-left:30px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:30px}@media (min-width:1200px){.uk-grid{margin-left:-40px}.uk-grid>*{padding-left:40px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:40px}}.uk-grid-column-small,.uk-grid-small{margin-left:-15px}.uk-grid-column-small>*,.uk-grid-small>*{padding-left:15px}*+.uk-grid-margin-small,.uk-grid+.uk-grid-row-small,.uk-grid+.uk-grid-small,.uk-grid-row-small>.uk-grid-margin,.uk-grid-small>.uk-grid-margin{margin-top:15px}.uk-grid-column-medium,.uk-grid-medium{margin-left:-30px}.uk-grid-column-medium>*,.uk-grid-medium>*{padding-left:30px}*+.uk-grid-margin-medium,.uk-grid+.uk-grid-medium,.uk-grid+.uk-grid-row-medium,.uk-grid-medium>.uk-grid-margin,.uk-grid-row-medium>.uk-grid-margin{margin-top:30px}.uk-grid-column-large,.uk-grid-large{margin-left:-40px}.uk-grid-column-large>*,.uk-grid-large>*{padding-left:40px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:40px}@media (min-width:1200px){.uk-grid-column-large,.uk-grid-large{margin-left:-70px}.uk-grid-column-large>*,.uk-grid-large>*{padding-left:70px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:70px}}.uk-grid-collapse,.uk-grid-column-collapse{margin-left:0}.uk-grid-collapse>*,.uk-grid-column-collapse>*{padding-left:0}.uk-grid+.uk-grid-collapse,.uk-grid+.uk-grid-row-collapse,.uk-grid-collapse>.uk-grid-margin,.uk-grid-row-collapse>.uk-grid-margin{margin-top:0}.uk-grid-divider>*{position:relative}.uk-grid-divider>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;border-left:1px solid #e5e5e5}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;left:0;right:0;border-top:1px solid #e5e5e5}.uk-grid-divider{margin-left:-60px}.uk-grid-divider>*{padding-left:60px}.uk-grid-divider>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}@media (min-width:1200px){.uk-grid-divider{margin-left:-80px}.uk-grid-divider>*{padding-left:80px}.uk-grid-divider>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}}.uk-grid-divider.uk-grid-column-small,.uk-grid-divider.uk-grid-small{margin-left:-30px}.uk-grid-divider.uk-grid-column-small>*,.uk-grid-divider.uk-grid-small>*{padding-left:30px}.uk-grid-divider.uk-grid-column-small>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-small>:not(.uk-first-column)::before{left:15px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin{margin-top:30px}.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin::before{top:-15px;left:30px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin::before{top:-15px}.uk-grid-divider.uk-grid-column-small.uk-grid-stack>.uk-grid-margin::before{left:30px}.uk-grid-divider.uk-grid-column-medium,.uk-grid-divider.uk-grid-medium{margin-left:-60px}.uk-grid-divider.uk-grid-column-medium>*,.uk-grid-divider.uk-grid-medium>*{padding-left:60px}.uk-grid-divider.uk-grid-column-medium>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-medium>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px}.uk-grid-divider.uk-grid-column-medium.uk-grid-stack>.uk-grid-margin::before{left:60px}.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-left:-80px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-left:80px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-40px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{left:80px}@media (min-width:1200px){.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-left:-140px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-left:140px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:70px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:140px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-70px;left:140px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-70px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{left:140px}}.uk-grid-item-match,.uk-grid-match>*{display:flex;flex-wrap:wrap}.uk-grid-item-match>:not([class*=uk-width]),.uk-grid-match>*>:not([class*=uk-width]){box-sizing:border-box;width:100%;flex:auto}.uk-tile{display:flow-root;position:relative;box-sizing:border-box;padding-left:15px;padding-right:15px;padding-top:40px;padding-bottom:40px}@media (min-width:640px){.uk-tile{padding-left:30px;padding-right:30px}}@media (min-width:960px){.uk-tile{padding-left:40px;padding-right:40px;padding-top:70px;padding-bottom:70px}}.uk-tile>:last-child{margin-bottom:0}.uk-tile-xsmall{padding-top:20px;padding-bottom:20px}.uk-tile-small{padding-top:40px;padding-bottom:40px}.uk-tile-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-tile-large{padding-top:140px;padding-bottom:140px}}.uk-tile-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-tile-xlarge{padding-top:210px;padding-bottom:210px}}.uk-tile-default{background:#fff}.uk-tile-muted{background:#f8f8f8}.uk-tile-primary{background:#1e87f0}.uk-tile-secondary{background:#222}.uk-card{position:relative;box-sizing:border-box;transition:box-shadow .1s ease-in-out}.uk-card-body{display:flow-root;padding:30px 30px}.uk-card-header{display:flow-root;padding:15px 30px}.uk-card-footer{display:flow-root;padding:15px 30px}@media (min-width:1200px){.uk-card-body{padding:40px 40px}.uk-card-header{padding:20px 40px}.uk-card-footer{padding:20px 40px}}.uk-card-body>:last-child,.uk-card-footer>:last-child,.uk-card-header>:last-child{margin-bottom:0}.uk-card-title{font-size:1.5rem;line-height:1.4}.uk-card-badge{position:absolute;top:30px;right:30px;z-index:1}.uk-card-badge:first-child+*{margin-top:0}.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover{background:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default{background:#fff;color:#666;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-default .uk-card-title{color:#333}.uk-card-default.uk-card-hover:hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default .uk-card-header{border-bottom:1px solid #e5e5e5}.uk-card-default .uk-card-footer{border-top:1px solid #e5e5e5}.uk-card-primary{background:#1e87f0;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-primary .uk-card-title{color:#fff}.uk-card-primary.uk-card-hover:hover{background-color:#1e87f0;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-secondary{background:#222;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-secondary .uk-card-title{color:#fff}.uk-card-secondary.uk-card-hover:hover{background-color:#222;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-small .uk-card-body,.uk-card-small.uk-card-body{padding:20px 20px}.uk-card-small .uk-card-header{padding:13px 20px}.uk-card-small .uk-card-footer{padding:13px 20px}@media (min-width:1200px){.uk-card-large .uk-card-body,.uk-card-large.uk-card-body{padding:70px 70px}.uk-card-large .uk-card-header{padding:35px 70px}.uk-card-large .uk-card-footer{padding:35px 70px}}.uk-card-body>.uk-nav-default{margin-left:-30px;margin-right:-30px}.uk-card-body>.uk-nav-default:only-child{margin-top:-15px;margin-bottom:-15px}.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-body .uk-nav-default>li>a{padding-left:30px;padding-right:30px}.uk-card-body .uk-nav-default .uk-nav-sub{padding-left:45px}@media (min-width:1200px){.uk-card-body>.uk-nav-default{margin-left:-40px;margin-right:-40px}.uk-card-body>.uk-nav-default:only-child{margin-top:-25px;margin-bottom:-25px}.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-body .uk-nav-default>li>a{padding-left:40px;padding-right:40px}.uk-card-body .uk-nav-default .uk-nav-sub{padding-left:55px}}.uk-card-small>.uk-nav-default{margin-left:-20px;margin-right:-20px}.uk-card-small>.uk-nav-default:only-child{margin-top:-5px;margin-bottom:-5px}.uk-card-small .uk-nav-default .uk-nav-divider,.uk-card-small .uk-nav-default .uk-nav-header,.uk-card-small .uk-nav-default>li>a{padding-left:20px;padding-right:20px}.uk-card-small .uk-nav-default .uk-nav-sub{padding-left:35px}@media (min-width:1200px){.uk-card-large>.uk-nav-default{margin:0}.uk-card-large>.uk-nav-default:only-child{margin:0}.uk-card-large .uk-nav-default .uk-nav-divider,.uk-card-large .uk-nav-default .uk-nav-header,.uk-card-large .uk-nav-default>li>a{padding-left:0;padding-right:0}.uk-card-large .uk-nav-default .uk-nav-sub{padding-left:15px}}.uk-close{color:#999;transition:.1s ease-in-out;transition-property:color,opacity}.uk-close:focus,.uk-close:hover{color:#666;outline:0}.uk-spinner>*{animation:uk-spinner-rotate 1.4s linear infinite}@keyframes uk-spinner-rotate{0%{transform:rotate(0)}100%{transform:rotate(270deg)}}.uk-spinner>*>*{stroke-dasharray:88px;stroke-dashoffset:0;transform-origin:center;animation:uk-spinner-dash 1.4s ease-in-out infinite;stroke-width:1;stroke-linecap:round}@keyframes uk-spinner-dash{0%{stroke-dashoffset:88px}50%{stroke-dashoffset:22px;transform:rotate(135deg)}100%{stroke-dashoffset:88px;transform:rotate(450deg)}}.uk-totop{padding:5px;color:#999;transition:color .1s ease-in-out}.uk-totop:focus,.uk-totop:hover{color:#666;outline:0}.uk-totop:active{color:#333}.uk-marker{padding:5px;background:#222;color:#fff;border-radius:500px}.uk-marker:focus,.uk-marker:hover{color:#fff;outline:0}.uk-alert{position:relative;margin-bottom:20px;padding:15px 29px 15px 15px;background:#f8f8f8;color:#666}*+.uk-alert{margin-top:20px}.uk-alert>:last-child{margin-bottom:0}.uk-alert-close{position:absolute;top:20px;right:15px;color:inherit;opacity:.4}.uk-alert-close:first-child+*{margin-top:0}.uk-alert-close:focus,.uk-alert-close:hover{color:inherit;opacity:.8}.uk-alert-primary{background:#d8eafc;color:#1e87f0}.uk-alert-success{background:#edfbf6;color:#32d296}.uk-alert-warning{background:#fff6ee;color:#faa05a}.uk-alert-danger{background:#fef4f6;color:#f0506e}.uk-alert h1,.uk-alert h2,.uk-alert h3,.uk-alert h4,.uk-alert h5,.uk-alert h6{color:inherit}.uk-alert a:not([class]){color:inherit;text-decoration:underline}.uk-alert a:not([class]):hover{color:inherit;text-decoration:underline}.uk-badge{box-sizing:border-box;min-width:22px;height:22px;padding:0 5px;border-radius:500px;vertical-align:middle;background:#1e87f0;color:#fff;font-size:.875rem;display:inline-flex;justify-content:center;align-items:center}.uk-badge:focus,.uk-badge:hover{color:#fff;text-decoration:none;outline:0}.uk-label{display:inline-block;padding:0 10px;background:#1e87f0;line-height:1.5;font-size:.875rem;color:#fff;vertical-align:middle;white-space:nowrap;border-radius:2px;text-transform:uppercase}.uk-label-success{background-color:#32d296;color:#fff}.uk-label-warning{background-color:#faa05a;color:#fff}.uk-label-danger{background-color:#f0506e;color:#fff}.uk-overlay{padding:30px 30px}.uk-overlay>:last-child{margin-bottom:0}.uk-overlay-default{background:rgba(255,255,255,.8)}.uk-overlay-primary{background:rgba(34,34,34,.8)}.uk-article{display:flow-root}.uk-article>:last-child{margin-bottom:0}.uk-article+.uk-article{margin-top:70px}.uk-article-title{font-size:2.23125rem;line-height:1.2}@media (min-width:960px){.uk-article-title{font-size:2.625rem}}.uk-article-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-article-meta a{color:#999}.uk-article-meta a:hover{color:#666;text-decoration:none}.uk-comment-body{display:flow-root;overflow-wrap:break-word;word-wrap:break-word}.uk-comment-header{display:flow-root;margin-bottom:20px}.uk-comment-body>:last-child,.uk-comment-header>:last-child{margin-bottom:0}.uk-comment-title{font-size:1.25rem;line-height:1.4}.uk-comment-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-comment-list{padding:0;list-style:none}.uk-comment-list>:nth-child(n+2){margin-top:70px}.uk-comment-list .uk-comment~ul{margin:70px 0 0 0;padding-left:30px;list-style:none}@media (min-width:960px){.uk-comment-list .uk-comment~ul{padding-left:100px}}.uk-comment-list .uk-comment~ul>:nth-child(n+2){margin-top:70px}.uk-comment-primary{padding:30px;background-color:#f8f8f8}.uk-search{display:inline-block;position:relative;max-width:100%;margin:0}.uk-search-input::-webkit-search-cancel-button,.uk-search-input::-webkit-search-decoration{-webkit-appearance:none}.uk-search-input::-moz-placeholder{opacity:1}.uk-search-input{box-sizing:border-box;margin:0;border-radius:0;font:inherit;overflow:visible;-webkit-appearance:none;vertical-align:middle;width:100%;border:none;color:#666}.uk-search-input:focus{outline:0}.uk-search-input:-ms-input-placeholder{color:#999!important}.uk-search-input::placeholder{color:#999}.uk-search-icon:focus{outline:0}.uk-search .uk-search-icon{position:absolute;top:0;bottom:0;left:0;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-search .uk-search-icon:hover{color:#999}.uk-search .uk-search-icon:not(a):not(button):not(input){pointer-events:none}.uk-search .uk-search-icon-flip{right:0;left:auto}.uk-search-default{width:180px}.uk-search-default .uk-search-input{height:40px;padding-left:6px;padding-right:6px;background:0 0;border:1px solid #e5e5e5}.uk-search-default .uk-search-input:focus{background-color:transparent}.uk-search-default .uk-search-icon{width:40px}.uk-search-default .uk-search-icon:not(.uk-search-icon-flip)~.uk-search-input{padding-left:40px}.uk-search-default .uk-search-icon-flip~.uk-search-input{padding-right:40px}.uk-search-navbar{width:400px}.uk-search-navbar .uk-search-input{height:40px;background:0 0;font-size:1.5rem}.uk-search-navbar .uk-search-icon{width:40px}.uk-search-navbar .uk-search-icon:not(.uk-search-icon-flip)~.uk-search-input{padding-left:40px}.uk-search-navbar .uk-search-icon-flip~.uk-search-input{padding-right:40px}.uk-search-large{width:500px}.uk-search-large .uk-search-input{height:80px;background:0 0;font-size:2.625rem}.uk-search-large .uk-search-icon{width:80px}.uk-search-large .uk-search-icon:not(.uk-search-icon-flip)~.uk-search-input{padding-left:80px}.uk-search-large .uk-search-icon-flip~.uk-search-input{padding-right:80px}.uk-search-toggle{color:#999}.uk-search-toggle:focus,.uk-search-toggle:hover{color:#666}.uk-nav,.uk-nav ul{margin:0;padding:0;list-style:none}.uk-nav li>a{display:block;text-decoration:none}.uk-nav li>a:focus{outline:0}.uk-nav>li>a{padding:5px 0}ul.uk-nav-sub{padding:5px 0 5px 15px}.uk-nav-sub ul{padding-left:15px}.uk-nav-sub a{padding:2px 0}.uk-nav-parent-icon>.uk-parent>a::after{content:"";width:1.5em;height:1.5em;float:right;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22%23666%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-nav-parent-icon>.uk-parent.uk-open>a::after{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22%23666%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-nav-header{padding:5px 0;text-transform:uppercase;font-size:.875rem}.uk-nav-header:not(:first-child){margin-top:20px}.uk-nav-divider{margin:5px 0}.uk-nav-default{font-size:.875rem}.uk-nav-default>li>a{color:#999}.uk-nav-default>li>a:focus,.uk-nav-default>li>a:hover{color:#666}.uk-nav-default>li.uk-active>a{color:#333}.uk-nav-default .uk-nav-header{color:#333}.uk-nav-default .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-default .uk-nav-sub a{color:#999}.uk-nav-default .uk-nav-sub a:focus,.uk-nav-default .uk-nav-sub a:hover{color:#666}.uk-nav-default .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-primary>li>a{font-size:1.5rem;line-height:1.5;color:#999}.uk-nav-primary>li>a:focus,.uk-nav-primary>li>a:hover{color:#666}.uk-nav-primary>li.uk-active>a{color:#333}.uk-nav-primary .uk-nav-header{color:#333}.uk-nav-primary .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-primary .uk-nav-sub a{color:#999}.uk-nav-primary .uk-nav-sub a:focus,.uk-nav-primary .uk-nav-sub a:hover{color:#666}.uk-nav-primary .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-center{text-align:center}.uk-nav-center .uk-nav-sub,.uk-nav-center .uk-nav-sub ul{padding-left:0}.uk-nav-center.uk-nav-parent-icon>.uk-parent>a::after{position:absolute}.uk-navbar{display:flex;position:relative}.uk-navbar-container:not(.uk-navbar-transparent){background:#f8f8f8}.uk-navbar-container>::after,.uk-navbar-container>::before{display:none!important}.uk-navbar-center,.uk-navbar-center-left>*,.uk-navbar-center-right>*,.uk-navbar-left,.uk-navbar-right{display:flex;align-items:center}.uk-navbar-right{margin-left:auto}.uk-navbar-center:only-child{margin-left:auto;margin-right:auto;position:relative}.uk-navbar-center:not(:only-child){position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:max-content;box-sizing:border-box;z-index:990}.uk-navbar-center-left,.uk-navbar-center-right{position:absolute;top:0}.uk-navbar-center-left{right:100%}.uk-navbar-center-right{left:100%}[class*=uk-navbar-center-]{width:max-content;box-sizing:border-box}.uk-navbar-nav{display:flex;margin:0;padding:0;list-style:none}.uk-navbar-center:only-child,.uk-navbar-left,.uk-navbar-right{flex-wrap:wrap}.uk-navbar-item,.uk-navbar-nav>li>a,.uk-navbar-toggle{display:flex;justify-content:center;align-items:center;box-sizing:border-box;min-height:80px;padding:0 15px;font-size:.875rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";text-decoration:none}.uk-navbar-nav>li>a{color:#999;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-navbar-nav>li:hover>a,.uk-navbar-nav>li>a.uk-open,.uk-navbar-nav>li>a:focus{color:#666;outline:0}.uk-navbar-nav>li>a:active{color:#333}.uk-navbar-nav>li.uk-active>a{color:#333}.uk-navbar-item{color:#666}.uk-navbar-toggle{color:#999}.uk-navbar-toggle.uk-open,.uk-navbar-toggle:focus,.uk-navbar-toggle:hover{color:#666;outline:0;text-decoration:none}.uk-navbar-subtitle{font-size:.875rem}.uk-navbar-dropdown{display:none;position:absolute;z-index:1020;box-sizing:border-box;width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-navbar-dropdown.uk-open{display:block}[class*=uk-navbar-dropdown-top]{margin-top:-15px}[class*=uk-navbar-dropdown-bottom]{margin-top:15px}[class*=uk-navbar-dropdown-left]{margin-left:-15px}[class*=uk-navbar-dropdown-right]{margin-left:15px}.uk-navbar-dropdown-grid{margin-left:-50px}.uk-navbar-dropdown-grid>*{padding-left:50px}.uk-navbar-dropdown-grid>.uk-grid-margin{margin-top:50px}.uk-navbar-dropdown-stack .uk-navbar-dropdown-grid>*{width:100%!important}.uk-navbar-dropdown-width-2:not(.uk-navbar-dropdown-stack){width:400px}.uk-navbar-dropdown-width-3:not(.uk-navbar-dropdown-stack){width:600px}.uk-navbar-dropdown-width-4:not(.uk-navbar-dropdown-stack){width:800px}.uk-navbar-dropdown-width-5:not(.uk-navbar-dropdown-stack){width:1000px}.uk-navbar-dropdown-dropbar{margin-top:0;margin-bottom:0;box-shadow:none}.uk-navbar-dropdown-nav{font-size:.875rem}.uk-navbar-dropdown-nav>li>a{color:#999}.uk-navbar-dropdown-nav>li>a:focus,.uk-navbar-dropdown-nav>li>a:hover{color:#666}.uk-navbar-dropdown-nav>li.uk-active>a{color:#333}.uk-navbar-dropdown-nav .uk-nav-header{color:#333}.uk-navbar-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-navbar-dropdown-nav .uk-nav-sub a{color:#999}.uk-navbar-dropdown-nav .uk-nav-sub a:focus,.uk-navbar-dropdown-nav .uk-nav-sub a:hover{color:#666}.uk-navbar-dropdown-nav .uk-nav-sub li.uk-active>a{color:#333}.uk-navbar-dropbar{background:#fff}.uk-navbar-dropbar-slide{position:absolute;z-index:980;left:0;right:0;box-shadow:0 5px 7px rgba(0,0,0,.05)}.uk-navbar-container>.uk-container .uk-navbar-left{margin-left:-15px;margin-right:-15px}.uk-navbar-container>.uk-container .uk-navbar-right{margin-right:-15px}.uk-navbar-dropdown-grid>*{position:relative}.uk-navbar-dropdown-grid>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;left:25px;border-left:1px solid #e5e5e5}.uk-navbar-dropdown-grid.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;top:-25px;left:50px;right:0;border-top:1px solid #e5e5e5}.uk-subnav{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none}.uk-subnav>*{flex:none;padding-left:20px;position:relative}.uk-subnav>*>:first-child{display:block;color:#999;font-size:.875rem;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-subnav>*>a:focus,.uk-subnav>*>a:hover{color:#666;text-decoration:none;outline:0}.uk-subnav>.uk-active>a{color:#333}.uk-subnav-divider{margin-left:-41px}.uk-subnav-divider>*{display:flex;align-items:center}.uk-subnav-divider>::before{content:"";height:1.5em;margin-left:0;margin-right:20px;border-left:1px solid transparent}.uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-left-color:#e5e5e5}.uk-subnav-pill>*>:first-child{padding:5px 10px;background:0 0;color:#999}.uk-subnav-pill>*>a:focus,.uk-subnav-pill>*>a:hover{background-color:#f8f8f8;color:#666}.uk-subnav-pill>*>a:active{background-color:#f8f8f8;color:#666}.uk-subnav-pill>.uk-active>a{background-color:#1e87f0;color:#fff}.uk-subnav>.uk-disabled>a{color:#999}.uk-breadcrumb{display:flex;flex-wrap:wrap;padding:0;list-style:none}.uk-breadcrumb>*{flex:none}.uk-breadcrumb>*>*{display:inline-block;font-size:.875rem;color:#999}.uk-breadcrumb>*>:focus,.uk-breadcrumb>*>:hover{color:#666;text-decoration:none}.uk-breadcrumb>:last-child>a:not([href]),.uk-breadcrumb>:last-child>span{color:#666}.uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{content:"/";display:inline-block;margin:0 20px;font-size:.875rem;color:#999}.uk-pagination{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none}.uk-pagination>*{flex:none;padding-left:20px;position:relative}.uk-pagination>*>*{display:block;color:#999;transition:color .1s ease-in-out}.uk-pagination>*>:focus,.uk-pagination>*>:hover{color:#666;text-decoration:none}.uk-pagination>.uk-active>*{color:#666}.uk-pagination>.uk-disabled>*{color:#999}.uk-tab{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none;position:relative}.uk-tab::before{content:"";position:absolute;bottom:0;left:20px;right:0;border-bottom:1px solid #e5e5e5}.uk-tab>*{flex:none;padding-left:20px;position:relative}.uk-tab>*>a{display:block;text-align:center;padding:5px 10px;color:#999;border-bottom:1px solid transparent;font-size:.875rem;text-transform:uppercase;transition:color .1s ease-in-out}.uk-tab>*>a:focus,.uk-tab>*>a:hover{color:#666;text-decoration:none}.uk-tab>.uk-active>a{color:#333;border-color:#1e87f0}.uk-tab>.uk-disabled>a{color:#999}.uk-tab-bottom::before{top:0;bottom:auto}.uk-tab-bottom>*>a{border-top:1px solid transparent;border-bottom:none}.uk-tab-left,.uk-tab-right{flex-direction:column;margin-left:0}.uk-tab-left>*,.uk-tab-right>*{padding-left:0}.uk-tab-left::before{top:0;bottom:0;left:auto;right:0;border-left:1px solid #e5e5e5;border-bottom:none}.uk-tab-right::before{top:0;bottom:0;left:0;right:auto;border-left:1px solid #e5e5e5;border-bottom:none}.uk-tab-left>*>a{text-align:left;border-right:1px solid transparent;border-bottom:none}.uk-tab-right>*>a{text-align:left;border-left:1px solid transparent;border-bottom:none}.uk-tab .uk-dropdown{margin-left:30px}.uk-slidenav{padding:5px 10px;color:rgba(102,102,102,.5);transition:color .1s ease-in-out}.uk-slidenav:focus,.uk-slidenav:hover{color:rgba(102,102,102,.9);outline:0}.uk-slidenav:active{color:rgba(102,102,102,.5)}.uk-slidenav-large{padding:10px 10px}.uk-slidenav-container{display:flex}.uk-dotnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-12px}.uk-dotnav>*{flex:none;padding-left:12px}.uk-dotnav>*>*{display:block;box-sizing:border-box;width:10px;height:10px;border-radius:50%;background:0 0;text-indent:100%;overflow:hidden;white-space:nowrap;border:1px solid rgba(102,102,102,.4);transition:.2s ease-in-out;transition-property:background-color,border-color}.uk-dotnav>*>:focus,.uk-dotnav>*>:hover{background-color:rgba(102,102,102,.6);outline:0;border-color:transparent}.uk-dotnav>*>:active{background-color:rgba(102,102,102,.2);border-color:transparent}.uk-dotnav>.uk-active>*{background-color:rgba(102,102,102,.6);border-color:transparent}.uk-dotnav-vertical{flex-direction:column;margin-left:0;margin-top:-12px}.uk-dotnav-vertical>*{padding-left:0;padding-top:12px}.uk-thumbnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-15px}.uk-thumbnav>*{padding-left:15px}.uk-thumbnav>*>*{display:inline-block;position:relative}.uk-thumbnav>*>::after{content:"";position:absolute;top:0;bottom:0;left:0;right:0;background:rgba(255,255,255,.4);transition:background-color .1s ease-in-out}.uk-thumbnav>*>:focus,.uk-thumbnav>*>:hover{outline:0}.uk-thumbnav>*>:focus::after,.uk-thumbnav>*>:hover::after{background-color:transparent}.uk-thumbnav>.uk-active>::after{background-color:transparent}.uk-thumbnav-vertical{flex-direction:column;margin-left:0;margin-top:-15px}.uk-thumbnav-vertical>*{padding-left:0;padding-top:15px}.uk-accordion{padding:0;list-style:none}.uk-accordion>:nth-child(n+2){margin-top:20px}.uk-accordion-title{display:block;font-size:1.25rem;line-height:1.4;color:#333;overflow:hidden}.uk-accordion-title::before{content:"";width:1.4em;height:1.4em;margin-left:10px;float:right;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-accordion-title:focus,.uk-accordion-title:hover{color:#666;text-decoration:none;outline:0}.uk-accordion-content{display:flow-root;margin-top:20px}.uk-accordion-content>:last-child{margin-bottom:0}.uk-drop{display:none;position:absolute;z-index:1020;box-sizing:border-box;width:300px}.uk-drop.uk-open{display:block}[class*=uk-drop-top]{margin-top:-20px}[class*=uk-drop-bottom]{margin-top:20px}[class*=uk-drop-left]{margin-left:-20px}[class*=uk-drop-right]{margin-left:20px}.uk-drop-stack .uk-drop-grid>*{width:100%!important}.uk-dropdown{display:none;position:absolute;z-index:1020;box-sizing:border-box;min-width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-dropdown.uk-open{display:block}.uk-dropdown-nav{white-space:nowrap;font-size:.875rem}.uk-dropdown-nav>li>a{color:#999}.uk-dropdown-nav>li.uk-active>a,.uk-dropdown-nav>li>a:focus,.uk-dropdown-nav>li>a:hover{color:#666}.uk-dropdown-nav .uk-nav-header{color:#333}.uk-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-dropdown-nav .uk-nav-sub a{color:#999}.uk-dropdown-nav .uk-nav-sub a:focus,.uk-dropdown-nav .uk-nav-sub a:hover,.uk-dropdown-nav .uk-nav-sub li.uk-active>a{color:#666}[class*=uk-dropdown-top]{margin-top:-10px}[class*=uk-dropdown-bottom]{margin-top:10px}[class*=uk-dropdown-left]{margin-left:-10px}[class*=uk-dropdown-right]{margin-left:10px}.uk-dropdown-stack .uk-dropdown-grid>*{width:100%!important}.uk-modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:15px 15px;background:rgba(0,0,0,.6);opacity:0;transition:opacity .15s linear}@media (min-width:640px){.uk-modal{padding:50px 30px}}@media (min-width:960px){.uk-modal{padding-left:40px;padding-right:40px}}.uk-modal.uk-open{opacity:1}.uk-modal-page{overflow:hidden}.uk-modal-dialog{position:relative;box-sizing:border-box;margin:0 auto;width:600px;max-width:calc(100% - .01px)!important;background:#fff;opacity:0;transform:translateY(-100px);transition:.3s linear;transition-property:opacity,transform}.uk-open>.uk-modal-dialog{opacity:1;transform:translateY(0)}.uk-modal-container .uk-modal-dialog{width:1200px}.uk-modal-full{padding:0;background:0 0}.uk-modal-full .uk-modal-dialog{margin:0;width:100%;max-width:100%;transform:translateY(0)}.uk-modal-body{display:flow-root;padding:30px 30px}.uk-modal-header{display:flow-root;padding:15px 30px;background:#fff;border-bottom:1px solid #e5e5e5}.uk-modal-footer{display:flow-root;padding:15px 30px;background:#fff;border-top:1px solid #e5e5e5}.uk-modal-body>:last-child,.uk-modal-footer>:last-child,.uk-modal-header>:last-child{margin-bottom:0}.uk-modal-title{font-size:2rem;line-height:1.3}[class*=uk-modal-close-]{position:absolute;z-index:1010;top:10px;right:10px;padding:5px}[class*=uk-modal-close-]:first-child+*{margin-top:0}.uk-modal-close-outside{top:0;right:-5px;transform:translate(0,-100%);color:#fff}.uk-modal-close-outside:hover{color:#fff}@media (min-width:960px){.uk-modal-close-outside{right:0;transform:translate(100%,-100%)}}.uk-modal-close-full{top:0;right:0;padding:20px;background:#fff}.uk-lightbox{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;background:#000;opacity:0;transition:opacity .15s linear;touch-action:pinch-zoom}.uk-lightbox.uk-open{display:block;opacity:1}.uk-lightbox-page{overflow:hidden}.uk-lightbox-items>*{position:absolute;top:0;right:0;bottom:0;left:0;display:none;justify-content:center;align-items:center;color:rgba(255,255,255,.7);will-change:transform,opacity}.uk-lightbox-items>*>*{max-width:100vw;max-height:100vh}.uk-lightbox-items>:focus{outline:0}.uk-lightbox-items>*>:not(iframe){width:auto;height:auto}.uk-lightbox-items>.uk-active{display:flex}.uk-lightbox-toolbar{padding:10px 10px;background:rgba(0,0,0,.3);color:rgba(255,255,255,.7)}.uk-lightbox-toolbar>*{color:rgba(255,255,255,.7)}.uk-lightbox-toolbar-icon{padding:5px;color:rgba(255,255,255,.7)}.uk-lightbox-toolbar-icon:hover{color:#fff}.uk-lightbox-button{box-sizing:border-box;width:50px;height:50px;background:rgba(0,0,0,.3);color:rgba(255,255,255,.7);display:inline-flex;justify-content:center;align-items:center}.uk-lightbox-button:hover{color:#fff}.uk-lightbox-caption:empty{display:none}.uk-lightbox-iframe{width:80%;height:80%}.uk-slideshow{-webkit-tap-highlight-color:transparent}.uk-slideshow-items{position:relative;z-index:0;margin:0;padding:0;list-style:none;overflow:hidden;-webkit-touch-callout:none}.uk-slideshow-items>*{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;will-change:transform,opacity;touch-action:pan-y}.uk-slideshow-items>:focus{outline:0}.uk-slideshow-items>:not(.uk-active){display:none}.uk-slider{-webkit-tap-highlight-color:transparent}.uk-slider-container{overflow:hidden}.uk-slider-items{will-change:transform;position:relative}.uk-slider-items:not(.uk-grid){display:flex;margin:0;padding:0;list-style:none;-webkit-touch-callout:none}.uk-slider-items.uk-grid{flex-wrap:nowrap}.uk-slider-items>*{flex:none;position:relative;touch-action:pan-y}.uk-slider-items>:focus{outline:0}.uk-sticky-fixed{z-index:980;box-sizing:border-box;margin:0!important;-webkit-backface-visibility:hidden;backface-visibility:hidden}.uk-sticky[class*=uk-animation-]{animation-duration:.2s}.uk-sticky.uk-animation-reverse{animation-duration:.2s}.uk-offcanvas{display:none;position:fixed;top:0;bottom:0;left:0;z-index:1000}.uk-offcanvas-flip .uk-offcanvas{right:0;left:auto}.uk-offcanvas-bar{position:absolute;top:0;bottom:0;left:-270px;box-sizing:border-box;width:270px;padding:20px 20px;background:#222;overflow-y:auto;-webkit-overflow-scrolling:touch}@media (min-width:960px){.uk-offcanvas-bar{left:-350px;width:350px;padding:40px 40px}}.uk-offcanvas-flip .uk-offcanvas-bar{left:auto;right:-270px}@media (min-width:960px){.uk-offcanvas-flip .uk-offcanvas-bar{right:-350px}}.uk-open>.uk-offcanvas-bar{left:0}.uk-offcanvas-flip .uk-open>.uk-offcanvas-bar{left:auto;right:0}.uk-offcanvas-bar-animation{transition:left .3s ease-out}.uk-offcanvas-flip .uk-offcanvas-bar-animation{transition-property:right}.uk-offcanvas-reveal{position:absolute;top:0;bottom:0;left:0;width:0;overflow:hidden;transition:width .3s ease-out}.uk-offcanvas-reveal .uk-offcanvas-bar{left:0}.uk-offcanvas-flip .uk-offcanvas-reveal .uk-offcanvas-bar{left:auto;right:0}.uk-open>.uk-offcanvas-reveal{width:270px}@media (min-width:960px){.uk-open>.uk-offcanvas-reveal{width:350px}}.uk-offcanvas-flip .uk-offcanvas-reveal{right:0;left:auto}.uk-offcanvas-close{position:absolute;z-index:1000;top:20px;right:20px;padding:5px}.uk-offcanvas-overlay{width:100vw;touch-action:none}.uk-offcanvas-overlay::before{content:"";position:absolute;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,.1);opacity:0;transition:opacity .15s linear}.uk-offcanvas-overlay.uk-open::before{opacity:1}.uk-offcanvas-container,.uk-offcanvas-page{overflow-x:hidden}.uk-offcanvas-container{position:relative;left:0;transition:left .3s ease-out;box-sizing:border-box;width:100%}:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{left:270px}.uk-offcanvas-flip.uk-offcanvas-container-animation{left:-270px}@media (min-width:960px){:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{left:350px}.uk-offcanvas-flip.uk-offcanvas-container-animation{left:-350px}}.uk-switcher{margin:0;padding:0;list-style:none}.uk-switcher>:not(.uk-active){display:none}.uk-switcher>*>:last-child{margin-bottom:0}.uk-leader{overflow:hidden}.uk-leader-fill::after{display:inline-block;margin-left:15px;width:0;content:attr(data-fill);white-space:nowrap}.uk-leader-fill.uk-leader-hide::after{display:none}.uk-leader-fill-content::before{content:'.'}:root{--uk-leader-fill-content:.}.uk-iconnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-10px}.uk-iconnav>*{padding-left:10px}.uk-iconnav>*>a{display:block;color:#999}.uk-iconnav>*>a:focus,.uk-iconnav>*>a:hover{color:#666;outline:0}.uk-iconnav>.uk-active>a{color:#666}.uk-iconnav-vertical{flex-direction:column;margin-left:0;margin-top:-10px}.uk-iconnav-vertical>*{padding-left:0;padding-top:10px}.uk-notification{position:fixed;top:10px;left:10px;z-index:1040;box-sizing:border-box;width:350px}.uk-notification-bottom-right,.uk-notification-top-right{left:auto;right:10px}.uk-notification-bottom-center,.uk-notification-top-center{left:50%;margin-left:-175px}.uk-notification-bottom-center,.uk-notification-bottom-left,.uk-notification-bottom-right{top:auto;bottom:10px}@media (max-width:639px){.uk-notification{left:10px;right:10px;width:auto;margin:0}}.uk-notification-message{position:relative;padding:15px;background:#f8f8f8;color:#666;font-size:1.25rem;line-height:1.4;cursor:pointer}*+.uk-notification-message{margin-top:10px}.uk-notification-close{display:none;position:absolute;top:20px;right:15px}.uk-notification-message:hover .uk-notification-close{display:block}.uk-notification-message-primary{color:#1e87f0}.uk-notification-message-success{color:#32d296}.uk-notification-message-warning{color:#faa05a}.uk-notification-message-danger{color:#f0506e}.uk-tooltip{display:none;position:absolute;z-index:1030;top:0;box-sizing:border-box;max-width:200px;padding:3px 6px;background:#666;border-radius:2px;color:#fff;font-size:12px}.uk-tooltip.uk-active{display:block}[class*=uk-tooltip-top]{margin-top:-10px}[class*=uk-tooltip-bottom]{margin-top:10px}[class*=uk-tooltip-left]{margin-left:-10px}[class*=uk-tooltip-right]{margin-left:10px}.uk-placeholder{margin-bottom:20px;padding:30px 30px;background:0 0;border:1px dashed #e5e5e5}*+.uk-placeholder{margin-top:20px}.uk-placeholder>:last-child{margin-bottom:0}.uk-progress{vertical-align:baseline;-webkit-appearance:none;-moz-appearance:none;display:block;width:100%;border:0;background-color:#f8f8f8;margin-bottom:20px;height:15px;border-radius:500px;overflow:hidden}*+.uk-progress{margin-top:20px}.uk-progress:indeterminate{color:transparent}.uk-progress::-webkit-progress-bar{background-color:#f8f8f8;border-radius:500px;overflow:hidden}.uk-progress:indeterminate::-moz-progress-bar{width:0}.uk-progress::-webkit-progress-value{background-color:#1e87f0;transition:width .6s ease}.uk-progress::-moz-progress-bar{background-color:#1e87f0}.uk-progress::-ms-fill{background-color:#1e87f0;transition:width .6s ease;border:0}.uk-sortable{position:relative}.uk-sortable svg{pointer-events:none}.uk-sortable>:last-child{margin-bottom:0}.uk-sortable-drag{position:fixed!important;z-index:1050!important;pointer-events:none}.uk-sortable-placeholder{opacity:0;pointer-events:none}.uk-sortable-empty{min-height:50px}.uk-sortable-handle:hover{cursor:move}.uk-countdown-number{font-variant-numeric:tabular-nums;font-size:2rem;line-height:.8}@media (min-width:640px){.uk-countdown-number{font-size:4rem}}@media (min-width:960px){.uk-countdown-number{font-size:6rem}}.uk-countdown-separator{font-size:1rem;line-height:1.6}@media (min-width:640px){.uk-countdown-separator{font-size:2rem}}@media (min-width:960px){.uk-countdown-separator{font-size:3rem}}[class*=uk-animation-]{animation-duration:.5s;animation-timing-function:ease-out;animation-fill-mode:both}.uk-animation-fade{animation-name:uk-fade;animation-duration:.8s;animation-timing-function:linear}.uk-animation-scale-up{animation-name:uk-fade-scale-02}.uk-animation-scale-down{animation-name:uk-fade-scale-18}.uk-animation-slide-top{animation-name:uk-fade-top}.uk-animation-slide-bottom{animation-name:uk-fade-bottom}.uk-animation-slide-left{animation-name:uk-fade-left}.uk-animation-slide-right{animation-name:uk-fade-right}.uk-animation-slide-top-small{animation-name:uk-fade-top-small}.uk-animation-slide-bottom-small{animation-name:uk-fade-bottom-small}.uk-animation-slide-left-small{animation-name:uk-fade-left-small}.uk-animation-slide-right-small{animation-name:uk-fade-right-small}.uk-animation-slide-top-medium{animation-name:uk-fade-top-medium}.uk-animation-slide-bottom-medium{animation-name:uk-fade-bottom-medium}.uk-animation-slide-left-medium{animation-name:uk-fade-left-medium}.uk-animation-slide-right-medium{animation-name:uk-fade-right-medium}.uk-animation-kenburns{animation-name:uk-scale-kenburns;animation-duration:15s}.uk-animation-shake{animation-name:uk-shake}.uk-animation-stroke{animation-name:uk-stroke;stroke-dasharray:var(--uk-animation-stroke);animation-duration:2s}.uk-animation-reverse{animation-direction:reverse;animation-timing-function:ease-in}.uk-animation-fast{animation-duration:.1s}.uk-animation-toggle:not(:hover):not(:focus) [class*=uk-animation-]{animation-name:none}.uk-animation-toggle{-webkit-tap-highlight-color:transparent}.uk-animation-toggle:focus{outline:0}@keyframes uk-fade{0%{opacity:0}100%{opacity:1}}@keyframes uk-fade-top{0%{opacity:0;transform:translateY(-100%)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom{0%{opacity:0;transform:translateY(100%)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left{0%{opacity:0;transform:translateX(-100%)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right{0%{opacity:0;transform:translateX(100%)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-top-small{0%{opacity:0;transform:translateY(-10px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom-small{0%{opacity:0;transform:translateY(10px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left-small{0%{opacity:0;transform:translateX(-10px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right-small{0%{opacity:0;transform:translateX(10px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-top-medium{0%{opacity:0;transform:translateY(-50px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom-medium{0%{opacity:0;transform:translateY(50px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left-medium{0%{opacity:0;transform:translateX(-50px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right-medium{0%{opacity:0;transform:translateX(50px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-scale-02{0%{opacity:0;transform:scale(.2)}100%{opacity:1;transform:scale(1)}}@keyframes uk-fade-scale-18{0%{opacity:0;transform:scale(1.8)}100%{opacity:1;transform:scale(1)}}@keyframes uk-scale-kenburns{0%{transform:scale(1)}100%{transform:scale(1.2)}}@keyframes uk-shake{0%,100%{transform:translateX(0)}10%{transform:translateX(-9px)}20%{transform:translateX(8px)}30%{transform:translateX(-7px)}40%{transform:translateX(6px)}50%{transform:translateX(-5px)}60%{transform:translateX(4px)}70%{transform:translateX(-3px)}80%{transform:translateX(2px)}90%{transform:translateX(-1px)}}@keyframes uk-stroke{0%{stroke-dashoffset:var(--uk-animation-stroke)}100%{stroke-dashoffset:0}}[class*=uk-child-width]>*{box-sizing:border-box;width:100%}.uk-child-width-1-2>*{width:50%}.uk-child-width-1-3>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4>*{width:25%}.uk-child-width-1-5>*{width:20%}.uk-child-width-1-6>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto>*{width:auto}.uk-child-width-expand>:not([class*=uk-width]){flex:1;min-width:1px}@media (min-width:640px){.uk-child-width-1-1\@s>*{width:100%}.uk-child-width-1-2\@s>*{width:50%}.uk-child-width-1-3\@s>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@s>*{width:25%}.uk-child-width-1-5\@s>*{width:20%}.uk-child-width-1-6\@s>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@s>*{width:auto}.uk-child-width-expand\@s>:not([class*=uk-width]){flex:1;min-width:1px}}@media (min-width:960px){.uk-child-width-1-1\@m>*{width:100%}.uk-child-width-1-2\@m>*{width:50%}.uk-child-width-1-3\@m>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@m>*{width:25%}.uk-child-width-1-5\@m>*{width:20%}.uk-child-width-1-6\@m>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@m>*{width:auto}.uk-child-width-expand\@m>:not([class*=uk-width]){flex:1;min-width:1px}}@media (min-width:1200px){.uk-child-width-1-1\@l>*{width:100%}.uk-child-width-1-2\@l>*{width:50%}.uk-child-width-1-3\@l>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@l>*{width:25%}.uk-child-width-1-5\@l>*{width:20%}.uk-child-width-1-6\@l>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@l>*{width:auto}.uk-child-width-expand\@l>:not([class*=uk-width]){flex:1;min-width:1px}}@media (min-width:1600px){.uk-child-width-1-1\@xl>*{width:100%}.uk-child-width-1-2\@xl>*{width:50%}.uk-child-width-1-3\@xl>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@xl>*{width:25%}.uk-child-width-1-5\@xl>*{width:20%}.uk-child-width-1-6\@xl>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@xl>*{width:auto}.uk-child-width-expand\@xl>:not([class*=uk-width]){flex:1;min-width:1px}}[class*=uk-width]{box-sizing:border-box;width:100%;max-width:100%}.uk-width-1-2{width:50%}.uk-width-1-3{width:calc(100% * 1 / 3.001)}.uk-width-2-3{width:calc(100% * 2 / 3.001)}.uk-width-1-4{width:25%}.uk-width-3-4{width:75%}.uk-width-1-5{width:20%}.uk-width-2-5{width:40%}.uk-width-3-5{width:60%}.uk-width-4-5{width:80%}.uk-width-1-6{width:calc(100% * 1 / 6.001)}.uk-width-5-6{width:calc(100% * 5 / 6.001)}.uk-width-small{width:150px}.uk-width-medium{width:300px}.uk-width-large{width:450px}.uk-width-xlarge{width:600px}.uk-width-2xlarge{width:750px}.uk-width-auto{width:auto}.uk-width-expand{flex:1;min-width:1px}@media (min-width:640px){.uk-width-1-1\@s{width:100%}.uk-width-1-2\@s{width:50%}.uk-width-1-3\@s{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@s{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@s{width:25%}.uk-width-3-4\@s{width:75%}.uk-width-1-5\@s{width:20%}.uk-width-2-5\@s{width:40%}.uk-width-3-5\@s{width:60%}.uk-width-4-5\@s{width:80%}.uk-width-1-6\@s{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@s{width:calc(100% * 5 / 6.001)}.uk-width-small\@s{width:150px}.uk-width-medium\@s{width:300px}.uk-width-large\@s{width:450px}.uk-width-xlarge\@s{width:600px}.uk-width-2xlarge\@s{width:750px}.uk-width-auto\@s{width:auto}.uk-width-expand\@s{flex:1;min-width:1px}}@media (min-width:960px){.uk-width-1-1\@m{width:100%}.uk-width-1-2\@m{width:50%}.uk-width-1-3\@m{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@m{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@m{width:25%}.uk-width-3-4\@m{width:75%}.uk-width-1-5\@m{width:20%}.uk-width-2-5\@m{width:40%}.uk-width-3-5\@m{width:60%}.uk-width-4-5\@m{width:80%}.uk-width-1-6\@m{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@m{width:calc(100% * 5 / 6.001)}.uk-width-small\@m{width:150px}.uk-width-medium\@m{width:300px}.uk-width-large\@m{width:450px}.uk-width-xlarge\@m{width:600px}.uk-width-2xlarge\@m{width:750px}.uk-width-auto\@m{width:auto}.uk-width-expand\@m{flex:1;min-width:1px}}@media (min-width:1200px){.uk-width-1-1\@l{width:100%}.uk-width-1-2\@l{width:50%}.uk-width-1-3\@l{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@l{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@l{width:25%}.uk-width-3-4\@l{width:75%}.uk-width-1-5\@l{width:20%}.uk-width-2-5\@l{width:40%}.uk-width-3-5\@l{width:60%}.uk-width-4-5\@l{width:80%}.uk-width-1-6\@l{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@l{width:calc(100% * 5 / 6.001)}.uk-width-small\@l{width:150px}.uk-width-medium\@l{width:300px}.uk-width-large\@l{width:450px}.uk-width-xlarge\@l{width:600px}.uk-width-2xlarge\@l{width:750px}.uk-width-auto\@l{width:auto}.uk-width-expand\@l{flex:1;min-width:1px}}@media (min-width:1600px){.uk-width-1-1\@xl{width:100%}.uk-width-1-2\@xl{width:50%}.uk-width-1-3\@xl{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@xl{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@xl{width:25%}.uk-width-3-4\@xl{width:75%}.uk-width-1-5\@xl{width:20%}.uk-width-2-5\@xl{width:40%}.uk-width-3-5\@xl{width:60%}.uk-width-4-5\@xl{width:80%}.uk-width-1-6\@xl{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@xl{width:calc(100% * 5 / 6.001)}.uk-width-small\@xl{width:150px}.uk-width-medium\@xl{width:300px}.uk-width-large\@xl{width:450px}.uk-width-xlarge\@xl{width:600px}.uk-width-2xlarge\@xl{width:750px}.uk-width-auto\@xl{width:auto}.uk-width-expand\@xl{flex:1;min-width:1px}}[class*=uk-height]{box-sizing:border-box}.uk-height-1-1{height:100%}.uk-height-viewport{min-height:100vh}.uk-height-small{height:150px}.uk-height-medium{height:300px}.uk-height-large{height:450px}.uk-height-max-small{max-height:150px}.uk-height-max-medium{max-height:300px}.uk-height-max-large{max-height:450px}.uk-text-lead{font-size:1.5rem;line-height:1.5;color:#333}.uk-text-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-text-meta a{color:#999}.uk-text-meta a:hover{color:#666;text-decoration:none}.uk-text-small{font-size:.875rem;line-height:1.5}.uk-text-large{font-size:1.5rem;line-height:1.5}.uk-text-light{font-weight:300}.uk-text-normal{font-weight:400}.uk-text-bold{font-weight:700}.uk-text-lighter{font-weight:lighter}.uk-text-bolder{font-weight:bolder}.uk-text-italic{font-style:italic}.uk-text-capitalize{text-transform:capitalize!important}.uk-text-uppercase{text-transform:uppercase!important}.uk-text-lowercase{text-transform:lowercase!important}.uk-text-muted{color:#999!important}.uk-text-emphasis{color:#333!important}.uk-text-primary{color:#1e87f0!important}.uk-text-secondary{color:#222!important}.uk-text-success{color:#32d296!important}.uk-text-warning{color:#faa05a!important}.uk-text-danger{color:#f0506e!important}.uk-text-background{-webkit-background-clip:text;display:inline-block;color:#1e87f0!important}@supports (-webkit-background-clip:text){.uk-text-background{background-color:#1e87f0;color:transparent!important}}.uk-text-left{text-align:left!important}.uk-text-right{text-align:right!important}.uk-text-center{text-align:center!important}.uk-text-justify{text-align:justify!important}@media (min-width:640px){.uk-text-left\@s{text-align:left!important}.uk-text-right\@s{text-align:right!important}.uk-text-center\@s{text-align:center!important}}@media (min-width:960px){.uk-text-left\@m{text-align:left!important}.uk-text-right\@m{text-align:right!important}.uk-text-center\@m{text-align:center!important}}@media (min-width:1200px){.uk-text-left\@l{text-align:left!important}.uk-text-right\@l{text-align:right!important}.uk-text-center\@l{text-align:center!important}}@media (min-width:1600px){.uk-text-left\@xl{text-align:left!important}.uk-text-right\@xl{text-align:right!important}.uk-text-center\@xl{text-align:center!important}}.uk-text-top{vertical-align:top!important}.uk-text-middle{vertical-align:middle!important}.uk-text-bottom{vertical-align:bottom!important}.uk-text-baseline{vertical-align:baseline!important}.uk-text-nowrap{white-space:nowrap}.uk-text-truncate{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}td.uk-text-truncate,th.uk-text-truncate{max-width:0}.uk-text-break{overflow-wrap:break-word;word-wrap:break-word}td.uk-text-break,th.uk-text-break{word-break:break-all}[class*=uk-column-]{column-gap:30px}@media (min-width:1200px){[class*=uk-column-]{column-gap:40px}}[class*=uk-column-] img{transform:translate3d(0,0,0)}.uk-column-divider{column-rule:1px solid #e5e5e5;column-gap:60px}@media (min-width:1200px){.uk-column-divider{column-gap:80px}}.uk-column-1-2{column-count:2}.uk-column-1-3{column-count:3}.uk-column-1-4{column-count:4}.uk-column-1-5{column-count:5}.uk-column-1-6{column-count:6}@media (min-width:640px){.uk-column-1-2\@s{column-count:2}.uk-column-1-3\@s{column-count:3}.uk-column-1-4\@s{column-count:4}.uk-column-1-5\@s{column-count:5}.uk-column-1-6\@s{column-count:6}}@media (min-width:960px){.uk-column-1-2\@m{column-count:2}.uk-column-1-3\@m{column-count:3}.uk-column-1-4\@m{column-count:4}.uk-column-1-5\@m{column-count:5}.uk-column-1-6\@m{column-count:6}}@media (min-width:1200px){.uk-column-1-2\@l{column-count:2}.uk-column-1-3\@l{column-count:3}.uk-column-1-4\@l{column-count:4}.uk-column-1-5\@l{column-count:5}.uk-column-1-6\@l{column-count:6}}@media (min-width:1600px){.uk-column-1-2\@xl{column-count:2}.uk-column-1-3\@xl{column-count:3}.uk-column-1-4\@xl{column-count:4}.uk-column-1-5\@xl{column-count:5}.uk-column-1-6\@xl{column-count:6}}.uk-column-span{column-span:all}.uk-cover{max-width:none;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}iframe.uk-cover{pointer-events:none}.uk-cover-container{overflow:hidden;position:relative}.uk-background-default{background-color:#fff}.uk-background-muted{background-color:#f8f8f8}.uk-background-primary{background-color:#1e87f0}.uk-background-secondary{background-color:#222}.uk-background-contain,.uk-background-cover{background-position:50% 50%;background-repeat:no-repeat}.uk-background-cover{background-size:cover}.uk-background-contain{background-size:contain}.uk-background-top-left{background-position:0 0}.uk-background-top-center{background-position:50% 0}.uk-background-top-right{background-position:100% 0}.uk-background-center-left{background-position:0 50%}.uk-background-center-center{background-position:50% 50%}.uk-background-center-right{background-position:100% 50%}.uk-background-bottom-left{background-position:0 100%}.uk-background-bottom-center{background-position:50% 100%}.uk-background-bottom-right{background-position:100% 100%}.uk-background-norepeat{background-repeat:no-repeat}.uk-background-fixed{background-attachment:fixed;backface-visibility:hidden}@media (pointer:coarse){.uk-background-fixed{background-attachment:scroll}}@media (max-width:639px){.uk-background-image\@s{background-image:none!important}}@media (max-width:959px){.uk-background-image\@m{background-image:none!important}}@media (max-width:1199px){.uk-background-image\@l{background-image:none!important}}@media (max-width:1599px){.uk-background-image\@xl{background-image:none!important}}.uk-background-blend-multiply{background-blend-mode:multiply}.uk-background-blend-screen{background-blend-mode:screen}.uk-background-blend-overlay{background-blend-mode:overlay}.uk-background-blend-darken{background-blend-mode:darken}.uk-background-blend-lighten{background-blend-mode:lighten}.uk-background-blend-color-dodge{background-blend-mode:color-dodge}.uk-background-blend-color-burn{background-blend-mode:color-burn}.uk-background-blend-hard-light{background-blend-mode:hard-light}.uk-background-blend-soft-light{background-blend-mode:soft-light}.uk-background-blend-difference{background-blend-mode:difference}.uk-background-blend-exclusion{background-blend-mode:exclusion}.uk-background-blend-hue{background-blend-mode:hue}.uk-background-blend-saturation{background-blend-mode:saturation}.uk-background-blend-color{background-blend-mode:color}.uk-background-blend-luminosity{background-blend-mode:luminosity}[class*=uk-align]{display:block;margin-bottom:30px}*+[class*=uk-align]{margin-top:30px}.uk-align-center{margin-left:auto;margin-right:auto}.uk-align-left{margin-top:0;margin-right:30px;float:left}.uk-align-right{margin-top:0;margin-left:30px;float:right}@media (min-width:640px){.uk-align-left\@s{margin-top:0;margin-right:30px;float:left}.uk-align-right\@s{margin-top:0;margin-left:30px;float:right}}@media (min-width:960px){.uk-align-left\@m{margin-top:0;margin-right:30px;float:left}.uk-align-right\@m{margin-top:0;margin-left:30px;float:right}}@media (min-width:1200px){.uk-align-left\@l{margin-top:0;float:left}.uk-align-right\@l{margin-top:0;float:right}.uk-align-left,.uk-align-left\@l,.uk-align-left\@m,.uk-align-left\@s{margin-right:40px}.uk-align-right,.uk-align-right\@l,.uk-align-right\@m,.uk-align-right\@s{margin-left:40px}}@media (min-width:1600px){.uk-align-left\@xl{margin-top:0;margin-right:40px;float:left}.uk-align-right\@xl{margin-top:0;margin-left:40px;float:right}}.uk-svg,.uk-svg:not(.uk-preserve) [fill*='#']:not(.uk-preserve){fill:currentcolor}.uk-svg:not(.uk-preserve) [stroke*='#']:not(.uk-preserve){stroke:currentcolor}.uk-svg{transform:translate(0,0)}.uk-panel{display:flow-root;position:relative;box-sizing:border-box}.uk-panel>:last-child{margin-bottom:0}.uk-panel-scrollable{height:170px;padding:10px;border:1px solid #e5e5e5;overflow:auto;-webkit-overflow-scrolling:touch;resize:both}.uk-clearfix::before{content:"";display:table-cell}.uk-clearfix::after{content:"";display:table;clear:both}.uk-float-left{float:left}.uk-float-right{float:right}[class*=uk-float-]{max-width:100%}.uk-overflow-hidden{overflow:hidden}.uk-overflow-auto{overflow:auto;-webkit-overflow-scrolling:touch}.uk-overflow-auto>:last-child{margin-bottom:0}.uk-resize{resize:both}.uk-resize-vertical{resize:vertical}.uk-display-block{display:block!important}.uk-display-inline{display:inline!important}.uk-display-inline-block{display:inline-block!important}[class*=uk-inline]{display:inline-block;position:relative;max-width:100%;vertical-align:middle;-webkit-backface-visibility:hidden}.uk-inline-clip{overflow:hidden}.uk-preserve-width,.uk-preserve-width canvas,.uk-preserve-width img,.uk-preserve-width svg,.uk-preserve-width video{max-width:none}.uk-responsive-height,.uk-responsive-width{box-sizing:border-box}.uk-responsive-width{max-width:100%!important;height:auto}.uk-responsive-height{max-height:100%;width:auto;max-width:none}.uk-border-circle{border-radius:50%}.uk-border-pill{border-radius:500px}.uk-border-rounded{border-radius:5px}.uk-inline-clip[class*=uk-border-]{-webkit-transform:translateZ(0)}.uk-box-shadow-small{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-medium{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-large{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-xlarge{box-shadow:0 28px 50px rgba(0,0,0,.16)}[class*=uk-box-shadow-hover]{transition:box-shadow .1s ease-in-out}.uk-box-shadow-hover-small:hover{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-hover-medium:hover{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-hover-large:hover{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-hover-xlarge:hover{box-shadow:0 28px 50px rgba(0,0,0,.16)}@supports (filter:blur(0)){.uk-box-shadow-bottom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-box-shadow-bottom::before{content:'';position:absolute;bottom:-30px;left:0;right:0;height:30px;border-radius:100%;background:#444;filter:blur(20px)}.uk-box-shadow-bottom>*{position:relative}}.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{display:block;margin-right:10px;float:left;font-size:4.5em;line-height:1;margin-bottom:-2px}@-moz-document url-prefix(){.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{margin-top:1.1%}}@supports (-ms-ime-align:auto){.uk-dropcap>p:first-of-type::first-letter{font-size:1em}}.uk-logo{font-size:1.5rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";color:#666;text-decoration:none}.uk-logo:focus,.uk-logo:hover{color:#666;outline:0;text-decoration:none}.uk-logo-inverse{display:none}.uk-disabled{pointer-events:none}.uk-drag,.uk-drag *{cursor:move}.uk-drag iframe{pointer-events:none}.uk-dragover{box-shadow:0 0 20px rgba(100,100,100,.3)}.uk-blend-multiply{mix-blend-mode:multiply}.uk-blend-screen{mix-blend-mode:screen}.uk-blend-overlay{mix-blend-mode:overlay}.uk-blend-darken{mix-blend-mode:darken}.uk-blend-lighten{mix-blend-mode:lighten}.uk-blend-color-dodge{mix-blend-mode:color-dodge}.uk-blend-color-burn{mix-blend-mode:color-burn}.uk-blend-hard-light{mix-blend-mode:hard-light}.uk-blend-soft-light{mix-blend-mode:soft-light}.uk-blend-difference{mix-blend-mode:difference}.uk-blend-exclusion{mix-blend-mode:exclusion}.uk-blend-hue{mix-blend-mode:hue}.uk-blend-saturation{mix-blend-mode:saturation}.uk-blend-color{mix-blend-mode:color}.uk-blend-luminosity{mix-blend-mode:luminosity}.uk-transform-center{transform:translate(-50%,-50%)}.uk-transform-origin-top-left{transform-origin:0 0}.uk-transform-origin-top-center{transform-origin:50% 0}.uk-transform-origin-top-right{transform-origin:100% 0}.uk-transform-origin-center-left{transform-origin:0 50%}.uk-transform-origin-center-right{transform-origin:100% 50%}.uk-transform-origin-bottom-left{transform-origin:0 100%}.uk-transform-origin-bottom-center{transform-origin:50% 100%}.uk-transform-origin-bottom-right{transform-origin:100% 100%}.uk-flex{display:flex}.uk-flex-inline{display:inline-flex}.uk-flex-inline::after,.uk-flex-inline::before,.uk-flex::after,.uk-flex::before{display:none}.uk-flex-left{justify-content:flex-start}.uk-flex-center{justify-content:center}.uk-flex-right{justify-content:flex-end}.uk-flex-between{justify-content:space-between}.uk-flex-around{justify-content:space-around}@media (min-width:640px){.uk-flex-left\@s{justify-content:flex-start}.uk-flex-center\@s{justify-content:center}.uk-flex-right\@s{justify-content:flex-end}.uk-flex-between\@s{justify-content:space-between}.uk-flex-around\@s{justify-content:space-around}}@media (min-width:960px){.uk-flex-left\@m{justify-content:flex-start}.uk-flex-center\@m{justify-content:center}.uk-flex-right\@m{justify-content:flex-end}.uk-flex-between\@m{justify-content:space-between}.uk-flex-around\@m{justify-content:space-around}}@media (min-width:1200px){.uk-flex-left\@l{justify-content:flex-start}.uk-flex-center\@l{justify-content:center}.uk-flex-right\@l{justify-content:flex-end}.uk-flex-between\@l{justify-content:space-between}.uk-flex-around\@l{justify-content:space-around}}@media (min-width:1600px){.uk-flex-left\@xl{justify-content:flex-start}.uk-flex-center\@xl{justify-content:center}.uk-flex-right\@xl{justify-content:flex-end}.uk-flex-between\@xl{justify-content:space-between}.uk-flex-around\@xl{justify-content:space-around}}.uk-flex-stretch{align-items:stretch}.uk-flex-top{align-items:flex-start}.uk-flex-middle{align-items:center}.uk-flex-bottom{align-items:flex-end}.uk-flex-row{flex-direction:row}.uk-flex-row-reverse{flex-direction:row-reverse}.uk-flex-column{flex-direction:column}.uk-flex-column-reverse{flex-direction:column-reverse}.uk-flex-nowrap{flex-wrap:nowrap}.uk-flex-wrap{flex-wrap:wrap}.uk-flex-wrap-reverse{flex-wrap:wrap-reverse}.uk-flex-wrap-stretch{align-content:stretch}.uk-flex-wrap-top{align-content:flex-start}.uk-flex-wrap-middle{align-content:center}.uk-flex-wrap-bottom{align-content:flex-end}.uk-flex-wrap-between{align-content:space-between}.uk-flex-wrap-around{align-content:space-around}.uk-flex-first{order:-1}.uk-flex-last{order:99}@media (min-width:640px){.uk-flex-first\@s{order:-1}.uk-flex-last\@s{order:99}}@media (min-width:960px){.uk-flex-first\@m{order:-1}.uk-flex-last\@m{order:99}}@media (min-width:1200px){.uk-flex-first\@l{order:-1}.uk-flex-last\@l{order:99}}@media (min-width:1600px){.uk-flex-first\@xl{order:-1}.uk-flex-last\@xl{order:99}}.uk-flex-none{flex:none}.uk-flex-auto{flex:auto}.uk-flex-1{flex:1}.uk-margin{margin-bottom:20px}*+.uk-margin{margin-top:20px!important}.uk-margin-top{margin-top:20px!important}.uk-margin-bottom{margin-bottom:20px!important}.uk-margin-left{margin-left:20px!important}.uk-margin-right{margin-right:20px!important}.uk-margin-small{margin-bottom:10px}*+.uk-margin-small{margin-top:10px!important}.uk-margin-small-top{margin-top:10px!important}.uk-margin-small-bottom{margin-bottom:10px!important}.uk-margin-small-left{margin-left:10px!important}.uk-margin-small-right{margin-right:10px!important}.uk-margin-medium{margin-bottom:40px}*+.uk-margin-medium{margin-top:40px!important}.uk-margin-medium-top{margin-top:40px!important}.uk-margin-medium-bottom{margin-bottom:40px!important}.uk-margin-medium-left{margin-left:40px!important}.uk-margin-medium-right{margin-right:40px!important}.uk-margin-large{margin-bottom:40px}*+.uk-margin-large{margin-top:40px!important}.uk-margin-large-top{margin-top:40px!important}.uk-margin-large-bottom{margin-bottom:40px!important}.uk-margin-large-left{margin-left:40px!important}.uk-margin-large-right{margin-right:40px!important}@media (min-width:1200px){.uk-margin-large{margin-bottom:70px}*+.uk-margin-large{margin-top:70px!important}.uk-margin-large-top{margin-top:70px!important}.uk-margin-large-bottom{margin-bottom:70px!important}.uk-margin-large-left{margin-left:70px!important}.uk-margin-large-right{margin-right:70px!important}}.uk-margin-xlarge{margin-bottom:70px}*+.uk-margin-xlarge{margin-top:70px!important}.uk-margin-xlarge-top{margin-top:70px!important}.uk-margin-xlarge-bottom{margin-bottom:70px!important}.uk-margin-xlarge-left{margin-left:70px!important}.uk-margin-xlarge-right{margin-right:70px!important}@media (min-width:1200px){.uk-margin-xlarge{margin-bottom:140px}*+.uk-margin-xlarge{margin-top:140px!important}.uk-margin-xlarge-top{margin-top:140px!important}.uk-margin-xlarge-bottom{margin-bottom:140px!important}.uk-margin-xlarge-left{margin-left:140px!important}.uk-margin-xlarge-right{margin-right:140px!important}}.uk-margin-auto{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-top{margin-top:auto!important}.uk-margin-auto-bottom{margin-bottom:auto!important}.uk-margin-auto-left{margin-left:auto!important}.uk-margin-auto-right{margin-right:auto!important}.uk-margin-auto-vertical{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:640px){.uk-margin-auto\@s{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@s{margin-left:auto!important}.uk-margin-auto-right\@s{margin-right:auto!important}}@media (min-width:960px){.uk-margin-auto\@m{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@m{margin-left:auto!important}.uk-margin-auto-right\@m{margin-right:auto!important}}@media (min-width:1200px){.uk-margin-auto\@l{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@l{margin-left:auto!important}.uk-margin-auto-right\@l{margin-right:auto!important}}@media (min-width:1600px){.uk-margin-auto\@xl{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@xl{margin-left:auto!important}.uk-margin-auto-right\@xl{margin-right:auto!important}}.uk-margin-remove{margin:0!important}.uk-margin-remove-top{margin-top:0!important}.uk-margin-remove-bottom{margin-bottom:0!important}.uk-margin-remove-left{margin-left:0!important}.uk-margin-remove-right{margin-right:0!important}.uk-margin-remove-vertical{margin-top:0!important;margin-bottom:0!important}.uk-margin-remove-adjacent+*,.uk-margin-remove-first-child>:first-child{margin-top:0!important}.uk-margin-remove-last-child>:last-child{margin-bottom:0!important}@media (min-width:640px){.uk-margin-remove-left\@s{margin-left:0!important}.uk-margin-remove-right\@s{margin-right:0!important}}@media (min-width:960px){.uk-margin-remove-left\@m{margin-left:0!important}.uk-margin-remove-right\@m{margin-right:0!important}}@media (min-width:1200px){.uk-margin-remove-left\@l{margin-left:0!important}.uk-margin-remove-right\@l{margin-right:0!important}}@media (min-width:1600px){.uk-margin-remove-left\@xl{margin-left:0!important}.uk-margin-remove-right\@xl{margin-right:0!important}}.uk-padding{padding:30px}@media (min-width:1200px){.uk-padding{padding:40px}}.uk-padding-small{padding:15px}.uk-padding-large{padding:30px}@media (min-width:1200px){.uk-padding-large{padding:70px}}.uk-padding-remove{padding:0!important}.uk-padding-remove-top{padding-top:0!important}.uk-padding-remove-bottom{padding-bottom:0!important}.uk-padding-remove-left{padding-left:0!important}.uk-padding-remove-right{padding-right:0!important}.uk-padding-remove-vertical{padding-top:0!important;padding-bottom:0!important}.uk-padding-remove-horizontal{padding-left:0!important;padding-right:0!important}[class*=uk-position-bottom],[class*=uk-position-center],[class*=uk-position-left],[class*=uk-position-right],[class*=uk-position-top]{position:absolute!important;max-width:100%}.uk-position-top{top:0;left:0;right:0}.uk-position-bottom{bottom:0;left:0;right:0}.uk-position-left{top:0;bottom:0;left:0}.uk-position-right{top:0;bottom:0;right:0}.uk-position-top-left{top:0;left:0}.uk-position-top-right{top:0;right:0}.uk-position-bottom-left{bottom:0;left:0}.uk-position-bottom-right{bottom:0;right:0}.uk-position-center{top:50%;left:50%;transform:translate(-50%,-50%);width:max-content;max-width:100%;box-sizing:border-box}[class*=uk-position-center-left],[class*=uk-position-center-right]{top:50%;transform:translateY(-50%)}.uk-position-center-left{left:0}.uk-position-center-right{right:0}.uk-position-center-left-out{right:100%;width:max-content}.uk-position-center-right-out{left:100%;width:max-content}.uk-position-bottom-center,.uk-position-top-center{left:50%;transform:translateX(-50%);width:max-content;max-width:100%;box-sizing:border-box}.uk-position-top-center{top:0}.uk-position-bottom-center{bottom:0}.uk-position-cover{position:absolute;top:0;bottom:0;left:0;right:0}.uk-position-relative{position:relative!important}.uk-position-absolute{position:absolute!important}.uk-position-fixed{position:fixed!important}.uk-position-z-index{z-index:1}.uk-position-small{max-width:calc(100% - (15px * 2));margin:15px}.uk-position-small.uk-position-center{transform:translate(-50%,-50%) translate(-15px,-15px)}.uk-position-small[class*=uk-position-center-left],.uk-position-small[class*=uk-position-center-right]{transform:translateY(-50%) translateY(-15px)}.uk-position-small.uk-position-bottom-center,.uk-position-small.uk-position-top-center{transform:translateX(-50%) translateX(-15px)}.uk-position-medium{max-width:calc(100% - (30px * 2));margin:30px}.uk-position-medium.uk-position-center{transform:translate(-50%,-50%) translate(-30px,-30px)}.uk-position-medium[class*=uk-position-center-left],.uk-position-medium[class*=uk-position-center-right]{transform:translateY(-50%) translateY(-30px)}.uk-position-medium.uk-position-bottom-center,.uk-position-medium.uk-position-top-center{transform:translateX(-50%) translateX(-30px)}.uk-position-large{max-width:calc(100% - (30px * 2));margin:30px}.uk-position-large.uk-position-center{transform:translate(-50%,-50%) translate(-30px,-30px)}.uk-position-large[class*=uk-position-center-left],.uk-position-large[class*=uk-position-center-right]{transform:translateY(-50%) translateY(-30px)}.uk-position-large.uk-position-bottom-center,.uk-position-large.uk-position-top-center{transform:translateX(-50%) translateX(-30px)}@media (min-width:1200px){.uk-position-large{max-width:calc(100% - (50px * 2));margin:50px}.uk-position-large.uk-position-center{transform:translate(-50%,-50%) translate(-50px,-50px)}.uk-position-large[class*=uk-position-center-left],.uk-position-large[class*=uk-position-center-right]{transform:translateY(-50%) translateY(-50px)}.uk-position-large.uk-position-bottom-center,.uk-position-large.uk-position-top-center{transform:translateX(-50%) translateX(-50px)}}.uk-transition-toggle{-webkit-tap-highlight-color:transparent}.uk-transition-toggle:focus{outline:0}.uk-transition-fade,[class*=uk-transition-scale],[class*=uk-transition-slide]{transition:.3s ease-out;transition-property:opacity,transform,filter;opacity:0}.uk-transition-active.uk-active .uk-transition-fade,.uk-transition-toggle:focus .uk-transition-fade,.uk-transition-toggle:hover .uk-transition-fade{opacity:1}.uk-transition-scale-up{transform:scale(1,1)}.uk-transition-scale-down{transform:scale(1.1,1.1)}.uk-transition-active.uk-active .uk-transition-scale-up,.uk-transition-toggle:focus .uk-transition-scale-up,.uk-transition-toggle:hover .uk-transition-scale-up{opacity:1;transform:scale(1.1,1.1)}.uk-transition-active.uk-active .uk-transition-scale-down,.uk-transition-toggle:focus .uk-transition-scale-down,.uk-transition-toggle:hover .uk-transition-scale-down{opacity:1;transform:scale(1,1)}.uk-transition-slide-top{transform:translateY(-100%)}.uk-transition-slide-bottom{transform:translateY(100%)}.uk-transition-slide-left{transform:translateX(-100%)}.uk-transition-slide-right{transform:translateX(100%)}.uk-transition-slide-top-small{transform:translateY(-10px)}.uk-transition-slide-bottom-small{transform:translateY(10px)}.uk-transition-slide-left-small{transform:translateX(-10px)}.uk-transition-slide-right-small{transform:translateX(10px)}.uk-transition-slide-top-medium{transform:translateY(-50px)}.uk-transition-slide-bottom-medium{transform:translateY(50px)}.uk-transition-slide-left-medium{transform:translateX(-50px)}.uk-transition-slide-right-medium{transform:translateX(50px)}.uk-transition-active.uk-active [class*=uk-transition-slide],.uk-transition-toggle:focus [class*=uk-transition-slide],.uk-transition-toggle:hover [class*=uk-transition-slide]{opacity:1;transform:translate(0,0)}.uk-transition-opaque{opacity:1}.uk-transition-slow{transition-duration:.7s}.uk-hidden,[hidden]{display:none!important}@media (min-width:640px){.uk-hidden\@s{display:none!important}}@media (min-width:960px){.uk-hidden\@m{display:none!important}}@media (min-width:1200px){.uk-hidden\@l{display:none!important}}@media (min-width:1600px){.uk-hidden\@xl{display:none!important}}@media (max-width:639px){.uk-visible\@s{display:none!important}}@media (max-width:959px){.uk-visible\@m{display:none!important}}@media (max-width:1199px){.uk-visible\@l{display:none!important}}@media (max-width:1599px){.uk-visible\@xl{display:none!important}}.uk-invisible{visibility:hidden!important}.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-within){position:absolute!important;width:0!important;height:0!important;padding:0!important;margin:0!important;overflow:hidden!important}.uk-visible-toggle:not(:hover):not(:focus) .uk-invisible-hover:not(:focus-within){opacity:0!important}.uk-visible-toggle{-webkit-tap-highlight-color:transparent}.uk-visible-toggle:focus{outline:0}@media (pointer:coarse){.uk-hidden-touch{display:none!important}}.uk-hidden-notouch{display:none!important}@media (pointer:coarse){.uk-hidden-notouch{display:block!important}}.uk-card-primary.uk-card-body,.uk-card-primary>:not([class*=uk-card-media]),.uk-card-secondary.uk-card-body,.uk-card-secondary>:not([class*=uk-card-media]),.uk-light,.uk-offcanvas-bar,.uk-overlay-primary,.uk-section-primary:not(.uk-preserve-color),.uk-section-secondary:not(.uk-preserve-color),.uk-tile-primary:not(.uk-preserve-color),.uk-tile-secondary:not(.uk-preserve-color){color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link,.uk-card-primary.uk-card-body a,.uk-card-primary>:not([class*=uk-card-media]) .uk-link,.uk-card-primary>:not([class*=uk-card-media]) a,.uk-card-secondary.uk-card-body .uk-link,.uk-card-secondary.uk-card-body a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link,.uk-card-secondary>:not([class*=uk-card-media]) a,.uk-light .uk-link,.uk-light a,.uk-offcanvas-bar .uk-link,.uk-offcanvas-bar a,.uk-overlay-primary .uk-link,.uk-overlay-primary a,.uk-section-primary:not(.uk-preserve-color) .uk-link,.uk-section-primary:not(.uk-preserve-color) a,.uk-section-secondary:not(.uk-preserve-color) .uk-link,.uk-section-secondary:not(.uk-preserve-color) a,.uk-tile-primary:not(.uk-preserve-color) .uk-link,.uk-tile-primary:not(.uk-preserve-color) a,.uk-tile-secondary:not(.uk-preserve-color) .uk-link,.uk-tile-secondary:not(.uk-preserve-color) a{color:#fff}.uk-card-primary.uk-card-body .uk-link:hover,.uk-card-primary.uk-card-body a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-primary>:not([class*=uk-card-media]) a:hover,.uk-card-secondary.uk-card-body .uk-link:hover,.uk-card-secondary.uk-card-body a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) a:hover,.uk-light .uk-link:hover,.uk-light a:hover,.uk-offcanvas-bar .uk-link:hover,.uk-offcanvas-bar a:hover,.uk-overlay-primary .uk-link:hover,.uk-overlay-primary a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link:hover,.uk-section-primary:not(.uk-preserve-color) a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-section-secondary:not(.uk-preserve-color) a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-primary:not(.uk-preserve-color) a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-secondary:not(.uk-preserve-color) a:hover{color:#fff}.uk-card-primary.uk-card-body :not(pre)>code,.uk-card-primary.uk-card-body :not(pre)>kbd,.uk-card-primary.uk-card-body :not(pre)>samp,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-card-secondary.uk-card-body :not(pre)>code,.uk-card-secondary.uk-card-body :not(pre)>kbd,.uk-card-secondary.uk-card-body :not(pre)>samp,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-light :not(pre)>code,.uk-light :not(pre)>kbd,.uk-light :not(pre)>samp,.uk-offcanvas-bar :not(pre)>code,.uk-offcanvas-bar :not(pre)>kbd,.uk-offcanvas-bar :not(pre)>samp,.uk-overlay-primary :not(pre)>code,.uk-overlay-primary :not(pre)>kbd,.uk-overlay-primary :not(pre)>samp,.uk-section-primary:not(.uk-preserve-color) :not(pre)>code,.uk-section-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>samp{color:rgba(255,255,255,.7);background:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body em,.uk-card-primary>:not([class*=uk-card-media]) em,.uk-card-secondary.uk-card-body em,.uk-card-secondary>:not([class*=uk-card-media]) em,.uk-light em,.uk-offcanvas-bar em,.uk-overlay-primary em,.uk-section-primary:not(.uk-preserve-color) em,.uk-section-secondary:not(.uk-preserve-color) em,.uk-tile-primary:not(.uk-preserve-color) em,.uk-tile-secondary:not(.uk-preserve-color) em{color:#fff}.uk-card-primary.uk-card-body .uk-h1,.uk-card-primary.uk-card-body .uk-h2,.uk-card-primary.uk-card-body .uk-h3,.uk-card-primary.uk-card-body .uk-h4,.uk-card-primary.uk-card-body .uk-h5,.uk-card-primary.uk-card-body .uk-h6,.uk-card-primary.uk-card-body .uk-heading-2xlarge,.uk-card-primary.uk-card-body .uk-heading-large,.uk-card-primary.uk-card-body .uk-heading-medium,.uk-card-primary.uk-card-body .uk-heading-small,.uk-card-primary.uk-card-body .uk-heading-xlarge,.uk-card-primary.uk-card-body h1,.uk-card-primary.uk-card-body h2,.uk-card-primary.uk-card-body h3,.uk-card-primary.uk-card-body h4,.uk-card-primary.uk-card-body h5,.uk-card-primary.uk-card-body h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-h1,.uk-card-primary>:not([class*=uk-card-media]) .uk-h2,.uk-card-primary>:not([class*=uk-card-media]) .uk-h3,.uk-card-primary>:not([class*=uk-card-media]) .uk-h4,.uk-card-primary>:not([class*=uk-card-media]) .uk-h5,.uk-card-primary>:not([class*=uk-card-media]) .uk-h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-primary>:not([class*=uk-card-media]) h1,.uk-card-primary>:not([class*=uk-card-media]) h2,.uk-card-primary>:not([class*=uk-card-media]) h3,.uk-card-primary>:not([class*=uk-card-media]) h4,.uk-card-primary>:not([class*=uk-card-media]) h5,.uk-card-primary>:not([class*=uk-card-media]) h6,.uk-card-secondary.uk-card-body .uk-h1,.uk-card-secondary.uk-card-body .uk-h2,.uk-card-secondary.uk-card-body .uk-h3,.uk-card-secondary.uk-card-body .uk-h4,.uk-card-secondary.uk-card-body .uk-h5,.uk-card-secondary.uk-card-body .uk-h6,.uk-card-secondary.uk-card-body .uk-heading-2xlarge,.uk-card-secondary.uk-card-body .uk-heading-large,.uk-card-secondary.uk-card-body .uk-heading-medium,.uk-card-secondary.uk-card-body .uk-heading-small,.uk-card-secondary.uk-card-body .uk-heading-xlarge,.uk-card-secondary.uk-card-body h1,.uk-card-secondary.uk-card-body h2,.uk-card-secondary.uk-card-body h3,.uk-card-secondary.uk-card-body h4,.uk-card-secondary.uk-card-body h5,.uk-card-secondary.uk-card-body h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h1,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h2,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h3,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h4,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h5,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-secondary>:not([class*=uk-card-media]) h1,.uk-card-secondary>:not([class*=uk-card-media]) h2,.uk-card-secondary>:not([class*=uk-card-media]) h3,.uk-card-secondary>:not([class*=uk-card-media]) h4,.uk-card-secondary>:not([class*=uk-card-media]) h5,.uk-card-secondary>:not([class*=uk-card-media]) h6,.uk-light .uk-h1,.uk-light .uk-h2,.uk-light .uk-h3,.uk-light .uk-h4,.uk-light .uk-h5,.uk-light .uk-h6,.uk-light .uk-heading-2xlarge,.uk-light .uk-heading-large,.uk-light .uk-heading-medium,.uk-light .uk-heading-small,.uk-light .uk-heading-xlarge,.uk-light h1,.uk-light h2,.uk-light h3,.uk-light h4,.uk-light h5,.uk-light h6,.uk-offcanvas-bar .uk-h1,.uk-offcanvas-bar .uk-h2,.uk-offcanvas-bar .uk-h3,.uk-offcanvas-bar .uk-h4,.uk-offcanvas-bar .uk-h5,.uk-offcanvas-bar .uk-h6,.uk-offcanvas-bar .uk-heading-2xlarge,.uk-offcanvas-bar .uk-heading-large,.uk-offcanvas-bar .uk-heading-medium,.uk-offcanvas-bar .uk-heading-small,.uk-offcanvas-bar .uk-heading-xlarge,.uk-offcanvas-bar h1,.uk-offcanvas-bar h2,.uk-offcanvas-bar h3,.uk-offcanvas-bar h4,.uk-offcanvas-bar h5,.uk-offcanvas-bar h6,.uk-overlay-primary .uk-h1,.uk-overlay-primary .uk-h2,.uk-overlay-primary .uk-h3,.uk-overlay-primary .uk-h4,.uk-overlay-primary .uk-h5,.uk-overlay-primary .uk-h6,.uk-overlay-primary .uk-heading-2xlarge,.uk-overlay-primary .uk-heading-large,.uk-overlay-primary .uk-heading-medium,.uk-overlay-primary .uk-heading-small,.uk-overlay-primary .uk-heading-xlarge,.uk-overlay-primary h1,.uk-overlay-primary h2,.uk-overlay-primary h3,.uk-overlay-primary h4,.uk-overlay-primary h5,.uk-overlay-primary h6,.uk-section-primary:not(.uk-preserve-color) .uk-h1,.uk-section-primary:not(.uk-preserve-color) .uk-h2,.uk-section-primary:not(.uk-preserve-color) .uk-h3,.uk-section-primary:not(.uk-preserve-color) .uk-h4,.uk-section-primary:not(.uk-preserve-color) .uk-h5,.uk-section-primary:not(.uk-preserve-color) .uk-h6,.uk-section-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-primary:not(.uk-preserve-color) .uk-heading-large,.uk-section-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-primary:not(.uk-preserve-color) .uk-heading-small,.uk-section-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-primary:not(.uk-preserve-color) h1,.uk-section-primary:not(.uk-preserve-color) h2,.uk-section-primary:not(.uk-preserve-color) h3,.uk-section-primary:not(.uk-preserve-color) h4,.uk-section-primary:not(.uk-preserve-color) h5,.uk-section-primary:not(.uk-preserve-color) h6,.uk-section-secondary:not(.uk-preserve-color) .uk-h1,.uk-section-secondary:not(.uk-preserve-color) .uk-h2,.uk-section-secondary:not(.uk-preserve-color) .uk-h3,.uk-section-secondary:not(.uk-preserve-color) .uk-h4,.uk-section-secondary:not(.uk-preserve-color) .uk-h5,.uk-section-secondary:not(.uk-preserve-color) .uk-h6,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-secondary:not(.uk-preserve-color) h1,.uk-section-secondary:not(.uk-preserve-color) h2,.uk-section-secondary:not(.uk-preserve-color) h3,.uk-section-secondary:not(.uk-preserve-color) h4,.uk-section-secondary:not(.uk-preserve-color) h5,.uk-section-secondary:not(.uk-preserve-color) h6,.uk-tile-primary:not(.uk-preserve-color) .uk-h1,.uk-tile-primary:not(.uk-preserve-color) .uk-h2,.uk-tile-primary:not(.uk-preserve-color) .uk-h3,.uk-tile-primary:not(.uk-preserve-color) .uk-h4,.uk-tile-primary:not(.uk-preserve-color) .uk-h5,.uk-tile-primary:not(.uk-preserve-color) .uk-h6,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-primary:not(.uk-preserve-color) h1,.uk-tile-primary:not(.uk-preserve-color) h2,.uk-tile-primary:not(.uk-preserve-color) h3,.uk-tile-primary:not(.uk-preserve-color) h4,.uk-tile-primary:not(.uk-preserve-color) h5,.uk-tile-primary:not(.uk-preserve-color) h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-h1,.uk-tile-secondary:not(.uk-preserve-color) .uk-h2,.uk-tile-secondary:not(.uk-preserve-color) .uk-h3,.uk-tile-secondary:not(.uk-preserve-color) .uk-h4,.uk-tile-secondary:not(.uk-preserve-color) .uk-h5,.uk-tile-secondary:not(.uk-preserve-color) .uk-h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-secondary:not(.uk-preserve-color) h1,.uk-tile-secondary:not(.uk-preserve-color) h2,.uk-tile-secondary:not(.uk-preserve-color) h3,.uk-tile-secondary:not(.uk-preserve-color) h4,.uk-tile-secondary:not(.uk-preserve-color) h5,.uk-tile-secondary:not(.uk-preserve-color) h6{color:#fff}.uk-card-primary.uk-card-body blockquote,.uk-card-primary>:not([class*=uk-card-media]) blockquote,.uk-card-secondary.uk-card-body blockquote,.uk-card-secondary>:not([class*=uk-card-media]) blockquote,.uk-light blockquote,.uk-offcanvas-bar blockquote,.uk-overlay-primary blockquote,.uk-section-primary:not(.uk-preserve-color) blockquote,.uk-section-secondary:not(.uk-preserve-color) blockquote,.uk-tile-primary:not(.uk-preserve-color) blockquote,.uk-tile-secondary:not(.uk-preserve-color) blockquote{color:#fff}.uk-card-primary.uk-card-body blockquote footer,.uk-card-primary>:not([class*=uk-card-media]) blockquote footer,.uk-card-secondary.uk-card-body blockquote footer,.uk-card-secondary>:not([class*=uk-card-media]) blockquote footer,.uk-light blockquote footer,.uk-offcanvas-bar blockquote footer,.uk-overlay-primary blockquote footer,.uk-section-primary:not(.uk-preserve-color) blockquote footer,.uk-section-secondary:not(.uk-preserve-color) blockquote footer,.uk-tile-primary:not(.uk-preserve-color) blockquote footer,.uk-tile-secondary:not(.uk-preserve-color) blockquote footer{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-hr,.uk-card-primary.uk-card-body hr,.uk-card-primary>:not([class*=uk-card-media]) .uk-hr,.uk-card-primary>:not([class*=uk-card-media]) hr,.uk-card-secondary.uk-card-body .uk-hr,.uk-card-secondary.uk-card-body hr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-hr,.uk-card-secondary>:not([class*=uk-card-media]) hr,.uk-light .uk-hr,.uk-light hr,.uk-offcanvas-bar .uk-hr,.uk-offcanvas-bar hr,.uk-overlay-primary .uk-hr,.uk-overlay-primary hr,.uk-section-primary:not(.uk-preserve-color) .uk-hr,.uk-section-primary:not(.uk-preserve-color) hr,.uk-section-secondary:not(.uk-preserve-color) .uk-hr,.uk-section-secondary:not(.uk-preserve-color) hr,.uk-tile-primary:not(.uk-preserve-color) .uk-hr,.uk-tile-primary:not(.uk-preserve-color) hr,.uk-tile-secondary:not(.uk-preserve-color) .uk-hr,.uk-tile-secondary:not(.uk-preserve-color) hr{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-link-muted,.uk-card-primary.uk-card-body .uk-link-muted a,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-card-secondary.uk-card-body .uk-link-muted,.uk-card-secondary.uk-card-body .uk-link-muted a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-light .uk-link-muted,.uk-light .uk-link-muted a,.uk-offcanvas-bar .uk-link-muted,.uk-offcanvas-bar .uk-link-muted a,.uk-overlay-primary .uk-link-muted,.uk-overlay-primary .uk-link-muted a,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-muted a:hover,.uk-card-primary.uk-card-body .uk-link-muted:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted:hover,.uk-card-secondary.uk-card-body .uk-link-muted a:hover,.uk-card-secondary.uk-card-body .uk-link-muted:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted:hover,.uk-light .uk-link-muted a:hover,.uk-light .uk-link-muted:hover,.uk-offcanvas-bar .uk-link-muted a:hover,.uk-offcanvas-bar .uk-link-muted:hover,.uk-overlay-primary .uk-link-muted a:hover,.uk-overlay-primary .uk-link-muted:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link-text a:hover,.uk-card-primary.uk-card-body .uk-link-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-text:hover,.uk-card-secondary.uk-card-body .uk-link-text a:hover,.uk-card-secondary.uk-card-body .uk-link-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-text:hover,.uk-light .uk-link-text a:hover,.uk-light .uk-link-text:hover,.uk-offcanvas-bar .uk-link-text a:hover,.uk-offcanvas-bar .uk-link-text:hover,.uk-overlay-primary .uk-link-text a:hover,.uk-overlay-primary .uk-link-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-text:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-heading a:hover,.uk-card-primary.uk-card-body .uk-link-heading:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-heading:hover,.uk-card-secondary.uk-card-body .uk-link-heading a:hover,.uk-card-secondary.uk-card-body .uk-link-heading:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-heading:hover,.uk-light .uk-link-heading a:hover,.uk-light .uk-link-heading:hover,.uk-offcanvas-bar .uk-link-heading a:hover,.uk-offcanvas-bar .uk-link-heading:hover,.uk-overlay-primary .uk-link-heading a:hover,.uk-overlay-primary .uk-link-heading:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-heading:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-heading:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-heading:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-heading:hover{color:#fff}.uk-card-primary.uk-card-body .uk-heading-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-card-secondary.uk-card-body .uk-heading-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-light .uk-heading-divider,.uk-offcanvas-bar .uk-heading-divider,.uk-overlay-primary .uk-heading-divider,.uk-section-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-divider{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-bullet::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-card-secondary.uk-card-body .uk-heading-bullet::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-light .uk-heading-bullet::before,.uk-offcanvas-bar .uk-heading-bullet::before,.uk-overlay-primary .uk-heading-bullet::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-bullet::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-line>::after,.uk-card-primary.uk-card-body .uk-heading-line>::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-card-secondary.uk-card-body .uk-heading-line>::after,.uk-card-secondary.uk-card-body .uk-heading-line>::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-light .uk-heading-line>::after,.uk-light .uk-heading-line>::before,.uk-offcanvas-bar .uk-heading-line>::after,.uk-offcanvas-bar .uk-heading-line>::before,.uk-overlay-primary .uk-heading-line>::after,.uk-overlay-primary .uk-heading-line>::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-card-secondary.uk-card-body .uk-divider-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-light .uk-divider-icon,.uk-offcanvas-bar .uk-divider-icon,.uk-overlay-primary .uk-divider-icon,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22rgba%28255,%20255,%20255,%200.2%29%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-divider-icon::after,.uk-card-primary.uk-card-body .uk-divider-icon::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-card-secondary.uk-card-body .uk-divider-icon::after,.uk-card-secondary.uk-card-body .uk-divider-icon::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-light .uk-divider-icon::after,.uk-light .uk-divider-icon::before,.uk-offcanvas-bar .uk-divider-icon::after,.uk-offcanvas-bar .uk-divider-icon::before,.uk-overlay-primary .uk-divider-icon::after,.uk-overlay-primary .uk-divider-icon::before,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-small::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-card-secondary.uk-card-body .uk-divider-small::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-light .uk-divider-small::after,.uk-offcanvas-bar .uk-divider-small::after,.uk-overlay-primary .uk-divider-small::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-small::after{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-vertical,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-card-secondary.uk-card-body .uk-divider-vertical,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-light .uk-divider-vertical,.uk-offcanvas-bar .uk-divider-vertical,.uk-overlay-primary .uk-divider-vertical,.uk-section-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-vertical{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-muted li::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-muted li::marker,.uk-card-secondary.uk-card-body .uk-list-muted li::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-muted li::marker,.uk-light .uk-list-muted li::marker,.uk-offcanvas-bar .uk-list-muted li::marker,.uk-overlay-primary .uk-list-muted li::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-muted li::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-muted li::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-muted li::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-muted li::marker{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-list-emphasis li::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-emphasis li::marker,.uk-card-secondary.uk-card-body .uk-list-emphasis li::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-emphasis li::marker,.uk-light .uk-list-emphasis li::marker,.uk-offcanvas-bar .uk-list-emphasis li::marker,.uk-overlay-primary .uk-list-emphasis li::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-emphasis li::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-emphasis li::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-emphasis li::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-emphasis li::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-primary li::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-primary li::marker,.uk-card-secondary.uk-card-body .uk-list-primary li::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-primary li::marker,.uk-light .uk-list-primary li::marker,.uk-offcanvas-bar .uk-list-primary li::marker,.uk-overlay-primary .uk-list-primary li::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-primary li::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-primary li::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-primary li::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-primary li::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-secondary li::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-secondary li::marker,.uk-card-secondary.uk-card-body .uk-list-secondary li::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-secondary li::marker,.uk-light .uk-list-secondary li::marker,.uk-offcanvas-bar .uk-list-secondary li::marker,.uk-overlay-primary .uk-list-secondary li::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-secondary li::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-secondary li::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-secondary li::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-secondary li::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-bullet>li::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-bullet>li::before,.uk-card-secondary.uk-card-body .uk-list-bullet>li::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-bullet>li::before,.uk-light .uk-list-bullet>li::before,.uk-offcanvas-bar .uk-list-bullet>li::before,.uk-overlay-primary .uk-list-bullet>li::before,.uk-section-primary:not(.uk-preserve-color) .uk-list-bullet>li::before,.uk-section-secondary:not(.uk-preserve-color) .uk-list-bullet>li::before,.uk-tile-primary:not(.uk-preserve-color) .uk-list-bullet>li::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-bullet>li::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-list-divider>li:nth-child(n+2),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-divider>li:nth-child(n+2),.uk-card-secondary.uk-card-body .uk-list-divider>li:nth-child(n+2),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-divider>li:nth-child(n+2),.uk-light .uk-list-divider>li:nth-child(n+2),.uk-offcanvas-bar .uk-list-divider>li:nth-child(n+2),.uk-overlay-primary .uk-list-divider>li:nth-child(n+2),.uk-section-primary:not(.uk-preserve-color) .uk-list-divider>li:nth-child(n+2),.uk-section-secondary:not(.uk-preserve-color) .uk-list-divider>li:nth-child(n+2),.uk-tile-primary:not(.uk-preserve-color) .uk-list-divider>li:nth-child(n+2),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-divider>li:nth-child(n+2){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>li:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>li:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>li:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>li:nth-of-type(odd),.uk-light .uk-list-striped>li:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>li:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>li:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd){border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>li:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>li:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>li:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>li:nth-of-type(odd),.uk-light .uk-list-striped>li:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>li:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>li:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>li:nth-of-type(odd){background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-table th,.uk-card-primary>:not([class*=uk-card-media]) .uk-table th,.uk-card-secondary.uk-card-body .uk-table th,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table th,.uk-light .uk-table th,.uk-offcanvas-bar .uk-table th,.uk-overlay-primary .uk-table th,.uk-section-primary:not(.uk-preserve-color) .uk-table th,.uk-section-secondary:not(.uk-preserve-color) .uk-table th,.uk-tile-primary:not(.uk-preserve-color) .uk-table th,.uk-tile-secondary:not(.uk-preserve-color) .uk-table th{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-table caption,.uk-card-primary>:not([class*=uk-card-media]) .uk-table caption,.uk-card-secondary.uk-card-body .uk-table caption,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table caption,.uk-light .uk-table caption,.uk-offcanvas-bar .uk-table caption,.uk-overlay-primary .uk-table caption,.uk-section-primary:not(.uk-preserve-color) .uk-table caption,.uk-section-secondary:not(.uk-preserve-color) .uk-table caption,.uk-tile-primary:not(.uk-preserve-color) .uk-table caption,.uk-tile-secondary:not(.uk-preserve-color) .uk-table caption{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-primary.uk-card-body .uk-table>tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-card-secondary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-secondary.uk-card-body .uk-table>tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-light .uk-table tbody tr.uk-active,.uk-light .uk-table>tr.uk-active,.uk-offcanvas-bar .uk-table tbody tr.uk-active,.uk-offcanvas-bar .uk-table>tr.uk-active,.uk-overlay-primary .uk-table tbody tr.uk-active,.uk-overlay-primary .uk-table>tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-primary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-light .uk-table-divider>:first-child>tr:not(:first-child),.uk-light .uk-table-divider>:not(:first-child)>tr,.uk-light .uk-table-divider>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:first-child>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:not(:first-child)>tr,.uk-offcanvas-bar .uk-table-divider>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:first-child>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:not(:first-child)>tr,.uk-overlay-primary .uk-table-divider>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-light .uk-table-striped tbody tr:nth-of-type(odd),.uk-light .uk-table-striped>tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped tbody tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped>tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped tbody tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped>tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd){background:rgba(255,255,255,.1);border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-primary.uk-card-body .uk-table-hover>tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover>tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-light .uk-table-hover tbody tr:hover,.uk-light .uk-table-hover>tr:hover,.uk-offcanvas-bar .uk-table-hover tbody tr:hover,.uk-offcanvas-bar .uk-table-hover>tr:hover,.uk-overlay-primary .uk-table-hover tbody tr:hover,.uk-overlay-primary .uk-table-hover>tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link,.uk-light .uk-icon-link,.uk-offcanvas-bar .uk-icon-link,.uk-overlay-primary .uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-link:focus,.uk-card-primary.uk-card-body .uk-icon-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-card-secondary.uk-card-body .uk-icon-link:focus,.uk-card-secondary.uk-card-body .uk-icon-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-light .uk-icon-link:focus,.uk-light .uk-icon-link:hover,.uk-offcanvas-bar .uk-icon-link:focus,.uk-offcanvas-bar .uk-icon-link:hover,.uk-overlay-primary .uk-icon-link:focus,.uk-overlay-primary .uk-icon-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:focus,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-active>.uk-icon-link,.uk-card-primary.uk-card-body .uk-icon-link:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-card-secondary.uk-card-body .uk-active>.uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-light .uk-active>.uk-icon-link,.uk-light .uk-icon-link:active,.uk-offcanvas-bar .uk-active>.uk-icon-link,.uk-offcanvas-bar .uk-icon-link:active,.uk-overlay-primary .uk-active>.uk-icon-link,.uk-overlay-primary .uk-icon-link:active,.uk-section-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-section-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button,.uk-card-secondary.uk-card-body .uk-icon-button,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button,.uk-light .uk-icon-button,.uk-offcanvas-bar .uk-icon-button,.uk-overlay-primary .uk-icon-button,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-button:focus,.uk-card-primary.uk-card-body .uk-icon-button:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-card-secondary.uk-card-body .uk-icon-button:focus,.uk-card-secondary.uk-card-body .uk-icon-button:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-light .uk-icon-button:focus,.uk-light .uk-icon-button:hover,.uk-offcanvas-bar .uk-icon-button:focus,.uk-offcanvas-bar .uk-icon-button:hover,.uk-overlay-primary .uk-icon-button:focus,.uk-overlay-primary .uk-icon-button:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:focus,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:hover{background-color:rgba(242,242,242,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-card-secondary.uk-card-body .uk-icon-button:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-light .uk-icon-button:active,.uk-offcanvas-bar .uk-icon-button:active,.uk-overlay-primary .uk-icon-button:active,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:active{background-color:rgba(230,230,230,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-input,.uk-card-primary.uk-card-body .uk-select,.uk-card-primary.uk-card-body .uk-textarea,.uk-card-primary>:not([class*=uk-card-media]) .uk-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-select,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea,.uk-card-secondary.uk-card-body .uk-input,.uk-card-secondary.uk-card-body .uk-select,.uk-card-secondary.uk-card-body .uk-textarea,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea,.uk-light .uk-input,.uk-light .uk-select,.uk-light .uk-textarea,.uk-offcanvas-bar .uk-input,.uk-offcanvas-bar .uk-select,.uk-offcanvas-bar .uk-textarea,.uk-overlay-primary .uk-input,.uk-overlay-primary .uk-select,.uk-overlay-primary .uk-textarea,.uk-section-primary:not(.uk-preserve-color) .uk-input,.uk-section-primary:not(.uk-preserve-color) .uk-select,.uk-section-primary:not(.uk-preserve-color) .uk-textarea,.uk-section-secondary:not(.uk-preserve-color) .uk-input,.uk-section-secondary:not(.uk-preserve-color) .uk-select,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea,.uk-tile-primary:not(.uk-preserve-color) .uk-input,.uk-tile-primary:not(.uk-preserve-color) .uk-select,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea,.uk-tile-secondary:not(.uk-preserve-color) .uk-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-select,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7);background-clip:padding-box;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-input:focus,.uk-card-primary.uk-card-body .uk-select:focus,.uk-card-primary.uk-card-body .uk-textarea:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-card-secondary.uk-card-body .uk-input:focus,.uk-card-secondary.uk-card-body .uk-select:focus,.uk-card-secondary.uk-card-body .uk-textarea:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-light .uk-input:focus,.uk-light .uk-select:focus,.uk-light .uk-textarea:focus,.uk-offcanvas-bar .uk-input:focus,.uk-offcanvas-bar .uk-select:focus,.uk-offcanvas-bar .uk-textarea:focus,.uk-overlay-primary .uk-input:focus,.uk-overlay-primary .uk-select:focus,.uk-overlay-primary .uk-textarea:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-select:focus,.uk-section-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea:focus{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7);border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-input::-ms-input-placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-input::-ms-input-placeholder,.uk-card-secondary.uk-card-body .uk-input::-ms-input-placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input::-ms-input-placeholder,.uk-light .uk-input::-ms-input-placeholder,.uk-offcanvas-bar .uk-input::-ms-input-placeholder,.uk-overlay-primary .uk-input::-ms-input-placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-input::-ms-input-placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-input::-ms-input-placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-input::-ms-input-placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-input::-ms-input-placeholder{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-card-secondary.uk-card-body .uk-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-light .uk-input::placeholder,.uk-offcanvas-bar .uk-input::placeholder,.uk-overlay-primary .uk-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-textarea::-ms-input-placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea::-ms-input-placeholder,.uk-card-secondary.uk-card-body .uk-textarea::-ms-input-placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea::-ms-input-placeholder,.uk-light .uk-textarea::-ms-input-placeholder,.uk-offcanvas-bar .uk-textarea::-ms-input-placeholder,.uk-overlay-primary .uk-textarea::-ms-input-placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-textarea::-ms-input-placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea::-ms-input-placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea::-ms-input-placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea::-ms-input-placeholder{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-textarea::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-card-secondary.uk-card-body .uk-textarea::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-light .uk-textarea::placeholder,.uk-offcanvas-bar .uk-textarea::placeholder,.uk-overlay-primary .uk-textarea::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-primary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-card-secondary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-light .uk-select:not([multiple]):not([size]),.uk-offcanvas-bar .uk-select:not([multiple]):not([size]),.uk-overlay-primary .uk-select:not([multiple]):not([size]),.uk-section-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-section-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]){background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-input[list]:focus,.uk-card-primary.uk-card-body .uk-input[list]:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-card-secondary.uk-card-body .uk-input[list]:focus,.uk-card-secondary.uk-card-body .uk-input[list]:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-light .uk-input[list]:focus,.uk-light .uk-input[list]:hover,.uk-offcanvas-bar .uk-input[list]:focus,.uk-offcanvas-bar .uk-input[list]:hover,.uk-overlay-primary .uk-input[list]:focus,.uk-overlay-primary .uk-input[list]:hover,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox,.uk-card-primary.uk-card-body .uk-radio,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio,.uk-card-secondary.uk-card-body .uk-checkbox,.uk-card-secondary.uk-card-body .uk-radio,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio,.uk-light .uk-checkbox,.uk-light .uk-radio,.uk-offcanvas-bar .uk-checkbox,.uk-offcanvas-bar .uk-radio,.uk-overlay-primary .uk-checkbox,.uk-overlay-primary .uk-radio,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox,.uk-section-primary:not(.uk-preserve-color) .uk-radio,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-section-secondary:not(.uk-preserve-color) .uk-radio,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-primary:not(.uk-preserve-color) .uk-radio,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio{background-color:rgba(242,242,242,.1);border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-checkbox:focus,.uk-card-primary.uk-card-body .uk-radio:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-card-secondary.uk-card-body .uk-checkbox:focus,.uk-card-secondary.uk-card-body .uk-radio:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-light .uk-checkbox:focus,.uk-light .uk-radio:focus,.uk-offcanvas-bar .uk-checkbox:focus,.uk-offcanvas-bar .uk-radio:focus,.uk-overlay-primary .uk-checkbox:focus,.uk-overlay-primary .uk-radio:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:focus{border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-checkbox:checked,.uk-light .uk-checkbox:indeterminate,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-color:#fff;border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-checkbox:checked:focus,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-primary.uk-card-body .uk-radio:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-secondary.uk-card-body .uk-radio:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-light .uk-checkbox:checked:focus,.uk-light .uk-checkbox:indeterminate:focus,.uk-light .uk-radio:checked:focus,.uk-offcanvas-bar .uk-checkbox:checked:focus,.uk-offcanvas-bar .uk-checkbox:indeterminate:focus,.uk-offcanvas-bar .uk-radio:checked:focus,.uk-overlay-primary .uk-checkbox:checked:focus,.uk-overlay-primary .uk-checkbox:indeterminate:focus,.uk-overlay-primary .uk-radio:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked:focus{background-color:#e6e6e6}.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-light .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-light .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-form-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-label,.uk-card-secondary.uk-card-body .uk-form-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-label,.uk-light .uk-form-label,.uk-offcanvas-bar .uk-form-label,.uk-overlay-primary .uk-form-label,.uk-section-primary:not(.uk-preserve-color) .uk-form-label,.uk-section-secondary:not(.uk-preserve-color) .uk-form-label,.uk-tile-primary:not(.uk-preserve-color) .uk-form-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-label{color:#fff}.uk-card-primary.uk-card-body .uk-form-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon,.uk-card-secondary.uk-card-body .uk-form-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon,.uk-light .uk-form-icon,.uk-offcanvas-bar .uk-form-icon,.uk-overlay-primary .uk-form-icon,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-form-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-card-secondary.uk-card-body .uk-form-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-light .uk-form-icon:hover,.uk-offcanvas-bar .uk-form-icon:hover,.uk-overlay-primary .uk-form-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default,.uk-card-secondary.uk-card-body .uk-button-default,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default,.uk-light .uk-button-default,.uk-offcanvas-bar .uk-button-default,.uk-overlay-primary .uk-button-default,.uk-section-primary:not(.uk-preserve-color) .uk-button-default,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default{background-color:transparent;color:#fff;border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default:focus,.uk-card-primary.uk-card-body .uk-button-default:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-card-secondary.uk-card-body .uk-button-default:focus,.uk-card-secondary.uk-card-body .uk-button-default:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-light .uk-button-default:focus,.uk-light .uk-button-default:hover,.uk-offcanvas-bar .uk-button-default:focus,.uk-offcanvas-bar .uk-button-default:hover,.uk-overlay-primary .uk-button-default:focus,.uk-overlay-primary .uk-button-default:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:focus,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:hover{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-default.uk-active,.uk-card-primary.uk-card-body .uk-button-default:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-card-secondary.uk-card-body .uk-button-default.uk-active,.uk-card-secondary.uk-card-body .uk-button-default:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-light .uk-button-default.uk-active,.uk-light .uk-button-default:active,.uk-offcanvas-bar .uk-button-default.uk-active,.uk-offcanvas-bar .uk-button-default:active,.uk-overlay-primary .uk-button-default.uk-active,.uk-overlay-primary .uk-button-default:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:active{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary,.uk-card-secondary.uk-card-body .uk-button-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary,.uk-light .uk-button-primary,.uk-offcanvas-bar .uk-button-primary,.uk-overlay-primary .uk-button-primary,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-primary:focus,.uk-card-primary.uk-card-body .uk-button-primary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-card-secondary.uk-card-body .uk-button-primary:focus,.uk-card-secondary.uk-card-body .uk-button-primary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-light .uk-button-primary:focus,.uk-light .uk-button-primary:hover,.uk-offcanvas-bar .uk-button-primary:focus,.uk-offcanvas-bar .uk-button-primary:hover,.uk-overlay-primary .uk-button-primary:focus,.uk-overlay-primary .uk-button-primary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:focus,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-primary.uk-active,.uk-card-primary.uk-card-body .uk-button-primary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-card-secondary.uk-card-body .uk-button-primary.uk-active,.uk-card-secondary.uk-card-body .uk-button-primary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-light .uk-button-primary.uk-active,.uk-light .uk-button-primary:active,.uk-offcanvas-bar .uk-button-primary.uk-active,.uk-offcanvas-bar .uk-button-primary:active,.uk-overlay-primary .uk-button-primary.uk-active,.uk-overlay-primary .uk-button-primary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-card-secondary.uk-card-body .uk-button-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-light .uk-button-secondary,.uk-offcanvas-bar .uk-button-secondary,.uk-overlay-primary .uk-button-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary:focus,.uk-card-primary.uk-card-body .uk-button-secondary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-card-secondary.uk-card-body .uk-button-secondary:focus,.uk-card-secondary.uk-card-body .uk-button-secondary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-light .uk-button-secondary:focus,.uk-light .uk-button-secondary:hover,.uk-offcanvas-bar .uk-button-secondary:focus,.uk-offcanvas-bar .uk-button-secondary:hover,.uk-overlay-primary .uk-button-secondary:focus,.uk-overlay-primary .uk-button-secondary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:focus,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary.uk-active,.uk-card-primary.uk-card-body .uk-button-secondary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-card-secondary.uk-card-body .uk-button-secondary.uk-active,.uk-card-secondary.uk-card-body .uk-button-secondary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-light .uk-button-secondary.uk-active,.uk-light .uk-button-secondary:active,.uk-offcanvas-bar .uk-button-secondary.uk-active,.uk-offcanvas-bar .uk-button-secondary:active,.uk-overlay-primary .uk-button-secondary.uk-active,.uk-overlay-primary .uk-button-secondary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-text,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text,.uk-card-secondary.uk-card-body .uk-button-text,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text,.uk-light .uk-button-text,.uk-offcanvas-bar .uk-button-text,.uk-overlay-primary .uk-button-text,.uk-section-primary:not(.uk-preserve-color) .uk-button-text,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text{color:#fff}.uk-card-primary.uk-card-body .uk-button-text::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-card-secondary.uk-card-body .uk-button-text::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-light .uk-button-text::before,.uk-offcanvas-bar .uk-button-text::before,.uk-overlay-primary .uk-button-text::before,.uk-section-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text::before{border-bottom-color:#fff}.uk-card-primary.uk-card-body .uk-button-text:focus,.uk-card-primary.uk-card-body .uk-button-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-card-secondary.uk-card-body .uk-button-text:focus,.uk-card-secondary.uk-card-body .uk-button-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-light .uk-button-text:focus,.uk-light .uk-button-text:hover,.uk-offcanvas-bar .uk-button-text:focus,.uk-offcanvas-bar .uk-button-text:hover,.uk-overlay-primary .uk-button-text:focus,.uk-overlay-primary .uk-button-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:focus,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:hover{color:#fff}.uk-card-primary.uk-card-body .uk-button-text:disabled,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-card-secondary.uk-card-body .uk-button-text:disabled,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-light .uk-button-text:disabled,.uk-offcanvas-bar .uk-button-text:disabled,.uk-overlay-primary .uk-button-text:disabled,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:disabled{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-button-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link,.uk-card-secondary.uk-card-body .uk-button-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link,.uk-light .uk-button-link,.uk-offcanvas-bar .uk-button-link,.uk-overlay-primary .uk-button-link,.uk-section-primary:not(.uk-preserve-color) .uk-button-link,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-button-link:focus,.uk-card-primary.uk-card-body .uk-button-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-card-secondary.uk-card-body .uk-button-link:focus,.uk-card-secondary.uk-card-body .uk-button-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-light .uk-button-link:focus,.uk-light .uk-button-link:hover,.uk-offcanvas-bar .uk-button-link:focus,.uk-offcanvas-bar .uk-button-link:hover,.uk-overlay-primary .uk-button-link:focus,.uk-overlay-primary .uk-button-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-link:focus,.uk-section-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-light .uk-grid-divider>:not(.uk-first-column)::before,.uk-offcanvas-bar .uk-grid-divider>:not(.uk-first-column)::before,.uk-overlay-primary .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-light .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-offcanvas-bar .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-overlay-primary .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-close,.uk-card-primary>:not([class*=uk-card-media]) .uk-close,.uk-card-secondary.uk-card-body .uk-close,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close,.uk-light .uk-close,.uk-offcanvas-bar .uk-close,.uk-overlay-primary .uk-close,.uk-section-primary:not(.uk-preserve-color) .uk-close,.uk-section-secondary:not(.uk-preserve-color) .uk-close,.uk-tile-primary:not(.uk-preserve-color) .uk-close,.uk-tile-secondary:not(.uk-preserve-color) .uk-close{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-close:focus,.uk-card-primary.uk-card-body .uk-close:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-close:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-close:hover,.uk-card-secondary.uk-card-body .uk-close:focus,.uk-card-secondary.uk-card-body .uk-close:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close:hover,.uk-light .uk-close:focus,.uk-light .uk-close:hover,.uk-offcanvas-bar .uk-close:focus,.uk-offcanvas-bar .uk-close:hover,.uk-overlay-primary .uk-close:focus,.uk-overlay-primary .uk-close:hover,.uk-section-primary:not(.uk-preserve-color) .uk-close:focus,.uk-section-primary:not(.uk-preserve-color) .uk-close:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-close:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-close:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-close:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-close:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop,.uk-card-secondary.uk-card-body .uk-totop,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop,.uk-light .uk-totop,.uk-offcanvas-bar .uk-totop,.uk-overlay-primary .uk-totop,.uk-section-primary:not(.uk-preserve-color) .uk-totop,.uk-section-secondary:not(.uk-preserve-color) .uk-totop,.uk-tile-primary:not(.uk-preserve-color) .uk-totop,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-totop:focus,.uk-card-primary.uk-card-body .uk-totop:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-card-secondary.uk-card-body .uk-totop:focus,.uk-card-secondary.uk-card-body .uk-totop:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-light .uk-totop:focus,.uk-light .uk-totop:hover,.uk-offcanvas-bar .uk-totop:focus,.uk-offcanvas-bar .uk-totop:hover,.uk-overlay-primary .uk-totop:focus,.uk-overlay-primary .uk-totop:hover,.uk-section-primary:not(.uk-preserve-color) .uk-totop:focus,.uk-section-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:active,.uk-card-secondary.uk-card-body .uk-totop:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:active,.uk-light .uk-totop:active,.uk-offcanvas-bar .uk-totop:active,.uk-overlay-primary .uk-totop:active,.uk-section-primary:not(.uk-preserve-color) .uk-totop:active,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:active{color:#fff}.uk-card-primary.uk-card-body .uk-marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker,.uk-card-secondary.uk-card-body .uk-marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker,.uk-light .uk-marker,.uk-offcanvas-bar .uk-marker,.uk-overlay-primary .uk-marker,.uk-section-primary:not(.uk-preserve-color) .uk-marker,.uk-section-secondary:not(.uk-preserve-color) .uk-marker,.uk-tile-primary:not(.uk-preserve-color) .uk-marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker{background:#f8f8f8;color:#666}.uk-card-primary.uk-card-body .uk-marker:focus,.uk-card-primary.uk-card-body .uk-marker:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-card-secondary.uk-card-body .uk-marker:focus,.uk-card-secondary.uk-card-body .uk-marker:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-light .uk-marker:focus,.uk-light .uk-marker:hover,.uk-offcanvas-bar .uk-marker:focus,.uk-offcanvas-bar .uk-marker:hover,.uk-overlay-primary .uk-marker:focus,.uk-overlay-primary .uk-marker:hover,.uk-section-primary:not(.uk-preserve-color) .uk-marker:focus,.uk-section-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-marker:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-marker:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker:hover{color:#666}.uk-card-primary.uk-card-body .uk-badge,.uk-card-primary>:not([class*=uk-card-media]) .uk-badge,.uk-card-secondary.uk-card-body .uk-badge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-badge,.uk-light .uk-badge,.uk-offcanvas-bar .uk-badge,.uk-overlay-primary .uk-badge,.uk-section-primary:not(.uk-preserve-color) .uk-badge,.uk-section-secondary:not(.uk-preserve-color) .uk-badge,.uk-tile-primary:not(.uk-preserve-color) .uk-badge,.uk-tile-secondary:not(.uk-preserve-color) .uk-badge{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-badge:focus,.uk-card-primary.uk-card-body .uk-badge:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-badge:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-badge:hover,.uk-card-secondary.uk-card-body .uk-badge:focus,.uk-card-secondary.uk-card-body .uk-badge:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-badge:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-badge:hover,.uk-light .uk-badge:focus,.uk-light .uk-badge:hover,.uk-offcanvas-bar .uk-badge:focus,.uk-offcanvas-bar .uk-badge:hover,.uk-overlay-primary .uk-badge:focus,.uk-overlay-primary .uk-badge:hover,.uk-section-primary:not(.uk-preserve-color) .uk-badge:focus,.uk-section-primary:not(.uk-preserve-color) .uk-badge:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-badge:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-badge:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-badge:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-badge:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-badge:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-badge:hover{color:#666}.uk-card-primary.uk-card-body .uk-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-label,.uk-card-secondary.uk-card-body .uk-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-label,.uk-light .uk-label,.uk-offcanvas-bar .uk-label,.uk-overlay-primary .uk-label,.uk-section-primary:not(.uk-preserve-color) .uk-label,.uk-section-secondary:not(.uk-preserve-color) .uk-label,.uk-tile-primary:not(.uk-preserve-color) .uk-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-label{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-article-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-article-meta,.uk-card-secondary.uk-card-body .uk-article-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-article-meta,.uk-light .uk-article-meta,.uk-offcanvas-bar .uk-article-meta,.uk-overlay-primary .uk-article-meta,.uk-section-primary:not(.uk-preserve-color) .uk-article-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-article-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input,.uk-light .uk-search-input,.uk-offcanvas-bar .uk-search-input,.uk-overlay-primary .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-search-input:-ms-input-placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input:-ms-input-placeholder,.uk-card-secondary.uk-card-body .uk-search-input:-ms-input-placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input:-ms-input-placeholder,.uk-light .uk-search-input:-ms-input-placeholder,.uk-offcanvas-bar .uk-search-input:-ms-input-placeholder,.uk-overlay-primary .uk-search-input:-ms-input-placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-search-input:-ms-input-placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input:-ms-input-placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input:-ms-input-placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input:-ms-input-placeholder{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-search-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-card-secondary.uk-card-body .uk-search-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-light .uk-search-input::placeholder,.uk-offcanvas-bar .uk-search-input::placeholder,.uk-overlay-primary .uk-search-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-light .uk-search .uk-search-icon,.uk-offcanvas-bar .uk-search .uk-search-icon,.uk-overlay-primary .uk-search .uk-search-icon,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-light .uk-search .uk-search-icon:hover,.uk-offcanvas-bar .uk-search .uk-search-icon:hover,.uk-overlay-primary .uk-search .uk-search-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-light .uk-search-default .uk-search-input,.uk-offcanvas-bar .uk-search-default .uk-search-input,.uk-overlay-primary .uk-search-default .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-light .uk-search-default .uk-search-input:focus,.uk-offcanvas-bar .uk-search-default .uk-search-input:focus,.uk-overlay-primary .uk-search-default .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus{background-color:transparent}.uk-card-primary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-light .uk-search-navbar .uk-search-input,.uk-offcanvas-bar .uk-search-navbar .uk-search-input,.uk-overlay-primary .uk-search-navbar .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input{background-color:transparent}.uk-card-primary.uk-card-body .uk-search-large .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-large .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-light .uk-search-large .uk-search-input,.uk-offcanvas-bar .uk-search-large .uk-search-input,.uk-overlay-primary .uk-search-large .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input{background-color:transparent}.uk-card-primary.uk-card-body .uk-search-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-card-secondary.uk-card-body .uk-search-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-light .uk-search-toggle,.uk-offcanvas-bar .uk-search-toggle,.uk-overlay-primary .uk-search-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-toggle:focus,.uk-card-primary.uk-card-body .uk-search-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-card-secondary.uk-card-body .uk-search-toggle:focus,.uk-card-secondary.uk-card-body .uk-search-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-light .uk-search-toggle:focus,.uk-light .uk-search-toggle:hover,.uk-offcanvas-bar .uk-search-toggle:focus,.uk-offcanvas-bar .uk-search-toggle:hover,.uk-overlay-primary .uk-search-toggle:focus,.uk-overlay-primary .uk-search-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-parent-icon>.uk-parent>a::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-parent-icon>.uk-parent>a::after,.uk-card-secondary.uk-card-body .uk-nav-parent-icon>.uk-parent>a::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-parent-icon>.uk-parent>a::after,.uk-light .uk-nav-parent-icon>.uk-parent>a::after,.uk-offcanvas-bar .uk-nav-parent-icon>.uk-parent>a::after,.uk-overlay-primary .uk-nav-parent-icon>.uk-parent>a::after,.uk-section-primary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent>a::after,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent>a::after,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent>a::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent>a::after{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-card-secondary.uk-card-body .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-light .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-offcanvas-bar .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-overlay-primary .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-section-primary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent.uk-open>a::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-parent-icon>.uk-parent.uk-open>a::after{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-nav-default>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-card-secondary.uk-card-body .uk-nav-default>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-light .uk-nav-default>li>a,.uk-offcanvas-bar .uk-nav-default>li>a,.uk-overlay-primary .uk-nav-default>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default>li>a:focus,.uk-card-primary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-default>li>a:focus,.uk-card-secondary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-light .uk-nav-default>li>a:focus,.uk-light .uk-nav-default>li>a:hover,.uk-offcanvas-bar .uk-nav-default>li>a:focus,.uk-offcanvas-bar .uk-nav-default>li>a:hover,.uk-overlay-primary .uk-nav-default>li>a:focus,.uk-overlay-primary .uk-nav-default>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-light .uk-nav-default>li.uk-active>a,.uk-offcanvas-bar .uk-nav-default>li.uk-active>a,.uk-overlay-primary .uk-nav-default>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-light .uk-nav-default .uk-nav-header,.uk-offcanvas-bar .uk-nav-default .uk-nav-header,.uk-overlay-primary .uk-nav-default .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-light .uk-nav-default .uk-nav-divider,.uk-offcanvas-bar .uk-nav-default .uk-nav-divider,.uk-overlay-primary .uk-nav-default .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-light .uk-nav-default .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a,.uk-overlay-primary .uk-nav-default .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a:focus,.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a:focus,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-light .uk-nav-default .uk-nav-sub a:focus,.uk-light .uk-nav-default .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a:focus,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-default .uk-nav-sub a:focus,.uk-overlay-primary .uk-nav-default .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-light .uk-nav-primary>li>a,.uk-offcanvas-bar .uk-nav-primary>li>a,.uk-overlay-primary .uk-nav-primary>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary>li>a:focus,.uk-card-primary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a:focus,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-light .uk-nav-primary>li>a:focus,.uk-light .uk-nav-primary>li>a:hover,.uk-offcanvas-bar .uk-nav-primary>li>a:focus,.uk-offcanvas-bar .uk-nav-primary>li>a:hover,.uk-overlay-primary .uk-nav-primary>li>a:focus,.uk-overlay-primary .uk-nav-primary>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-light .uk-nav-primary>li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary>li.uk-active>a,.uk-overlay-primary .uk-nav-primary>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-light .uk-nav-primary .uk-nav-header,.uk-offcanvas-bar .uk-nav-primary .uk-nav-header,.uk-overlay-primary .uk-nav-primary .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-light .uk-nav-primary .uk-nav-divider,.uk-offcanvas-bar .uk-nav-primary .uk-nav-divider,.uk-overlay-primary .uk-nav-primary .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-light .uk-nav-primary .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a:focus,.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a:focus,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-light .uk-nav-primary .uk-nav-sub a:focus,.uk-light .uk-nav-primary .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a:focus,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a:focus,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-light .uk-navbar-nav>li>a,.uk-offcanvas-bar .uk-navbar-nav>li>a,.uk-overlay-primary .uk-navbar-nav>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-primary.uk-card-body .uk-navbar-nav>li>a.uk-open,.uk-card-primary.uk-card-body .uk-navbar-nav>li>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a.uk-open,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:focus,.uk-card-secondary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a.uk-open,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a.uk-open,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:focus,.uk-light .uk-navbar-nav>li:hover>a,.uk-light .uk-navbar-nav>li>a.uk-open,.uk-light .uk-navbar-nav>li>a:focus,.uk-offcanvas-bar .uk-navbar-nav>li:hover>a,.uk-offcanvas-bar .uk-navbar-nav>li>a.uk-open,.uk-offcanvas-bar .uk-navbar-nav>li>a:focus,.uk-overlay-primary .uk-navbar-nav>li:hover>a,.uk-overlay-primary .uk-navbar-nav>li>a.uk-open,.uk-overlay-primary .uk-navbar-nav>li>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a.uk-open,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a.uk-open,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a.uk-open,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a.uk-open,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:focus{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-light .uk-navbar-nav>li>a:active,.uk-offcanvas-bar .uk-navbar-nav>li>a:active,.uk-overlay-primary .uk-navbar-nav>li>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-light .uk-navbar-nav>li.uk-active>a,.uk-offcanvas-bar .uk-navbar-nav>li.uk-active>a,.uk-overlay-primary .uk-navbar-nav>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-item,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-card-secondary.uk-card-body .uk-navbar-item,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-light .uk-navbar-item,.uk-offcanvas-bar .uk-navbar-item,.uk-overlay-primary .uk-navbar-item,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-item{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-card-secondary.uk-card-body .uk-navbar-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-light .uk-navbar-toggle,.uk-offcanvas-bar .uk-navbar-toggle,.uk-overlay-primary .uk-navbar-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-toggle.uk-open,.uk-card-primary.uk-card-body .uk-navbar-toggle:focus,.uk-card-primary.uk-card-body .uk-navbar-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle.uk-open,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-card-secondary.uk-card-body .uk-navbar-toggle.uk-open,.uk-card-secondary.uk-card-body .uk-navbar-toggle:focus,.uk-card-secondary.uk-card-body .uk-navbar-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle.uk-open,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-light .uk-navbar-toggle.uk-open,.uk-light .uk-navbar-toggle:focus,.uk-light .uk-navbar-toggle:hover,.uk-offcanvas-bar .uk-navbar-toggle.uk-open,.uk-offcanvas-bar .uk-navbar-toggle:focus,.uk-offcanvas-bar .uk-navbar-toggle:hover,.uk-overlay-primary .uk-navbar-toggle.uk-open,.uk-overlay-primary .uk-navbar-toggle:focus,.uk-overlay-primary .uk-navbar-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle.uk-open,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle:focus,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle.uk-open,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle.uk-open,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle.uk-open,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-light .uk-subnav>*>:first-child,.uk-offcanvas-bar .uk-subnav>*>:first-child,.uk-overlay-primary .uk-subnav>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav>*>a:focus,.uk-card-primary.uk-card-body .uk-subnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav>*>a:focus,.uk-card-secondary.uk-card-body .uk-subnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-light .uk-subnav>*>a:focus,.uk-light .uk-subnav>*>a:hover,.uk-offcanvas-bar .uk-subnav>*>a:focus,.uk-offcanvas-bar .uk-subnav>*>a:hover,.uk-overlay-primary .uk-subnav>*>a:focus,.uk-overlay-primary .uk-subnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-light .uk-subnav>.uk-active>a,.uk-offcanvas-bar .uk-subnav>.uk-active>a,.uk-overlay-primary .uk-subnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-light .uk-subnav-pill>*>:first-child,.uk-offcanvas-bar .uk-subnav-pill>*>:first-child,.uk-overlay-primary .uk-subnav-pill>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child{background-color:transparent;color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:focus,.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:focus,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-light .uk-subnav-pill>*>a:focus,.uk-light .uk-subnav-pill>*>a:hover,.uk-offcanvas-bar .uk-subnav-pill>*>a:focus,.uk-offcanvas-bar .uk-subnav-pill>*>a:hover,.uk-overlay-primary .uk-subnav-pill>*>a:focus,.uk-overlay-primary .uk-subnav-pill>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-light .uk-subnav-pill>*>a:active,.uk-offcanvas-bar .uk-subnav-pill>*>a:active,.uk-overlay-primary .uk-subnav-pill>*>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-light .uk-subnav-pill>.uk-active>a,.uk-offcanvas-bar .uk-subnav-pill>.uk-active>a,.uk-overlay-primary .uk-subnav-pill>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-light .uk-subnav>.uk-disabled>a,.uk-offcanvas-bar .uk-subnav>.uk-disabled>a,.uk-overlay-primary .uk-subnav>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-light .uk-breadcrumb>*>*,.uk-offcanvas-bar .uk-breadcrumb>*>*,.uk-overlay-primary .uk-breadcrumb>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>:focus,.uk-card-primary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>:focus,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-light .uk-breadcrumb>*>:focus,.uk-light .uk-breadcrumb>*>:hover,.uk-offcanvas-bar .uk-breadcrumb>*>:focus,.uk-offcanvas-bar .uk-breadcrumb>*>:hover,.uk-overlay-primary .uk-breadcrumb>*>:focus,.uk-overlay-primary .uk-breadcrumb>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:focus,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-light .uk-breadcrumb>:last-child>*,.uk-offcanvas-bar .uk-breadcrumb>:last-child>*,.uk-overlay-primary .uk-breadcrumb>:last-child>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-card-secondary.uk-card-body .uk-pagination>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-light .uk-pagination>*>*,.uk-offcanvas-bar .uk-pagination>*>*,.uk-overlay-primary .uk-pagination>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>:focus,.uk-card-primary.uk-card-body .uk-pagination>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-card-secondary.uk-card-body .uk-pagination>*>:focus,.uk-card-secondary.uk-card-body .uk-pagination>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-light .uk-pagination>*>:focus,.uk-light .uk-pagination>*>:hover,.uk-offcanvas-bar .uk-pagination>*>:focus,.uk-offcanvas-bar .uk-pagination>*>:hover,.uk-overlay-primary .uk-pagination>*>:focus,.uk-overlay-primary .uk-pagination>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>:focus,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-light .uk-pagination>.uk-active>*,.uk-offcanvas-bar .uk-pagination>.uk-active>*,.uk-overlay-primary .uk-pagination>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-light .uk-pagination>.uk-disabled>*,.uk-offcanvas-bar .uk-pagination>.uk-disabled>*,.uk-overlay-primary .uk-pagination>.uk-disabled>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab::before,.uk-card-secondary.uk-card-body .uk-tab::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab::before,.uk-light .uk-tab::before,.uk-offcanvas-bar .uk-tab::before,.uk-overlay-primary .uk-tab::before,.uk-section-primary:not(.uk-preserve-color) .uk-tab::before,.uk-section-secondary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-primary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab::before{border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-tab>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-card-secondary.uk-card-body .uk-tab>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-light .uk-tab>*>a,.uk-offcanvas-bar .uk-tab>*>a,.uk-overlay-primary .uk-tab>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab>*>a:focus,.uk-card-primary.uk-card-body .uk-tab>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-card-secondary.uk-card-body .uk-tab>*>a:focus,.uk-card-secondary.uk-card-body .uk-tab>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-light .uk-tab>*>a:focus,.uk-light .uk-tab>*>a:hover,.uk-offcanvas-bar .uk-tab>*>a:focus,.uk-offcanvas-bar .uk-tab>*>a:hover,.uk-overlay-primary .uk-tab>*>a:focus,.uk-overlay-primary .uk-tab>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-tab>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-light .uk-tab>.uk-active>a,.uk-offcanvas-bar .uk-tab>.uk-active>a,.uk-overlay-primary .uk-tab>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a{color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-light .uk-tab>.uk-disabled>a,.uk-offcanvas-bar .uk-tab>.uk-disabled>a,.uk-overlay-primary .uk-tab>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-slidenav,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav,.uk-card-secondary.uk-card-body .uk-slidenav,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav,.uk-light .uk-slidenav,.uk-offcanvas-bar .uk-slidenav,.uk-overlay-primary .uk-slidenav,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-slidenav:focus,.uk-card-primary.uk-card-body .uk-slidenav:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-card-secondary.uk-card-body .uk-slidenav:focus,.uk-card-secondary.uk-card-body .uk-slidenav:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-light .uk-slidenav:focus,.uk-light .uk-slidenav:hover,.uk-offcanvas-bar .uk-slidenav:focus,.uk-offcanvas-bar .uk-slidenav:hover,.uk-overlay-primary .uk-slidenav:focus,.uk-overlay-primary .uk-slidenav:hover,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:focus,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:hover{color:rgba(255,255,255,.95)}.uk-card-primary.uk-card-body .uk-slidenav:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-card-secondary.uk-card-body .uk-slidenav:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-light .uk-slidenav:active,.uk-offcanvas-bar .uk-slidenav:active,.uk-overlay-primary .uk-slidenav:active,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-dotnav>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-card-secondary.uk-card-body .uk-dotnav>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-light .uk-dotnav>*>*,.uk-offcanvas-bar .uk-dotnav>*>*,.uk-overlay-primary .uk-dotnav>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>*{background-color:transparent;border-color:rgba(255,255,255,.9)}.uk-card-primary.uk-card-body .uk-dotnav>*>:focus,.uk-card-primary.uk-card-body .uk-dotnav>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-card-secondary.uk-card-body .uk-dotnav>*>:focus,.uk-card-secondary.uk-card-body .uk-dotnav>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-light .uk-dotnav>*>:focus,.uk-light .uk-dotnav>*>:hover,.uk-offcanvas-bar .uk-dotnav>*>:focus,.uk-offcanvas-bar .uk-dotnav>*>:hover,.uk-overlay-primary .uk-dotnav>*>:focus,.uk-overlay-primary .uk-dotnav>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:focus,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>*>:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-card-secondary.uk-card-body .uk-dotnav>*>:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-light .uk-dotnav>*>:active,.uk-offcanvas-bar .uk-dotnav>*>:active,.uk-overlay-primary .uk-dotnav>*>:active,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active{background-color:rgba(255,255,255,.5);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-card-secondary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-light .uk-dotnav>.uk-active>*,.uk-offcanvas-bar .uk-dotnav>.uk-active>*,.uk-overlay-primary .uk-dotnav>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-accordion-title,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-card-secondary.uk-card-body .uk-accordion-title,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-light .uk-accordion-title,.uk-offcanvas-bar .uk-accordion-title,.uk-overlay-primary .uk-accordion-title,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title{color:#fff}.uk-card-primary.uk-card-body .uk-accordion-title:focus,.uk-card-primary.uk-card-body .uk-accordion-title:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-card-secondary.uk-card-body .uk-accordion-title:focus,.uk-card-secondary.uk-card-body .uk-accordion-title:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-light .uk-accordion-title:focus,.uk-light .uk-accordion-title:hover,.uk-offcanvas-bar .uk-accordion-title:focus,.uk-offcanvas-bar .uk-accordion-title:hover,.uk-overlay-primary .uk-accordion-title:focus,.uk-overlay-primary .uk-accordion-title:hover,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title:focus,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-iconnav>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-card-secondary.uk-card-body .uk-iconnav>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-light .uk-iconnav>*>a,.uk-offcanvas-bar .uk-iconnav>*>a,.uk-overlay-primary .uk-iconnav>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-iconnav>*>a:focus,.uk-card-primary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-iconnav>*>a:focus,.uk-card-secondary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-light .uk-iconnav>*>a:focus,.uk-light .uk-iconnav>*>a:hover,.uk-offcanvas-bar .uk-iconnav>*>a:focus,.uk-offcanvas-bar .uk-iconnav>*>a:hover,.uk-overlay-primary .uk-iconnav>*>a:focus,.uk-overlay-primary .uk-iconnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a:focus,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-light .uk-iconnav>.uk-active>a,.uk-offcanvas-bar .uk-iconnav>.uk-active>a,.uk-overlay-primary .uk-iconnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-text-lead,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-lead,.uk-card-secondary.uk-card-body .uk-text-lead,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-lead,.uk-light .uk-text-lead,.uk-offcanvas-bar .uk-text-lead,.uk-overlay-primary .uk-text-lead,.uk-section-primary:not(.uk-preserve-color) .uk-text-lead,.uk-section-secondary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-primary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-lead{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-text-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-meta,.uk-card-secondary.uk-card-body .uk-text-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-meta,.uk-light .uk-text-meta,.uk-offcanvas-bar .uk-text-meta,.uk-overlay-primary .uk-text-meta,.uk-section-primary:not(.uk-preserve-color) .uk-text-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-text-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-muted,.uk-card-secondary.uk-card-body .uk-text-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-muted,.uk-light .uk-text-muted,.uk-offcanvas-bar .uk-text-muted,.uk-overlay-primary .uk-text-muted,.uk-section-primary:not(.uk-preserve-color) .uk-text-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-muted{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-text-emphasis,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-card-secondary.uk-card-body .uk-text-emphasis,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-light .uk-text-emphasis,.uk-offcanvas-bar .uk-text-emphasis,.uk-overlay-primary .uk-text-emphasis,.uk-section-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-section-secondary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-emphasis{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-primary,.uk-card-secondary.uk-card-body .uk-text-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-primary,.uk-light .uk-text-primary,.uk-offcanvas-bar .uk-text-primary,.uk-overlay-primary .uk-text-primary,.uk-section-primary:not(.uk-preserve-color) .uk-text-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-primary{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-card-secondary.uk-card-body .uk-text-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-light .uk-text-secondary,.uk-offcanvas-bar .uk-text-secondary,.uk-overlay-primary .uk-text-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-secondary{color:#fff!important}.uk-card-primary.uk-card-body .uk-column-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-column-divider,.uk-card-secondary.uk-card-body .uk-column-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-column-divider,.uk-light .uk-column-divider,.uk-offcanvas-bar .uk-column-divider,.uk-overlay-primary .uk-column-divider,.uk-section-primary:not(.uk-preserve-color) .uk-column-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-column-divider{column-rule-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-logo,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo,.uk-card-secondary.uk-card-body .uk-logo,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo,.uk-light .uk-logo,.uk-offcanvas-bar .uk-logo,.uk-overlay-primary .uk-logo,.uk-section-primary:not(.uk-preserve-color) .uk-logo,.uk-section-secondary:not(.uk-preserve-color) .uk-logo,.uk-tile-primary:not(.uk-preserve-color) .uk-logo,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-logo:focus,.uk-card-primary.uk-card-body .uk-logo:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-card-secondary.uk-card-body .uk-logo:focus,.uk-card-secondary.uk-card-body .uk-logo:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-light .uk-logo:focus,.uk-light .uk-logo:hover,.uk-offcanvas-bar .uk-logo:focus,.uk-offcanvas-bar .uk-logo:hover,.uk-overlay-primary .uk-logo:focus,.uk-overlay-primary .uk-logo:hover,.uk-section-primary:not(.uk-preserve-color) .uk-logo:focus,.uk-section-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-logo:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-logo:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-card-primary>:not([class*=uk-card-media]) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-card-secondary.uk-card-body .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-light .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-offcanvas-bar .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-overlay-primary .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-section-primary:not(.uk-preserve-color) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-section-secondary:not(.uk-preserve-color) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-tile-primary:not(.uk-preserve-color) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type),.uk-tile-secondary:not(.uk-preserve-color) .uk-logo>:not(.uk-logo-inverse):not(:only-of-type){display:none}.uk-card-primary.uk-card-body .uk-logo-inverse,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-card-secondary.uk-card-body .uk-logo-inverse,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-light .uk-logo-inverse,.uk-offcanvas-bar .uk-logo-inverse,.uk-overlay-primary .uk-logo-inverse,.uk-section-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-section-secondary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo-inverse{display:inline}.uk-card-primary.uk-card-body .uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-light .uk-accordion-title::before,.uk-offcanvas-bar .uk-accordion-title::before,.uk-overlay-primary .uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-light .uk-open>.uk-accordion-title::before,.uk-offcanvas-bar .uk-open>.uk-accordion-title::before,.uk-overlay-primary .uk-open>.uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}@media print{*,::after,::before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}}
\ No newline at end of file
diff --git a/webclient/view/default/ui/js/suggest-tag.js b/webclient/view/default/ui/js/suggest-tag.js
new file mode 100644 (file)
index 0000000..2cfdcef
--- /dev/null
@@ -0,0 +1,137 @@
+/**
+ * remove a tag from the tag "cloud"
+ *
+ * @param String tagString
+ * @param String targetStartString
+ */
+function removeTag(tagString,targetStartString) {
+    let toRemove = document.getElementById(targetStartString + '-' + tagString);
+    let saveInput = document.getElementById(targetStartString + '-save');
+
+    if(toRemove && saveInput) {
+        let newSaveValue = _removeFromCommaString(saveInput.value,tagString);
+        saveInput.value = newSaveValue;
+        toRemove.remove();
+    }
+    else {
+        console.log("Delete element not found");
+    }
+}
+
+/**
+ * add a tag to the visible tag "cloud" and hidden form input
+ * used in the form for saving
+ *
+ * @param Object e
+ * @param String targetStartString
+ */
+function addTag(e,targetStartString) {
+    e = e || window.event;
+
+    if(e.keyCode === 13) {
+        let elem = e.srcElement || e.target;
+        let saveInput = document.getElementById(targetStartString + '-save');
+        let listBox = document.getElementById(targetStartString + '-listbox');
+        let newTagTemplate = document.getElementById(targetStartString + '-template');
+
+        if(saveInput && listBox && elem && newTagTemplate) {
+            let toAdd = elem.value;
+            let newSaveValue = _appendToCommaString(saveInput.value,toAdd);
+
+            let newT = newTagTemplate.cloneNode(true);
+            newT = _fillTagTemplate(newT,toAdd,targetStartString);
+            listBox.appendChild(newT);
+
+            saveInput.value = newSaveValue;
+        }
+
+        elem.value = '';
+        e.preventDefault();
+    }
+}
+
+/**
+ * add given string to given existing string seperated with a comma
+ *
+ * @param String theString
+ * @param String toAdd
+ * @returns {string}
+ * @private
+ */
+function _appendToCommaString(theString,toAdd) {
+    if(theString.length > 0 && toAdd.length > 0) {
+        let theArray = theString.split(',');
+        if(!theArray.includes(toAdd)) {
+            theString = theString + "," + toAdd
+        }
+    }
+    else if (toAdd.length > 0) {
+        theString = toAdd;
+    }
+
+    return theString;
+}
+
+/**
+ * add given string to given existing string seperated with a comma
+ *
+ * @param String theString
+ * @param String toAdd
+ * @returns {string}
+ * @private
+ */
+function _removeFromCommaString(theString,toRemove) {
+    if(theString.length > 0 && toRemove.length > 0) {
+        let theArray = theString.split(',');
+
+        if(theArray.includes(toRemove)) {
+            for( let i = theArray.length-1; i >= 0; i--){
+                if ( theArray[i] === toRemove) theArray.splice(i, 1);
+            }
+
+            theString = theArray.join(",");
+        }
+    }
+
+    return theString;
+}
+
+/**
+ * remove from given list the given value if it exists
+ *
+ * @param Object list
+ * @param String value
+ * @private
+ */
+function _removeFromDatalist(list, value) {
+    if(list.options.length > 0 && value && value.length > 0) {
+        for (i = 0; i < list.options.length; i++) {
+            if(list.options[i].value == value) {
+                list.options[i].remove();
+            }
+        }
+    }
+}
+
+/**
+ * fill the tag template with the right data and js calls
+ * depends on the html template created in the html code
+ *
+ * @param Object el The already cloned node
+ * @param String newTagString The new tag name
+ * @param String targetStartString
+ * @returns Object the cloned el
+ * @private
+ */
+function _fillTagTemplate(el,newTagString,targetStartString) {
+    el.removeAttribute('style');
+    el.setAttribute('id',targetStartString + '-' + newTagString);
+
+    let spanEl = el.querySelector('span');
+    spanEl.innerHTML = newTagString;
+
+    let aEl = el.querySelector('a');
+    aEl.setAttribute('onclick', "removeTag('"+newTagString+"','"+targetStartString+"');");
+
+    return el;
+}
diff --git a/webclient/view/default/ui/js/uikit-icons.min.js b/webclient/view/default/ui/js/uikit-icons.min.js
new file mode 100644 (file)
index 0000000..2f980c0
--- /dev/null
@@ -0,0 +1,3 @@
+/*! UIkit 3.4.4 | https://www.getuikit.com | (c) 2014 - 2020 YOOtheme | MIT License */
+
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define("uikiticons",i):(t=t||self).UIkitIcons=i()}(this,function(){"use strict";function i(t){i.installed||t.icon.add({"500px":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.624,11.866c-0.141,0.132,0.479,0.658,0.662,0.418c0.051-0.046,0.607-0.61,0.662-0.664c0,0,0.738,0.719,0.814,0.719 c0.1,0,0.207-0.055,0.322-0.17c0.27-0.269,0.135-0.416,0.066-0.495l-0.631-0.616l0.658-0.668c0.146-0.156,0.021-0.314-0.1-0.449 c-0.182-0.18-0.359-0.226-0.471-0.125l-0.656,0.654l-0.654-0.654c-0.033-0.034-0.08-0.045-0.124-0.045 c-0.079,0-0.191,0.068-0.307,0.181c-0.202,0.202-0.247,0.351-0.133,0.462l0.665,0.665L9.624,11.866z"/><path d="M11.066,2.884c-1.061,0-2.185,0.248-3.011,0.604c-0.087,0.034-0.141,0.106-0.15,0.205C7.893,3.784,7.919,3.909,7.982,4.066 c0.05,0.136,0.187,0.474,0.452,0.372c0.844-0.326,1.779-0.507,2.633-0.507c0.963,0,1.9,0.191,2.781,0.564 c0.695,0.292,1.357,0.719,2.078,1.34c0.051,0.044,0.105,0.068,0.164,0.068c0.143,0,0.273-0.137,0.389-0.271 c0.191-0.214,0.324-0.395,0.135-0.575c-0.686-0.654-1.436-1.138-2.363-1.533C13.24,3.097,12.168,2.884,11.066,2.884z"/><path d="M16.43,15.747c-0.092-0.028-0.242,0.05-0.309,0.119l0,0c-0.652,0.652-1.42,1.169-2.268,1.521 c-0.877,0.371-1.814,0.551-2.779,0.551c-0.961,0-1.896-0.189-2.775-0.564c-0.848-0.36-1.612-0.879-2.268-1.53 c-0.682-0.688-1.196-1.455-1.529-2.268c-0.325-0.799-0.471-1.643-0.471-1.643c-0.045-0.24-0.258-0.249-0.567-0.203 c-0.128,0.021-0.519,0.079-0.483,0.36v0.01c0.105,0.644,0.289,1.284,0.545,1.895c0.417,0.969,1.002,1.849,1.756,2.604 c0.757,0.754,1.636,1.34,2.604,1.757C8.901,18.785,9.97,19,11.088,19c1.104,0,2.186-0.215,3.188-0.645 c1.838-0.896,2.604-1.757,2.604-1.757c0.182-0.204,0.227-0.317-0.1-0.643C16.779,15.956,16.525,15.774,16.43,15.747z"/><path d="M5.633,13.287c0.293,0.71,0.723,1.341,1.262,1.882c0.54,0.54,1.172,0.971,1.882,1.264c0.731,0.303,1.509,0.461,2.298,0.461 c0.801,0,1.578-0.158,2.297-0.461c0.711-0.293,1.344-0.724,1.883-1.264c0.543-0.541,0.971-1.172,1.264-1.882 c0.314-0.721,0.463-1.5,0.463-2.298c0-0.79-0.148-1.569-0.463-2.289c-0.293-0.699-0.721-1.329-1.264-1.881 c-0.539-0.541-1.172-0.959-1.867-1.263c-0.721-0.303-1.5-0.461-2.299-0.461c-0.802,0-1.613,0.159-2.322,0.461 c-0.577,0.25-1.544,0.867-2.119,1.454v0.012V2.108h8.16C15.1,2.104,15.1,1.69,15.1,1.552C15.1,1.417,15.1,1,14.809,1H5.915 C5.676,1,5.527,1.192,5.527,1.384v6.84c0,0.214,0.273,0.372,0.529,0.428c0.5,0.105,0.614-0.056,0.737-0.224l0,0 c0.18-0.273,0.776-0.884,0.787-0.894c0.901-0.905,2.117-1.408,3.416-1.408c1.285,0,2.5,0.501,3.412,1.408 c0.914,0.914,1.408,2.122,1.408,3.405c0,1.288-0.508,2.496-1.408,3.405c-0.9,0.896-2.152,1.406-3.438,1.406 c-0.877,0-1.711-0.229-2.433-0.671v-4.158c0-0.553,0.237-1.151,0.643-1.614c0.462-0.519,1.094-0.799,1.782-0.799 c0.664,0,1.293,0.253,1.758,0.715c0.459,0.459,0.709,1.071,0.709,1.723c0,1.385-1.094,2.468-2.488,2.468 c-0.273,0-0.769-0.121-0.781-0.125c-0.281-0.087-0.405,0.306-0.438,0.436c-0.159,0.496,0.079,0.585,0.123,0.607 c0.452,0.137,0.743,0.157,1.129,0.157c1.973,0,3.572-1.6,3.572-3.57c0-1.964-1.6-3.552-3.572-3.552c-0.97,0-1.872,0.36-2.546,1.038 c-0.656,0.631-1.027,1.487-1.027,2.322v3.438v-0.011c-0.372-0.42-0.732-1.041-0.981-1.682c-0.102-0.248-0.315-0.202-0.607-0.113 c-0.135,0.035-0.519,0.157-0.44,0.439C5.372,12.799,5.577,13.164,5.633,13.287z"/></svg>',album:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="5" y="2" width="10" height="1"/><rect x="3" y="4" width="14" height="1"/><rect fill="none" stroke="#000" x="1.5" y="6.5" width="17" height="11"/></svg>',"arrow-down":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="10.5,16.08 5.63,10.66 6.37,10 10.5,14.58 14.63,10 15.37,10.66"/><line fill="none" stroke="#000" x1="10.5" y1="4" x2="10.5" y2="15"/></svg>',"arrow-left":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="10 14 5 9.5 10 5"/><line fill="none" stroke="#000" x1="16" y1="9.5" x2="5" y2="9.52"/></svg>',"arrow-right":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="10 5 15 9.5 10 14"/><line fill="none" stroke="#000" x1="4" y1="9.5" x2="15" y2="9.5"/></svg>',"arrow-up":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="10.5,4 15.37,9.4 14.63,10.08 10.5,5.49 6.37,10.08 5.63,9.4"/><line fill="none" stroke="#000" x1="10.5" y1="16" x2="10.5" y2="5"/></svg>',ban:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/><line fill="none" stroke="#000" stroke-width="1.1" x1="4" y1="3.5" x2="16" y2="16.5"/></svg>',behance:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.5,10.6c-0.4-0.5-0.9-0.9-1.6-1.1c1.7-1,2.2-3.2,0.7-4.7C7.8,4,6.3,4,5.2,4C3.5,4,1.7,4,0,4v12c1.7,0,3.4,0,5.2,0 c1,0,2.1,0,3.1-0.5C10.2,14.6,10.5,12.3,9.5,10.6L9.5,10.6z M5.6,6.1c1.8,0,1.8,2.7-0.1,2.7c-1,0-2,0-2.9,0V6.1H5.6z M2.6,13.8v-3.1 c1.1,0,2.1,0,3.2,0c2.1,0,2.1,3.2,0.1,3.2L2.6,13.8z"/><path d="M19.9,10.9C19.7,9.2,18.7,7.6,17,7c-4.2-1.3-7.3,3.4-5.3,7.1c0.9,1.7,2.8,2.3,4.7,2.1c1.7-0.2,2.9-1.3,3.4-2.9h-2.2 c-0.4,1.3-2.4,1.5-3.5,0.6c-0.4-0.4-0.6-1.1-0.6-1.7H20C20,11.7,19.9,10.9,19.9,10.9z M13.5,10.6c0-1.6,2.3-2.7,3.5-1.4 c0.4,0.4,0.5,0.9,0.6,1.4H13.5L13.5,10.6z"/><rect x="13" y="4" width="5" height="1.4"/></svg>',bell:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M17,15.5 L3,15.5 C2.99,14.61 3.79,13.34 4.1,12.51 C4.58,11.3 4.72,10.35 5.19,7.01 C5.54,4.53 5.89,3.2 7.28,2.16 C8.13,1.56 9.37,1.5 9.81,1.5 L9.96,1.5 C9.96,1.5 11.62,1.41 12.67,2.17 C14.08,3.2 14.42,4.54 14.77,7.02 C15.26,10.35 15.4,11.31 15.87,12.52 C16.2,13.34 17.01,14.61 17,15.5 L17,15.5 Z"/><path fill="none" stroke="#000" d="M12.39,16 C12.39,17.37 11.35,18.43 9.91,18.43 C8.48,18.43 7.42,17.37 7.42,16"/></svg>',bold:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5,15.3 C5.66,15.3 5.9,15 5.9,14.53 L5.9,5.5 C5.9,4.92 5.56,4.7 5,4.7 L5,4 L8.95,4 C12.6,4 13.7,5.37 13.7,6.9 C13.7,7.87 13.14,9.17 10.86,9.59 L10.86,9.7 C13.25,9.86 14.29,11.28 14.3,12.54 C14.3,14.47 12.94,16 9,16 L5,16 L5,15.3 Z M9,9.3 C11.19,9.3 11.8,8.5 11.85,7 C11.85,5.65 11.3,4.8 9,4.8 L7.67,4.8 L7.67,9.3 L9,9.3 Z M9.185,15.22 C11.97,15 12.39,14 12.4,12.58 C12.4,11.15 11.39,10 9,10 L7.67,10 L7.67,15 L9.18,15 Z"/></svg>',bolt:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4.74,20 L7.73,12 L3,12 L15.43,1 L12.32,9 L17.02,9 L4.74,20 L4.74,20 L4.74,20 Z M9.18,11 L7.1,16.39 L14.47,10 L10.86,10 L12.99,4.67 L5.61,11 L9.18,11 L9.18,11 L9.18,11 Z"/></svg>',bookmark:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="5.5 1.5 15.5 1.5 15.5 17.5 10.5 12.5 5.5 17.5"/></svg>',calendar:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M 2,3 2,17 18,17 18,3 2,3 Z M 17,16 3,16 3,8 17,8 17,16 Z M 17,7 3,7 3,4 17,4 17,7 Z"/><rect width="1" height="3" x="6" y="2"/><rect width="1" height="3" x="13" y="2"/></svg>',camera:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10.8" r="3.8"/><path fill="none" stroke="#000" d="M1,4.5 C0.7,4.5 0.5,4.7 0.5,5 L0.5,17 C0.5,17.3 0.7,17.5 1,17.5 L19,17.5 C19.3,17.5 19.5,17.3 19.5,17 L19.5,5 C19.5,4.7 19.3,4.5 19,4.5 L13.5,4.5 L13.5,2.9 C13.5,2.6 13.3,2.5 13,2.5 L7,2.5 C6.7,2.5 6.5,2.6 6.5,2.9 L6.5,4.5 L1,4.5 L1,4.5 Z"/></svg>',cart:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="7.3" cy="17.3" r="1.4"/><circle cx="13.3" cy="17.3" r="1.4"/><polyline fill="none" stroke="#000" points="0 2 3.2 4 5.3 12.5 16 12.5 18 6.5 8 6.5"/></svg>',check:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.1" points="4,10 8,15 17,4"/></svg>',"chevron-double-left":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="10 14 6 10 10 6"/><polyline fill="none" stroke="#000" stroke-width="1.03" points="14 14 10 10 14 6"/></svg>',"chevron-double-right":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="10 6 14 10 10 14"/><polyline fill="none" stroke="#000" stroke-width="1.03" points="6 6 10 10 6 14"/></svg>',"chevron-down":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="16 7 10 13 4 7"/></svg>',"chevron-left":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="13 16 7 10 13 4"/></svg>',"chevron-right":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="7 4 13 10 7 16"/></svg>',"chevron-up":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.03" points="4 13 10 7 16 13"/></svg>',clock:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/><rect x="9" y="4" width="1" height="7"/><path fill="none" stroke="#000" stroke-width="1.1" d="M13.018,14.197 L9.445,10.625"/></svg>',close:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.06" d="M16,16 L4,4"/><path fill="none" stroke="#000" stroke-width="1.06" d="M16,4 L4,16"/></svg>',"cloud-download":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M6.5,14.61 L3.75,14.61 C1.96,14.61 0.5,13.17 0.5,11.39 C0.5,9.76 1.72,8.41 3.3,8.2 C3.38,5.31 5.75,3 8.68,3 C11.19,3 13.31,4.71 13.89,7.02 C14.39,6.8 14.93,6.68 15.5,6.68 C17.71,6.68 19.5,8.45 19.5,10.64 C19.5,12.83 17.71,14.6 15.5,14.6 L12.5,14.6"/><polyline fill="none" stroke="#000" points="11.75 16 9.5 18.25 7.25 16"/><path fill="none" stroke="#000" d="M9.5,18 L9.5,9.5"/></svg>',"cloud-upload":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M6.5,14.61 L3.75,14.61 C1.96,14.61 0.5,13.17 0.5,11.39 C0.5,9.76 1.72,8.41 3.31,8.2 C3.38,5.31 5.75,3 8.68,3 C11.19,3 13.31,4.71 13.89,7.02 C14.39,6.8 14.93,6.68 15.5,6.68 C17.71,6.68 19.5,8.45 19.5,10.64 C19.5,12.83 17.71,14.6 15.5,14.6 L12.5,14.6"/><polyline fill="none" stroke="#000" points="7.25 11.75 9.5 9.5 11.75 11.75"/><path fill="none" stroke="#000" d="M9.5,18 L9.5,9.5"/></svg>',code:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.01" points="13,4 19,10 13,16"/><polyline fill="none" stroke="#000" stroke-width="1.01" points="7,4 1,10 7,16"/></svg>',cog:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" cx="9.997" cy="10" r="3.31"/><path fill="none" stroke="#000" d="M18.488,12.285 L16.205,16.237 C15.322,15.496 14.185,15.281 13.303,15.791 C12.428,16.289 12.047,17.373 12.246,18.5 L7.735,18.5 C7.938,17.374 7.553,16.299 6.684,15.791 C5.801,15.27 4.655,15.492 3.773,16.237 L1.5,12.285 C2.573,11.871 3.317,10.999 3.317,9.991 C3.305,8.98 2.573,8.121 1.5,7.716 L3.765,3.784 C4.645,4.516 5.794,4.738 6.687,4.232 C7.555,3.722 7.939,2.637 7.735,1.5 L12.263,1.5 C12.072,2.637 12.441,3.71 13.314,4.22 C14.206,4.73 15.343,4.516 16.225,3.794 L18.487,7.714 C17.404,8.117 16.661,8.988 16.67,10.009 C16.672,11.018 17.415,11.88 18.488,12.285 L18.488,12.285 Z"/></svg>',comment:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6,18.71 L6,14 L1,14 L1,1 L19,1 L19,14 L10.71,14 L6,18.71 L6,18.71 Z M2,13 L7,13 L7,16.29 L10.29,13 L18,13 L18,2 L2,2 L2,13 L2,13 Z"/></svg>',commenting:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="1.5,1.5 18.5,1.5 18.5,13.5 10.5,13.5 6.5,17.5 6.5,13.5 1.5,13.5"/><circle cx="10" cy="8" r="1"/><circle cx="6" cy="8" r="1"/><circle cx="14" cy="8" r="1"/></svg>',comments:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="2 0.5 19.5 0.5 19.5 13"/><path d="M5,19.71 L5,15 L0,15 L0,2 L18,2 L18,15 L9.71,15 L5,19.71 L5,19.71 L5,19.71 Z M1,14 L6,14 L6,17.29 L9.29,14 L17,14 L17,3 L1,3 L1,14 L1,14 L1,14 Z"/></svg>',copy:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" x="3.5" y="2.5" width="12" height="16"/><polyline fill="none" stroke="#000" points="5 0.5 17.5 0.5 17.5 17"/></svg>',"credit-card":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" x="1.5" y="4.5" width="17" height="12"/><rect x="1" y="7" width="18" height="3"/></svg>',database:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><ellipse fill="none" stroke="#000" cx="10" cy="4.64" rx="7.5" ry="3.14"/><path fill="none" stroke="#000" d="M17.5,8.11 C17.5,9.85 14.14,11.25 10,11.25 C5.86,11.25 2.5,9.84 2.5,8.11"/><path fill="none" stroke="#000" d="M17.5,11.25 C17.5,12.99 14.14,14.39 10,14.39 C5.86,14.39 2.5,12.98 2.5,11.25"/><path fill="none" stroke="#000" d="M17.49,4.64 L17.5,14.36 C17.5,16.1 14.14,17.5 10,17.5 C5.86,17.5 2.5,16.09 2.5,14.36 L2.5,4.64"/></svg>',desktop:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="8" y="15" width="1" height="2"/><rect x="11" y="15" width="1" height="2"/><rect x="5" y="16" width="10" height="1"/><rect fill="none" stroke="#000" x="1.5" y="3.5" width="17" height="11"/></svg>',download:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="14,10 9.5,14.5 5,10"/><rect x="3" y="17" width="13" height="1"/><line fill="none" stroke="#000" x1="9.5" y1="13.91" x2="9.5" y2="3"/></svg>',dribbble:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.4" d="M1.3,8.9c0,0,5,0.1,8.6-1c1.4-0.4,2.6-0.9,4-1.9 c1.4-1.1,2.5-2.5,2.5-2.5"/><path fill="none" stroke="#000" stroke-width="1.4" d="M3.9,16.6c0,0,1.7-2.8,3.5-4.2 c1.8-1.3,4-2,5.7-2.2C16,10,19,10.6,19,10.6"/><path fill="none" stroke="#000" stroke-width="1.4" d="M6.9,1.6c0,0,3.3,4.6,4.2,6.8 c0.4,0.9,1.3,3.1,1.9,5.2c0.6,2,0.9,4.4,0.9,4.4"/><circle fill="none" stroke="#000" stroke-width="1.4" cx="10" cy="10" r="9"/></svg>',etsy:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path d="M8,4.26C8,4.07,8,4,8.31,4h4.46c.79,0,1.22.67,1.53,1.91l.25,1h.76c.14-2.82.26-4,.26-4S13.65,3,12.52,3H6.81L3.75,2.92v.84l1,.2c.73.11.9.27,1,1,0,0,.06,2,.06,5.17s-.06,5.14-.06,5.14c0,.59-.23.81-1,.94l-1,.2v.84l3.06-.1h5.11c1.15,0,3.82.1,3.82.1,0-.7.45-3.88.51-4.22h-.73l-.76,1.69a2.25,2.25,0,0,1-2.45,1.47H9.4c-1,0-1.44-.4-1.44-1.24V10.44s2.16,0,2.86.06c.55,0,.85.19,1.06,1l.23,1H13L12.9,9.94,13,7.41h-.85l-.28,1.13c-.16.74-.28.84-1,1-1,.1-2.89.09-2.89.09Z"/></svg>',expand:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="13 2 18 2 18 7 17 7 17 3 13 3"/><polygon points="2 13 3 13 3 17 7 17 7 18 2 18"/><path fill="none" stroke="#000" stroke-width="1.1" d="M11,9 L17,3"/><path fill="none" stroke="#000" stroke-width="1.1" d="M3,17 L9,11"/></svg>',facebook:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11,10h2.6l0.4-3H11V5.3c0-0.9,0.2-1.5,1.5-1.5H14V1.1c-0.3,0-1-0.1-2.1-0.1C9.6,1,8,2.4,8,5v2H5.5v3H8v8h3V10z"/></svg>',"file-edit":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M18.65,1.68 C18.41,1.45 18.109,1.33 17.81,1.33 C17.499,1.33 17.209,1.45 16.98,1.68 L8.92,9.76 L8,12.33 L10.55,11.41 L18.651,3.34 C19.12,2.87 19.12,2.15 18.65,1.68 L18.65,1.68 L18.65,1.68 Z"/><polyline fill="none" stroke="#000" points="16.5 8.482 16.5 18.5 3.5 18.5 3.5 1.5 14.211 1.5"/></svg>',"file-pdf":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" width="13" height="17" x="3.5" y="1.5"/><path d="M14.65 11.67c-.48.3-1.37-.19-1.79-.37a4.65 4.65 0 0 1 1.49.06c.35.1.36.28.3.31zm-6.3.06l.43-.79a14.7 14.7 0 0 0 .75-1.64 5.48 5.48 0 0 0 1.25 1.55l.2.15a16.36 16.36 0 0 0-2.63.73zM9.5 5.32c.2 0 .32.5.32.97a1.99 1.99 0 0 1-.23 1.04 5.05 5.05 0 0 1-.17-1.3s0-.71.08-.71zm-3.9 9a4.35 4.35 0 0 1 1.21-1.46l.24-.22a4.35 4.35 0 0 1-1.46 1.68zm9.23-3.3a2.05 2.05 0 0 0-1.32-.3 11.07 11.07 0 0 0-1.58.11 4.09 4.09 0 0 1-.74-.5 5.39 5.39 0 0 1-1.32-2.06 10.37 10.37 0 0 0 .28-2.62 1.83 1.83 0 0 0-.07-.25.57.57 0 0 0-.52-.4H9.4a.59.59 0 0 0-.6.38 6.95 6.95 0 0 0 .37 3.14c-.26.63-1 2.12-1 2.12-.3.58-.57 1.08-.82 1.5l-.8.44A3.11 3.11 0 0 0 5 14.16a.39.39 0 0 0 .15.42l.24.13c1.15.56 2.28-1.74 2.66-2.42a23.1 23.1 0 0 1 3.59-.85 4.56 4.56 0 0 0 2.91.8.5.5 0 0 0 .3-.21 1.1 1.1 0 0 0 .12-.75.84.84 0 0 0-.14-.25z"/></svg>',"file-text":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" width="13" height="17" x="3.5" y="1.5"/><line fill="none" stroke="#000" x1="6" x2="12" y1="12.5" y2="12.5"/><line fill="none" stroke="#000" x1="6" x2="14" y1="8.5" y2="8.5"/><line fill="none" stroke="#000" x1="6" x2="14" y1="6.5" y2="6.5"/><line fill="none" stroke="#000" x1="6" x2="14" y1="10.5" y2="10.5"/></svg>',file:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" x="3.5" y="1.5" width="13" height="17"/></svg>',flickr:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="5.5" cy="9.5" r="3.5"/><circle cx="14.5" cy="9.5" r="3.5"/></svg>',folder:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="9.5 5.5 8.5 3.5 1.5 3.5 1.5 16.5 18.5 16.5 18.5 5.5"/></svg>',forward:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.47,13.11 C4.02,10.02 6.27,7.85 9.04,6.61 C9.48,6.41 10.27,6.13 11,5.91 L11,2 L18.89,9 L11,16 L11,12.13 C9.25,12.47 7.58,13.19 6.02,14.25 C3.03,16.28 1.63,18.54 1.63,18.54 C1.63,18.54 1.38,15.28 2.47,13.11 L2.47,13.11 Z M5.3,13.53 C6.92,12.4 9.04,11.4 12,10.92 L12,13.63 L17.36,9 L12,4.25 L12,6.8 C11.71,6.86 10.86,7.02 9.67,7.49 C6.79,8.65 4.58,10.96 3.49,13.08 C3.18,13.7 2.68,14.87 2.49,16 C3.28,15.05 4.4,14.15 5.3,13.53 L5.3,13.53 Z"/></svg>',foursquare:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.23,2 C15.96,2 16.4,2.41 16.5,2.86 C16.57,3.15 16.56,3.44 16.51,3.73 C16.46,4.04 14.86,11.72 14.75,12.03 C14.56,12.56 14.16,12.82 13.61,12.83 C13.03,12.84 11.09,12.51 10.69,13 C10.38,13.38 7.79,16.39 6.81,17.53 C6.61,17.76 6.4,17.96 6.08,17.99 C5.68,18.04 5.29,17.87 5.17,17.45 C5.12,17.28 5.1,17.09 5.1,16.91 C5.1,12.4 4.86,7.81 5.11,3.31 C5.17,2.5 5.81,2.12 6.53,2 L15.23,2 L15.23,2 Z M9.76,11.42 C9.94,11.19 10.17,11.1 10.45,11.1 L12.86,11.1 C13.12,11.1 13.31,10.94 13.36,10.69 C13.37,10.64 13.62,9.41 13.74,8.83 C13.81,8.52 13.53,8.28 13.27,8.28 C12.35,8.29 11.42,8.28 10.5,8.28 C9.84,8.28 9.83,7.69 9.82,7.21 C9.8,6.85 10.13,6.55 10.5,6.55 C11.59,6.56 12.67,6.55 13.76,6.55 C14.03,6.55 14.23,6.4 14.28,6.14 C14.34,5.87 14.67,4.29 14.67,4.29 C14.67,4.29 14.82,3.74 14.19,3.74 L7.34,3.74 C7,3.75 6.84,4.02 6.84,4.33 C6.84,7.58 6.85,14.95 6.85,14.99 C6.87,15 8.89,12.51 9.76,11.42 L9.76,11.42 Z"/></svg>',future:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline points="19 2 18 2 18 6 14 6 14 7 19 7 19 2"/><path fill="none" stroke="#000" stroke-width="1.1" d="M18,6.548 C16.709,3.29 13.354,1 9.6,1 C4.6,1 0.6,5 0.6,10 C0.6,15 4.6,19 9.6,19 C14.6,19 18.6,15 18.6,10"/><rect x="9" y="4" width="1" height="7"/><path d="M13.018,14.197 L9.445,10.625" fill="none" stroke="#000" stroke-width="1.1"/></svg>',"git-branch":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.2" cx="7" cy="3" r="2"/><circle fill="none" stroke="#000" stroke-width="1.2" cx="14" cy="6" r="2"/><circle fill="none" stroke="#000" stroke-width="1.2" cx="7" cy="17" r="2"/><path fill="none" stroke="#000" stroke-width="2" d="M14,8 C14,10.41 12.43,10.87 10.56,11.25 C9.09,11.54 7,12.06 7,15 L7,5"/></svg>',"git-fork":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.2" cx="5.79" cy="2.79" r="1.79"/><circle fill="none" stroke="#000" stroke-width="1.2" cx="14.19" cy="2.79" r="1.79"/><circle fill="none" stroke="#000" stroke-width="1.2" cx="10.03" cy="16.79" r="1.79"/><path fill="none" stroke="#000" stroke-width="2" d="M5.79,4.57 L5.79,6.56 C5.79,9.19 10.03,10.22 10.03,13.31 C10.03,14.86 10.04,14.55 10.04,14.55 C10.04,14.37 10.04,14.86 10.04,13.31 C10.04,10.22 14.2,9.19 14.2,6.56 L14.2,4.57"/></svg>',"github-alt":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10,0.5 C4.75,0.5 0.5,4.76 0.5,10.01 C0.5,15.26 4.75,19.51 10,19.51 C15.24,19.51 19.5,15.26 19.5,10.01 C19.5,4.76 15.25,0.5 10,0.5 L10,0.5 Z M12.81,17.69 C12.81,17.69 12.81,17.7 12.79,17.69 C12.47,17.75 12.35,17.59 12.35,17.36 L12.35,16.17 C12.35,15.45 12.09,14.92 11.58,14.56 C12.2,14.51 12.77,14.39 13.26,14.21 C13.87,13.98 14.36,13.69 14.74,13.29 C15.42,12.59 15.76,11.55 15.76,10.17 C15.76,9.25 15.45,8.46 14.83,7.8 C15.1,7.08 15.07,6.29 14.75,5.44 L14.51,5.42 C14.34,5.4 14.06,5.46 13.67,5.61 C13.25,5.78 12.79,6.03 12.31,6.35 C11.55,6.16 10.81,6.05 10.09,6.05 C9.36,6.05 8.61,6.15 7.88,6.35 C7.28,5.96 6.75,5.68 6.26,5.54 C6.07,5.47 5.9,5.44 5.78,5.44 L5.42,5.44 C5.06,6.29 5.04,7.08 5.32,7.8 C4.7,8.46 4.4,9.25 4.4,10.17 C4.4,11.94 4.96,13.16 6.08,13.84 C6.53,14.13 7.05,14.32 7.69,14.43 C8.03,14.5 8.32,14.54 8.55,14.55 C8.07,14.89 7.82,15.42 7.82,16.16 L7.82,17.51 C7.8,17.69 7.7,17.8 7.51,17.8 C4.21,16.74 1.82,13.65 1.82,10.01 C1.82,5.5 5.49,1.83 10,1.83 C14.5,1.83 18.17,5.5 18.17,10.01 C18.18,13.53 15.94,16.54 12.81,17.69 L12.81,17.69 Z"/></svg>',github:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10,1 C5.03,1 1,5.03 1,10 C1,13.98 3.58,17.35 7.16,18.54 C7.61,18.62 7.77,18.34 7.77,18.11 C7.77,17.9 7.76,17.33 7.76,16.58 C5.26,17.12 4.73,15.37 4.73,15.37 C4.32,14.33 3.73,14.05 3.73,14.05 C2.91,13.5 3.79,13.5 3.79,13.5 C4.69,13.56 5.17,14.43 5.17,14.43 C5.97,15.8 7.28,15.41 7.79,15.18 C7.87,14.6 8.1,14.2 8.36,13.98 C6.36,13.75 4.26,12.98 4.26,9.53 C4.26,8.55 4.61,7.74 5.19,7.11 C5.1,6.88 4.79,5.97 5.28,4.73 C5.28,4.73 6.04,4.49 7.75,5.65 C8.47,5.45 9.24,5.35 10,5.35 C10.76,5.35 11.53,5.45 12.25,5.65 C13.97,4.48 14.72,4.73 14.72,4.73 C15.21,5.97 14.9,6.88 14.81,7.11 C15.39,7.74 15.73,8.54 15.73,9.53 C15.73,12.99 13.63,13.75 11.62,13.97 C11.94,14.25 12.23,14.8 12.23,15.64 C12.23,16.84 12.22,17.81 12.22,18.11 C12.22,18.35 12.38,18.63 12.84,18.54 C16.42,17.35 19,13.98 19,10 C19,5.03 14.97,1 10,1 L10,1 Z"/></svg>',gitter:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="3.5" y="1" width="1.531" height="11.471"/><rect x="7.324" y="4.059" width="1.529" height="15.294"/><rect x="11.148" y="4.059" width="1.527" height="15.294"/><rect x="14.971" y="4.059" width="1.529" height="8.412"/></svg>',"google-plus":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.9,9c0,2.7-0.6,5-3.2,6.3c-3.7,1.8-8.1,0.2-9.4-3.6C-1.1,7.6,1.9,3.3,6.1,3c1.7-0.1,3.2,0.3,4.6,1.3 c0.1,0.1,0.3,0.2,0.4,0.4c-0.5,0.5-1.2,1-1.7,1.6c-1-0.8-2.1-1.1-3.5-0.9C5,5.6,4.2,6,3.6,6.7c-1.3,1.3-1.5,3.4-0.5,5 c1,1.7,2.6,2.3,4.6,1.9c1.4-0.3,2.4-1.2,2.6-2.6H6.9V9H12.9z"/><polygon points="20,9 20,11 18,11 18,13 16,13 16,11 14,11 14,9 16,9 16,7 18,7 18,9"/></svg>',google:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.86,9.09 C18.46,12.12 17.14,16.05 13.81,17.56 C9.45,19.53 4.13,17.68 2.47,12.87 C0.68,7.68 4.22,2.42 9.5,2.03 C11.57,1.88 13.42,2.37 15.05,3.65 C15.22,3.78 15.37,3.93 15.61,4.14 C14.9,4.81 14.23,5.45 13.5,6.14 C12.27,5.08 10.84,4.72 9.28,4.98 C8.12,5.17 7.16,5.76 6.37,6.63 C4.88,8.27 4.62,10.86 5.76,12.82 C6.95,14.87 9.17,15.8 11.57,15.25 C13.27,14.87 14.76,13.33 14.89,11.75 L10.51,11.75 L10.51,9.09 L17.86,9.09 L17.86,9.09 Z"/></svg>',grid:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="3" height="3"/><rect x="8" y="2" width="3" height="3"/><rect x="14" y="2" width="3" height="3"/><rect x="2" y="8" width="3" height="3"/><rect x="8" y="8" width="3" height="3"/><rect x="14" y="8" width="3" height="3"/><rect x="2" y="14" width="3" height="3"/><rect x="8" y="14" width="3" height="3"/><rect x="14" y="14" width="3" height="3"/></svg>',happy:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="13" cy="7" r="1"/><circle cx="7" cy="7" r="1"/><circle fill="none" stroke="#000" cx="10" cy="10" r="8.5"/><path fill="none" stroke="#000" d="M14.6,11.4 C13.9,13.3 12.1,14.5 10,14.5 C7.9,14.5 6.1,13.3 5.4,11.4"/></svg>',hashtag:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.431,8 L15.661,7 L12.911,7 L13.831,3 L12.901,3 L11.98,7 L9.29,7 L10.21,3 L9.281,3 L8.361,7 L5.23,7 L5,8 L8.13,8 L7.21,12 L4.23,12 L4,13 L6.98,13 L6.061,17 L6.991,17 L7.911,13 L10.601,13 L9.681,17 L10.611,17 L11.531,13 L14.431,13 L14.661,12 L11.76,12 L12.681,8 L15.431,8 Z M10.831,12 L8.141,12 L9.061,8 L11.75,8 L10.831,12 Z"/></svg>',heart:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.03" d="M10,4 C10,4 8.1,2 5.74,2 C3.38,2 1,3.55 1,6.73 C1,8.84 2.67,10.44 2.67,10.44 L10,18 L17.33,10.44 C17.33,10.44 19,8.84 19,6.73 C19,3.55 16.62,2 14.26,2 C11.9,2 10,4 10,4 L10,4 Z"/></svg>',history:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="#000" points="1 2 2 2 2 6 6 6 6 7 1 7 1 2"/><path fill="none" stroke="#000" stroke-width="1.1" d="M2.1,6.548 C3.391,3.29 6.746,1 10.5,1 C15.5,1 19.5,5 19.5,10 C19.5,15 15.5,19 10.5,19 C5.5,19 1.5,15 1.5,10"/><rect x="9" y="4" width="1" height="7"/><path fill="none" stroke="#000" stroke-width="1.1" d="M13.018,14.197 L9.445,10.625"/></svg>',home:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="18.65 11.35 10 2.71 1.35 11.35 0.65 10.65 10 1.29 19.35 10.65"/><polygon points="15 4 18 4 18 7 17 7 17 5 15 5"/><polygon points="3 11 4 11 4 18 7 18 7 12 12 12 12 18 16 18 16 11 17 11 17 19 11 19 11 13 8 13 8 19 3 19"/></svg>',image:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="16.1" cy="6.1" r="1.1"/><rect fill="none" stroke="#000" x=".5" y="2.5" width="19" height="15"/><polyline fill="none" stroke="#000" stroke-width="1.01" points="4,13 8,9 13,14"/><polyline fill="none" stroke="#000" stroke-width="1.01" points="11,12 12.5,10.5 16,14"/></svg>',info:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.13,11.59 C11.97,12.84 10.35,14.12 9.1,14.16 C6.17,14.2 9.89,9.46 8.74,8.37 C9.3,8.16 10.62,7.83 10.62,8.81 C10.62,9.63 10.12,10.55 9.88,11.32 C8.66,15.16 12.13,11.15 12.14,11.18 C12.16,11.21 12.16,11.35 12.13,11.59 C12.08,11.95 12.16,11.35 12.13,11.59 L12.13,11.59 Z M11.56,5.67 C11.56,6.67 9.36,7.15 9.36,6.03 C9.36,5 11.56,4.54 11.56,5.67 L11.56,5.67 Z"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/></svg>',instagram:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M13.55,1H6.46C3.45,1,1,3.44,1,6.44v7.12c0,3,2.45,5.44,5.46,5.44h7.08c3.02,0,5.46-2.44,5.46-5.44V6.44 C19.01,3.44,16.56,1,13.55,1z M17.5,14c0,1.93-1.57,3.5-3.5,3.5H6c-1.93,0-3.5-1.57-3.5-3.5V6c0-1.93,1.57-3.5,3.5-3.5h8 c1.93,0,3.5,1.57,3.5,3.5V14z"/><circle cx="14.87" cy="5.26" r="1.09"/><path d="M10.03,5.45c-2.55,0-4.63,2.06-4.63,4.6c0,2.55,2.07,4.61,4.63,4.61c2.56,0,4.63-2.061,4.63-4.61 C14.65,7.51,12.58,5.45,10.03,5.45L10.03,5.45L10.03,5.45z M10.08,13c-1.66,0-3-1.34-3-2.99c0-1.65,1.34-2.99,3-2.99s3,1.34,3,2.99 C13.08,11.66,11.74,13,10.08,13L10.08,13L10.08,13z"/></svg>',italic:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.63,5.48 L10.15,14.52 C10,15.08 10.37,15.25 11.92,15.3 L11.72,16 L6,16 L6.2,15.31 C7.78,15.26 8.19,15.09 8.34,14.53 L10.82,5.49 C10.97,4.92 10.63,4.76 9.09,4.71 L9.28,4 L15,4 L14.81,4.69 C13.23,4.75 12.78,4.91 12.63,5.48 L12.63,5.48 Z"/></svg>',joomla:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.8,13.4l1.7-1.7L5.9,8c-0.6-0.5-0.6-1.5,0-2c0.6-0.6,1.4-0.6,2,0l1.7-1.7c-1-1-2.3-1.3-3.6-1C5.8,2.2,4.8,1.4,3.7,1.4 c-1.3,0-2.3,1-2.3,2.3c0,1.1,0.8,2,1.8,2.3c-0.4,1.3-0.1,2.8,1,3.8L7.8,13.4L7.8,13.4z"/><path d="M10.2,4.3c1-1,2.5-1.4,3.8-1c0.2-1.1,1.1-2,2.3-2c1.3,0,2.3,1,2.3,2.3c0,1.2-0.9,2.2-2,2.3c0.4,1.3,0,2.8-1,3.8L13.9,8 c0.6-0.5,0.6-1.5,0-2c-0.5-0.6-1.5-0.6-2,0L8.2,9.7L6.5,8"/><path d="M14.1,16.8c-1.3,0.4-2.8,0.1-3.8-1l1.7-1.7c0.6,0.6,1.5,0.6,2,0c0.5-0.6,0.6-1.5,0-2l-3.7-3.7L12,6.7l3.7,3.7 c1,1,1.3,2.4,1,3.6c1.1,0.2,2,1.1,2,2.3c0,1.3-1,2.3-2.3,2.3C15.2,18.6,14.3,17.8,14.1,16.8"/><path d="M13.2,12.2l-3.7,3.7c-1,1-2.4,1.3-3.6,1c-0.2,1-1.2,1.8-2.2,1.8c-1.3,0-2.3-1-2.3-2.3c0-1.1,0.8-2,1.8-2.3 c-0.3-1.3,0-2.7,1-3.7l1.7,1.7c-0.6,0.6-0.6,1.5,0,2c0.6,0.6,1.4,0.6,2,0l3.7-3.7"/></svg>',laptop:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect y="16" width="20" height="1"/><rect fill="none" stroke="#000" x="2.5" y="4.5" width="15" height="10"/></svg>',lifesaver:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10,0.5 C4.76,0.5 0.5,4.76 0.5,10 C0.5,15.24 4.76,19.5 10,19.5 C15.24,19.5 19.5,15.24 19.5,10 C19.5,4.76 15.24,0.5 10,0.5 L10,0.5 Z M10,1.5 C11.49,1.5 12.89,1.88 14.11,2.56 L11.85,4.82 C11.27,4.61 10.65,4.5 10,4.5 C9.21,4.5 8.47,4.67 7.79,4.96 L5.58,2.75 C6.87,1.95 8.38,1.5 10,1.5 L10,1.5 Z M4.96,7.8 C4.67,8.48 4.5,9.21 4.5,10 C4.5,10.65 4.61,11.27 4.83,11.85 L2.56,14.11 C1.88,12.89 1.5,11.49 1.5,10 C1.5,8.38 1.95,6.87 2.75,5.58 L4.96,7.79 L4.96,7.8 L4.96,7.8 Z M10,18.5 C8.25,18.5 6.62,17.97 5.27,17.06 L7.46,14.87 C8.22,15.27 9.08,15.5 10,15.5 C10.79,15.5 11.53,15.33 12.21,15.04 L14.42,17.25 C13.13,18.05 11.62,18.5 10,18.5 L10,18.5 Z M10,14.5 C7.52,14.5 5.5,12.48 5.5,10 C5.5,7.52 7.52,5.5 10,5.5 C12.48,5.5 14.5,7.52 14.5,10 C14.5,12.48 12.48,14.5 10,14.5 L10,14.5 Z M15.04,12.21 C15.33,11.53 15.5,10.79 15.5,10 C15.5,9.08 15.27,8.22 14.87,7.46 L17.06,5.27 C17.97,6.62 18.5,8.25 18.5,10 C18.5,11.62 18.05,13.13 17.25,14.42 L15.04,12.21 L15.04,12.21 Z"/></svg>',link:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M10.625,12.375 L7.525,15.475 C6.825,16.175 5.925,16.175 5.225,15.475 L4.525,14.775 C3.825,14.074 3.825,13.175 4.525,12.475 L7.625,9.375"/><path fill="none" stroke="#000" stroke-width="1.1" d="M9.325,7.375 L12.425,4.275 C13.125,3.575 14.025,3.575 14.724,4.275 L15.425,4.975 C16.125,5.675 16.125,6.575 15.425,7.275 L12.325,10.375"/><path fill="none" stroke="#000" stroke-width="1.1" d="M7.925,11.875 L11.925,7.975"/></svg>',linkedin:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.77,17.89 L5.77,7.17 L2.21,7.17 L2.21,17.89 L5.77,17.89 L5.77,17.89 Z M3.99,5.71 C5.23,5.71 6.01,4.89 6.01,3.86 C5.99,2.8 5.24,2 4.02,2 C2.8,2 2,2.8 2,3.85 C2,4.88 2.77,5.7 3.97,5.7 L3.99,5.7 L3.99,5.71 L3.99,5.71 Z"/><path d="M7.75,17.89 L11.31,17.89 L11.31,11.9 C11.31,11.58 11.33,11.26 11.43,11.03 C11.69,10.39 12.27,9.73 13.26,9.73 C14.55,9.73 15.06,10.71 15.06,12.15 L15.06,17.89 L18.62,17.89 L18.62,11.74 C18.62,8.45 16.86,6.92 14.52,6.92 C12.6,6.92 11.75,7.99 11.28,8.73 L11.3,8.73 L11.3,7.17 L7.75,7.17 C7.79,8.17 7.75,17.89 7.75,17.89 L7.75,17.89 L7.75,17.89 Z"/></svg>',list:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="4" width="12" height="1"/><rect x="6" y="9" width="12" height="1"/><rect x="6" y="14" width="12" height="1"/><rect x="2" y="4" width="2" height="1"/><rect x="2" y="9" width="2" height="1"/><rect x="2" y="14" width="2" height="1"/></svg>',location:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.01" d="M10,0.5 C6.41,0.5 3.5,3.39 3.5,6.98 C3.5,11.83 10,19 10,19 C10,19 16.5,11.83 16.5,6.98 C16.5,3.39 13.59,0.5 10,0.5 L10,0.5 Z"/><circle fill="none" stroke="#000" cx="10" cy="6.8" r="2.3"/></svg>',lock:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" height="10" width="13" y="8.5" x="3.5"/><path fill="none" stroke="#000" d="M6.5,8 L6.5,4.88 C6.5,3.01 8.07,1.5 10,1.5 C11.93,1.5 13.5,3.01 13.5,4.88 L13.5,8"/></svg>',mail:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="1.4,6.5 10,11 18.6,6.5"/><path d="M 1,4 1,16 19,16 19,4 1,4 Z M 18,15 2,15 2,5 18,5 18,15 Z"/></svg>',menu:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="4" width="16" height="1"/><rect x="2" y="9" width="16" height="1"/><rect x="2" y="14" width="16" height="1"/></svg>',microphone:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><line fill="none" stroke="#000" x1="10" x2="10" y1="16.44" y2="18.5"/><line fill="none" stroke="#000" x1="7" x2="13" y1="18.5" y2="18.5"/><path fill="none" stroke="#000" stroke-width="1.1" d="M13.5 4.89v5.87a3.5 3.5 0 0 1-7 0V4.89a3.5 3.5 0 0 1 7 0z"/><path fill="none" stroke="#000" stroke-width="1.1" d="M15.5 10.36V11a5.5 5.5 0 0 1-11 0v-.6"/></svg>',"minus-circle":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="9.5" cy="9.5" r="9"/><line fill="none" stroke="#000" x1="5" y1="9.5" x2="14" y2="9.5"/></svg>',minus:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect height="1" width="18" y="9" x="1"/></svg>',"more-vertical":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="3" r="2"/><circle cx="10" cy="10" r="2"/><circle cx="10" cy="17" r="2"/></svg>',more:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="3" cy="10" r="2"/><circle cx="10" cy="10" r="2"/><circle cx="17" cy="10" r="2"/></svg>',move:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="4,5 1,5 1,9 2,9 2,6 4,6"/><polygon points="1,16 2,16 2,18 4,18 4,19 1,19"/><polygon points="14,16 14,19 11,19 11,18 13,18 13,16"/><rect fill="none" stroke="#000" x="5.5" y="1.5" width="13" height="13"/><rect x="1" y="11" width="1" height="3"/><rect x="6" y="18" width="3" height="1"/></svg>',nut:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="2.5,5.7 10,1.3 17.5,5.7 17.5,14.3 10,18.7 2.5,14.3"/><circle fill="none" stroke="#000" cx="10" cy="10" r="3.5"/></svg>',pagekit:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="3,1 17,1 17,16 10,16 10,13 14,13 14,4 6,4 6,16 10,16 10,19 3,19"/></svg>',"paint-bucket":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.21,1 L0,11.21 L8.1,19.31 L18.31,9.1 L10.21,1 L10.21,1 Z M16.89,9.1 L15,11 L1.7,11 L10.21,2.42 L16.89,9.1 Z"/><path fill="none" stroke="#000" stroke-width="1.1" d="M6.42,2.33 L11.7,7.61"/><path d="M18.49,12 C18.49,12 20,14.06 20,15.36 C20,16.28 19.24,17 18.49,17 L18.49,17 C17.74,17 17,16.28 17,15.36 C17,14.06 18.49,12 18.49,12 L18.49,12 Z"/></svg>',pencil:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M17.25,6.01 L7.12,16.1 L3.82,17.2 L5.02,13.9 L15.12,3.88 C15.71,3.29 16.66,3.29 17.25,3.88 C17.83,4.47 17.83,5.42 17.25,6.01 L17.25,6.01 Z"/><path fill="none" stroke="#000" d="M15.98,7.268 L13.851,5.148"/></svg>',"phone-landscape":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M17,5.5 C17.8,5.5 18.5,6.2 18.5,7 L18.5,14 C18.5,14.8 17.8,15.5 17,15.5 L3,15.5 C2.2,15.5 1.5,14.8 1.5,14 L1.5,7 C1.5,6.2 2.2,5.5 3,5.5 L17,5.5 L17,5.5 L17,5.5 Z"/><circle cx="3.8" cy="10.5" r=".8"/></svg>',phone:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M15.5,17 C15.5,17.8 14.8,18.5 14,18.5 L7,18.5 C6.2,18.5 5.5,17.8 5.5,17 L5.5,3 C5.5,2.2 6.2,1.5 7,1.5 L14,1.5 C14.8,1.5 15.5,2.2 15.5,3 L15.5,17 L15.5,17 L15.5,17 Z"/><circle cx="10.5" cy="16.5" r=".8"/></svg>',pinterest:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.21,1 C5.5,1 3,4.16 3,7.61 C3,9.21 3.85,11.2 5.22,11.84 C5.43,11.94 5.54,11.89 5.58,11.69 C5.62,11.54 5.8,10.8 5.88,10.45 C5.91,10.34 5.89,10.24 5.8,10.14 C5.36,9.59 5,8.58 5,7.65 C5,5.24 6.82,2.91 9.93,2.91 C12.61,2.91 14.49,4.74 14.49,7.35 C14.49,10.3 13,12.35 11.06,12.35 C9.99,12.35 9.19,11.47 9.44,10.38 C9.75,9.08 10.35,7.68 10.35,6.75 C10.35,5.91 9.9,5.21 8.97,5.21 C7.87,5.21 6.99,6.34 6.99,7.86 C6.99,8.83 7.32,9.48 7.32,9.48 C7.32,9.48 6.24,14.06 6.04,14.91 C5.7,16.35 6.08,18.7 6.12,18.9 C6.14,19.01 6.26,19.05 6.33,18.95 C6.44,18.81 7.74,16.85 8.11,15.44 C8.24,14.93 8.79,12.84 8.79,12.84 C9.15,13.52 10.19,14.09 11.29,14.09 C14.58,14.09 16.96,11.06 16.96,7.3 C16.94,3.7 14,1 10.21,1"/></svg>',"play-circle":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" stroke-width="1.1" points="8.5 7 13.5 10 8.5 13"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/></svg>',play:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="6.5,5 14.5,10 6.5,15"/></svg>',"plus-circle":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="9.5" cy="9.5" r="9"/><line fill="none" stroke="#000" x1="9.5" y1="5" x2="9.5" y2="14"/><line fill="none" stroke="#000" x1="5" y1="9.5" x2="14" y2="9.5"/></svg>',plus:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="1" width="1" height="17"/><rect x="1" y="9" width="17" height="1"/></svg>',print:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="4.5 13.5 1.5 13.5 1.5 6.5 18.5 6.5 18.5 13.5 15.5 13.5"/><polyline fill="none" stroke="#000" points="15.5 6.5 15.5 2.5 4.5 2.5 4.5 6.5"/><rect fill="none" stroke="#000" width="11" height="6" x="4.5" y="11.5"/><rect width="8" height="1" x="6" y="13"/><rect width="8" height="1" x="6" y="15"/></svg>',pull:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="6.85,8 9.5,10.6 12.15,8 12.85,8.7 9.5,12 6.15,8.7"/><line fill="none" stroke="#000" x1="9.5" y1="11" x2="9.5" y2="2"/><polyline fill="none" stroke="#000" points="6,5.5 3.5,5.5 3.5,18.5 15.5,18.5 15.5,5.5 13,5.5"/></svg>',push:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="12.15,4 9.5,1.4 6.85,4 6.15,3.3 9.5,0 12.85,3.3"/><line fill="none" stroke="#000" x1="9.5" y1="10" x2="9.5" y2="1"/><polyline fill="none" stroke="#000" points="6 5.5 3.5 5.5 3.5 18.5 15.5 18.5 15.5 5.5 13 5.5"/></svg>',question:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/><circle cx="10.44" cy="14.42" r="1.05"/><path fill="none" stroke="#000" stroke-width="1.2" d="M8.17,7.79 C8.17,4.75 12.72,4.73 12.72,7.72 C12.72,8.67 11.81,9.15 11.23,9.75 C10.75,10.24 10.51,10.73 10.45,11.4 C10.44,11.53 10.43,11.64 10.43,11.75"/></svg>',"quote-right":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.27,7.79 C17.27,9.45 16.97,10.43 15.99,12.02 C14.98,13.64 13,15.23 11.56,15.97 L11.1,15.08 C12.34,14.2 13.14,13.51 14.02,11.82 C14.27,11.34 14.41,10.92 14.49,10.54 C14.3,10.58 14.09,10.6 13.88,10.6 C12.06,10.6 10.59,9.12 10.59,7.3 C10.59,5.48 12.06,4 13.88,4 C15.39,4 16.67,5.02 17.05,6.42 C17.19,6.82 17.27,7.27 17.27,7.79 L17.27,7.79 Z"/><path d="M8.68,7.79 C8.68,9.45 8.38,10.43 7.4,12.02 C6.39,13.64 4.41,15.23 2.97,15.97 L2.51,15.08 C3.75,14.2 4.55,13.51 5.43,11.82 C5.68,11.34 5.82,10.92 5.9,10.54 C5.71,10.58 5.5,10.6 5.29,10.6 C3.47,10.6 2,9.12 2,7.3 C2,5.48 3.47,4 5.29,4 C6.8,4 8.08,5.02 8.46,6.42 C8.6,6.82 8.68,7.27 8.68,7.79 L8.68,7.79 Z"/></svg>',receiver:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.01" d="M6.189,13.611C8.134,15.525 11.097,18.239 13.867,18.257C16.47,18.275 18.2,16.241 18.2,16.241L14.509,12.551L11.539,13.639L6.189,8.29L7.313,5.355L3.76,1.8C3.76,1.8 1.732,3.537 1.7,6.092C1.667,8.809 4.347,11.738 6.189,13.611"/></svg>',reddit:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19 9.05a2.56 2.56 0 0 0-2.56-2.56 2.59 2.59 0 0 0-1.88.82 10.63 10.63 0 0 0-4.14-1v-.08c.58-1.62 1.58-3.89 2.7-4.1.38-.08.77.12 1.19.57a1.15 1.15 0 0 0-.06.37 1.48 1.48 0 1 0 1.51-1.45 1.43 1.43 0 0 0-.76.19A2.29 2.29 0 0 0 12.91 1c-2.11.43-3.39 4.38-3.63 5.19 0 0 0 .11-.06.11a10.65 10.65 0 0 0-3.75 1A2.56 2.56 0 0 0 1 9.05a2.42 2.42 0 0 0 .72 1.76A5.18 5.18 0 0 0 1.24 13c0 3.66 3.92 6.64 8.73 6.64s8.74-3 8.74-6.64a5.23 5.23 0 0 0-.46-2.13A2.58 2.58 0 0 0 19 9.05zm-16.88 0a1.44 1.44 0 0 1 2.27-1.19 7.68 7.68 0 0 0-2.07 1.91 1.33 1.33 0 0 1-.2-.72zM10 18.4c-4.17 0-7.55-2.4-7.55-5.4S5.83 7.53 10 7.53 17.5 10 17.5 13s-3.38 5.4-7.5 5.4zm7.69-8.61a7.62 7.62 0 0 0-2.09-1.91 1.41 1.41 0 0 1 .84-.28 1.47 1.47 0 0 1 1.44 1.45 1.34 1.34 0 0 1-.21.72z"/><path d="M6.69 12.58a1.39 1.39 0 1 1 1.39-1.39 1.38 1.38 0 0 1-1.38 1.39z"/><path d="M14.26 11.2a1.39 1.39 0 1 1-1.39-1.39 1.39 1.39 0 0 1 1.39 1.39z"/><path d="M13.09 14.88a.54.54 0 0 1-.09.77 5.3 5.3 0 0 1-3.26 1.19 5.61 5.61 0 0 1-3.4-1.22.55.55 0 1 1 .73-.83 4.09 4.09 0 0 0 5.25 0 .56.56 0 0 1 .77.09z"/></svg>',refresh:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M17.08,11.15 C17.09,11.31 17.1,11.47 17.1,11.64 C17.1,15.53 13.94,18.69 10.05,18.69 C6.16,18.68 3,15.53 3,11.63 C3,7.74 6.16,4.58 10.05,4.58 C10.9,4.58 11.71,4.73 12.46,5"/><polyline fill="none" stroke="#000" points="9.9 2 12.79 4.89 9.79 7.9"/></svg>',reply:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.7,13.11 C16.12,10.02 13.84,7.85 11.02,6.61 C10.57,6.41 9.75,6.13 9,5.91 L9,2 L1,9 L9,16 L9,12.13 C10.78,12.47 12.5,13.19 14.09,14.25 C17.13,16.28 18.56,18.54 18.56,18.54 C18.56,18.54 18.81,15.28 17.7,13.11 L17.7,13.11 Z M14.82,13.53 C13.17,12.4 11.01,11.4 8,10.92 L8,13.63 L2.55,9 L8,4.25 L8,6.8 C8.3,6.86 9.16,7.02 10.37,7.49 C13.3,8.65 15.54,10.96 16.65,13.08 C16.97,13.7 17.48,14.86 17.68,16 C16.87,15.05 15.73,14.15 14.82,13.53 L14.82,13.53 Z"/></svg>',rss:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="3.12" cy="16.8" r="1.85"/><path fill="none" stroke="#000" stroke-width="1.1" d="M1.5,8.2 C1.78,8.18 2.06,8.16 2.35,8.16 C7.57,8.16 11.81,12.37 11.81,17.57 C11.81,17.89 11.79,18.19 11.76,18.5"/><path fill="none" stroke="#000" stroke-width="1.1" d="M1.5,2.52 C1.78,2.51 2.06,2.5 2.35,2.5 C10.72,2.5 17.5,9.24 17.5,17.57 C17.5,17.89 17.49,18.19 17.47,18.5"/></svg>',search:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="9" cy="9" r="7"/><path fill="none" stroke="#000" stroke-width="1.1" d="M14,14 L18,18 L14,14 Z"/></svg>',server:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="3" width="1" height="2"/><rect x="5" y="3" width="1" height="2"/><rect x="7" y="3" width="1" height="2"/><rect x="16" y="3" width="1" height="1"/><rect x="16" y="10" width="1" height="1"/><circle fill="none" stroke="#000" cx="9.9" cy="17.4" r="1.4"/><rect x="3" y="10" width="1" height="2"/><rect x="5" y="10" width="1" height="2"/><rect x="9.5" y="14" width="1" height="2"/><rect x="3" y="17" width="6" height="1"/><rect x="11" y="17" width="6" height="1"/><rect fill="none" stroke="#000" x="1.5" y="1.5" width="17" height="5"/><rect fill="none" stroke="#000" x="1.5" y="8.5" width="17" height="5"/></svg>',settings:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><ellipse fill="none" stroke="#000" cx="6.11" cy="3.55" rx="2.11" ry="2.15"/><ellipse fill="none" stroke="#000" cx="6.11" cy="15.55" rx="2.11" ry="2.15"/><circle fill="none" stroke="#000" cx="13.15" cy="9.55" r="2.15"/><rect x="1" y="3" width="3" height="1"/><rect x="10" y="3" width="8" height="1"/><rect x="1" y="9" width="8" height="1"/><rect x="15" y="9" width="3" height="1"/><rect x="1" y="15" width="3" height="1"/><rect x="10" y="15" width="8" height="1"/></svg>',shrink:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="11 4 12 4 12 8 16 8 16 9 11 9"/><polygon points="4 11 9 11 9 16 8 16 8 12 4 12"/><path fill="none" stroke="#000" stroke-width="1.1" d="M12,8 L18,2"/><path fill="none" stroke="#000" stroke-width="1.1" d="M2,18 L8,12"/></svg>',"sign-in":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="7 2 17 2 17 17 7 17 7 16 16 16 16 3 7 3"/><polygon points="9.1 13.4 8.5 12.8 11.28 10 4 10 4 9 11.28 9 8.5 6.2 9.1 5.62 13 9.5"/></svg>',"sign-out":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="13.1 13.4 12.5 12.8 15.28 10 8 10 8 9 15.28 9 12.5 6.2 13.1 5.62 17 9.5"/><polygon points="13 2 3 2 3 17 13 17 13 16 4 16 4 3 13 3"/></svg>',social:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><line fill="none" stroke="#000" stroke-width="1.1" x1="13.4" y1="14" x2="6.3" y2="10.7"/><line fill="none" stroke="#000" stroke-width="1.1" x1="13.5" y1="5.5" x2="6.5" y2="8.8"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="15.5" cy="4.6" r="2.3"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="15.5" cy="14.8" r="2.3"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="4.5" cy="9.8" r="2.3"/></svg>',soundcloud:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.2,9.4c-0.4,0-0.8,0.1-1.101,0.2c-0.199-2.5-2.399-4.5-5-4.5c-0.6,0-1.2,0.1-1.7,0.3C9.2,5.5,9.1,5.6,9.1,5.6V15h8 c1.601,0,2.801-1.2,2.801-2.8C20,10.7,18.7,9.4,17.2,9.4L17.2,9.4z"/><rect x="6" y="6.5" width="1.5" height="8.5"/><rect x="3" y="8" width="1.5" height="7"/><rect y="10" width="1.5" height="5"/></svg>',star:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" stroke-width="1.01" points="10 2 12.63 7.27 18.5 8.12 14.25 12.22 15.25 18 10 15.27 4.75 18 5.75 12.22 1.5 8.12 7.37 7.27"/></svg>',strikethrough:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6,13.02 L6.65,13.02 C7.64,15.16 8.86,16.12 10.41,16.12 C12.22,16.12 12.92,14.93 12.92,13.89 C12.92,12.55 11.99,12.03 9.74,11.23 C8.05,10.64 6.23,10.11 6.23,7.83 C6.23,5.5 8.09,4.09 10.4,4.09 C11.44,4.09 12.13,4.31 12.72,4.54 L13.33,4 L13.81,4 L13.81,7.59 L13.16,7.59 C12.55,5.88 11.52,4.89 10.07,4.89 C8.84,4.89 7.89,5.69 7.89,7.03 C7.89,8.29 8.89,8.78 10.88,9.45 C12.57,10.03 14.38,10.6 14.38,12.91 C14.38,14.75 13.27,16.93 10.18,16.93 C9.18,16.93 8.17,16.69 7.46,16.39 L6.52,17 L6,17 L6,13.02 L6,13.02 Z"/><rect x="3" y="10" width="15" height="1"/></svg>',table:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="3" width="18" height="1"/><rect x="1" y="7" width="18" height="1"/><rect x="1" y="11" width="18" height="1"/><rect x="1" y="15" width="18" height="1"/></svg>',"tablet-landscape":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M1.5,5 C1.5,4.2 2.2,3.5 3,3.5 L17,3.5 C17.8,3.5 18.5,4.2 18.5,5 L18.5,16 C18.5,16.8 17.8,17.5 17,17.5 L3,17.5 C2.2,17.5 1.5,16.8 1.5,16 L1.5,5 L1.5,5 L1.5,5 Z"/><circle cx="3.7" cy="10.5" r=".8"/></svg>',tablet:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M5,18.5 C4.2,18.5 3.5,17.8 3.5,17 L3.5,3 C3.5,2.2 4.2,1.5 5,1.5 L16,1.5 C16.8,1.5 17.5,2.2 17.5,3 L17.5,17 C17.5,17.8 16.8,18.5 16,18.5 L5,18.5 L5,18.5 L5,18.5 Z"/><circle cx="10.5" cy="16.3" r=".8"/></svg>',tag:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" stroke-width="1.1" d="M17.5,3.71 L17.5,7.72 C17.5,7.96 17.4,8.2 17.21,8.39 L8.39,17.2 C7.99,17.6 7.33,17.6 6.93,17.2 L2.8,13.07 C2.4,12.67 2.4,12.01 2.8,11.61 L11.61,2.8 C11.81,2.6 12.08,2.5 12.34,2.5 L16.19,2.5 C16.52,2.5 16.86,2.63 17.11,2.88 C17.35,3.11 17.48,3.4 17.5,3.71 L17.5,3.71 Z"/><circle cx="14" cy="6" r="1"/></svg>',thumbnails:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" x="3.5" y="3.5" width="5" height="5"/><rect fill="none" stroke="#000" x="11.5" y="3.5" width="5" height="5"/><rect fill="none" stroke="#000" x="11.5" y="11.5" width="5" height="5"/><rect fill="none" stroke="#000" x="3.5" y="11.5" width="5" height="5"/></svg>',trash:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="6.5 3 6.5 1.5 13.5 1.5 13.5 3"/><polyline fill="none" stroke="#000" points="4.5 4 4.5 18.5 15.5 18.5 15.5 4"/><rect x="8" y="7" width="1" height="9"/><rect x="11" y="7" width="1" height="9"/><rect x="2" y="3" width="16" height="1"/></svg>',"triangle-down":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="5 7 15 7 10 12"/></svg>',"triangle-left":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="12 5 7 10 12 15"/></svg>',"triangle-right":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="8 5 13 10 8 15"/></svg>',"triangle-up":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="5 13 10 8 15 13"/></svg>',tripadvisor:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19.021,7.866C19.256,6.862,20,5.854,20,5.854h-3.346C14.781,4.641,12.504,4,9.98,4C7.363,4,4.999,4.651,3.135,5.876H0\tc0,0,0.738,0.987,0.976,1.988c-0.611,0.837-0.973,1.852-0.973,2.964c0,2.763,2.249,5.009,5.011,5.009\tc1.576,0,2.976-0.737,3.901-1.879l1.063,1.599l1.075-1.615c0.475,0.611,1.1,1.111,1.838,1.451c1.213,0.547,2.574,0.612,3.825,0.15\tc2.589-0.963,3.913-3.852,2.964-6.439c-0.175-0.463-0.4-0.876-0.675-1.238H19.021z M16.38,14.594\tc-1.002,0.371-2.088,0.328-3.06-0.119c-0.688-0.317-1.252-0.817-1.657-1.438c-0.164-0.25-0.313-0.52-0.417-0.811\tc-0.124-0.328-0.186-0.668-0.217-1.014c-0.063-0.689,0.037-1.396,0.339-2.043c0.448-0.971,1.251-1.71,2.25-2.079\tc2.075-0.765,4.375,0.3,5.14,2.366c0.762,2.066-0.301,4.37-2.363,5.134L16.38,14.594L16.38,14.594z M8.322,13.066\tc-0.72,1.059-1.935,1.76-3.309,1.76c-2.207,0-4.001-1.797-4.001-3.996c0-2.203,1.795-4.002,4.001-4.002\tc2.204,0,3.999,1.8,3.999,4.002c0,0.137-0.024,0.261-0.04,0.396c-0.067,0.678-0.284,1.313-0.648,1.853v-0.013H8.322z M2.472,10.775\tc0,1.367,1.112,2.479,2.476,2.479c1.363,0,2.472-1.11,2.472-2.479c0-1.359-1.11-2.468-2.472-2.468\tC3.584,8.306,2.473,9.416,2.472,10.775L2.472,10.775z M12.514,10.775c0,1.367,1.104,2.479,2.471,2.479\tc1.363,0,2.474-1.108,2.474-2.479c0-1.359-1.11-2.468-2.474-2.468c-1.364,0-2.477,1.109-2.477,2.468H12.514z M3.324,10.775\tc0-0.893,0.726-1.618,1.614-1.618c0.889,0,1.625,0.727,1.625,1.618c0,0.898-0.725,1.627-1.625,1.627\tc-0.901,0-1.625-0.729-1.625-1.627H3.324z M13.354,10.775c0-0.893,0.726-1.618,1.627-1.618c0.886,0,1.61,0.727,1.61,1.618\tc0,0.898-0.726,1.627-1.626,1.627s-1.625-0.729-1.625-1.627H13.354z M9.977,4.875c1.798,0,3.425,0.324,4.849,0.968\tc-0.535,0.015-1.061,0.108-1.586,0.3c-1.264,0.463-2.264,1.388-2.815,2.604c-0.262,0.551-0.398,1.133-0.448,1.72\tC9.79,7.905,7.677,5.873,5.076,5.82C6.501,5.208,8.153,4.875,9.94,4.875H9.977z"/></svg>',tumblr:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.885,8.598c0,0,0,3.393,0,4.996c0,0.282,0,0.66,0.094,0.942c0.377,1.509,1.131,2.545,2.545,3.11 c1.319,0.472,2.356,0.472,3.676,0c0.565-0.188,1.132-0.659,1.132-0.659l-0.849-2.263c0,0-1.036,0.378-1.603,0.283 c-0.565-0.094-1.226-0.66-1.226-1.508c0-1.603,0-4.902,0-4.902h2.828V5.771h-2.828V2H8.205c0,0-0.094,0.66-0.188,0.942 C7.828,3.791,7.262,4.733,6.603,5.394C5.848,6.147,5,6.43,5,6.43v2.168H6.885z"/></svg>',tv:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="7" y="16" width="6" height="1"/><rect fill="none" stroke="#000" x=".5" y="3.5" width="19" height="11"/></svg>',twitter:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19,4.74 C18.339,5.029 17.626,5.229 16.881,5.32 C17.644,4.86 18.227,4.139 18.503,3.28 C17.79,3.7 17.001,4.009 16.159,4.17 C15.485,3.45 14.526,3 13.464,3 C11.423,3 9.771,4.66 9.771,6.7 C9.771,6.99 9.804,7.269 9.868,7.539 C6.795,7.38 4.076,5.919 2.254,3.679 C1.936,4.219 1.754,4.86 1.754,5.539 C1.754,6.82 2.405,7.95 3.397,8.61 C2.79,8.589 2.22,8.429 1.723,8.149 L1.723,8.189 C1.723,9.978 2.997,11.478 4.686,11.82 C4.376,11.899 4.049,11.939 3.713,11.939 C3.475,11.939 3.245,11.919 3.018,11.88 C3.49,13.349 4.852,14.419 6.469,14.449 C5.205,15.429 3.612,16.019 1.882,16.019 C1.583,16.019 1.29,16.009 1,15.969 C2.635,17.019 4.576,17.629 6.662,17.629 C13.454,17.629 17.17,12 17.17,7.129 C17.17,6.969 17.166,6.809 17.157,6.649 C17.879,6.129 18.504,5.478 19,4.74"/></svg>',uikit:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon points="14.4,3.1 11.3,5.1 15,7.3 15,12.9 10,15.7 5,12.9 5,8.5 2,6.8 2,14.8 9.9,19.5 18,14.8 18,5.3"/><polygon points="9.8,4.2 6.7,2.4 9.8,0.4 12.9,2.3"/></svg>',unlock:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect fill="none" stroke="#000" x="3.5" y="8.5" width="13" height="10"/><path fill="none" stroke="#000" d="M6.5,8.5 L6.5,4.9 C6.5,3 8.1,1.5 10,1.5 C11.9,1.5 13.5,3 13.5,4.9"/></svg>',upload:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" points="5 8 9.5 3.5 14 8"/><rect x="3" y="17" width="13" height="1"/><line fill="none" stroke="#000" x1="9.5" y1="15" x2="9.5" y2="4"/></svg>',user:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="9.9" cy="6.4" r="4.4"/><path fill="none" stroke="#000" stroke-width="1.1" d="M1.5,19 C2.3,14.5 5.8,11.2 10,11.2 C14.2,11.2 17.7,14.6 18.5,19.2"/></svg>',users:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="7.7" cy="8.6" r="3.5"/><path fill="none" stroke="#000" stroke-width="1.1" d="M1,18.1 C1.7,14.6 4.4,12.1 7.6,12.1 C10.9,12.1 13.7,14.8 14.3,18.3"/><path fill="none" stroke="#000" stroke-width="1.1" d="M11.4,4 C12.8,2.4 15.4,2.8 16.3,4.7 C17.2,6.6 15.7,8.9 13.6,8.9 C16.5,8.9 18.8,11.3 19.2,14.1"/></svg>',"video-camera":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><polygon fill="none" stroke="#000" points="17.5 6.9 17.5 13.1 13.5 10.4 13.5 14.5 2.5 14.5 2.5 5.5 13.5 5.5 13.5 9.6 17.5 6.9"/></svg>',vimeo:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.065,7.59C1.84,7.367,1.654,7.082,1.468,6.838c-0.332-0.42-0.137-0.411,0.274-0.772c1.026-0.91,2.004-1.896,3.127-2.688 c1.017-0.713,2.365-1.173,3.286-0.039c0.849,1.045,0.869,2.629,1.084,3.891c0.215,1.309,0.421,2.648,0.88,3.901 c0.127,0.352,0.37,1.018,0.81,1.074c0.567,0.078,1.145-0.917,1.408-1.289c0.684-0.987,1.611-2.317,1.494-3.587 c-0.115-1.349-1.572-1.095-2.482-0.773c0.146-1.514,1.555-3.216,2.912-3.792c1.439-0.597,3.579-0.587,4.302,1.036 c0.772,1.759,0.078,3.802-0.763,5.396c-0.918,1.731-2.1,3.333-3.363,4.829c-1.114,1.329-2.432,2.787-4.093,3.422 c-1.897,0.723-3.021-0.686-3.667-2.318c-0.705-1.777-1.056-3.771-1.565-5.621C4.898,8.726,4.644,7.836,4.136,7.191 C3.473,6.358,2.72,7.141,2.065,7.59C1.977,7.502,2.115,7.551,2.065,7.59L2.065,7.59z"/></svg>',warning:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="14" r="1"/><circle fill="none" stroke="#000" stroke-width="1.1" cx="10" cy="10" r="9"/><path d="M10.97,7.72 C10.85,9.54 10.56,11.29 10.56,11.29 C10.51,11.87 10.27,12 9.99,12 C9.69,12 9.49,11.87 9.43,11.29 C9.43,11.29 9.16,9.54 9.03,7.72 C8.96,6.54 9.03,6 9.03,6 C9.03,5.45 9.46,5.02 9.99,5 C10.53,5.01 10.97,5.44 10.97,6 C10.97,6 11.04,6.54 10.97,7.72 L10.97,7.72 Z"/></svg>',whatsapp:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M16.7,3.3c-1.8-1.8-4.1-2.8-6.7-2.8c-5.2,0-9.4,4.2-9.4,9.4c0,1.7,0.4,3.3,1.3,4.7l-1.3,4.9l5-1.3c1.4,0.8,2.9,1.2,4.5,1.2 l0,0l0,0c5.2,0,9.4-4.2,9.4-9.4C19.5,7.4,18.5,5,16.7,3.3 M10.1,17.7L10.1,17.7c-1.4,0-2.8-0.4-4-1.1l-0.3-0.2l-3,0.8l0.8-2.9 l-0.2-0.3c-0.8-1.2-1.2-2.7-1.2-4.2c0-4.3,3.5-7.8,7.8-7.8c2.1,0,4.1,0.8,5.5,2.3c1.5,1.5,2.3,3.4,2.3,5.5 C17.9,14.2,14.4,17.7,10.1,17.7 M14.4,11.9c-0.2-0.1-1.4-0.7-1.6-0.8c-0.2-0.1-0.4-0.1-0.5,0.1c-0.2,0.2-0.6,0.8-0.8,0.9 c-0.1,0.2-0.3,0.2-0.5,0.1c-0.2-0.1-1-0.4-1.9-1.2c-0.7-0.6-1.2-1.4-1.3-1.6c-0.1-0.2,0-0.4,0.1-0.5C8,8.8,8.1,8.7,8.2,8.5 c0.1-0.1,0.2-0.2,0.2-0.4c0.1-0.2,0-0.3,0-0.4C8.4,7.6,7.9,6.5,7.7,6C7.5,5.5,7.3,5.6,7.2,5.6c-0.1,0-0.3,0-0.4,0 c-0.2,0-0.4,0.1-0.6,0.3c-0.2,0.2-0.8,0.8-0.8,2c0,1.2,0.8,2.3,1,2.4c0.1,0.2,1.7,2.5,4,3.5c0.6,0.2,1,0.4,1.3,0.5 c0.6,0.2,1.1,0.2,1.5,0.1c0.5-0.1,1.4-0.6,1.6-1.1c0.2-0.5,0.2-1,0.1-1.1C14.8,12.1,14.6,12,14.4,11.9"/></svg>',wordpress:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10,0.5c-5.2,0-9.5,4.3-9.5,9.5s4.3,9.5,9.5,9.5c5.2,0,9.5-4.3,9.5-9.5S15.2,0.5,10,0.5L10,0.5L10,0.5z M15.6,3.9h-0.1 c-0.8,0-1.4,0.7-1.4,1.5c0,0.7,0.4,1.3,0.8,1.9c0.3,0.6,0.7,1.3,0.7,2.3c0,0.7-0.3,1.5-0.6,2.7L14.1,15l-3-8.9 c0.5,0,0.9-0.1,0.9-0.1C12.5,6,12.5,5.3,12,5.4c0,0-1.3,0.1-2.2,0.1C9,5.5,7.7,5.4,7.7,5.4C7.2,5.3,7.2,6,7.6,6c0,0,0.4,0.1,0.9,0.1 l1.3,3.5L8,15L5,6.1C5.5,6.1,5.9,6,5.9,6C6.4,6,6.3,5.3,5.9,5.4c0,0-1.3,0.1-2.2,0.1c-0.2,0-0.3,0-0.5,0c1.5-2.2,4-3.7,6.9-3.7 C12.2,1.7,14.1,2.6,15.6,3.9L15.6,3.9L15.6,3.9z M2.5,6.6l3.9,10.8c-2.7-1.3-4.6-4.2-4.6-7.4C1.8,8.8,2,7.6,2.5,6.6L2.5,6.6L2.5,6.6 z M10.2,10.7l2.5,6.9c0,0,0,0.1,0.1,0.1C11.9,18,11,18.2,10,18.2c-0.8,0-1.6-0.1-2.3-0.3L10.2,10.7L10.2,10.7L10.2,10.7z M14.2,17.1 l2.5-7.3c0.5-1.2,0.6-2.1,0.6-2.9c0-0.3,0-0.6-0.1-0.8c0.6,1.2,1,2.5,1,4C18.3,13,16.6,15.7,14.2,17.1L14.2,17.1L14.2,17.1z"/></svg>',world:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="#000" d="M1,10.5 L19,10.5"/><path fill="none" stroke="#000" d="M2.35,15.5 L17.65,15.5"/><path fill="none" stroke="#000" d="M2.35,5.5 L17.523,5.5"/><path fill="none" stroke="#000" d="M10,19.46 L9.98,19.46 C7.31,17.33 5.61,14.141 5.61,10.58 C5.61,7.02 7.33,3.83 10,1.7 C10.01,1.7 9.99,1.7 10,1.7 L10,1.7 C12.67,3.83 14.4,7.02 14.4,10.58 C14.4,14.141 12.67,17.33 10,19.46 L10,19.46 L10,19.46 L10,19.46 Z"/><circle fill="none" stroke="#000" cx="10" cy="10.5" r="9"/></svg>',xing:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4.4,4.56 C4.24,4.56 4.11,4.61 4.05,4.72 C3.98,4.83 3.99,4.97 4.07,5.12 L5.82,8.16 L5.82,8.17 L3.06,13.04 C2.99,13.18 2.99,13.33 3.06,13.44 C3.12,13.55 3.24,13.62 3.4,13.62 L6,13.62 C6.39,13.62 6.57,13.36 6.71,13.12 C6.71,13.12 9.41,8.35 9.51,8.16 C9.49,8.14 7.72,5.04 7.72,5.04 C7.58,4.81 7.39,4.56 6.99,4.56 L4.4,4.56 L4.4,4.56 Z"/><path d="M15.3,1 C14.91,1 14.74,1.25 14.6,1.5 C14.6,1.5 9.01,11.42 8.82,11.74 C8.83,11.76 12.51,18.51 12.51,18.51 C12.64,18.74 12.84,19 13.23,19 L15.82,19 C15.98,19 16.1,18.94 16.16,18.83 C16.23,18.72 16.23,18.57 16.16,18.43 L12.5,11.74 L12.5,11.72 L18.25,1.56 C18.32,1.42 18.32,1.27 18.25,1.16 C18.21,1.06 18.08,1 17.93,1 L15.3,1 L15.3,1 Z"/></svg>',yelp:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.175,14.971c-0.112,0.77-1.686,2.767-2.406,3.054c-0.246,0.1-0.487,0.076-0.675-0.069\tc-0.122-0.096-2.446-3.859-2.446-3.859c-0.194-0.293-0.157-0.682,0.083-0.978c0.234-0.284,0.581-0.393,0.881-0.276\tc0.016,0.01,4.21,1.394,4.332,1.482c0.178,0.148,0.263,0.379,0.225,0.646L17.175,14.971L17.175,14.971z M11.464,10.789\tc-0.203-0.307-0.199-0.666,0.009-0.916c0,0,2.625-3.574,2.745-3.657c0.203-0.135,0.452-0.141,0.69-0.025\tc0.691,0.335,2.085,2.405,2.167,3.199v0.027c0.024,0.271-0.082,0.491-0.273,0.623c-0.132,0.083-4.43,1.155-4.43,1.155\tc-0.322,0.096-0.68-0.06-0.882-0.381L11.464,10.789z M9.475,9.563C9.32,9.609,8.848,9.757,8.269,8.817c0,0-3.916-6.16-4.007-6.351\tc-0.057-0.212,0.011-0.455,0.202-0.65C5.047,1.211,8.21,0.327,9.037,0.529c0.27,0.069,0.457,0.238,0.522,0.479\tc0.047,0.266,0.433,5.982,0.488,7.264C10.098,9.368,9.629,9.517,9.475,9.563z M9.927,19.066c-0.083,0.225-0.273,0.373-0.54,0.421\tc-0.762,0.13-3.15-0.751-3.647-1.342c-0.096-0.131-0.155-0.262-0.167-0.394c-0.011-0.095,0-0.189,0.036-0.272\tc0.061-0.155,2.917-3.538,2.917-3.538c0.214-0.272,0.595-0.355,0.952-0.213c0.345,0.13,0.56,0.428,0.536,0.749\tC10.014,14.479,9.977,18.923,9.927,19.066z M3.495,13.912c-0.235-0.009-0.444-0.148-0.568-0.382c-0.089-0.17-0.151-0.453-0.19-0.794\tC2.63,11.701,2.761,10.144,3.07,9.648c0.145-0.226,0.357-0.345,0.592-0.336c0.154,0,4.255,1.667,4.255,1.667\tc0.321,0.118,0.521,0.453,0.5,0.833c-0.023,0.37-0.236,0.655-0.551,0.738L3.495,13.912z"/></svg>',youtube:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15,4.1c1,0.1,2.3,0,3,0.8c0.8,0.8,0.9,2.1,0.9,3.1C19,9.2,19,10.9,19,12c-0.1,1.1,0,2.4-0.5,3.4c-0.5,1.1-1.4,1.5-2.5,1.6 c-1.2,0.1-8.6,0.1-11,0c-1.1-0.1-2.4-0.1-3.2-1c-0.7-0.8-0.7-2-0.8-3C1,11.8,1,10.1,1,8.9c0-1.1,0-2.4,0.5-3.4C2,4.5,3,4.3,4.1,4.2 C5.3,4.1,12.6,4,15,4.1z M8,7.5v6l5.5-3L8,7.5z"/></svg>'})}return"undefined"!=typeof window&&window.UIkit&&window.UIkit.use(i),i});
\ No newline at end of file
diff --git a/webclient/view/default/ui/js/uikit.min.js b/webclient/view/default/ui/js/uikit.min.js
new file mode 100644 (file)
index 0000000..5fddab3
--- /dev/null
@@ -0,0 +1,3 @@
+/*! UIkit 3.5.3 | https://www.getuikit.com | (c) 2014 - 2020 YOOtheme | MIT License */
+
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define("uikit",e):(t=t||self).UIkit=e()}(this,function(){"use strict";var t=Object.prototype,i=t.hasOwnProperty;function l(t,e){return i.call(t,e)}var e={},n=/([a-z\d])([A-Z])/g;function d(t){return t in e||(e[t]=t.replace(n,"$1-$2").toLowerCase()),e[t]}var r=/-(\w)/g;function f(t){return t.replace(r,o)}function o(t,e){return e?e.toUpperCase():""}function p(t){return t.length?o(0,t.charAt(0))+t.slice(1):""}var s=String.prototype,a=s.startsWith||function(t){return 0===this.lastIndexOf(t,0)};function w(t,e){return a.call(t,e)}var h=s.endsWith||function(t){return this.substr(-t.length)===t};function u(t,e){return h.call(t,e)}function c(t,e){return!!~this.indexOf(t,e)}var m=Array.prototype,g=s.includes||c,v=m.includes||c;function b(t,e){return t&&(D(t)?g:v).call(t,e)}var x=m.findIndex||function(t){for(var e=arguments,i=0;i<this.length;i++)if(t.call(e[1],this[i],i,this))return i;return-1};function y(t,e){return x.call(t,e)}var k=Array.isArray;function $(t){return"function"==typeof t}function I(t){return null!==t&&"object"==typeof t}var S=t.toString;function T(t){return"[object Object]"===S.call(t)}function E(t){return I(t)&&t===t.window}function _(t){return I(t)&&9===t.nodeType}function C(t){return I(t)&&!!t.jquery}function A(t){return I(t)&&1<=t.nodeType}function M(t){return I(t)&&1===t.nodeType}function N(t){return S.call(t).match(/^\[object (NodeList|HTMLCollection)\]$/)}function z(t){return"boolean"==typeof t}function D(t){return"string"==typeof t}function B(t){return"number"==typeof t}function P(t){return B(t)||D(t)&&!isNaN(t-parseFloat(t))}function O(t){return!(k(t)?t.length:I(t)&&Object.keys(t).length)}function H(t){return void 0===t}function L(t){return z(t)?t:"true"===t||"1"===t||""===t||"false"!==t&&"0"!==t&&t}function F(t){var e=Number(t);return!isNaN(e)&&e}function j(t){return parseFloat(t)||0}function W(t){return A(t)?t:N(t)||C(t)?t[0]:k(t)?W(t[0]):null}function V(t){return A(t)?[t]:N(t)?m.slice.call(t):k(t)?t.map(W).filter(Boolean):C(t)?t.toArray():[]}function R(t){return E(t)?t:(t=W(t))?(_(t)?t:t.ownerDocument).defaultView:window}function q(t){return k(t)?t:D(t)?t.split(/,(?![^(]*\))/).map(function(t){return P(t)?F(t):L(t.trim())}):[t]}function U(t){return t?u(t,"ms")?j(t):1e3*j(t):0}function Y(t,i){return t===i||I(t)&&I(i)&&Object.keys(t).length===Object.keys(i).length&&J(t,function(t,e){return t===i[e]})}function X(t,e,i){return t.replace(new RegExp(e+"|"+i,"g"),function(t){return t===e?i:e})}var G=Object.assign||function(t){for(var e=[],i=arguments.length-1;0<i--;)e[i]=arguments[i+1];t=Object(t);for(var n=0;n<e.length;n++){var r=e[n];if(null!==r)for(var o in r)l(r,o)&&(t[o]=r[o])}return t};function K(t){return t[t.length-1]}function J(t,e){for(var i in t)if(!1===e(t[i],i))return!1;return!0}function Z(t,r){return t.sort(function(t,e){var i=t[r];void 0===i&&(i=0);var n=e[r];return void 0===n&&(n=0),n<i?1:i<n?-1:0})}function Q(t,i){var n=new Set;return t.filter(function(t){var e=t[i];return!n.has(e)&&(n.add(e)||!0)})}function tt(t,e,i){return void 0===e&&(e=0),void 0===i&&(i=1),Math.min(Math.max(F(t)||0,e),i)}function et(){}function it(t,e){return t.left<e.right&&t.right>e.left&&t.top<e.bottom&&t.bottom>e.top}function nt(t,e){return t.x<=e.right&&t.x>=e.left&&t.y<=e.bottom&&t.y>=e.top}var rt={ratio:function(t,e,i){var n="width"===e?"height":"width",r={};return r[n]=t[e]?Math.round(i*t[n]/t[e]):t[n],r[e]=i,r},contain:function(i,n){var r=this;return J(i=G({},i),function(t,e){return i=i[e]>n[e]?r.ratio(i,e,n[e]):i}),i},cover:function(i,n){var r=this;return J(i=this.contain(i,n),function(t,e){return i=i[e]<n[e]?r.ratio(i,e,n[e]):i}),i}};function ot(t,e,i){if(I(e))for(var n in e)ot(t,n,e[n]);else{if(H(i))return(t=W(t))&&t.getAttribute(e);V(t).forEach(function(t){$(i)&&(i=i.call(t,ot(t,e))),null===i?at(t,e):t.setAttribute(e,i)})}}function st(t,e){return V(t).some(function(t){return t.hasAttribute(e)})}function at(t,e){t=V(t),e.split(" ").forEach(function(e){return t.forEach(function(t){return t.hasAttribute(e)&&t.removeAttribute(e)})})}function ht(t,e){for(var i=0,n=[e,"data-"+e];i<n.length;i++)if(st(t,n[i]))return ot(t,n[i])}var ut="undefined"!=typeof window,ct=ut&&/msie|trident/i.test(window.navigator.userAgent),lt=ut&&"rtl"===ot(document.documentElement,"dir"),dt=ut&&"ontouchstart"in window,ft=ut&&window.PointerEvent,pt=ut&&(dt||window.DocumentTouch&&document instanceof DocumentTouch||navigator.maxTouchPoints),mt=ft?"pointerdown":dt?"touchstart":"mousedown",gt=ft?"pointermove":dt?"touchmove":"mousemove",vt=ft?"pointerup":dt?"touchend":"mouseup",wt=ft?"pointerenter":dt?"":"mouseenter",bt=ft?"pointerleave":dt?"":"mouseleave",xt=ft?"pointercancel":"touchcancel";function yt(t,e){return W(t)||It(t,$t(t,e))}function kt(t,e){var i=V(t);return i.length&&i||St(t,$t(t,e))}function $t(t,e){return void 0===e&&(e=document),Ct(t)||_(e)?e:e.ownerDocument}function It(t,e){return W(Tt(t,e,"querySelector"))}function St(t,e){return V(Tt(t,e,"querySelectorAll"))}function Tt(t,s,e){if(void 0===s&&(s=document),!t||!D(t))return null;var a;Ct(t=t.replace(_t,"$1 *"))&&(a=[],t=t.match(At).map(function(t){return t.replace(/,$/,"").trim()}).map(function(t,e){var i,n,r,o=s;return"!"===t[0]&&(i=t.substr(1).trim().split(" "),o=Bt(Pt(s),i[0]),t=i.slice(1).join(" ").trim()),"-"===t[0]&&(n=t.substr(1).trim().split(" "),r=(o||s).previousElementSibling,o=zt(r,t.substr(1))?r:null,t=n.slice(1).join(" ")),o?(o.id||(o.id="uk-"+Date.now()+e,a.push(function(){return at(o,"id")})),"#"+Ht(o.id)+" "+t):null}).filter(Boolean).join(","),s=document);try{return s[e](t)}catch(t){return null}finally{a&&a.forEach(function(t){return t()})}}var Et=/(^|[^\\],)\s*[!>+~-]/,_t=/([!>+~-])(?=\s+[!>+~-]|\s*$)/g;function Ct(t){return D(t)&&t.match(Et)}var At=/.*?[^\\](?:,|$)/g;var Mt=ut?Element.prototype:{},Nt=Mt.matches||Mt.webkitMatchesSelector||Mt.msMatchesSelector||et;function zt(t,e){return V(t).some(function(t){return Nt.call(t,e)})}var Dt=Mt.closest||function(t){var e=this;do{if(zt(e,t))return e}while(e=Pt(e))};function Bt(t,e){return w(e,">")&&(e=e.slice(1)),M(t)?Dt.call(t,e):V(t).map(function(t){return Bt(t,e)}).filter(Boolean)}function Pt(t){return(t=W(t))&&M(t.parentNode)&&t.parentNode}var Ot=ut&&window.CSS&&CSS.escape||function(t){return t.replace(/([^\x7f-\uFFFF\w-])/g,function(t){return"\\"+t})};function Ht(t){return D(t)?Ot.call(null,t):""}var Lt={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,menuitem:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0};function Ft(t){return V(t).some(function(t){return Lt[t.tagName.toLowerCase()]})}function jt(t){return V(t).some(function(t){return t.offsetWidth||t.offsetHeight||t.getClientRects().length})}var Wt="input,select,textarea,button";function Vt(t){return V(t).some(function(t){return zt(t,Wt)})}function Rt(t,e){return V(t).filter(function(t){return zt(t,e)})}function qt(t,e){return D(e)?zt(t,e)||!!Bt(t,e):t===e||(_(e)?e.documentElement:W(e)).contains(W(t))}function Ut(t,e){for(var i=[];t=Pt(t);)e&&!zt(t,e)||i.push(t);return i}function Yt(t,e){var i=(t=W(t))?V(t.children):[];return e?Rt(i,e):i}function Xt(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];var i,n,r=Qt(t),o=r[0],s=r[1],a=r[2],h=r[3],u=r[4],o=ne(o);return 1<h.length&&(i=h,h=function(t){return k(t.detail)?i.apply(void 0,[t].concat(t.detail)):i(t)}),u&&u.self&&(n=h,h=function(t){if(t.target===t.currentTarget||t.target===t.current)return n.call(null,t)}),a&&(h=function(t,n,r){var o=this;return function(i){t.forEach(function(t){var e=">"===n[0]?St(n,t).reverse().filter(function(t){return qt(i.target,t)})[0]:Bt(i.target,n);e&&(i.delegate=t,i.current=e,r.call(o,i))})}}(o,a,h)),u=te(u),s.split(" ").forEach(function(e){return o.forEach(function(t){return t.addEventListener(e,h,u)})}),function(){return Gt(o,s,h,u)}}function Gt(t,e,i,n){void 0===n&&(n=!1),n=te(n),t=ne(t),e.split(" ").forEach(function(e){return t.forEach(function(t){return t.removeEventListener(e,i,n)})})}function Kt(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];var i=Qt(t),n=i[0],r=i[1],o=i[2],s=i[3],a=i[4],h=i[5],u=Xt(n,r,o,function(t){var e=!h||h(t);e&&(u(),s(t,e))},a);return u}function Jt(t,i,n){return ne(t).reduce(function(t,e){return t&&e.dispatchEvent(Zt(i,!0,!0,n))},!0)}function Zt(t,e,i,n){var r;return void 0===e&&(e=!0),void 0===i&&(i=!1),D(t)&&((r=document.createEvent("CustomEvent")).initCustomEvent(t,e,i,n),t=r),t}function Qt(t){return $(t[2])&&t.splice(2,0,!1),t}function te(t){return t&&ct&&!z(t)?!!t.capture:t}function ee(t){return t&&"addEventListener"in t}function ie(t){return ee(t)?t:W(t)}function ne(t){return k(t)?t.map(ie).filter(Boolean):D(t)?St(t):ee(t)?[t]:V(t)}function re(t){return"touch"===t.pointerType||!!t.touches}function oe(t){var e=t.touches,i=t.changedTouches,n=e&&e[0]||i&&i[0]||t;return{x:n.clientX,y:n.clientY}}function se(){var i=this;this.promise=new ae(function(t,e){i.reject=e,i.resolve=t})}var ae=ut&&window.Promise||ce,he=2,ue=ut&&window.setImmediate||setTimeout;function ce(t){this.state=he,this.value=void 0,this.deferred=[];var e=this;try{t(function(t){e.resolve(t)},function(t){e.reject(t)})}catch(t){e.reject(t)}}ce.reject=function(i){return new ce(function(t,e){e(i)})},ce.resolve=function(i){return new ce(function(t,e){t(i)})},ce.all=function(o){return new ce(function(i,t){var n=[],r=0;0===o.length&&i(n);for(var e=0;e<o.length;e+=1)ce.resolve(o[e]).then(function(e){return function(t){n[e]=t,(r+=1)===o.length&&i(n)}}(e),t)})},ce.race=function(n){return new ce(function(t,e){for(var i=0;i<n.length;i+=1)ce.resolve(n[i]).then(t,e)})};var le=ce.prototype;function de(s,a){return new ae(function(t,e){var i=G({data:null,method:"GET",headers:{},xhr:new XMLHttpRequest,beforeSend:et,responseType:""},a);i.beforeSend(i);var n=i.xhr;for(var r in i)if(r in n)try{n[r]=i[r]}catch(t){}for(var o in n.open(i.method.toUpperCase(),s),i.headers)n.setRequestHeader(o,i.headers[o]);Xt(n,"load",function(){0===n.status||200<=n.status&&n.status<300||304===n.status?t(n):e(G(Error(n.statusText),{xhr:n,status:n.status}))}),Xt(n,"error",function(){return e(G(Error("Network Error"),{xhr:n}))}),Xt(n,"timeout",function(){return e(G(Error("Network Timeout"),{xhr:n}))}),n.send(i.data)})}function fe(n,r,o){return new ae(function(t,e){var i=new Image;i.onerror=e,i.onload=function(){return t(i)},o&&(i.sizes=o),r&&(i.srcset=r),i.src=n})}function pe(t){var e;"loading"===document.readyState?e=Xt(document,"DOMContentLoaded",function(){e(),t()}):t()}function me(t,e){return e?V(t).indexOf(W(e)):Yt(Pt(t)).indexOf(t)}function ge(t,e,i,n){void 0===i&&(i=0),void 0===n&&(n=!1);var r=(e=V(e)).length;return t=P(t)?F(t):"next"===t?i+1:"previous"===t?i-1:me(e,t),n?tt(t,0,r-1):(t%=r)<0?t+r:t}function ve(t){return(t=Me(t)).innerHTML="",t}function we(t,e){return t=Me(t),H(e)?t.innerHTML:be(t.hasChildNodes()?ve(t):t,e)}function be(e,t){return e=Me(e),ke(t,function(t){return e.appendChild(t)})}function xe(e,t){return e=Me(e),ke(t,function(t){return e.parentNode.insertBefore(t,e)})}function ye(e,t){return e=Me(e),ke(t,function(t){return e.nextSibling?xe(e.nextSibling,t):be(e.parentNode,t)})}function ke(t,e){return(t=D(t)?Ce(t):t)?"length"in t?V(t).map(e):e(t):null}function $e(t){V(t).map(function(t){return t.parentNode&&t.parentNode.removeChild(t)})}function Ie(t,e){for(e=W(xe(t,e));e.firstChild;)e=e.firstChild;return be(e,t),e}function Se(t,e){return V(V(t).map(function(t){return t.hasChildNodes?Ie(V(t.childNodes),e):be(t,e)}))}function Te(t){V(t).map(Pt).filter(function(t,e,i){return i.indexOf(t)===e}).forEach(function(t){xe(t,t.childNodes),$e(t)})}le.resolve=function(t){var e=this;if(e.state===he){if(t===e)throw new TypeError("Promise settled with itself.");var i=!1;try{var n=t&&t.then;if(null!==t&&I(t)&&$(n))return void n.call(t,function(t){i||e.resolve(t),i=!0},function(t){i||e.reject(t),i=!0})}catch(t){return void(i||e.reject(t))}e.state=0,e.value=t,e.notify()}},le.reject=function(t){var e=this;if(e.state===he){if(t===e)throw new TypeError("Promise settled with itself.");e.state=1,e.value=t,e.notify()}},le.notify=function(){var o=this;ue(function(){if(o.state!==he)for(;o.deferred.length;){var t=o.deferred.shift(),e=t[0],i=t[1],n=t[2],r=t[3];try{0===o.state?$(e)?n(e.call(void 0,o.value)):n(o.value):1===o.state&&($(i)?n(i.call(void 0,o.value)):r(o.value))}catch(t){r(t)}}})},le.then=function(i,n){var r=this;return new ce(function(t,e){r.deferred.push([i,n,t,e]),r.notify()})},le.catch=function(t){return this.then(void 0,t)};var Ee=/^\s*<(\w+|!)[^>]*>/,_e=/^<(\w+)\s*\/?>(?:<\/\1>)?$/;function Ce(t){var e=_e.exec(t);if(e)return document.createElement(e[1]);var i=document.createElement("div");return Ee.test(t)?i.insertAdjacentHTML("beforeend",t.trim()):i.textContent=t,1<i.childNodes.length?V(i.childNodes):i.firstChild}function Ae(t,e){if(M(t))for(e(t),t=t.firstElementChild;t;){var i=t.nextElementSibling;Ae(t,e),t=i}}function Me(t,e){return D(t)?ze(t)?W(Ce(t)):It(t,e):W(t)}function Ne(t,e){return D(t)?ze(t)?V(Ce(t)):St(t,e):V(t)}function ze(t){return"<"===t[0]||t.match(/^\s*</)}function De(t){for(var e=[],i=arguments.length-1;0<i--;)e[i]=arguments[i+1];Fe(t,e,"add")}function Be(t){for(var e=[],i=arguments.length-1;0<i--;)e[i]=arguments[i+1];Fe(t,e,"remove")}function Pe(t,e){ot(t,"class",function(t){return(t||"").replace(new RegExp("\\b"+e+"\\b","g"),"")})}function Oe(t){for(var e=[],i=arguments.length-1;0<i--;)e[i]=arguments[i+1];e[0]&&Be(t,e[0]),e[1]&&De(t,e[1])}function He(t,e){return e&&V(t).some(function(t){return t.classList.contains(e.split(" ")[0])})}function Le(t){for(var n,r=[],e=arguments.length-1;0<e--;)r[e]=arguments[e+1];r.length&&(n=D(K(r=je(r)))?[]:r.pop(),r=r.filter(Boolean),V(t).forEach(function(t){for(var e=t.classList,i=0;i<r.length;i++)We.Force?e.toggle.apply(e,[r[i]].concat(n)):e[(H(n)?!e.contains(r[i]):n)?"add":"remove"](r[i])}))}function Fe(t,i,n){(i=je(i).filter(Boolean)).length&&V(t).forEach(function(t){var e=t.classList;We.Multiple?e[n].apply(e,i):i.forEach(function(t){return e[n](t)})})}function je(t){return t.reduce(function(t,e){return t.concat.call(t,D(e)&&b(e," ")?e.trim().split(" "):e)},[])}var We={get Multiple(){return this.get("_multiple")},get Force(){return this.get("_force")},get:function(t){var e;return l(this,t)||((e=document.createElement("_").classList).add("a","b"),e.toggle("c",!1),this._multiple=e.contains("b"),this._force=!e.contains("c")),this[t]}},Ve={"animation-iteration-count":!0,"column-count":!0,"fill-opacity":!0,"flex-grow":!0,"flex-shrink":!0,"font-weight":!0,"line-height":!0,opacity:!0,order:!0,orphans:!0,"stroke-dasharray":!0,"stroke-dashoffset":!0,widows:!0,"z-index":!0,zoom:!0};function Re(t,e,r){return V(t).map(function(i){if(D(e)){if(e=Ke(e),H(r))return Ue(i,e);r||B(r)?i.style[e]=P(r)&&!Ve[e]?r+"px":r:i.style.removeProperty(e)}else{if(k(e)){var n=qe(i);return e.reduce(function(t,e){return t[e]=n[Ke(e)],t},{})}I(e)&&J(e,function(t,e){return Re(i,e,t)})}return i})[0]}function qe(t,e){return(t=W(t)).ownerDocument.defaultView.getComputedStyle(t,e)}function Ue(t,e,i){return qe(t,i)[e]}var Ye={};function Xe(t){var e,i=document.documentElement;return ct?(t in Ye||(De(e=be(i,document.createElement("div")),"uk-"+t),Ye[t]=Ue(e,"content",":before").replace(/^["'](.*)["']$/,"$1"),$e(e)),Ye[t]):qe(i).getPropertyValue("--uk-"+t)}var Ge={};function Ke(t){return Ge[t]||(Ge[t]=function(t){t=d(t);var e=document.documentElement.style;if(t in e)return t;var i,n=Je.length;for(;n--;)if((i="-"+Je[n]+"-"+t)in e)return i}(t)||t)}var Je=["webkit","moz","ms"];function Ze(t,s,a,h){return void 0===a&&(a=400),void 0===h&&(h="linear"),ae.all(V(t).map(function(o){return new ae(function(i,n){for(var t in s){var e=Re(o,t);""===e&&Re(o,t,e)}var r=setTimeout(function(){return Jt(o,"transitionend")},a);Kt(o,"transitionend transitioncanceled",function(t){var e=t.type;clearTimeout(r),Be(o,"uk-transition"),Re(o,{transitionProperty:"",transitionDuration:"",transitionTimingFunction:""}),("transitioncanceled"===e?n:i)()},{self:!0}),De(o,"uk-transition"),Re(o,G({transitionProperty:Object.keys(s).map(Ke).join(","),transitionDuration:a+"ms",transitionTimingFunction:h},s))})}))}var Qe={start:Ze,stop:function(t){return Jt(t,"transitionend"),ae.resolve()},cancel:function(t){Jt(t,"transitioncanceled")},inProgress:function(t){return He(t,"uk-transition")}},ti="uk-animation-";function ei(t,e,s,a,h){return void 0===s&&(s=200),ae.all(V(t).map(function(o){return new ae(function(i,n){Jt(o,"animationcancel");var r=setTimeout(function(){return Jt(o,"animationend")},s);Kt(o,"animationend animationcancel",function(t){var e=t.type;clearTimeout(r),("animationcancel"===e?n:i)(),Re(o,"animationDuration",""),Pe(o,ti+"\\S*")},{self:!0}),Re(o,"animationDuration",s+"ms"),De(o,e,ti+(h?"leave":"enter")),w(e,ti)&&De(o,a&&"uk-transform-origin-"+a,h&&ti+"reverse")})}))}var ii=new RegExp(ti+"(enter|leave)"),ni={in:ei,out:function(t,e,i,n){return ei(t,e,i,n,!0)},inProgress:function(t){return ii.test(ot(t,"class"))},cancel:function(t){Jt(t,"animationcancel")}},ri={width:["x","left","right"],height:["y","top","bottom"]};function oi(t,e,c,l,d,i,n,r){c=mi(c),l=mi(l);var f={element:c,target:l};if(!t||!e)return f;var o,p=ai(t),m=ai(e),g=m;return pi(g,c,p,-1),pi(g,l,m,1),d=gi(d,p.width,p.height),i=gi(i,m.width,m.height),d.x+=i.x,d.y+=i.y,g.left+=d.x,g.top+=d.y,n&&(o=[ai(R(t))],r&&o.unshift(ai(r)),J(ri,function(t,s){var a=t[0],h=t[1],u=t[2];!0!==n&&!b(n,a)||o.some(function(n){var t=c[a]===h?-p[s]:c[a]===u?p[s]:0,e=l[a]===h?m[s]:l[a]===u?-m[s]:0;if(g[h]<n[h]||g[h]+p[s]>n[u]){var i=p[s]/2,r="center"===l[a]?-m[s]/2:0;return"center"===c[a]&&(o(i,r)||o(-i,-r))||o(t,e)}function o(e,t){var i=(g[h]+e+t-2*d[a]).toFixed(4);if(i>=n[h]&&i+p[s]<=n[u])return g[h]=i,["element","target"].forEach(function(t){f[t][a]=e?f[t][a]===ri[s][1]?ri[s][2]:ri[s][1]:f[t][a]}),!0}})})),si(t,g),f}function si(i,n){if(!n)return ai(i);var r=si(i),o=Re(i,"position");["left","top"].forEach(function(t){var e;t in n&&(e=Re(i,t),Re(i,t,n[t]-r[t]+j("absolute"===o&&"auto"===e?hi(i)[t]:e)))})}function ai(t){if(!t)return{};var e,i,n=R(t),r=n.pageYOffset,o=n.pageXOffset;if(E(t)){var s=t.innerHeight,a=t.innerWidth;return{top:r,left:o,height:s,width:a,bottom:r+s,right:o+a}}jt(t)||"none"!==Re(t,"display")||(e=ot(t,"style"),i=ot(t,"hidden"),ot(t,{style:(e||"")+";display:block !important;",hidden:null}));var h=(t=W(t)).getBoundingClientRect();return H(e)||ot(t,{style:e,hidden:i}),{height:h.height,width:h.width,top:h.top+r,left:h.left+o,bottom:h.bottom+r,right:h.right+o}}function hi(t,e){e=e||W(t).offsetParent||R(t).document.documentElement;var i=si(t),n=si(e);return{top:i.top-n.top-j(Re(e,"borderTopWidth")),left:i.left-n.left-j(Re(e,"borderLeftWidth"))}}function ui(t){var e=[0,0];t=W(t);do{if(e[0]+=t.offsetTop,e[1]+=t.offsetLeft,"fixed"===Re(t,"position")){var i=R(t);return e[0]+=i.pageYOffset,e[1]+=i.pageXOffset,e}}while(t=t.offsetParent);return e}var ci=di("height"),li=di("width");function di(n){var r=p(n);return function(t,e){if(H(e)){if(E(t))return t["inner"+r];if(_(t)){var i=t.documentElement;return Math.max(i["offset"+r],i["scroll"+r])}return(e="auto"===(e=Re(t=W(t),n))?t["offset"+r]:j(e)||0)-fi(t,n)}Re(t,n,e||0===e?+e+fi(t,n)+"px":"")}}function fi(i,t,e){return void 0===e&&(e="border-box"),Re(i,"boxSizing")===e?ri[t].slice(1).map(p).reduce(function(t,e){return t+j(Re(i,"padding"+e))+j(Re(i,"border"+e+"Width"))},0):0}function pi(o,s,a,h){J(ri,function(t,e){var i=t[0],n=t[1],r=t[2];s[i]===r?o[n]+=a[e]*h:"center"===s[i]&&(o[n]+=a[e]*h/2)})}function mi(t){var e=/left|center|right/,i=/top|center|bottom/;return 1===(t=(t||"").split(" ")).length&&(t=e.test(t[0])?t.concat("center"):i.test(t[0])?["center"].concat(t):["center","center"]),{x:e.test(t[0])?t[0]:"center",y:i.test(t[1])?t[1]:"center"}}function gi(t,e,i){var n=(t||"").split(" "),r=n[0],o=n[1];return{x:r?j(r)*(u(r,"%")?e/100:1):0,y:o?j(o)*(u(o,"%")?i/100:1):0}}function vi(t){switch(t){case"left":return"right";case"right":return"left";case"top":return"bottom";case"bottom":return"top";default:return t}}function wi(t,e,i){return void 0===e&&(e="width"),void 0===i&&(i=window),P(t)?+t:u(t,"vh")?bi(ci(R(i)),t):u(t,"vw")?bi(li(R(i)),t):u(t,"%")?bi(ai(i)[e],t):j(t)}function bi(t,e){return t*j(e)/100}var xi={reads:[],writes:[],read:function(t){return this.reads.push(t),$i(),t},write:function(t){return this.writes.push(t),$i(),t},clear:function(t){return Si(this.reads,t)||Si(this.writes,t)},flush:yi};function yi(t){void 0===t&&(t=1),Ii(xi.reads),Ii(xi.writes.splice(0,xi.writes.length)),xi.scheduled=!1,(xi.reads.length||xi.writes.length)&&$i(t+1)}var ki=5;function $i(t){if(!xi.scheduled){if(xi.scheduled=!0,ki<t)throw new Error("Maximum recursion limit reached.");t?ae.resolve().then(function(){return yi(t)}):requestAnimationFrame(function(){return yi()})}}function Ii(t){for(var e;e=t.shift();)e()}function Si(t,e){var i=t.indexOf(e);return!!~i&&!!t.splice(i,1)}function Ti(){}Ti.prototype={positions:[],init:function(){var e,t=this;this.positions=[],this.unbind=Xt(document,"mousemove",function(t){return e=oe(t)}),this.interval=setInterval(function(){e&&(t.positions.push(e),5<t.positions.length&&t.positions.shift())},50)},cancel:function(){this.unbind&&this.unbind(),this.interval&&clearInterval(this.interval)},movesTo:function(t){if(this.positions.length<2)return!1;var i=t.getBoundingClientRect(),e=i.left,n=i.right,r=i.top,o=i.bottom,s=this.positions[0],a=K(this.positions),h=[s,a];return!nt(a,i)&&[[{x:e,y:r},{x:n,y:o}],[{x:e,y:o},{x:n,y:r}]].some(function(t){var e=function(t,e){var i=t[0],n=i.x,r=i.y,o=t[1],s=o.x,a=o.y,h=e[0],u=h.x,c=h.y,l=e[1],d=l.x,f=l.y,p=(f-c)*(s-n)-(d-u)*(a-r);if(0==p)return!1;var m=((d-u)*(r-c)-(f-c)*(n-u))/p;if(m<0)return!1;return{x:n+m*(s-n),y:r+m*(a-r)}}(h,t);return e&&nt(e,i)})}};var Ei={};function _i(t,e,i){return Ei.computed($(t)?t.call(i,i):t,$(e)?e.call(i,i):e)}function Ci(t,e){return t=t&&!k(t)?[t]:t,e?t?t.concat(e):k(e)?e:[e]:t}function Ai(e,i,n){var r={};if($(i)&&(i=i.options),i.extends&&(e=Ai(e,i.extends,n)),i.mixins)for(var t=0,o=i.mixins.length;t<o;t++)e=Ai(e,i.mixins[t],n);for(var s in e)h(s);for(var a in i)l(e,a)||h(a);function h(t){r[t]=(Ei[t]||function(t,e){return H(e)?t:e})(e[t],i[t],n)}return r}function Mi(t,e){var i;void 0===e&&(e=[]);try{return t?w(t,"{")?JSON.parse(t):e.length&&!b(t,":")?((i={})[e[0]]=t,i):t.split(";").reduce(function(t,e){var i=e.split(/:(.*)/),n=i[0],r=i[1];return n&&!H(r)&&(t[n.trim()]=r.trim()),t},{}):{}}catch(t){return{}}}Ei.events=Ei.created=Ei.beforeConnect=Ei.connected=Ei.beforeDisconnect=Ei.disconnected=Ei.destroy=Ci,Ei.args=function(t,e){return!1!==e&&Ci(e||t)},Ei.update=function(t,e){return Z(Ci(t,$(e)?{read:e}:e),"order")},Ei.props=function(t,e){return k(e)&&(e=e.reduce(function(t,e){return t[e]=String,t},{})),Ei.methods(t,e)},Ei.computed=Ei.methods=function(t,e){return e?t?G({},t,e):e:t},Ei.data=function(e,i,t){return t?_i(e,i,t):i?e?function(t){return _i(e,i,t)}:i:e};function Ni(t){this.id=++zi,this.el=W(t)}var zi=0;function Di(t,e){try{t.contentWindow.postMessage(JSON.stringify(G({event:"command"},e)),"*")}catch(t){}}function Bi(h,u,c){if(void 0===u&&(u=0),void 0===c&&(c=0),!jt(h))return!1;var l=ji(h);return l.every(function(t,e){var i=si(l[e+1]||h),n=si(Fi(t)),r=n.top,o=n.left,s=n.bottom,a=n.right;return it(i,{top:r-u,left:o-c,bottom:s+u,right:a+c})})}function Pi(t,e){(t=(E(t)||_(t)?Wi:W)(t)).scrollTop=e}function Oi(t,e){void 0===e&&(e={});var c=e.offset;if(void 0===c&&(c=0),jt(t)){for(var l=ji(t).concat(t),i=ae.resolve(),n=function(u){i=i.then(function(){return new ae(function(i){var t,n=l[u],e=l[u+1],r=n.scrollTop,o=Math.ceil(hi(e,Fi(n)).top-c),s=(t=Math.abs(o),40*Math.pow(t,.375)),a=Date.now(),h=function(){var t,e=(t=tt((Date.now()-a)/s),.5*(1-Math.cos(Math.PI*t)));Pi(n,r+o*e),1!=e?requestAnimationFrame(h):i()};h()})})},r=0;r<l.length-1;r++)n(r);return i}}function Hi(t,e){if(void 0===e&&(e=0),!jt(t))return 0;var i=K(Li(t)),n=i.scrollHeight,r=i.scrollTop,o=si(Fi(i)).height,s=ui(t)[0]-r-ui(i)[0],a=Math.min(o,s+r);return tt(-1*(s-a)/Math.min(si(t).height+e+a,n-(s+r),n-o))}function Li(t,e){void 0===e&&(e=/auto|scroll/);var i=Wi(t),n=Ut(t).filter(function(t){return t===i||e.test(Re(t,"overflow"))&&t.scrollHeight>Math.round(si(t).height)}).reverse();return n.length?n:[i]}function Fi(t){return t===Wi(t)?window:t}function ji(t){return Li(t,/auto|scroll|hidden/)}function Wi(t){var e=R(t).document;return e.scrollingElement||e.documentElement}Ni.prototype.isVideo=function(){return this.isYoutube()||this.isVimeo()||this.isHTML5()},Ni.prototype.isHTML5=function(){return"VIDEO"===this.el.tagName},Ni.prototype.isIFrame=function(){return"IFRAME"===this.el.tagName},Ni.prototype.isYoutube=function(){return this.isIFrame()&&!!this.el.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/)},Ni.prototype.isVimeo=function(){return this.isIFrame()&&!!this.el.src.match(/vimeo\.com\/video\/.*/)},Ni.prototype.enableApi=function(){var e=this;if(this.ready)return this.ready;var i,r=this.isYoutube(),o=this.isVimeo();return r||o?this.ready=new ae(function(t){var n;Kt(e.el,"load",function(){var t;r&&(t=function(){return Di(e.el,{event:"listening",id:e.id})},i=setInterval(t,100),t())}),n=function(t){return r&&t.id===e.id&&"onReady"===t.event||o&&Number(t.player_id)===e.id},new ae(function(i){return Kt(window,"message",function(t,e){return i(e)},!1,function(t){var e=t.data;if(e&&D(e)){try{e=JSON.parse(e)}catch(t){return}return e&&n(e)}})}).then(function(){t(),i&&clearInterval(i)}),ot(e.el,"src",e.el.src+(b(e.el.src,"?")?"&":"?")+(r?"enablejsapi=1":"api=1&player_id="+e.id))}):ae.resolve()},Ni.prototype.play=function(){var t=this;if(this.isVideo())if(this.isIFrame())this.enableApi().then(function(){return Di(t.el,{func:"playVideo",method:"play"})});else if(this.isHTML5())try{var e=this.el.play();e&&e.catch(et)}catch(t){}},Ni.prototype.pause=function(){var t=this;this.isVideo()&&(this.isIFrame()?this.enableApi().then(function(){return Di(t.el,{func:"pauseVideo",method:"pause"})}):this.isHTML5()&&this.el.pause())},Ni.prototype.mute=function(){var t=this;this.isVideo()&&(this.isIFrame()?this.enableApi().then(function(){return Di(t.el,{func:"mute",method:"setVolume",value:0})}):this.isHTML5()&&(this.el.muted=!0,ot(this.el,"muted","")))};var Vi=ut&&window.IntersectionObserver||function(){function t(e,t){var i=this;void 0===t&&(t={});var n=t.rootMargin;void 0===n&&(n="0 0"),this.targets=[];var r,o=(n||"0 0").split(" ").map(j),s=o[0],a=o[1];this.offsetTop=s,this.offsetLeft=a,this.apply=function(){r=r||requestAnimationFrame(function(){return setTimeout(function(){var t=i.takeRecords();t.length&&e(t,i),r=!1})})},this.off=Xt(window,"scroll resize load",this.apply,{passive:!0,capture:!0})}return t.prototype.takeRecords=function(){var i=this;return this.targets.filter(function(t){var e=Bi(t.target,i.offsetTop,i.offsetLeft);if(null===t.isIntersecting||e^t.isIntersecting)return t.isIntersecting=e,!0})},t.prototype.observe=function(t){this.targets.push({target:t,isIntersecting:null}),this.apply()},t.prototype.disconnect=function(){this.targets=[],this.off()},t}();function Ri(t){return!(!w(t,"uk-")&&!w(t,"data-uk-"))&&f(t.replace("data-uk-","").replace("uk-",""))}function qi(t){this._init(t)}var Ui,Yi,Xi,Gi,Ki,Ji,Zi,Qi,tn;function en(t,e){if(t)for(var i in t)t[i]._connected&&t[i]._callUpdate(e)}function nn(t,e){var i={},n=t.args;void 0===n&&(n=[]);var r=t.props;void 0===r&&(r={});var o=t.el;if(!r)return i;for(var s in r){var a=d(s),h=ht(o,a);H(h)||(h=r[s]===Boolean&&""===h||on(r[s],h),("target"!==a||h&&!w(h,"_"))&&(i[s]=h))}var u=Mi(ht(o,e),n);for(var c in u){var l=f(c);void 0!==r[l]&&(i[l]=on(r[l],u[c]))}return i}function rn(e,i,n){T(i)||(i={name:n,handler:i});var t=i.name,r=i.el,o=i.handler,s=i.capture,a=i.passive,h=i.delegate,u=i.filter,c=i.self,r=$(r)?r.call(e):r||e.$el;k(r)?r.forEach(function(t){return rn(e,G({},i,{el:t}),n)}):!r||u&&!u.call(e)||e._events.push(Xt(r,t,h?D(h)?h:h.call(e):null,D(o)?e[o]:o.bind(e),{passive:a,capture:s,self:c}))}function on(t,e){return t===Boolean?L(e):t===Number?F(e):"list"===t?q(e):t?t(e):e}qi.util=Object.freeze({__proto__:null,ajax:de,getImage:fe,transition:Ze,Transition:Qe,animate:ei,Animation:ni,attr:ot,hasAttr:st,removeAttr:at,data:ht,addClass:De,removeClass:Be,removeClasses:Pe,replaceClass:Oe,hasClass:He,toggleClass:Le,positionAt:oi,offset:si,position:hi,offsetPosition:ui,height:ci,width:li,boxModelAdjust:fi,flipPosition:vi,toPx:wi,ready:pe,index:me,getIndex:ge,empty:ve,html:we,prepend:function(e,t){return(e=Me(e)).hasChildNodes()?ke(t,function(t){return e.insertBefore(t,e.firstChild)}):be(e,t)},append:be,before:xe,after:ye,remove:$e,wrapAll:Ie,wrapInner:Se,unwrap:Te,fragment:Ce,apply:Ae,$:Me,$$:Ne,inBrowser:ut,isIE:ct,isRtl:lt,hasTouch:pt,pointerDown:mt,pointerMove:gt,pointerUp:vt,pointerEnter:wt,pointerLeave:bt,pointerCancel:xt,on:Xt,off:Gt,once:Kt,trigger:Jt,createEvent:Zt,toEventTargets:ne,isTouch:re,getEventPos:oe,fastdom:xi,isVoidElement:Ft,isVisible:jt,selInput:Wt,isInput:Vt,filter:Rt,within:qt,parents:Ut,children:Yt,hasOwn:l,hyphenate:d,camelize:f,ucfirst:p,startsWith:w,endsWith:u,includes:b,findIndex:y,isArray:k,isFunction:$,isObject:I,isPlainObject:T,isWindow:E,isDocument:_,isJQuery:C,isNode:A,isElement:M,isNodeCollection:N,isBoolean:z,isString:D,isNumber:B,isNumeric:P,isEmpty:O,isUndefined:H,toBoolean:L,toNumber:F,toFloat:j,toNode:W,toNodes:V,toWindow:R,toList:q,toMs:U,isEqual:Y,swap:X,assign:G,last:K,each:J,sortBy:Z,uniqueBy:Q,clamp:tt,noop:et,intersectRect:it,pointInRect:nt,Dimensions:rt,MouseTracker:Ti,mergeOptions:Ai,parseOptions:Mi,Player:Ni,Promise:ae,Deferred:se,IntersectionObserver:Vi,query:yt,queryAll:kt,find:It,findAll:St,matches:zt,closest:Bt,parent:Pt,escape:Ht,css:Re,getStyles:qe,getStyle:Ue,getCssVar:Xe,propName:Ke,isInView:Bi,scrollTop:Pi,scrollIntoView:Oi,scrolledOver:Hi,scrollParents:Li,getViewport:Fi}),qi.data="__uikit__",qi.prefix="uk-",qi.options={},qi.version="3.5.3",Xi=(Ui=qi).data,Ui.use=function(t){if(!t.installed)return t.call(null,this),t.installed=!0,this},Ui.mixin=function(t,e){(e=(D(e)?Ui.component(e):e)||this).options=Ai(e.options,t)},Ui.extend=function(t){t=t||{};function e(t){this._init(t)}return((e.prototype=Object.create(this.prototype)).constructor=e).options=Ai(this.options,t),e.super=this,e.extend=this.extend,e},Ui.update=function(t,e){Ut(t=t?W(t):document.body).reverse().forEach(function(t){return en(t[Xi],e)}),Ae(t,function(t){return en(t[Xi],e)})},Object.defineProperty(Ui,"container",{get:function(){return Yi||document.body},set:function(t){Yi=Me(t)}}),(Gi=qi).prototype._callHook=function(t){var e=this,i=this.$options[t];i&&i.forEach(function(t){return t.call(e)})},Gi.prototype._callConnected=function(){this._connected||(this._data={},this._computeds={},this._frames={reads:{},writes:{}},this._initProps(),this._callHook("beforeConnect"),this._connected=!0,this._initEvents(),this._initObserver(),this._callHook("connected"),this._callUpdate())},Gi.prototype._callDisconnected=function(){this._connected&&(this._callHook("beforeDisconnect"),this._observer&&(this._observer.disconnect(),this._observer=null),this._unbindEvents(),this._callHook("disconnected"),this._connected=!1)},Gi.prototype._callUpdate=function(t){var o=this;void 0===t&&(t="update");var s=t.type||t;b(["update","resize"],s)&&this._callWatches();var e=this.$options.update,i=this._frames,a=i.reads,h=i.writes;e&&e.forEach(function(t,e){var i=t.read,n=t.write,r=t.events;"update"!==s&&!b(r,s)||(i&&!b(xi.reads,a[e])&&(a[e]=xi.read(function(){var t=o._connected&&i.call(o,o._data,s);!1===t&&n?xi.clear(h[e]):T(t)&&G(o._data,t)})),n&&!b(xi.writes,h[e])&&(h[e]=xi.write(function(){return o._connected&&n.call(o,o._data,s)})))})},Gi.prototype._callWatches=function(){var h,u=this,c=this._frames;c._watch||(h=!l(c,"_watch"),c._watch=xi.read(function(){if(u._connected){var t=u.$options.computed,e=u._computeds;for(var i in t){var n=l(e,i),r=e[i];delete e[i];var o=t[i],s=o.watch,a=o.immediate;s&&(h&&a||n&&!Y(r,u[i]))&&s.call(u,u[i],r)}c._watch=null}}))},Ji=0,(Ki=qi).prototype._init=function(t){(t=t||{}).data=function(t,e){var i=t.data,n=(t.el,e.args),r=e.props;void 0===r&&(r={});if(i=k(i)?O(n)?void 0:i.slice(0,n.length).reduce(function(t,e,i){return T(e)?G(t,e):t[n[i]]=e,t},{}):i)for(var o in i)H(i[o])?delete i[o]:i[o]=r[o]?on(r[o],i[o]):i[o];return i}(t,this.constructor.options),this.$options=Ai(this.constructor.options,t,this),this.$el=null,this.$props={},this._uid=Ji++,this._initData(),this._initMethods(),this._initComputeds(),this._callHook("created"),t.el&&this.$mount(t.el)},Ki.prototype._initData=function(){var t=this.$options.data;for(var e in void 0===t&&(t={}),t)this.$props[e]=this[e]=t[e]},Ki.prototype._initMethods=function(){var t=this.$options.methods;if(t)for(var e in t)this[e]=t[e].bind(this)},Ki.prototype._initComputeds=function(){var t=this.$options.computed;if(this._computeds={},t)for(var e in t)!function(n,r,o){Object.defineProperty(n,r,{enumerable:!0,get:function(){var t=n._computeds,e=n.$props,i=n.$el;return l(t,r)||(t[r]=(o.get||o).call(n,e,i)),t[r]},set:function(t){var e=n._computeds;e[r]=o.set?o.set.call(n,t):t,H(e[r])&&delete e[r]}})}(this,e,t[e])},Ki.prototype._initProps=function(t){var e;for(e in t=t||nn(this.$options,this.$name))H(t[e])||(this.$props[e]=t[e]);var i=[this.$options.computed,this.$options.methods];for(e in this.$props)e in t&&function(t,e){return t.every(function(t){return!t||!l(t,e)})}(i,e)&&(this[e]=this.$props[e])},Ki.prototype._initEvents=function(){var i=this;this._events=[];var t=this.$options.events;t&&t.forEach(function(t){if(l(t,"handler"))rn(i,t);else for(var e in t)rn(i,t[e],e)})},Ki.prototype._unbindEvents=function(){this._events.forEach(function(t){return t()}),delete this._events},Ki.prototype._initObserver=function(){var t,n=this,e=this.$options,r=e.attrs,i=e.props,o=e.el;!this._observer&&i&&!1!==r&&(r=k(r)?r:Object.keys(i),this._observer=new MutationObserver(function(t){var i=nn(n.$options,n.$name);t.some(function(t){var e=t.attributeName.replace("data-","");return(e===n.$name?r:[f(e)]).some(function(t){return!H(i[t])&&i[t]!==n.$props[t]})})&&n.$reset()}),t=r.map(d).concat(this.$name),this._observer.observe(o,{attributes:!0,attributeFilter:t.concat(t.map(function(t){return"data-"+t}))}))},Qi=(Zi=qi).data,tn={},Zi.component=function(s,t){var e=d(s);if(s=f(e),!t)return T(tn[s])&&(tn[s]=Zi.extend(tn[s])),tn[s];Zi[s]=function(t,i){for(var e=arguments.length,n=Array(e);e--;)n[e]=arguments[e];var r=Zi.component(s);return r.options.functional?new r({data:T(t)?t:[].concat(n)}):t?Ne(t).map(o)[0]:o(t);function o(t){var e=Zi.getComponent(t,s);if(e){if(!i)return e;e.$destroy()}return new r({el:t,data:i})}};var i=T(t)?G({},t):t.options;return i.name=s,i.install&&i.install(Zi,i,s),Zi._initialized&&!i.functional&&xi.read(function(){return Zi[s]("[uk-"+e+"],[data-uk-"+e+"]")}),tn[s]=T(t)?i:t},Zi.getComponents=function(t){return t&&t[Qi]||{}},Zi.getComponent=function(t,e){return Zi.getComponents(t)[e]},Zi.connect=function(t){if(t[Qi])for(var e in t[Qi])t[Qi][e]._callConnected();for(var i=0;i<t.attributes.length;i++){var n=Ri(t.attributes[i].name);n&&n in tn&&Zi[n](t)}},Zi.disconnect=function(t){for(var e in t[Qi])t[Qi][e]._callDisconnected()},function(n){var r=n.data;n.prototype.$create=function(t,e,i){return n[t](e,i)},n.prototype.$mount=function(t){var e=this.$options.name;t[r]||(t[r]={}),t[r][e]||((t[r][e]=this).$el=this.$options.el=this.$options.el||t,qt(t,document)&&this._callConnected())},n.prototype.$reset=function(){this._callDisconnected(),this._callConnected()},n.prototype.$destroy=function(t){void 0===t&&(t=!1);var e=this.$options,i=e.el,n=e.name;i&&this._callDisconnected(),this._callHook("destroy"),i&&i[r]&&(delete i[r][n],O(i[r])||delete i[r],t&&$e(this.$el))},n.prototype.$emit=function(t){this._callUpdate(t)},n.prototype.$update=function(t,e){void 0===t&&(t=this.$el),n.update(t,e)},n.prototype.$getComponent=n.getComponent;var e={};Object.defineProperties(n.prototype,{$container:Object.getOwnPropertyDescriptor(n,"container"),$name:{get:function(){var t=this.$options.name;return e[t]||(e[t]=n.prefix+d(t)),e[t]}}})}(qi);var sn={connected:function(){He(this.$el,this.$name)||De(this.$el,this.$name)}},an={props:{cls:Boolean,animation:"list",duration:Number,origin:String,transition:String},data:{cls:!1,animation:[!1],duration:200,origin:!1,transition:"linear",initProps:{overflow:"",height:"",paddingTop:"",paddingBottom:"",marginTop:"",marginBottom:""},hideProps:{overflow:"hidden",height:0,paddingTop:0,paddingBottom:0,marginTop:0,marginBottom:0}},computed:{hasAnimation:function(t){return!!t.animation[0]},hasTransition:function(t){var e=t.animation;return this.hasAnimation&&!0===e[0]}},methods:{toggleElement:function(t,i,n){var r=this;return ae.all(V(t).map(function(e){return new ae(function(t){return r._toggleElement(e,i,n).then(t,et)})}))},isToggled:function(t){var e=V(t||this.$el);return this.cls?He(e,this.cls.split(" ")[0]):!st(e,"hidden")},updateAria:function(t){!1===this.cls&&ot(t,"aria-hidden",!this.isToggled(t))},_toggleElement:function(t,e,i){var n=this;if(e=z(e)?e:ni.inProgress(t)?He(t,"uk-animation-leave"):Qe.inProgress(t)?"0px"===t.style.height:!this.isToggled(t),!Jt(t,"before"+(e?"show":"hide"),[this]))return ae.reject();var o,r=($(i)?i:!1!==i&&this.hasAnimation?this.hasTransition?hn(this):(o=this,function(t,e){ni.cancel(t);var i=o.animation,n=o.duration,r=o._toggle;return e?(r(t,!0),ni.in(t,i[0],n,o.origin)):ni.out(t,i[1]||i[0],n,o.origin).then(function(){return r(t,!1)})}):this._toggle)(t,e);Jt(t,e?"show":"hide",[this]);return(r||ae.resolve()).then(function(){Jt(t,e?"shown":"hidden",[n]),n.$update(t)})},_toggle:function(t,e){var i;t&&(e=Boolean(e),this.cls?(i=b(this.cls," ")||e!==He(t,this.cls))&&Le(t,this.cls,b(this.cls," ")?void 0:e):(i=e===st(t,"hidden"))&&ot(t,"hidden",e?null:""),Ne("[autofocus]",t).some(function(t){return jt(t)?t.focus()||!0:t.blur()}),this.updateAria(t),i&&(Jt(t,"toggled",[this]),this.$update(t)))}}};function hn(t){var s=t.isToggled,a=t.duration,h=t.initProps,u=t.hideProps,c=t.transition,l=t._toggle;return function(t,e){var i=Qe.inProgress(t),n=t.hasChildNodes?j(Re(t.firstElementChild,"marginTop"))+j(Re(t.lastElementChild,"marginBottom")):0,r=jt(t)?ci(t)+(i?0:n):0;Qe.cancel(t),s(t)||l(t,!0),ci(t,""),xi.flush();var o=ci(t)+(i?0:n);return ci(t,r),(e?Qe.start(t,G({},h,{overflow:"hidden",height:o}),Math.round(a*(1-r/o)),c):Qe.start(t,u,Math.round(a*(r/o)),c).then(function(){return l(t,!1)})).then(function(){return Re(t,h)})}}var un={mixins:[sn,an],props:{targets:String,active:null,collapsible:Boolean,multiple:Boolean,toggle:String,content:String,transition:String,offset:Number},data:{targets:"> *",active:!1,animation:[!0],collapsible:!0,multiple:!1,clsOpen:"uk-open",toggle:"> .uk-accordion-title",content:"> .uk-accordion-content",transition:"ease",offset:0},computed:{items:{get:function(t,e){return Ne(t.targets,e)},watch:function(t,e){var i,n=this;t.forEach(function(t){return cn(Me(n.content,t),!He(t,n.clsOpen))}),e||He(t,this.clsOpen)||(i=!1!==this.active&&t[Number(this.active)]||!this.collapsible&&t[0])&&this.toggle(i,!1)},immediate:!0}},events:[{name:"click",delegate:function(){return this.targets+" "+this.$props.toggle},handler:function(t){t.preventDefault(),this.toggle(me(Ne(this.targets+" "+this.$props.toggle,this.$el),t.current))}}],methods:{toggle:function(t,r){var o=this,e=[this.items[ge(t,this.items)]],i=Rt(this.items,"."+this.clsOpen);this.multiple||b(i,e[0])||(e=e.concat(i)),(this.collapsible||Rt(e,":not(."+this.clsOpen+")").length)&&e.forEach(function(t){return o.toggleElement(t,!He(t,o.clsOpen),function(e,i){Le(e,o.clsOpen,i);var n=Me((e._wrapper?"> * ":"")+o.content,e);if(!1!==r&&o.hasTransition)return e._wrapper||(e._wrapper=Ie(n,"<div"+(i?" hidden":"")+">")),cn(n,!1),hn(o)(e._wrapper,i).then(function(){var t;cn(n,!i),delete e._wrapper,Te(n),i&&(Bi(t=Me(o.$props.toggle,e))||Oi(t,{offset:o.offset}))});cn(n,!i)})})}}};function cn(t,e){ot(t,"hidden",e?"":null)}var ln={mixins:[sn,an],args:"animation",props:{close:String},data:{animation:[!0],selClose:".uk-alert-close",duration:150,hideProps:G({opacity:0},an.data.hideProps)},events:[{name:"click",delegate:function(){return this.selClose},handler:function(t){t.preventDefault(),this.close()}}],methods:{close:function(){var t=this;this.toggleElement(this.$el).then(function(){return t.$destroy(!0)})}}},dn={args:"autoplay",props:{automute:Boolean,autoplay:Boolean},data:{automute:!1,autoplay:!0},computed:{inView:function(t){return"inview"===t.autoplay}},connected:function(){this.inView&&!st(this.$el,"preload")&&(this.$el.preload="none"),this.player=new Ni(this.$el),this.automute&&this.player.mute()},update:{read:function(){return!!this.player&&{visible:jt(this.$el)&&"hidden"!==Re(this.$el,"visibility"),inView:this.inView&&Bi(this.$el)}},write:function(t){var e=t.visible,i=t.inView;!e||this.inView&&!i?this.player.pause():(!0===this.autoplay||this.inView&&i)&&this.player.play()},events:["resize","scroll"]}},fn={mixins:[sn,dn],props:{width:Number,height:Number},data:{automute:!0},update:{read:function(){var t=this.$el,e=function(t){for(;t=Pt(t);)if("static"!==Re(t,"position"))return t}(t)||t.parentNode,i=e.offsetHeight,n=e.offsetWidth,r=rt.cover({width:this.width||t.naturalWidth||t.videoWidth||t.clientWidth,height:this.height||t.naturalHeight||t.videoHeight||t.clientHeight},{width:n+(n%2?1:0),height:i+(i%2?1:0)});return!(!r.width||!r.height)&&r},write:function(t){var e=t.height,i=t.width;Re(this.$el,{height:e,width:i})},events:["resize"]}};var pn,mn={props:{pos:String,offset:null,flip:Boolean,clsPos:String},data:{pos:"bottom-"+(lt?"right":"left"),flip:!0,offset:!1,clsPos:""},computed:{pos:function(t){var e=t.pos;return(e+(b(e,"-")?"":"-center")).split("-")},dir:function(){return this.pos[0]},align:function(){return this.pos[1]}},methods:{positionAt:function(t,e,i){var n;Pe(t,this.clsPos+"-(top|bottom|left|right)(-[a-z]+)?");var r=this.offset,o=this.getAxis();P(r)||(r=(n=Me(r))?si(n)["x"===o?"left":"top"]-si(e)["x"===o?"right":"bottom"]:0);var s=oi(t,e,"x"===o?vi(this.dir)+" "+this.align:this.align+" "+vi(this.dir),"x"===o?this.dir+" "+this.align:this.align+" "+this.dir,"x"===o?""+("left"===this.dir?-r:r):" "+("top"===this.dir?-r:r),null,this.flip,i).target,a=s.x,h=s.y;this.dir="x"===o?a:h,this.align="x"===o?h:a,Le(t,this.clsPos+"-"+this.dir+"-"+this.align,!1===this.offset)},getAxis:function(){return"top"===this.dir||"bottom"===this.dir?"y":"x"}}},gn={mixins:[mn,an],args:"pos",props:{mode:"list",toggle:Boolean,boundary:Boolean,boundaryAlign:Boolean,delayShow:Number,delayHide:Number,clsDrop:String},data:{mode:["click","hover"],toggle:"- *",boundary:ut&&window,boundaryAlign:!1,delayShow:0,delayHide:800,clsDrop:!1,animation:["uk-animation-fade"],cls:"uk-open"},computed:{boundary:function(t,e){return yt(t.boundary,e)},clsDrop:function(t){return t.clsDrop||"uk-"+this.$options.name},clsPos:function(){return this.clsDrop}},created:function(){this.tracker=new Ti},connected:function(){De(this.$el,this.clsDrop);var t=this.$props.toggle;this.toggle=t&&this.$create("toggle",yt(t,this.$el),{target:this.$el,mode:this.mode}),this.toggle||Jt(this.$el,"updatearia")},disconnected:function(){this.isActive()&&(pn=null)},events:[{name:"click",delegate:function(){return"."+this.clsDrop+"-close"},handler:function(t){t.preventDefault(),this.hide(!1)}},{name:"click",delegate:function(){return'a[href^="#"]'},handler:function(t){var e=t.defaultPrevented,i=t.current.hash;e||!i||qt(i,this.$el)||this.hide(!1)}},{name:"beforescroll",handler:function(){this.hide(!1)}},{name:"toggle",self:!0,handler:function(t,e){t.preventDefault(),this.isToggled()?this.hide(!1):this.show(e,!1)}},{name:"toggleshow",self:!0,handler:function(t,e){t.preventDefault(),this.show(e)}},{name:"togglehide",self:!0,handler:function(t){t.preventDefault(),this.hide()}},{name:wt,filter:function(){return b(this.mode,"hover")},handler:function(t){re(t)||this.clearTimers()}},{name:bt,filter:function(){return b(this.mode,"hover")},handler:function(t){re(t)||this.hide()}},{name:"toggled",self:!0,handler:function(){this.isToggled()&&(this.clearTimers(),this.position())}},{name:"show",self:!0,handler:function(){var o=this;(pn=this).tracker.init(),Jt(this.$el,"updatearia"),Kt(this.$el,"hide",Xt(document,mt,function(t){var r=t.target;return!qt(r,o.$el)&&Kt(document,vt+" "+xt+" scroll",function(t){var e=t.defaultPrevented,i=t.type,n=t.target;e||i!==vt||r!==n||o.toggle&&qt(r,o.toggle.$el)||o.hide(!1)},!0)}),{self:!0}),Kt(this.$el,"hide",Xt(document,"keydown",function(t){27===t.keyCode&&(t.preventDefault(),o.hide(!1))}),{self:!0})}},{name:"beforehide",self:!0,handler:function(){this.clearTimers()}},{name:"hide",handler:function(t){var e=t.target;this.$el===e?(pn=this.isActive()?null:pn,Jt(this.$el,"updatearia"),this.tracker.cancel()):pn=null===pn&&qt(e,this.$el)&&this.isToggled()?this:pn}},{name:"updatearia",self:!0,handler:function(t,e){t.preventDefault(),this.updateAria(this.$el),(e||this.toggle)&&(ot((e||this.toggle).$el,"aria-expanded",this.isToggled()),Le(this.toggle.$el,this.cls,this.isToggled()))}}],update:{write:function(){this.isToggled()&&!ni.inProgress(this.$el)&&this.position()},events:["resize"]},methods:{show:function(t,e){var i,n=this;if(void 0===t&&(t=this.toggle),void 0===e&&(e=!0),this.isToggled()&&t&&this.toggle&&t.$el!==this.toggle.$el&&this.hide(!1),this.toggle=t,this.clearTimers(),!this.isActive()){if(pn){if(e&&pn.isDelaying)return void(this.showTimer=setTimeout(this.show,10));for(;pn&&i!==pn&&!qt(this.$el,pn.$el);)(i=pn).hide(!1)}this.showTimer=setTimeout(function(){return!n.isToggled()&&n.toggleElement(n.$el,!0)},e&&this.delayShow||0)}},hide:function(t){var e=this;void 0===t&&(t=!0);function i(){return e.toggleElement(e.$el,!1,!1)}var n,r;this.clearTimers(),this.isDelaying=(n=this.$el,r=[],Ae(n,function(t){return"static"!==Re(t,"position")&&r.push(t)}),r.some(function(t){return e.tracker.movesTo(t)})),t&&this.isDelaying?this.hideTimer=setTimeout(this.hide,50):t&&this.delayHide?this.hideTimer=setTimeout(i,this.delayHide):i()},clearTimers:function(){clearTimeout(this.showTimer),clearTimeout(this.hideTimer),this.showTimer=null,this.hideTimer=null,this.isDelaying=!1},isActive:function(){return pn===this},position:function(){Be(this.$el,this.clsDrop+"-stack"),Le(this.$el,this.clsDrop+"-boundary",this.boundaryAlign);var t,e=si(this.boundary),i=this.boundaryAlign?e:si(this.toggle.$el);"justify"===this.align?(t="y"===this.getAxis()?"width":"height",Re(this.$el,t,i[t])):this.$el.offsetWidth>Math.max(e.right-i.left,i.right-e.left)&&De(this.$el,this.clsDrop+"-stack"),this.positionAt(this.$el,this.boundaryAlign?this.boundary:this.toggle.$el,this.boundary)}}};var vn={mixins:[sn],args:"target",props:{target:Boolean},data:{target:!1},computed:{input:function(t,e){return Me(Wt,e)},state:function(){return this.input.nextElementSibling},target:function(t,e){var i=t.target;return i&&(!0===i&&this.input.parentNode===e&&this.input.nextElementSibling||yt(i,e))}},update:function(){var t,e,i,n=this.target,r=this.input;!n||n[e=Vt(n)?"value":"textContent"]!==(i=r.files&&r.files[0]?r.files[0].name:zt(r,"select")&&(t=Ne("option",r).filter(function(t){return t.selected})[0])?t.textContent:r.value)&&(n[e]=i)},events:[{name:"change",handler:function(){this.$update()}},{name:"reset",el:function(){return Bt(this.$el,"form")},handler:function(){this.$update()}}]},wn={update:{read:function(t){var e=Bi(this.$el);if(!e||t.isInView===e)return!1;t.isInView=e},write:function(){this.$el.src=""+this.$el.src},events:["scroll","resize"]}},bn={props:{margin:String,firstColumn:Boolean},data:{margin:"uk-margin-small-top",firstColumn:"uk-first-column"},update:{read:function(){return{columns:(t=this.$el.children,e=yn(t,"left","right"),lt?e.reverse():e),rows:xn(this.$el.children)};var t,e},write:function(t){var i=this,n=t.columns;t.rows.forEach(function(t,e){return t.forEach(function(t){Le(t,i.margin,0!==e),Le(t,i.firstColumn,b(n[0],t))})})},events:["resize"]}};function xn(t){return yn(t,"top","bottom")}function yn(t,e,i){for(var n=[[]],r=0;r<t.length;r++){var o=t[r];if(jt(o))for(var s=kn(o),a=n.length-1;0<=a;a--){var h=n[a];if(!h[0]){h.push(o);break}var u=void 0,u=h[0].offsetParent===o.offsetParent?kn(h[0]):(s=kn(o,!0),kn(h[0],!0));if(s[e]>=u[i]-1&&s[e]!==u[e]){n.push([o]);break}if(s[i]-1>u[e]||s[e]===u[e]){h.push(o);break}if(0===a){n.unshift([o]);break}}}return n}function kn(t,e){var i;void 0===e&&(e=!1);var n=t.offsetTop,r=t.offsetLeft,o=t.offsetHeight,s=t.offsetWidth;return e&&(n=(i=ui(t))[0],r=i[1]),{top:n,left:r,bottom:n+o,right:r+s}}var $n={extends:bn,mixins:[sn],name:"grid",props:{masonry:Boolean,parallax:Number},data:{margin:"uk-grid-margin",clsStack:"uk-grid-stack",masonry:!1,parallax:0},connected:function(){this.masonry&&De(this.$el,"uk-flex-top uk-flex-wrap-top")},update:[{write:function(t){var e=t.columns;Le(this.$el,this.clsStack,e.length<2)},events:["resize"]},{read:function(t){var e=t.columns,i=t.rows,n=Yt(this.$el);if(!n.length||!this.masonry&&!this.parallax)return!1;var r,o,s,a,h,u=n.some(Qe.inProgress),c=!1,l=e.map(function(t){return t.reduce(function(t,e){return t+e.offsetHeight},0)}),d=(r=n,o=this.margin,j((s=r.filter(function(t){return He(t,o)})[0])?Re(s,"marginTop"):Re(r[0],"paddingLeft"))*(i.length-1)),f=Math.max.apply(Math,l)+d;this.masonry&&(e=e.map(function(t){return Z(t,"offsetTop")}),a=e,h=i.map(function(t){return Math.max.apply(Math,t.map(function(t){return t.offsetHeight}))}),c=a.map(function(i){var n=0;return i.map(function(t,e){return n+=e?h[e-1]-i[e-1].offsetHeight:0})}));var p=Math.abs(this.parallax);return{padding:p=p&&l.reduce(function(t,e,i){return Math.max(t,e+d+(i%2?p:p/8)-f)},0),columns:e,translates:c,height:!u&&(this.masonry?f:"")}},write:function(t){var e=t.height,i=t.padding;Re(this.$el,"paddingBottom",i||""),!1!==e&&Re(this.$el,"height",e)},events:["resize"]},{read:function(t){var e=t.height;return{scrolled:!!this.parallax&&Hi(this.$el,e?e-ci(this.$el):0)*Math.abs(this.parallax)}},write:function(t){var e=t.columns,n=t.scrolled,r=t.translates;!1===n&&!r||e.forEach(function(t,i){return t.forEach(function(t,e){return Re(t,"transform",n||r?"translateY("+((r&&-r[i][e])+(n?i%2?n:n/8:0))+"px)":"")})})},events:["scroll","resize"]}]};var In=ct?{props:{selMinHeight:String},data:{selMinHeight:!1,forceHeight:!1},computed:{elements:function(t,e){var i=t.selMinHeight;return i?Ne(i,e):[e]}},update:[{read:function(){Re(this.elements,"height","")},order:-5,events:["resize"]},{write:function(){var i=this;this.elements.forEach(function(t){var e=j(Re(t,"minHeight"));e&&(i.forceHeight||Math.round(e+fi(t,"height","content-box"))>=t.offsetHeight)&&Re(t,"height",e)})},order:5,events:["resize"]}]}:{},Sn={mixins:[In],args:"target",props:{target:String,row:Boolean},data:{target:"> *",row:!0,forceHeight:!0},computed:{elements:function(t,e){return Ne(t.target,e)}},update:{read:function(){return{rows:(this.row?xn(this.elements):[this.elements]).map(Tn)}},write:function(t){t.rows.forEach(function(t){var i=t.heights;return t.elements.forEach(function(t,e){return Re(t,"minHeight",i[e])})})},events:["resize"]}};function Tn(t){var e;if(t.length<2)return{heights:[""],elements:t};var i=En(t),n=i.heights,r=i.max,o=t.some(function(t){return t.style.minHeight}),s=t.some(function(t,e){return!t.style.minHeight&&n[e]<r});return o&&s&&(Re(t,"minHeight",""),e=En(t),n=e.heights,r=e.max),{heights:n=t.map(function(t,e){return n[e]===r&&j(t.style.minHeight).toFixed(2)!==r.toFixed(2)?"":r}),elements:t}}function En(t){var e=t.map(function(t){return si(t).height-fi(t,"height","content-box")});return{heights:e,max:Math.max.apply(null,e)}}var _n={mixins:[In],props:{expand:Boolean,offsetTop:Boolean,offsetBottom:Boolean,minHeight:Number},data:{expand:!1,offsetTop:!1,offsetBottom:!1,minHeight:0},update:{read:function(t){var e=t.minHeight;if(!jt(this.$el))return!1;var i="",n=fi(this.$el,"height","content-box");if(this.expand){if(this.$el.dataset.heightExpand="",Me("[data-height-expand]")!==this.$el)return!1;i=ci(window)-(Cn(document.documentElement)-Cn(this.$el))-n||""}else{var r,i="calc(100vh";this.offsetTop&&(i+=0<(r=si(this.$el).top)&&r<ci(window)/2?" - "+r+"px":""),!0===this.offsetBottom?i+=" - "+Cn(this.$el.nextElementSibling)+"px":P(this.offsetBottom)?i+=" - "+this.offsetBottom+"vh":this.offsetBottom&&u(this.offsetBottom,"px")?i+=" - "+j(this.offsetBottom)+"px":D(this.offsetBottom)&&(i+=" - "+Cn(yt(this.offsetBottom,this.$el))+"px"),i+=(n?" - "+n+"px":"")+")"}return{minHeight:i,prev:e}},write:function(t){var e=t.minHeight,i=t.prev;Re(this.$el,{minHeight:e}),e!==i&&this.$update(this.$el,"resize"),this.minHeight&&j(Re(this.$el,"minHeight"))<this.minHeight&&Re(this.$el,"minHeight",this.minHeight)},events:["resize"]}};function Cn(t){return t&&si(t).height||0}var An={args:"src",props:{id:Boolean,icon:String,src:String,style:String,width:Number,height:Number,ratio:Number,class:String,strokeAnimation:Boolean,focusable:Boolean,attributes:"list"},data:{ratio:1,include:["style","class","focusable"],class:"",strokeAnimation:!1},beforeConnect:function(){this.class+=" uk-svg"},connected:function(){var t,e=this;!this.icon&&b(this.src,"#")&&(t=this.src.split("#"),this.src=t[0],this.icon=t[1]),this.svg=this.getSvg().then(function(t){return e.applyAttributes(t),e.svgEl=function(t,e){if(Ft(e)||"CANVAS"===e.tagName){ot(e,"hidden",!0);var i=e.nextElementSibling;return Bn(t,i)?i:ye(e,t)}var n=e.lastElementChild;return Bn(t,n)?n:be(e,t)}(t,e.$el)},et)},disconnected:function(){var e=this;Ft(this.$el)&&ot(this.$el,"hidden",null),this.svg&&this.svg.then(function(t){return(!e._connected||t!==e.svgEl)&&$e(t)},et),this.svg=this.svgEl=null},update:{read:function(){return!!(this.strokeAnimation&&this.svgEl&&jt(this.svgEl))},write:function(){var t,e;t=this.svgEl,(e=Dn(t))&&t.style.setProperty("--uk-animation-stroke",e)},type:["resize"]},methods:{getSvg:function(){var e=this;return function(i){if(Mn[i])return Mn[i];return Mn[i]=new ae(function(e,t){i?w(i,"data:")?e(decodeURIComponent(i.split(",")[1])):de(i).then(function(t){return e(t.response)},function(){return t("SVG not found.")}):t()})}(this.src).then(function(t){return function(t,e){e&&b(t,"<symbol")&&(t=function(t,e){if(!zn[t]){var i;for(zn[t]={},Nn.lastIndex=0;i=Nn.exec(t);)zn[t][i[3]]='<svg xmlns="http://www.w3.org/2000/svg"'+i[1]+"svg>"}return zn[t][e]}(t,e)||t);return(t=Me(t.substr(t.indexOf("<svg"))))&&t.hasChildNodes()&&t}(t,e.icon)||ae.reject("SVG not found.")})},applyAttributes:function(i){var n=this;for(var t in this.$options.props)this[t]&&b(this.include,t)&&ot(i,t,this[t]);for(var e in this.attributes){var r=this.attributes[e].split(":",2),o=r[0],s=r[1];ot(i,o,s)}this.id||at(i,"id");var a=["width","height"],h=[this.width,this.height];h.some(function(t){return t})||(h=a.map(function(t){return ot(i,t)}));var u=ot(i,"viewBox");u&&!h.some(function(t){return t})&&(h=u.split(" ").slice(2)),h.forEach(function(t,e){(t=(0|t)*n.ratio)&&ot(i,a[e],t),t&&!h[1^e]&&at(i,a[1^e])}),ot(i,"data-svg",this.icon||this.src)}}},Mn={};var Nn=/<symbol([^]*?id=(['"])(.+?)\2[^]*?<\/)symbol>/g,zn={};function Dn(t){return Math.ceil(Math.max.apply(Math,[0].concat(Ne("[stroke]",t).map(function(t){try{return t.getTotalLength()}catch(t){return 0}}))))}function Bn(t,e){return ot(t,"data-svg")===ot(e,"data-svg")}var Pn={spinner:'<svg width="30" height="30" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" cx="15" cy="15" r="14"/></svg>',totop:'<svg width="18" height="10" viewBox="0 0 18 10" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.2" points="1 9 9 1 17 9 "/></svg>',marker:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="4" width="1" height="11"/><rect x="4" y="9" width="11" height="1"/></svg>',"close-icon":'<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><line fill="none" stroke="#000" stroke-width="1.1" x1="1" y1="1" x2="13" y2="13"/><line fill="none" stroke="#000" stroke-width="1.1" x1="13" y1="1" x2="1" y2="13"/></svg>',"close-large":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><line fill="none" stroke="#000" stroke-width="1.4" x1="1" y1="1" x2="19" y2="19"/><line fill="none" stroke="#000" stroke-width="1.4" x1="19" y1="1" x2="1" y2="19"/></svg>',"navbar-toggle-icon":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect y="9" width="20" height="2"/><rect y="3" width="20" height="2"/><rect y="15" width="20" height="2"/></svg>',"overlay-icon":'<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><rect x="19" y="0" width="1" height="40"/><rect x="0" y="19" width="40" height="1"/></svg>',"pagination-next":'<svg width="7" height="12" viewBox="0 0 7 12" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.2" points="1 1 6 6 1 11"/></svg>',"pagination-previous":'<svg width="7" height="12" viewBox="0 0 7 12" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.2" points="6 1 1 6 6 11"/></svg>',"search-icon":'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="9" cy="9" r="7"/><path fill="none" stroke="#000" stroke-width="1.1" d="M14,14 L18,18 L14,14 Z"/></svg>',"search-large":'<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.8" cx="17.5" cy="17.5" r="16.5"/><line fill="none" stroke="#000" stroke-width="1.8" x1="38" y1="39" x2="29" y2="30"/></svg>',"search-navbar":'<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle fill="none" stroke="#000" stroke-width="1.1" cx="10.5" cy="10.5" r="9.5"/><line fill="none" stroke="#000" stroke-width="1.1" x1="23" y1="23" x2="17" y2="17"/></svg>',"slidenav-next":'<svg width="14px" height="24px" viewBox="0 0 14 24" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.4" points="1.225,23 12.775,12 1.225,1 "/></svg>',"slidenav-next-large":'<svg width="25px" height="40px" viewBox="0 0 25 40" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="2" points="4.002,38.547 22.527,20.024 4,1.5 "/></svg>',"slidenav-previous":'<svg width="14px" height="24px" viewBox="0 0 14 24" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="1.4" points="12.775,1 1.225,12 12.775,23 "/></svg>',"slidenav-previous-large":'<svg width="25px" height="40px" viewBox="0 0 25 40" xmlns="http://www.w3.org/2000/svg"><polyline fill="none" stroke="#000" stroke-width="2" points="20.527,1.5 2,20.024 20.525,38.547 "/></svg>'},On={install:function(r){r.icon.add=function(t,e){var i,n=D(t)?((i={})[t]=e,i):t;J(n,function(t,e){Pn[e]=t,delete Vn[e]}),r._initialized&&Ae(document.body,function(t){return J(r.getComponents(t),function(t){t.$options.isIcon&&t.icon in n&&t.$reset()})})}},extends:An,args:"icon",props:["icon"],data:{include:["focusable"]},isIcon:!0,beforeConnect:function(){De(this.$el,"uk-icon")},methods:{getSvg:function(){var t=function(t){if(!Pn[t])return null;Vn[t]||(Vn[t]=Me((Pn[function(t){return lt?X(X(t,"left","right"),"previous","next"):t}(t)]||Pn[t]).trim()));return Vn[t].cloneNode(!0)}(this.icon);return t?ae.resolve(t):ae.reject("Icon not found.")}}},Hn={args:!1,extends:On,data:function(t){return{icon:d(t.constructor.options.name)}},beforeConnect:function(){De(this.$el,this.$name)}},Ln={extends:Hn,beforeConnect:function(){De(this.$el,"uk-slidenav")},computed:{icon:function(t,e){var i=t.icon;return He(e,"uk-slidenav-large")?i+"-large":i}}},Fn={extends:Hn,computed:{icon:function(t,e){var i=t.icon;return He(e,"uk-search-icon")&&Ut(e,".uk-search-large").length?"search-large":Ut(e,".uk-search-navbar").length?"search-navbar":i}}},jn={extends:Hn,computed:{icon:function(){return"close-"+(He(this.$el,"uk-close-large")?"large":"icon")}}},Wn={extends:Hn,connected:function(){var e=this;this.svg.then(function(t){return 1!==e.ratio&&Re(Me("circle",t),"strokeWidth",1/e.ratio)},et)}},Vn={};var Rn={args:"dataSrc",props:{dataSrc:String,dataSrcset:Boolean,sizes:String,width:Number,height:Number,offsetTop:String,offsetLeft:String,target:String},data:{dataSrc:"",dataSrcset:!1,sizes:!1,width:!1,height:!1,offsetTop:"50vh",offsetLeft:0,target:!1},computed:{cacheKey:function(t){var e=t.dataSrc;return this.$name+"."+e},width:function(t){var e=t.width,i=t.dataWidth;return e||i},height:function(t){var e=t.height,i=t.dataHeight;return e||i},sizes:function(t){var e=t.sizes,i=t.dataSizes;return e||i},isImg:function(t,e){return Jn(e)},target:{get:function(t){var e=t.target;return[this.$el].concat(kt(e,this.$el))},watch:function(){this.observe()}},offsetTop:function(t){return wi(t.offsetTop,"height")},offsetLeft:function(t){return wi(t.offsetLeft,"width")}},connected:function(){Qn[this.cacheKey]?qn(this.$el,Qn[this.cacheKey]||this.dataSrc,this.dataSrcset,this.sizes):this.isImg&&this.width&&this.height&&qn(this.$el,function(t,e,i){var n;i&&(n=rt.ratio({width:t,height:e},"width",wi(Yn(i))),t=n.width,e=n.height);return'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="'+t+'" height="'+e+'"></svg>'}(this.width,this.height,this.sizes)),this.observer=new Vi(this.load,{rootMargin:this.offsetTop+"px "+this.offsetLeft+"px"}),requestAnimationFrame(this.observe)},disconnected:function(){this.observer.disconnect()},update:{read:function(t){var e=this,i=t.image;if(i||"complete"!==document.readyState||this.load(this.observer.takeRecords()),this.isImg)return!1;i&&i.then(function(t){return t&&""!==t.currentSrc&&qn(e.$el,Zn(t))})},write:function(t){var e,i,n,r,o;this.dataSrcset&&1!==window.devicePixelRatio&&(!(e=Re(this.$el,"backgroundSize")).match(/^(auto\s?)+$/)&&j(e)!==t.bgSize||(t.bgSize=(i=this.dataSrcset,n=this.sizes,r=wi(Yn(n)),(o=(i.match(Kn)||[]).map(j).sort(function(t,e){return t-e})).filter(function(t){return r<=t})[0]||o.pop()||""),Re(this.$el,"backgroundSize",t.bgSize+"px")))},events:["resize"]},methods:{load:function(t){var e=this;t.some(function(t){return H(t.isIntersecting)||t.isIntersecting})&&(this._data.image=fe(this.dataSrc,this.dataSrcset,this.sizes).then(function(t){return qn(e.$el,Zn(t),t.srcset,t.sizes),Qn[e.cacheKey]=Zn(t),t},et),this.observer.disconnect())},observe:function(){var e=this;this._connected&&!this._data.image&&this.target.forEach(function(t){return e.observer.observe(t)})}}};function qn(t,e,i,n){Jn(t)?(n&&(t.sizes=n),i&&(t.srcset=i),e&&(t.src=e)):e&&!b(t.style.backgroundImage,e)&&(Re(t,"backgroundImage","url("+Ht(e)+")"),Jt(t,Zt("load",!1)))}var Un=/\s*(.*?)\s*(\w+|calc\(.*?\))\s*(?:,|$)/g;function Yn(t){var e,i;for(Un.lastIndex=0;e=Un.exec(t);)if(!e[1]||window.matchMedia(e[1]).matches){e=w(i=e[2],"calc")?i.substring(5,i.length-1).replace(Xn,function(t){return wi(t)}).replace(/ /g,"").match(Gn).reduce(function(t,e){return t+ +e},0):i;break}return e||"100vw"}var Xn=/\d+(?:\w+|%)/g,Gn=/[+-]?(\d+)/g;var Kn=/\s+\d+w\s*(?:,|$)/g;function Jn(t){return"IMG"===t.tagName}function Zn(t){return t.currentSrc||t.src}var Qn,tr="__test__";try{(Qn=window.sessionStorage||{})[tr]=1,delete Qn[tr]}catch(t){Qn={}}var er={props:{media:Boolean},data:{media:!1},computed:{matchMedia:function(){var t=function(t){if(D(t)){if("@"===t[0])t=j(Xe("breakpoint-"+t.substr(1)));else if(isNaN(t))return t}return!(!t||isNaN(t))&&"(min-width: "+t+"px)"}(this.media);return!t||window.matchMedia(t).matches}}};var ir={mixins:[sn,er],props:{fill:String},data:{fill:"",clsWrapper:"uk-leader-fill",clsHide:"uk-leader-hide",attrFill:"data-fill"},computed:{fill:function(t){return t.fill||Xe("leader-fill-content")}},connected:function(){var t=Se(this.$el,'<span class="'+this.clsWrapper+'">');this.wrapper=t[0]},disconnected:function(){Te(this.wrapper.childNodes)},update:{read:function(t){var e=t.changed,i=t.width,n=i;return{width:i=Math.floor(this.$el.offsetWidth/2),fill:this.fill,changed:e||n!==i,hide:!this.matchMedia}},write:function(t){Le(this.wrapper,this.clsHide,t.hide),t.changed&&(t.changed=!1,ot(this.wrapper,this.attrFill,new Array(t.width).join(t.fill)))},events:["resize"]}},nr={props:{container:Boolean},data:{container:!0},computed:{container:function(t){var e=t.container;return!0===e&&this.$container||e&&Me(e)}}},rr=[],or={mixins:[sn,nr,an],props:{selPanel:String,selClose:String,escClose:Boolean,bgClose:Boolean,stack:Boolean},data:{cls:"uk-open",escClose:!0,bgClose:!0,overlay:!0,stack:!1},computed:{panel:function(t,e){return Me(t.selPanel,e)},transitionElement:function(){return this.panel},bgClose:function(t){return t.bgClose&&this.panel}},beforeDisconnect:function(){this.isToggled()&&this.toggleElement(this.$el,!1,!1)},events:[{name:"click",delegate:function(){return this.selClose},handler:function(t){t.preventDefault(),this.hide()}},{name:"toggle",self:!0,handler:function(t){t.defaultPrevented||(t.preventDefault(),this.isToggled()===b(rr,this)&&this.toggle())}},{name:"beforeshow",self:!0,handler:function(t){if(b(rr,this))return!1;!this.stack&&rr.length?(ae.all(rr.map(function(t){return t.hide()})).then(this.show),t.preventDefault()):rr.push(this)}},{name:"show",self:!0,handler:function(){var o=this;li(window)-li(document)&&this.overlay&&Re(document.body,"overflowY","scroll"),this.stack&&Re(this.$el,"zIndex",Re(this.$el,"zIndex")+rr.length),De(document.documentElement,this.clsPage),this.bgClose&&Kt(this.$el,"hide",Xt(document,mt,function(t){var r=t.target;K(rr)!==o||o.overlay&&!qt(r,o.$el)||qt(r,o.panel)||Kt(document,vt+" "+xt+" scroll",function(t){var e=t.defaultPrevented,i=t.type,n=t.target;e||i!==vt||r!==n||o.hide()},!0)}),{self:!0}),this.escClose&&Kt(this.$el,"hide",Xt(document,"keydown",function(t){27===t.keyCode&&K(rr)===o&&(t.preventDefault(),o.hide())}),{self:!0})}},{name:"hidden",self:!0,handler:function(){var e=this;rr.splice(rr.indexOf(this),1),rr.length||Re(document.body,"overflowY",""),Re(this.$el,"zIndex",""),rr.some(function(t){return t.clsPage===e.clsPage})||Be(document.documentElement,this.clsPage)}}],methods:{toggle:function(){return this.isToggled()?this.hide():this.show()},show:function(){var e=this;return this.container&&this.$el.parentNode!==this.container?(be(this.container,this.$el),new ae(function(t){return requestAnimationFrame(function(){return e.show().then(t)})})):this.toggleElement(this.$el,!0,sr(this))},hide:function(){return this.toggleElement(this.$el,!1,sr(this))}}};function sr(t){var s=t.transitionElement,a=t._toggle;return function(r,o){return new ae(function(i,n){return Kt(r,"show hide",function(){r._reject&&r._reject(),r._reject=n,a(r,o);var t=Kt(s,"transitionstart",function(){Kt(s,"transitionend transitioncancel",i,{self:!0}),clearTimeout(e)},{self:!0}),e=setTimeout(function(){t(),i()},U(Re(s,"transitionDuration")))})})}}var ar={install:function(t){var a=t.modal;function e(t,e,i,n){e=G({bgClose:!1,escClose:!0,labels:a.labels},e);var r=a.dialog(t(e),e),o=new se,s=!1;return Xt(r.$el,"submit","form",function(t){t.preventDefault(),o.resolve(n&&n(r)),s=!0,r.hide()}),Xt(r.$el,"hide",function(){return!s&&i(o)}),o.promise.dialog=r,o.promise}a.dialog=function(t,e){var i=a('<div class="uk-modal"> <div class="uk-modal-dialog">'+t+"</div> </div>",e);return i.show(),Xt(i.$el,"hidden",function(){return ae.resolve().then(function(){return i.$destroy(!0)})},{self:!0}),i},a.alert=function(i,t){return e(function(t){var e=t.labels;return'<div class="uk-modal-body">'+(D(i)?i:we(i))+'</div> <div class="uk-modal-footer uk-text-right"> <button class="uk-button uk-button-primary uk-modal-close" autofocus>'+e.ok+"</button> </div>"},t,function(t){return t.resolve()})},a.confirm=function(i,t){return e(function(t){var e=t.labels;return'<form> <div class="uk-modal-body">'+(D(i)?i:we(i))+'</div> <div class="uk-modal-footer uk-text-right"> <button class="uk-button uk-button-default uk-modal-close" type="button">'+e.cancel+'</button> <button class="uk-button uk-button-primary" autofocus>'+e.ok+"</button> </div> </form>"},t,function(t){return t.reject()})},a.prompt=function(i,n,t){return e(function(t){var e=t.labels;return'<form class="uk-form-stacked"> <div class="uk-modal-body"> <label>'+(D(i)?i:we(i))+'</label> <input class="uk-input" value="'+(n||"")+'" autofocus> </div> <div class="uk-modal-footer uk-text-right"> <button class="uk-button uk-button-default uk-modal-close" type="button">'+e.cancel+'</button> <button class="uk-button uk-button-primary">'+e.ok+"</button> </div> </form>"},t,function(t){return t.resolve(null)},function(t){return Me("input",t.$el).value})},a.labels={ok:"Ok",cancel:"Cancel"}},mixins:[or],data:{clsPage:"uk-modal-page",selPanel:".uk-modal-dialog",selClose:".uk-modal-close, .uk-modal-close-default, .uk-modal-close-outside, .uk-modal-close-full"},events:[{name:"show",self:!0,handler:function(){He(this.panel,"uk-margin-auto-vertical")?De(this.$el,"uk-flex"):Re(this.$el,"display","block"),ci(this.$el)}},{name:"hidden",self:!0,handler:function(){Re(this.$el,"display",""),Be(this.$el,"uk-flex")}}]};var hr={extends:un,data:{targets:"> .uk-parent",toggle:"> a",content:"> ul"}},ur={mixins:[sn,In],props:{dropdown:String,mode:"list",align:String,offset:Number,boundary:Boolean,boundaryAlign:Boolean,clsDrop:String,delayShow:Number,delayHide:Number,dropbar:Boolean,dropbarMode:String,dropbarAnchor:Boolean,duration:Number},data:{dropdown:".uk-navbar-nav > li",align:lt?"right":"left",clsDrop:"uk-navbar-dropdown",mode:void 0,offset:void 0,delayShow:void 0,delayHide:void 0,boundaryAlign:void 0,flip:"x",boundary:!0,dropbar:!1,dropbarMode:"slide",dropbarAnchor:!1,duration:200,forceHeight:!0,selMinHeight:".uk-navbar-nav > li > a, .uk-navbar-item, .uk-navbar-toggle"},computed:{boundary:function(t,e){var i=t.boundary,n=t.boundaryAlign;return!0===i||n?e:i},dropbarAnchor:function(t,e){return yt(t.dropbarAnchor,e)},pos:function(t){return"bottom-"+t.align},dropbar:{get:function(t){var e=t.dropbar;return e?(e=this._dropbar||yt(e,this.$el)||Me("+ .uk-navbar-dropbar",this.$el))||(this._dropbar=Me("<div></div>")):null},watch:function(t){De(t,"uk-navbar-dropbar")},immediate:!0},dropdowns:{get:function(t,e){return Ne(t.dropdown+" ."+t.clsDrop,e)},watch:function(t){var e=this;this.$create("drop",t.filter(function(t){return!e.getDropdown(t)}),G({},this.$props,{boundary:this.boundary,pos:this.pos,offset:this.dropbar||this.offset}))},immediate:!0}},disconnected:function(){this.dropbar&&$e(this.dropbar),delete this._dropbar},events:[{name:"mouseover",delegate:function(){return this.dropdown},handler:function(t){var e=t.current,i=this.getActive();i&&i.toggle&&!qt(i.toggle.$el,e)&&!i.tracker.movesTo(i.$el)&&i.hide(!1)}},{name:"mouseleave",el:function(){return this.dropbar},handler:function(){var t=this.getActive();t&&!this.dropdowns.some(function(t){return zt(t,":hover")})&&t.hide()}},{name:"beforeshow",capture:!0,filter:function(){return this.dropbar},handler:function(){this.dropbar.parentNode||ye(this.dropbarAnchor||this.$el,this.dropbar)}},{name:"show",filter:function(){return this.dropbar},handler:function(t,e){var i=e.$el,n=e.dir;Le(this.dropbar,"uk-navbar-dropbar-slide","slide"===this.dropbarMode||Ut(this.$el).some(function(t){return"static"!==Re(t,"position")})),this.clsDrop&&De(i,this.clsDrop+"-dropbar"),"bottom"===n&&this.transitionTo(i.offsetHeight+j(Re(i,"marginTop"))+j(Re(i,"marginBottom")),i)}},{name:"beforehide",filter:function(){return this.dropbar},handler:function(t,e){var i=e.$el,n=this.getActive();zt(this.dropbar,":hover")&&n&&n.$el===i&&t.preventDefault()}},{name:"hide",filter:function(){return this.dropbar},handler:function(t,e){var i=e.$el,n=this.getActive();(!n||n&&n.$el===i)&&this.transitionTo(0)}}],methods:{getActive:function(){var t=this.dropdowns.map(this.getDropdown).filter(function(t){return t&&t.isActive()})[0];return t&&b(t.mode,"hover")&&qt(t.toggle.$el,this.$el)&&t},transitionTo:function(t,e){var i=this,n=this.dropbar,r=jt(n)?ci(n):0;return Re(e=r<t&&e,"clip","rect(0,"+e.offsetWidth+"px,"+r+"px,0)"),ci(n,r),Qe.cancel([e,n]),ae.all([Qe.start(n,{height:t},this.duration),Qe.start(e,{clip:"rect(0,"+e.offsetWidth+"px,"+t+"px,0)"},this.duration)]).catch(et).then(function(){Re(e,{clip:""}),i.$update(n)})},getDropdown:function(t){return this.$getComponent(t,"drop")||this.$getComponent(t,"dropdown")}}},cr={mixins:[or],args:"mode",props:{mode:String,flip:Boolean,overlay:Boolean},data:{mode:"slide",flip:!1,overlay:!1,clsPage:"uk-offcanvas-page",clsContainer:"uk-offcanvas-container",selPanel:".uk-offcanvas-bar",clsFlip:"uk-offcanvas-flip",clsContainerAnimation:"uk-offcanvas-container-animation",clsSidebarAnimation:"uk-offcanvas-bar-animation",clsMode:"uk-offcanvas",clsOverlay:"uk-offcanvas-overlay",selClose:".uk-offcanvas-close",container:!1},computed:{clsFlip:function(t){var e=t.flip,i=t.clsFlip;return e?i:""},clsOverlay:function(t){var e=t.overlay,i=t.clsOverlay;return e?i:""},clsMode:function(t){var e=t.mode;return t.clsMode+"-"+e},clsSidebarAnimation:function(t){var e=t.mode,i=t.clsSidebarAnimation;return"none"===e||"reveal"===e?"":i},clsContainerAnimation:function(t){var e=t.mode,i=t.clsContainerAnimation;return"push"!==e&&"reveal"!==e?"":i},transitionElement:function(t){return"reveal"===t.mode?this.panel.parentNode:this.panel}},events:[{name:"click",delegate:function(){return'a[href^="#"]'},handler:function(t){var e=t.current.hash;!t.defaultPrevented&&e&&Me(e,document.body)&&this.hide()}},{name:"touchstart",passive:!0,el:function(){return this.panel},handler:function(t){var e=t.targetTouches;1===e.length&&(this.clientY=e[0].clientY)}},{name:"touchmove",self:!0,passive:!1,filter:function(){return this.overlay},handler:function(t){t.cancelable&&t.preventDefault()}},{name:"touchmove",passive:!1,el:function(){return this.panel},handler:function(t){var e,i,n,r,o;1===t.targetTouches.length&&(e=event.targetTouches[0].clientY-this.clientY,n=(i=this.panel).scrollTop,((r=i.scrollHeight)<=(o=i.clientHeight)||0===n&&0<e||r-n<=o&&e<0)&&t.cancelable&&t.preventDefault())}},{name:"show",self:!0,handler:function(){"reveal"!==this.mode||He(this.panel.parentNode,this.clsMode)||(Ie(this.panel,"<div>"),De(this.panel.parentNode,this.clsMode)),Re(document.documentElement,"overflowY",this.overlay?"hidden":""),De(document.body,this.clsContainer,this.clsFlip),Re(document.body,"touch-action","pan-y pinch-zoom"),Re(this.$el,"display","block"),De(this.$el,this.clsOverlay),De(this.panel,this.clsSidebarAnimation,"reveal"!==this.mode?this.clsMode:""),ci(document.body),De(document.body,this.clsContainerAnimation),this.clsContainerAnimation&&(lr().content+=",user-scalable=0")}},{name:"hide",self:!0,handler:function(){Be(document.body,this.clsContainerAnimation),Re(document.body,"touch-action","")}},{name:"hidden",self:!0,handler:function(){var t;this.clsContainerAnimation&&((t=lr()).content=t.content.replace(/,user-scalable=0$/,"")),"reveal"===this.mode&&Te(this.panel),Be(this.panel,this.clsSidebarAnimation,this.clsMode),Be(this.$el,this.clsOverlay),Re(this.$el,"display",""),Be(document.body,this.clsContainer,this.clsFlip),Re(document.documentElement,"overflowY","")}},{name:"swipeLeft swipeRight",handler:function(t){this.isToggled()&&u(t.type,"Left")^this.flip&&this.hide()}}]};function lr(){return Me('meta[name="viewport"]',document.head)||be(document.head,'<meta name="viewport">')}var dr={mixins:[sn],props:{selContainer:String,selContent:String},data:{selContainer:".uk-modal",selContent:".uk-modal-dialog"},computed:{container:function(t,e){return Bt(e,t.selContainer)},content:function(t,e){return Bt(e,t.selContent)}},connected:function(){Re(this.$el,"minHeight",150)},update:{read:function(){return!(!this.content||!this.container)&&{current:j(Re(this.$el,"maxHeight")),max:Math.max(150,ci(this.container)-(si(this.content).height-ci(this.$el)))}},write:function(t){var e=t.current,i=t.max;Re(this.$el,"maxHeight",i),Math.round(e)!==Math.round(i)&&Jt(this.$el,"resize")},events:["resize"]}},fr={props:["width","height"],connected:function(){De(this.$el,"uk-responsive-width")},update:{read:function(){return!!(jt(this.$el)&&this.width&&this.height)&&{width:li(this.$el.parentNode),height:this.height}},write:function(t){ci(this.$el,rt.contain({height:this.height,width:this.width},t).height)},events:["resize"]}},pr={props:{offset:Number},data:{offset:0},methods:{scrollTo:function(t){var e=this;t=t&&Me(t)||document.body,Jt(this.$el,"beforescroll",[this,t])&&Oi(t,{offset:this.offset}).then(function(){return Jt(e.$el,"scrolled",[e,t])})}},events:{click:function(t){t.defaultPrevented||(t.preventDefault(),this.scrollTo(Ht(decodeURIComponent(this.$el.hash)).substr(1)))}}},mr={args:"cls",props:{cls:String,target:String,hidden:Boolean,offsetTop:Number,offsetLeft:Number,repeat:Boolean,delay:Number},data:function(){return{cls:!1,target:!1,hidden:!0,offsetTop:0,offsetLeft:0,repeat:!1,delay:0,inViewClass:"uk-scrollspy-inview"}},computed:{elements:{get:function(t,e){var i=t.target;return i?Ne(i,e):[e]},watch:function(t){this.hidden&&Re(Rt(t,":not(."+this.inViewClass+")"),"visibility","hidden")},immediate:!0}},update:[{read:function(t){var i=this;t.update&&this.elements.forEach(function(t){var e=t._ukScrollspyState;(e=e||{cls:ht(t,"uk-scrollspy-class")||i.cls}).show=Bi(t,i.offsetTop,i.offsetLeft),t._ukScrollspyState=e})},write:function(n){var r=this;if(!n.update)return this.$emit(),n.update=!0;this.elements.forEach(function(e){function t(t){Re(e,"visibility",!t&&r.hidden?"hidden":""),Le(e,r.inViewClass,t),Le(e,i.cls),Jt(e,t?"inview":"outview"),i.inview=t,r.$update(e)}var i=e._ukScrollspyState;!i.show||i.inview||i.queued?!i.show&&i.inview&&!i.queued&&r.repeat&&t(!1):(i.queued=!0,n.promise=(n.promise||ae.resolve()).then(function(){return new ae(function(t){return setTimeout(t,r.delay)})}).then(function(){t(!0),setTimeout(function(){i.queued=!1,r.$emit()},300)}))})},events:["scroll","resize"]}]},gr={props:{cls:String,closest:String,scroll:Boolean,overflow:Boolean,offset:Number},data:{cls:"uk-active",closest:!1,scroll:!1,overflow:!0,offset:0},computed:{links:{get:function(t,e){return Ne('a[href^="#"]',e).filter(function(t){return t.hash})},watch:function(t){this.scroll&&this.$create("scroll",t,{offset:this.offset||0})},immediate:!0},targets:function(){return Ne(this.links.map(function(t){return Ht(t.hash).substr(1)}).join(","))},elements:function(t){var e=t.closest;return Bt(this.links,e||"*")}},update:[{read:function(){var i=this,t=this.targets.length;if(!t||!jt(this.$el))return!1;var e=K(Li(this.targets[0])),n=e.scrollTop,r=e.scrollHeight,o=Fi(e),s=r-si(o).height,a=!1;return n===s?a=t-1:(this.targets.every(function(t,e){if(hi(t,o).top-i.offset<=0)return a=e,!0}),!1===a&&this.overflow&&(a=0)),{active:a}},write:function(t){var e=t.active;this.links.forEach(function(t){return t.blur()}),Be(this.elements,this.cls),!1!==e&&Jt(this.$el,"active",[e,De(this.elements[e],this.cls)])},events:["scroll","resize"]}]},vr={mixins:[sn,er],props:{top:null,bottom:Boolean,offset:String,animation:String,clsActive:String,clsInactive:String,clsFixed:String,clsBelow:String,selTarget:String,widthElement:Boolean,showOnUp:Boolean,targetOffset:Number},data:{top:0,bottom:!1,offset:0,animation:"",clsActive:"uk-active",clsInactive:"",clsFixed:"uk-sticky-fixed",clsBelow:"uk-sticky-below",selTarget:"",widthElement:!1,showOnUp:!1,targetOffset:!1},computed:{offset:function(t){return wi(t.offset)},selTarget:function(t,e){var i=t.selTarget;return i&&Me(i,e)||e},widthElement:function(t,e){return yt(t.widthElement,e)||this.placeholder},isActive:{get:function(){return He(this.selTarget,this.clsActive)},set:function(t){t&&!this.isActive?(Oe(this.selTarget,this.clsInactive,this.clsActive),Jt(this.$el,"active")):t||He(this.selTarget,this.clsInactive)||(Oe(this.selTarget,this.clsActive,this.clsInactive),Jt(this.$el,"inactive"))}}},connected:function(){this.placeholder=Me("+ .uk-sticky-placeholder",this.$el)||Me('<div class="uk-sticky-placeholder"></div>'),this.isFixed=!1,this.isActive=!1},disconnected:function(){this.isFixed&&(this.hide(),Be(this.selTarget,this.clsInactive)),$e(this.placeholder),this.placeholder=null,this.widthElement=null},events:[{name:"load hashchange popstate",el:ut&&window,handler:function(){var n,r=this;!1!==this.targetOffset&&location.hash&&0<window.pageYOffset&&((n=Me(location.hash))&&xi.read(function(){var t=si(n).top,e=si(r.$el).top,i=r.$el.offsetHeight;r.isFixed&&t<=e+i&&e<=t+n.offsetHeight&&Pi(window,t-i-(P(r.targetOffset)?r.targetOffset:0)-r.offset)}))}}],update:[{read:function(t,e){var i=t.height;this.isActive&&"update"!==e&&(this.hide(),i=this.$el.offsetHeight,this.show()),i=this.isActive?i:this.$el.offsetHeight,this.topOffset=si(this.isFixed?this.placeholder:this.$el).top,this.bottomOffset=this.topOffset+i;var n=wr("bottom",this);return this.top=Math.max(j(wr("top",this)),this.topOffset)-this.offset,this.bottom=n&&n-this.$el.offsetHeight,this.inactive=!this.matchMedia,{lastScroll:!1,height:i,margins:Re(this.$el,["marginTop","marginBottom","marginLeft","marginRight"])}},write:function(t){var e=t.height,i=t.margins,n=this.placeholder;Re(n,G({height:e},i)),qt(n,document)||(ye(this.$el,n),ot(n,"hidden","")),this.isActive=!!this.isActive},events:["resize"]},{read:function(t){var e=t.scroll;return void 0===e&&(e=0),this.width=si(jt(this.widthElement)?this.widthElement:this.$el).width,this.scroll=window.pageYOffset,{dir:e<=this.scroll?"down":"up",scroll:this.scroll,visible:jt(this.$el),top:ui(this.placeholder)[0]}},write:function(t,e){var i=this,n=t.initTimestamp;void 0===n&&(n=0);var r=t.dir,o=t.lastDir,s=t.lastScroll,a=t.scroll,h=t.top,u=t.visible,c=performance.now();if(!((t.lastScroll=a)<0||a===s||!u||this.disabled||this.showOnUp&&"scroll"!==e||((300<c-n||r!==o)&&(t.initScroll=a,t.initTimestamp=c),t.lastDir=r,this.showOnUp&&!this.isFixed&&Math.abs(t.initScroll-a)<=30&&Math.abs(s-a)<=10)))if(this.inactive||a<this.top||this.showOnUp&&(a<=this.top||"down"===r||"up"===r&&!this.isFixed&&a<=this.bottomOffset)){if(!this.isFixed)return void(ni.inProgress(this.$el)&&a<h&&(ni.cancel(this.$el),this.hide()));this.isFixed=!1,this.animation&&a>this.topOffset?(ni.cancel(this.$el),ni.out(this.$el,this.animation).then(function(){return i.hide()},et)):this.hide()}else this.isFixed?this.update():this.animation?(ni.cancel(this.$el),this.show(),ni.in(this.$el,this.animation).catch(et)):this.show()},events:["resize","scroll"]}],methods:{show:function(){this.isFixed=!0,this.update(),ot(this.placeholder,"hidden",null)},hide:function(){this.isActive=!1,Be(this.$el,this.clsFixed,this.clsBelow),Re(this.$el,{position:"",top:"",width:""}),ot(this.placeholder,"hidden","")},update:function(){var t=0!==this.top||this.scroll>this.top,e=Math.max(0,this.offset);P(this.bottom)&&this.scroll>this.bottom-this.offset&&(e=this.bottom-this.scroll),Re(this.$el,{position:"fixed",top:e+"px",width:this.width}),this.isActive=t,Le(this.$el,this.clsBelow,this.scroll>this.bottomOffset),De(this.$el,this.clsFixed)}}};function wr(t,e){var i=e.$props,n=e.$el,r=e[t+"Offset"],o=i[t];if(o)return D(o)&&o.match(/^-?\d/)?r+wi(o):si(!0===o?n.parentNode:yt(o,n)).bottom}var br,xr,yr,kr={mixins:[an],args:"connect",props:{connect:String,toggle:String,active:Number,swiping:Boolean},data:{connect:"~.uk-switcher",toggle:"> * > :first-child",active:0,swiping:!0,cls:"uk-active",clsContainer:"uk-switcher",attrItem:"uk-switcher-item"},computed:{connects:{get:function(t,e){return kt(t.connect,e)},watch:function(t){var e=this;t.forEach(function(t){return e.updateAria(t.children)}),this.swiping&&Re(t,"touch-action","pan-y pinch-zoom")},immediate:!0},toggles:{get:function(t,e){return Ne(t.toggle,e).filter(function(t){return!zt(t,".uk-disabled *, .uk-disabled, [disabled]")})},watch:function(t){var e=this.index();this.show(~e&&e||t[this.active]||t[0])},immediate:!0},children:function(){var t=this;return Yt(this.$el).filter(function(e){return t.toggles.some(function(t){return qt(t,e)})})}},events:[{name:"click",delegate:function(){return this.toggle},handler:function(t){b(this.toggles,t.current)&&(t.preventDefault(),this.show(t.current))}},{name:"click",el:function(){return this.connects},delegate:function(){return"["+this.attrItem+"],[data-"+this.attrItem+"]"},handler:function(t){t.preventDefault(),this.show(ht(t.current,this.attrItem))}},{name:"swipeRight swipeLeft",filter:function(){return this.swiping},el:function(){return this.connects},handler:function(t){var e=t.type;this.show(u(e,"Left")?"next":"previous")}}],methods:{index:function(){var e=this;return y(this.children,function(t){return He(t,e.cls)})},show:function(t){var i=this,n=this.index(),r=ge(t,this.toggles,n);this.children.forEach(function(t,e){Le(t,i.cls,r===e),ot(i.toggles[e],"aria-expanded",r===e)}),this.connects.forEach(function(t){var e=t.children;return i.toggleElement(V(e).filter(function(t,e){return e!==r&&i.isToggled(t)}),!1,0<=n).then(function(){return i.toggleElement(e[r],!0,0<=n)})})}}},$r={mixins:[sn],extends:kr,props:{media:Boolean},data:{media:960,attrItem:"uk-tab-item"},connected:function(){var t=He(this.$el,"uk-tab-left")?"uk-tab-left":!!He(this.$el,"uk-tab-right")&&"uk-tab-right";t&&this.$create("toggle",this.$el,{cls:t,mode:"media",media:this.media})}},Ir={mixins:[er,an],args:"target",props:{href:String,target:null,mode:"list",queued:Boolean},data:{href:!1,target:!1,mode:"click",queued:!0},computed:{target:{get:function(t,e){var i=t.href,n=t.target;return(n=kt(n||i,e)).length&&n||[e]},watch:function(){Jt(this.target,"updatearia",[this])},immediate:!0}},events:[{name:wt+" "+bt,filter:function(){return b(this.mode,"hover")},handler:function(t){re(t)||this.toggle("toggle"+(t.type===wt?"show":"hide"))}},{name:"click",filter:function(){return b(this.mode,"click")||pt&&b(this.mode,"hover")},handler:function(t){var e;(Bt(t.target,'a[href="#"], a[href=""]')||(e=Bt(t.target,"a[href]"))&&(this.cls&&!He(this.target,this.cls.split(" ")[0])||!jt(this.target)||e.hash&&zt(this.target,e.hash)))&&t.preventDefault(),this.toggle()}}],update:{read:function(){return!(!b(this.mode,"media")||!this.media)&&{match:this.matchMedia}},write:function(t){var e=t.match,i=this.isToggled(this.target);(e?!i:i)&&this.toggle()},events:["resize"]},methods:{toggle:function(t){var e,i=this;Jt(this.target,t||"toggle",[this])&&(this.queued?(e=this.target.filter(this.isToggled),this.toggleElement(e,!1).then(function(){return i.toggleElement(i.target.filter(function(t){return!b(e,t)}),!0)})):this.toggleElement(this.target))}}};J(Object.freeze({__proto__:null,Accordion:un,Alert:ln,Cover:fn,Drop:gn,Dropdown:gn,FormCustom:vn,Gif:wn,Grid:$n,HeightMatch:Sn,HeightViewport:_n,Icon:On,Img:Rn,Leader:ir,Margin:bn,Modal:ar,Nav:hr,Navbar:ur,Offcanvas:cr,OverflowAuto:dr,Responsive:fr,Scroll:pr,Scrollspy:mr,ScrollspyNav:gr,Sticky:vr,Svg:An,Switcher:kr,Tab:$r,Toggle:Ir,Video:dn,Close:jn,Spinner:Wn,SlidenavNext:Ln,SlidenavPrevious:Ln,SearchIcon:Fn,Marker:Hn,NavbarToggleIcon:Hn,OverlayIcon:Hn,PaginationNext:Hn,PaginationPrevious:Hn,Totop:Hn}),function(t,e){return qi.component(e,t)}),qi.use(function(r){ut&&pe(function(){var e;r.update(),Xt(window,"load resize",function(){return r.update(null,"resize")}),Xt(document,"loadedmetadata load",function(t){var e=t.target;return r.update(e,"resize")},!0),Xt(window,"scroll",function(t){e||(e=!0,xi.write(function(){return e=!1}),r.update(null,t.type))},{passive:!0,capture:!0});var i,n=0;Xt(document,"animationstart",function(t){var e=t.target;(Re(e,"animationName")||"").match(/^uk-.*(left|right)/)&&(n++,Re(document.body,"overflowX","hidden"),setTimeout(function(){--n||Re(document.body,"overflowX","")},U(Re(e,"animationDuration"))+100))},!0),Xt(document,mt,function(t){var s,a;i&&i(),re(t)&&(s=oe(t),a="tagName"in t.target?t.target:t.target.parentNode,i=Kt(document,vt+" "+xt,function(t){var e=oe(t),r=e.x,o=e.y;(a&&r&&100<Math.abs(s.x-r)||o&&100<Math.abs(s.y-o))&&setTimeout(function(){var t,e,i,n;Jt(a,"swipe"),Jt(a,"swipe"+(t=s.x,e=s.y,i=r,n=o,Math.abs(t-i)>=Math.abs(e-n)?0<t-i?"Left":"Right":0<e-n?"Up":"Down"))})}))},{passive:!0})})}),xr=(br=qi).connect,yr=br.disconnect,ut&&window.MutationObserver&&xi.read(function(){document.body&&Ae(document.body,xr);new MutationObserver(function(t){var r=[];t.forEach(function(t){return i=r,n=(e=t).target,void(("attributes"!==e.type?function(t){for(var e=t.addedNodes,i=t.removedNodes,n=0;n<e.length;n++)Ae(e[n],xr);for(var r=0;r<i.length;r++)Ae(i[r],yr);return 1}:function(t){var e=t.target,i=t.attributeName;if("href"===i)return 1;var n=Ri(i);if(!(n&&n in br))return;if(st(e,i))return br[n](e),1;var r=br.getComponent(e,n);if(r)return r.$destroy(),1})(e)&&!i.some(function(t){return t.contains(n)})&&i.push(n.contains?n:n.parentNode));var e,i,n}),r.forEach(function(t){return br.update(t)})}).observe(document,{childList:!0,subtree:!0,characterData:!0,attributes:!0}),br._initialized=!0});var Sr={mixins:[sn],props:{date:String,clsWrapper:String},data:{date:"",clsWrapper:".uk-countdown-%unit%"},computed:{date:function(t){var e=t.date;return Date.parse(e)},days:function(t,e){return Me(t.clsWrapper.replace("%unit%","days"),e)},hours:function(t,e){return Me(t.clsWrapper.replace("%unit%","hours"),e)},minutes:function(t,e){return Me(t.clsWrapper.replace("%unit%","minutes"),e)},seconds:function(t,e){return Me(t.clsWrapper.replace("%unit%","seconds"),e)},units:function(){var e=this;return["days","hours","minutes","seconds"].filter(function(t){return e[t]})}},connected:function(){this.start()},disconnected:function(){var e=this;this.stop(),this.units.forEach(function(t){return ve(e[t])})},events:[{name:"visibilitychange",el:ut&&document,handler:function(){document.hidden?this.stop():this.start()}}],update:{write:function(){var t,e,n=this,r=(t=this.date,{total:e=t-Date.now(),seconds:e/1e3%60,minutes:e/1e3/60%60,hours:e/1e3/60/60%24,days:e/1e3/60/60/24});r.total<=0&&(this.stop(),r.days=r.hours=r.minutes=r.seconds=0),this.units.forEach(function(t){var e=(e=String(Math.floor(r[t]))).length<2?"0"+e:e,i=n[t];i.textContent!==e&&((e=e.split("")).length!==i.children.length&&we(i,e.map(function(){return"<span></span>"}).join("")),e.forEach(function(t,e){return i.children[e].textContent=t}))})}},methods:{start:function(){this.stop(),this.date&&this.units.length&&(this.$update(),this.timer=setInterval(this.$update,1e3))},stop:function(){this.timer&&(clearInterval(this.timer),this.timer=null)}}};var Tr,Er="uk-animation-target",_r={props:{animation:Number},data:{animation:150},computed:{target:function(){return this.$el}},methods:{animate:function(t){var n=this;!function(){if(Tr)return;(Tr=be(document.head,"<style>").sheet).insertRule("."+Er+" > * {\n            margin-top: 0 !important;\n            transform: none !important;\n        }",0)}();var r=Yt(this.target),o=r.map(function(t){return Cr(t,!0)}),e=ci(this.target),i=window.pageYOffset;t(),Qe.cancel(this.target),r.forEach(Qe.cancel),Ar(this.target),this.$update(this.target,"resize"),xi.flush();var s=ci(this.target),a=(r=r.concat(Yt(this.target).filter(function(t){return!b(r,t)}))).map(function(t,e){return!!(t.parentNode&&e in o)&&(o[e]?jt(t)?Mr(t):{opacity:0}:{opacity:jt(t)?1:0})}),o=a.map(function(t,e){var i=r[e].parentNode===n.target&&(o[e]||Cr(r[e]));return i&&(t?"opacity"in t||(i.opacity%1?t.opacity=1:delete i.opacity):delete i.opacity),i});return De(this.target,Er),r.forEach(function(t,e){return o[e]&&Re(t,o[e])}),Re(this.target,{height:e,display:"block"}),Pi(window,i),ae.all(r.map(function(t,e){return["top","left","height","width"].some(function(t){return o[e][t]!==a[e][t]})&&Qe.start(t,a[e],n.animation,"ease")}).concat(e!==s&&Qe.start(this.target,{height:s},this.animation,"ease"))).then(function(){r.forEach(function(t,e){return Re(t,{display:0===a[e].opacity?"none":"",zIndex:""})}),Ar(n.target),n.$update(n.target,"resize"),xi.flush()},et)}}};function Cr(t,e){var i=Re(t,"zIndex");return!!jt(t)&&G({display:"",opacity:e?Re(t,"opacity"):"0",pointerEvents:"none",position:"absolute",zIndex:"auto"===i?me(t):i},Mr(t))}function Ar(t){Re(t.children,{height:"",left:"",opacity:"",pointerEvents:"",position:"",top:"",width:""}),Be(t,Er),Re(t,{height:"",display:""})}function Mr(t){var e=si(t),i=e.height,n=e.width,r=hi(t);return{top:r.top,left:r.left,height:i,width:n}}var Nr={mixins:[_r],args:"target",props:{target:Boolean,selActive:Boolean},data:{target:null,selActive:!1,attrItem:"uk-filter-control",cls:"uk-active",animation:250},computed:{toggles:{get:function(t,e){t.attrItem;return Ne("["+this.attrItem+"],[data-"+this.attrItem+"]",e)},watch:function(){var e,i=this;this.updateState(),!1!==this.selActive&&(e=Ne(this.selActive,this.$el),this.toggles.forEach(function(t){return Le(t,i.cls,b(e,t))}))},immediate:!0},target:function(t,e){return Me(t.target,e)},children:{get:function(){return Yt(this.target)},watch:function(t,e){var i,n;n=e,(i=t).length===n.length&&i.every(function(t){return~n.indexOf(t)})||this.updateState()}}},events:[{name:"click",delegate:function(){return"["+this.attrItem+"],[data-"+this.attrItem+"]"},handler:function(t){t.preventDefault(),this.apply(t.current)}}],methods:{apply:function(t){this.setState(Dr(t,this.attrItem,this.getState()))},getState:function(){var i=this;return this.toggles.filter(function(t){return He(t,i.cls)}).reduce(function(t,e){return Dr(e,i.attrItem,t)},{filter:{"":""},sort:[]})},setState:function(u,t){var c=this;void 0===t&&(t=!0),u=G({filter:{"":""},sort:[]},u),Jt(this.$el,"beforeFilter",[this,u]);var l=this.children;this.toggles.forEach(function(t){return Le(t,c.cls,!!function(t,e,i){var n=i.filter;void 0===n&&(n={"":""});var r=i.sort,o=r[0],s=r[1],a=zr(t,e),h=a.filter;void 0===h&&(h="");var u=a.group;void 0===u&&(u="");var c=a.sort,l=a.order;void 0===l&&(l="asc");return H(c)?u in n&&h===n[u]||!h&&u&&!(u in n)&&!n[""]:o===c&&s===l}(t,c.attrItem,u))});function e(){var t,e,i=(t=u.filter,e="",J(t,function(t){return e+=t||""}),e);l.forEach(function(t){return Re(t,"display",i&&!zt(t,i)?"none":"")});var n,r,o,s=u.sort,a=s[0],h=s[1];a&&(r=a,o=h,Y(n=G([],l).sort(function(t,e){return ht(t,r).localeCompare(ht(e,r),void 0,{numeric:!0})*("asc"===o||-1)}),l)||n.forEach(function(t){return be(c.target,t)}))}t?this.animate(e).then(function(){return Jt(c.$el,"afterFilter",[c])}):(e(),Jt(this.$el,"afterFilter",[this]))},updateState:function(){var t=this;xi.write(function(){return t.setState(t.getState(),!1)})}}};function zr(t,e){return Mi(ht(t,e),["filter"])}function Dr(t,e,i){var n=zr(t,e),r=n.filter,o=n.group,s=n.sort,a=n.order;return void 0===a&&(a="asc"),(r||H(s))&&(o?r?(delete i.filter[""],i.filter[o]=r):(delete i.filter[o],(O(i.filter)||""in i.filter)&&(i.filter={"":r||""})):i.filter={"":r||""}),H(s)||(i.sort=[s,a]),i}var Br={slide:{show:function(t){return[{transform:Or(-100*t)},{transform:Or()}]},percent:Pr,translate:function(t,e){return[{transform:Or(-100*e*t)},{transform:Or(100*e*(1-t))}]}}};function Pr(t){return Math.abs(Re(t,"transform").split(",")[4]/t.offsetWidth)||0}function Or(t,e){return void 0===t&&(t=0),void 0===e&&(e="%"),t+=t?e:"",ct?"translateX("+t+")":"translate3d("+t+", 0, 0)"}function Hr(t){return"scale3d("+t+", "+t+", 1)"}var Lr=G({},Br,{fade:{show:function(){return[{opacity:0},{opacity:1}]},percent:function(t){return 1-Re(t,"opacity")},translate:function(t){return[{opacity:1-t},{opacity:t}]}},scale:{show:function(){return[{opacity:0,transform:Hr(.8)},{opacity:1,transform:Hr(1)}]},percent:function(t){return 1-Re(t,"opacity")},translate:function(t){return[{opacity:1-t,transform:Hr(1-.2*t)},{opacity:t,transform:Hr(.8+.2*t)}]}}});function Fr(t,e,i){Jt(t,Zt(e,!1,!1,i))}var jr={mixins:[{props:{autoplay:Boolean,autoplayInterval:Number,pauseOnHover:Boolean},data:{autoplay:!1,autoplayInterval:7e3,pauseOnHover:!0},connected:function(){this.autoplay&&this.startAutoplay()},disconnected:function(){this.stopAutoplay()},update:function(){ot(this.slides,"tabindex","-1")},events:[{name:"visibilitychange",el:ut&&document,filter:function(){return this.autoplay},handler:function(){document.hidden?this.stopAutoplay():this.startAutoplay()}}],methods:{startAutoplay:function(){var t=this;this.stopAutoplay(),this.interval=setInterval(function(){return(!t.draggable||!Me(":focus",t.$el))&&(!t.pauseOnHover||!zt(t.$el,":hover"))&&!t.stack.length&&t.show("next")},this.autoplayInterval)},stopAutoplay:function(){this.interval&&clearInterval(this.interval)}}},{props:{draggable:Boolean},data:{draggable:!0,threshold:10},created:function(){var n=this;["start","move","end"].forEach(function(t){var i=n[t];n[t]=function(t){var e=oe(t).x*(lt?-1:1);n.prevPos=e!==n.pos?n.pos:n.prevPos,n.pos=e,i(t)}})},events:[{name:mt,delegate:function(){return this.selSlides},handler:function(t){var e;!this.draggable||!re(t)&&(!(e=t.target).children.length&&e.childNodes.length)||Bt(t.target,Wt)||0<t.button||this.length<2||this.start(t)}},{name:"touchmove",passive:!1,handler:"move",filter:function(){return"touchmove"==gt},delegate:function(){return this.selSlides}},{name:"dragstart",handler:function(t){t.preventDefault()}}],methods:{start:function(){var t=this;this.drag=this.pos,this._transitioner?(this.percent=this._transitioner.percent(),this.drag+=this._transitioner.getDistance()*this.percent*this.dir,this._transitioner.cancel(),this._transitioner.translate(this.percent),this.dragging=!0,this.stack=[]):this.prevIndex=this.index;var e="touchmove"!=gt?Xt(document,gt,this.move,{passive:!1}):et;this.unbindMove=function(){e(),t.unbindMove=null},Xt(window,"scroll",this.unbindMove),Xt(window.visualViewport,"resize",this.unbindMove),Xt(document,vt+" "+xt,this.end,!0),Re(this.list,"userSelect","none")},move:function(t){var e=this;if(this.unbindMove){var i=this.pos-this.drag;if(!(0==i||this.prevPos===this.pos||!this.dragging&&Math.abs(i)<this.threshold)){Re(this.list,"pointerEvents","none"),t.cancelable&&t.preventDefault(),this.dragging=!0,this.dir=i<0?1:-1;for(var n=this.slides,r=this.prevIndex,o=Math.abs(i),s=this.getIndex(r+this.dir,r),a=this._getDistance(r,s)||n[r].offsetWidth;s!==r&&a<o;)this.drag-=a*this.dir,r=s,o-=a,s=this.getIndex(r+this.dir,r),a=this._getDistance(r,s)||n[r].offsetWidth;this.percent=o/a;var h,u=n[r],c=n[s],l=this.index!==s,d=r===s;[this.index,this.prevIndex].filter(function(t){return!b([s,r],t)}).forEach(function(t){Jt(n[t],"itemhidden",[e]),d&&(h=!0,e.prevIndex=r)}),(this.index===r&&this.prevIndex!==r||h)&&Jt(n[this.index],"itemshown",[this]),l&&(this.prevIndex=r,this.index=s,d||Jt(u,"beforeitemhide",[this]),Jt(c,"beforeitemshow",[this])),this._transitioner=this._translate(Math.abs(this.percent),u,!d&&c),l&&(d||Jt(u,"itemhide",[this]),Jt(c,"itemshow",[this]))}}},end:function(){var t;Gt(window,"scroll",this.unbindMove),Gt(window.visualViewport,"resize",this.unbindMove),this.unbindMove&&this.unbindMove(),Gt(document,vt,this.end,!0),this.dragging&&(this.dragging=null,this.index===this.prevIndex?(this.percent=1-this.percent,this.dir*=-1,this._show(!1,this.index,!0),this._transitioner=null):(t=(lt?this.dir*(lt?1:-1):this.dir)<0==this.prevPos>this.pos,this.index=t?this.index:this.prevIndex,t&&(this.percent=1-this.percent),this.show(0<this.dir&&!t||this.dir<0&&t?"next":"previous",!0))),Re(this.list,{userSelect:"",pointerEvents:""}),this.drag=this.percent=null}}},{data:{selNav:!1},computed:{nav:function(t,e){return Me(t.selNav,e)},selNavItem:function(t){var e=t.attrItem;return"["+e+"],[data-"+e+"]"},navItems:function(t,e){return Ne(this.selNavItem,e)}},update:{write:function(){var i=this;this.nav&&this.length!==this.nav.children.length&&we(this.nav,this.slides.map(function(t,e){return"<li "+i.attrItem+'="'+e+'"><a href></a></li>'}).join("")),Le(Ne(this.selNavItem,this.$el).concat(this.nav),"uk-hidden",!this.maxIndex),this.updateNav()},events:["resize"]},events:[{name:"click",delegate:function(){return this.selNavItem},handler:function(t){t.preventDefault(),this.show(ht(t.current,this.attrItem))}},{name:"itemshow",handler:"updateNav"}],methods:{updateNav:function(){var i=this,n=this.getValidIndex();this.navItems.forEach(function(t){var e=ht(t,i.attrItem);Le(t,i.clsActive,F(e)===n),Le(t,"uk-invisible",i.finite&&("previous"===e&&0===n||"next"===e&&n>=i.maxIndex))})}}}],props:{clsActivated:Boolean,easing:String,index:Number,finite:Boolean,velocity:Number,selSlides:String},data:function(){return{easing:"ease",finite:!1,velocity:1,index:0,prevIndex:-1,stack:[],percent:0,clsActive:"uk-active",clsActivated:!1,Transitioner:!1,transitionOptions:{}}},connected:function(){this.prevIndex=-1,this.index=this.getValidIndex(this.index),this.stack=[]},disconnected:function(){Be(this.slides,this.clsActive)},computed:{duration:function(t,e){var i=t.velocity;return Wr(e.offsetWidth/i)},list:function(t,e){return Me(t.selList,e)},maxIndex:function(){return this.length-1},selSlides:function(t){return t.selList+" "+(t.selSlides||"> *")},slides:{get:function(){return Ne(this.selSlides,this.$el)},watch:function(){this.$reset()}},length:function(){return this.slides.length}},events:{itemshown:function(){this.$update(this.list)}},methods:{show:function(t,e){var i=this;if(void 0===e&&(e=!1),!this.dragging&&this.length){var n=this.stack,r=e?0:n.length,o=function(){n.splice(r,1),n.length&&i.show(n.shift(),!0)};if(n[e?"unshift":"push"](t),!e&&1<n.length)2===n.length&&this._transitioner.forward(Math.min(this.duration,200));else{var s,a,h=this.getIndex(this.index),u=He(this.slides,this.clsActive)&&this.slides[h],c=this.getIndex(t,this.index),l=this.slides[c];if(u!==l){if(this.dir=(a=h,"next"!==(s=t)&&("previous"===s||s<a)?-1:1),this.prevIndex=h,this.index=c,u&&!Jt(u,"beforeitemhide",[this])||!Jt(l,"beforeitemshow",[this,u]))return this.index=this.prevIndex,void o();var d=this._show(u,l,e).then(function(){return u&&Jt(u,"itemhidden",[i]),Jt(l,"itemshown",[i]),new ae(function(t){xi.write(function(){n.shift(),n.length?i.show(n.shift(),!0):i._transitioner=null,t()})})});return u&&Jt(u,"itemhide",[this]),Jt(l,"itemshow",[this]),d}o()}}},getIndex:function(t,e){return void 0===t&&(t=this.index),void 0===e&&(e=this.index),tt(ge(t,this.slides,e,this.finite),0,this.maxIndex)},getValidIndex:function(t,e){return void 0===t&&(t=this.index),void 0===e&&(e=this.prevIndex),this.getIndex(t,e)},_show:function(t,e,i){if(this._transitioner=this._getTransitioner(t,e,this.dir,G({easing:i?e.offsetWidth<600?"cubic-bezier(0.25, 0.46, 0.45, 0.94)":"cubic-bezier(0.165, 0.84, 0.44, 1)":this.easing},this.transitionOptions)),!i&&!t)return this._translate(1),ae.resolve();var n=this.stack.length;return this._transitioner[1<n?"forward":"show"](1<n?Math.min(this.duration,75+75/(n-1)):this.duration,this.percent)},_getDistance:function(t,e){return this._getTransitioner(t,t!==e&&e).getDistance()},_translate:function(t,e,i){void 0===e&&(e=this.prevIndex),void 0===i&&(i=this.index);var n=this._getTransitioner(e!==i&&e,i);return n.translate(t),n},_getTransitioner:function(t,e,i,n){return void 0===t&&(t=this.prevIndex),void 0===e&&(e=this.index),void 0===i&&(i=this.dir||1),void 0===n&&(n=this.transitionOptions),new this.Transitioner(B(t)?this.slides[t]:t,B(e)?this.slides[e]:e,i*(lt?-1:1),n)}}};function Wr(t){return.5*t+300}var Vr={mixins:[jr],props:{animation:String},data:{animation:"slide",clsActivated:"uk-transition-active",Animations:Br,Transitioner:function(o,s,a,t){var e=t.animation,h=t.easing,i=e.percent,n=e.translate,r=e.show;void 0===r&&(r=et);var u=r(a),c=new se;return{dir:a,show:function(t,e,i){var n=this;void 0===e&&(e=0);var r=i?"linear":h;return t-=Math.round(t*tt(e,-1,1)),this.translate(e),Fr(s,"itemin",{percent:e,duration:t,timing:r,dir:a}),Fr(o,"itemout",{percent:1-e,duration:t,timing:r,dir:a}),ae.all([Qe.start(s,u[1],t,r),Qe.start(o,u[0],t,r)]).then(function(){n.reset(),c.resolve()},et),c.promise},stop:function(){return Qe.stop([s,o])},cancel:function(){Qe.cancel([s,o])},reset:function(){for(var t in u[0])Re([s,o],t,"")},forward:function(t,e){return void 0===e&&(e=this.percent()),Qe.cancel([s,o]),this.show(t,e,!0)},translate:function(t){this.reset();var e=n(t,a);Re(s,e[1]),Re(o,e[0]),Fr(s,"itemtranslatein",{percent:t,dir:a}),Fr(o,"itemtranslateout",{percent:1-t,dir:a})},percent:function(){return i(o||s,s,a)},getDistance:function(){return o&&o.offsetWidth}}}},computed:{animation:function(t){var e=t.animation,i=t.Animations;return G(i[e]||i.slide,{name:e})},transitionOptions:function(){return{animation:this.animation}}},events:{"itemshow itemhide itemshown itemhidden":function(t){var e=t.target;this.$update(e)},beforeitemshow:function(t){De(t.target,this.clsActive)},itemshown:function(t){De(t.target,this.clsActivated)},itemhidden:function(t){Be(t.target,this.clsActive,this.clsActivated)}}},Rr={mixins:[nr,or,an,Vr],functional:!0,props:{delayControls:Number,preload:Number,videoAutoplay:Boolean,template:String},data:function(){return{preload:1,videoAutoplay:!1,delayControls:3e3,items:[],cls:"uk-open",clsPage:"uk-lightbox-page",selList:".uk-lightbox-items",attrItem:"uk-lightbox-item",selClose:".uk-close-large",selCaption:".uk-lightbox-caption",pauseOnHover:!1,velocity:2,Animations:Lr,template:'<div class="uk-lightbox uk-overflow-hidden"> <ul class="uk-lightbox-items"></ul> <div class="uk-lightbox-toolbar uk-position-top uk-text-right uk-transition-slide-top uk-transition-opaque"> <button class="uk-lightbox-toolbar-icon uk-close-large" type="button" uk-close></button> </div> <a class="uk-lightbox-button uk-position-center-left uk-position-medium uk-transition-fade" href uk-slidenav-previous uk-lightbox-item="previous"></a> <a class="uk-lightbox-button uk-position-center-right uk-position-medium uk-transition-fade" href uk-slidenav-next uk-lightbox-item="next"></a> <div class="uk-lightbox-toolbar uk-lightbox-caption uk-position-bottom uk-text-center uk-transition-slide-bottom uk-transition-opaque"></div> </div>'}},created:function(){var t=Me(this.template),e=Me(this.selList,t);this.items.forEach(function(){return be(e,"<li>")}),this.$mount(be(this.container,t))},computed:{caption:function(t,e){t.selCaption;return Me(".uk-lightbox-caption",e)}},events:[{name:gt+" "+mt+" keydown",handler:"showControls"},{name:"click",self:!0,delegate:function(){return this.selSlides},handler:function(t){t.defaultPrevented||this.hide()}},{name:"shown",self:!0,handler:function(){this.showControls()}},{name:"hide",self:!0,handler:function(){this.hideControls(),Be(this.slides,this.clsActive),Qe.stop(this.slides)}},{name:"hidden",self:!0,handler:function(){this.$destroy(!0)}},{name:"keyup",el:ut&&document,handler:function(t){if(this.isToggled(this.$el)&&this.draggable)switch(t.keyCode){case 37:this.show("previous");break;case 39:this.show("next")}}},{name:"beforeitemshow",handler:function(t){this.isToggled()||(this.draggable=!1,t.preventDefault(),this.toggleElement(this.$el,!0,!1),this.animation=Lr.scale,Be(t.target,this.clsActive),this.stack.splice(1,0,this.index))}},{name:"itemshow",handler:function(){we(this.caption,this.getItem().caption||"");for(var t=-this.preload;t<=this.preload;t++)this.loadItem(this.index+t)}},{name:"itemshown",handler:function(){this.draggable=this.$props.draggable}},{name:"itemload",handler:function(t,r){var o=this,n=r.source,e=r.type,s=r.alt;void 0===s&&(s="");var a,h,i,u=r.poster,c=r.attrs;void 0===c&&(c={}),this.setItem(r,"<span uk-spinner></span>"),n&&(h={frameborder:"0",allow:"autoplay",allowfullscreen:"",style:"max-width: 100%; box-sizing: border-box;","uk-responsive":"","uk-video":""+this.videoAutoplay},"image"===e||n.match(/\.(jpe?g|png|gif|svg|webp)($|\?)/i)?fe(n,c.srcset,c.size).then(function(t){var e=t.width,i=t.height;return o.setItem(r,qr("img",G({src:n,width:e,height:i,alt:s},c)))},function(){return o.setError(r)}):"video"===e||n.match(/\.(mp4|webm|ogv)($|\?)/i)?(Xt(i=qr("video",G({src:n,poster:u,controls:"",playsinline:"","uk-video":""+this.videoAutoplay},c)),"loadedmetadata",function(){ot(i,{width:i.videoWidth,height:i.videoHeight}),o.setItem(r,i)}),Xt(i,"error",function(){return o.setError(r)})):"iframe"===e||n.match(/\.(html|php)($|\?)/i)?this.setItem(r,qr("iframe",G({src:n,frameborder:"0",allowfullscreen:"",class:"uk-lightbox-iframe"},c))):(a=n.match(/\/\/(?:.*?youtube(-nocookie)?\..*?[?&]v=|youtu\.be\/)([\w-]{11})[&?]?(.*)?/))?this.setItem(r,qr("iframe",G({src:"https://www.youtube"+(a[1]||"")+".com/embed/"+a[2]+(a[3]?"?"+a[3]:""),width:1920,height:1080},h,c))):(a=n.match(/\/\/.*?vimeo\.[a-z]+\/(\d+)[&?]?(.*)?/))&&de("https://vimeo.com/api/oembed.json?maxwidth=1920&url="+encodeURI(n),{responseType:"json",withCredentials:!1}).then(function(t){var e=t.response,i=e.height,n=e.width;return o.setItem(r,qr("iframe",G({src:"https://player.vimeo.com/video/"+a[1]+(a[2]?"?"+a[2]:""),width:n,height:i},h,c)))},function(){return o.setError(r)}))}}],methods:{loadItem:function(t){void 0===t&&(t=this.index);var e=this.getItem(t);this.getSlide(e).childElementCount||Jt(this.$el,"itemload",[e])},getItem:function(t){return void 0===t&&(t=this.index),this.items[ge(t,this.slides)]},setItem:function(t,e){Jt(this.$el,"itemloaded",[this,we(this.getSlide(t),e)])},getSlide:function(t){return this.slides[this.items.indexOf(t)]},setError:function(t){this.setItem(t,'<span uk-icon="icon: bolt; ratio: 2"></span>')},showControls:function(){clearTimeout(this.controlsTimer),this.controlsTimer=setTimeout(this.hideControls,this.delayControls),De(this.$el,"uk-active","uk-transition-active")},hideControls:function(){Be(this.$el,"uk-active","uk-transition-active")}}};function qr(t,e){var i=Ce("<"+t+">");return ot(i,e),i}var Ur,Yr={install:function(t,e){t.lightboxPanel||t.component("lightboxPanel",Rr);G(e.props,t.component("lightboxPanel").options.props)},props:{toggle:String},data:{toggle:"a"},computed:{toggles:{get:function(t,e){return Ne(t.toggle,e)},watch:function(){this.hide()}}},disconnected:function(){this.hide()},events:[{name:"click",delegate:function(){return this.toggle+":not(.uk-disabled)"},handler:function(t){t.preventDefault(),this.show(t.current)}}],methods:{show:function(t){var i,e=this,n=Q(this.toggles.map(Xr),"source");return M(t)&&(i=Xr(t).source,t=y(n,function(t){var e=t.source;return i===e})),this.panel=this.panel||this.$create("lightboxPanel",G({},this.$props,{items:n})),Xt(this.panel.$el,"hidden",function(){return e.panel=!1}),this.panel.show(t)},hide:function(){return this.panel&&this.panel.hide()}}};function Xr(e){var i={};return["href","caption","type","poster","alt","attrs"].forEach(function(t){i["href"===t?"source":t]=ht(e,t)}),i.attrs=Mi(i.attrs),i}var Gr={functional:!0,args:["message","status"],data:{message:"",status:"",timeout:5e3,group:null,pos:"top-center",clsContainer:"uk-notification",clsClose:"uk-notification-close",clsMsg:"uk-notification-message"},install:function(r){r.notification.closeAll=function(i,n){Ae(document.body,function(t){var e=r.getComponent(t,"notification");!e||i&&i!==e.group||e.close(n)})}},computed:{marginProp:function(t){return"margin"+(w(t.pos,"top")?"Top":"Bottom")},startProps:function(){var t={opacity:0};return t[this.marginProp]=-this.$el.offsetHeight,t}},created:function(){var t=Me("."+this.clsContainer+"-"+this.pos,this.$container)||be(this.$container,'<div class="'+this.clsContainer+" "+this.clsContainer+"-"+this.pos+'" style="display: block"></div>');this.$mount(be(t,'<div class="'+this.clsMsg+(this.status?" "+this.clsMsg+"-"+this.status:"")+'"> <a href class="'+this.clsClose+'" data-uk-close></a> <div>'+this.message+"</div> </div>"))},connected:function(){var t,e=this,i=j(Re(this.$el,this.marginProp));Qe.start(Re(this.$el,this.startProps),((t={opacity:1})[this.marginProp]=i,t)).then(function(){e.timeout&&(e.timer=setTimeout(e.close,e.timeout))})},events:((Ur={click:function(t){Bt(t.target,'a[href="#"],a[href=""]')&&t.preventDefault(),this.close()}})[wt]=function(){this.timer&&clearTimeout(this.timer)},Ur[bt]=function(){this.timeout&&(this.timer=setTimeout(this.close,this.timeout))},Ur),methods:{close:function(t){function e(){var t=i.$el.parentNode;Jt(i.$el,"close",[i]),$e(i.$el),t&&!t.hasChildNodes()&&$e(t)}var i=this;this.timer&&clearTimeout(this.timer),t?e():Qe.start(this.$el,this.startProps).then(e)}}};var Kr=["x","y","bgx","bgy","rotate","scale","color","backgroundColor","borderColor","opacity","blur","hue","grayscale","invert","saturate","sepia","fopacity","stroke"],Jr={mixins:[er],props:Kr.reduce(function(t,e){return t[e]="list",t},{}),data:Kr.reduce(function(t,e){return t[e]=void 0,t},{}),computed:{props:function(m,g){var v=this;return Kr.reduce(function(t,e){if(H(m[e]))return t;var i,n,r=e.match(/color/i),o=r||"opacity"===e,s=m[e].slice(0);o&&Re(g,e,""),s.length<2&&s.unshift(("scale"===e?1:o?Re(g,e):0)||0);var a,h,u,c,l,d,f=s.reduce(function(t,e){return D(e)&&e.replace(/-|\d/g,"").trim()||t},"");if(r?(a=g.style.color,s=s.map(function(t){return Re(Re(g,"color",t),"color").split(/[(),]/g).slice(1,-1).concat(1).slice(0,4).map(j)}),g.style.color=a):w(e,"bg")?(h="bgy"===e?"height":"width",s=s.map(function(t){return wi(t,h,v.$el)}),Re(g,"background-position-"+e[2],""),n=Re(g,"backgroundPosition").split(" ")["x"===e[2]?0:1],i=v.covers?(u=Math.min.apply(Math,s),c=Math.max.apply(Math,s),l=s.indexOf(u)<s.indexOf(c),d=c-u,s=s.map(function(t){return t-(l?u:c)}),(l?-d:0)+"px"):n):s=s.map(j),"stroke"===e){if(!s.some(function(t){return t}))return t;var p=Dn(v.$el);Re(g,"strokeDasharray",p),"%"===f&&(s=s.map(function(t){return t*p/100})),s=s.reverse(),e="strokeDashoffset"}return t[e]={steps:s,unit:f,pos:i,bgPos:n,diff:d},t},{})},bgProps:function(){var e=this;return["bgx","bgy"].filter(function(t){return t in e.props})},covers:function(t,e){return n=(i=e).style.backgroundSize,r="cover"===Re(Re(i,"backgroundSize",""),"backgroundSize"),i.style.backgroundSize=n,r;var i,n,r}},disconnected:function(){delete this._image},update:{read:function(t){var e,i,n,h,u,c,l=this;t.active=this.matchMedia,t.active&&(t.image||!this.covers||!this.bgProps.length||(e=Re(this.$el,"backgroundImage").replace(/^none|url\(["']?(.+?)["']?\)$/,"$1"))&&((i=new Image).src=e,(t.image=i).naturalWidth||(i.onload=function(){return l.$update()})),(n=t.image)&&n.naturalWidth&&(h={width:this.$el.offsetWidth,height:this.$el.offsetHeight},u={width:n.naturalWidth,height:n.naturalHeight},c=rt.cover(u,h),this.bgProps.forEach(function(t){var e,i=l.props[t],n=i.diff,r=i.bgPos,o=i.steps,s="bgy"===t?"height":"width",a=c[s]-h[s];a<n?h[s]=c[s]+n-a:n<a&&((e=h[s]/wi(r,s,l.$el))&&(l.props[t].steps=o.map(function(t){return t-(a-n)/e}))),c=rt.cover(u,h)}),t.dim=c))},write:function(t){var e=t.dim;t.active?e&&Re(this.$el,{backgroundSize:e.width+"px "+e.height+"px",backgroundRepeat:"no-repeat"}):Re(this.$el,{backgroundSize:"",backgroundRepeat:""})},events:["resize"]},methods:{reset:function(){var i=this;J(this.getCss(0),function(t,e){return Re(i.$el,e,"")})},getCss:function(l){var d=this.props;return Object.keys(d).reduce(function(t,e){var i=d[e],n=i.steps,r=i.unit,o=i.pos,s=function(t,e,i){void 0===i&&(i=2);var n=Zr(t,e),r=n[0],o=n[1],s=n[2];return(B(r)?r+Math.abs(r-o)*s*(r<o?1:-1):+o).toFixed(i)}(n,l);switch(e){case"x":case"y":r=r||"px",t.transform+=" translate"+p(e)+"("+j(s).toFixed("px"===r?0:2)+r+")";break;case"rotate":r=r||"deg",t.transform+=" rotate("+(s+r)+")";break;case"scale":t.transform+=" scale("+s+")";break;case"bgy":case"bgx":t["background-position-"+e[2]]="calc("+o+" + "+s+"px)";break;case"color":case"backgroundColor":case"borderColor":var a=Zr(n,l),h=a[0],u=a[1],c=a[2];t[e]="rgba("+h.map(function(t,e){return t+=c*(u[e]-t),3===e?j(t):parseInt(t,10)}).join(",")+")";break;case"blur":r=r||"px",t.filter+=" blur("+(s+r)+")";break;case"hue":r=r||"deg",t.filter+=" hue-rotate("+(s+r)+")";break;case"fopacity":r=r||"%",t.filter+=" opacity("+(s+r)+")";break;case"grayscale":case"invert":case"saturate":case"sepia":r=r||"%",t.filter+=" "+e+"("+(s+r)+")";break;default:t[e]=s}return t},{transform:"",filter:""})}}};function Zr(t,e){var i=t.length-1,n=Math.min(Math.floor(i*e),i-1),r=t.slice(n,n+2);return r.push(1===e?1:e%(1/i)*i),r}var Qr={mixins:[Jr],props:{target:String,viewport:Number,easing:Number},data:{target:!1,viewport:1,easing:1},computed:{target:function(t,e){var i=t.target;return function t(e){return e?"offsetTop"in e?e:t(e.parentNode):document.body}(i&&yt(i,e)||e)}},update:{read:function(t,e){var i=t.percent;if("scroll"!==e&&(i=!1),t.active){var n,r,o=i;return n=Hi(this.target)/(this.viewport||1),r=this.easing,{percent:i=tt(n*(1-(r-r*n))),style:o!==i&&this.getCss(i)}}},write:function(t){var e=t.style;t.active?e&&Re(this.$el,e):this.reset()},events:["scroll","resize"]}};var to={update:{write:function(){var t;this.stack.length||this.dragging||(t=this.getValidIndex(this.index),~this.prevIndex&&this.index===t||this.show(t))},events:["resize"]}};function eo(t,e,i){var n,r=ro(t,e);return i?r-(n=t,si(e).width/2-si(n).width/2):Math.min(r,io(e))}function io(t){return Math.max(0,no(t)-si(t).width)}function no(t){return so(t).reduce(function(t,e){return si(e).width+t},0)}function ro(t,e){return(hi(t).left+(lt?si(t).width-si(e).width:0))*(lt?-1:1)}function oo(t,e,i){Jt(t,Zt(e,!1,!1,i))}function so(t){return Yt(t)}var ao={mixins:[sn,jr,to],props:{center:Boolean,sets:Boolean},data:{center:!1,sets:!1,attrItem:"uk-slider-item",selList:".uk-slider-items",selNav:".uk-slider-nav",clsContainer:"uk-slider-container",Transitioner:function(r,n,o,t){var e=t.center,s=t.easing,a=t.list,h=new se,i=r?eo(r,a,e):eo(n,a,e)+si(n).width*o,u=n?eo(n,a,e):i+si(r).width*o*(lt?-1:1);return{dir:o,show:function(t,e,i){void 0===e&&(e=0);var n=i?"linear":s;return t-=Math.round(t*tt(e,-1,1)),this.translate(e),r&&this.updateTranslates(),e=r?e:tt(e,0,1),oo(this.getItemIn(),"itemin",{percent:e,duration:t,timing:n,dir:o}),r&&oo(this.getItemIn(!0),"itemout",{percent:1-e,duration:t,timing:n,dir:o}),Qe.start(a,{transform:Or(-u*(lt?-1:1),"px")},t,n).then(h.resolve,et),h.promise},stop:function(){return Qe.stop(a)},cancel:function(){Qe.cancel(a)},reset:function(){Re(a,"transform","")},forward:function(t,e){return void 0===e&&(e=this.percent()),Qe.cancel(a),this.show(t,e,!0)},translate:function(t){var e=this.getDistance()*o*(lt?-1:1);Re(a,"transform",Or(tt(e-e*t-u,-no(a),si(a).width)*(lt?-1:1),"px")),this.updateTranslates(),r&&(t=tt(t,-1,1),oo(this.getItemIn(),"itemtranslatein",{percent:t,dir:o}),oo(this.getItemIn(!0),"itemtranslateout",{percent:1-t,dir:o}))},percent:function(){return Math.abs((Re(a,"transform").split(",")[4]*(lt?-1:1)+i)/(u-i))},getDistance:function(){return Math.abs(u-i)},getItemIn:function(t){void 0===t&&(t=!1);var e=this.getActives(),i=Z(so(a),"offsetLeft"),n=me(i,e[0<o*(t?-1:1)?e.length-1:0]);return~n&&i[n+(r&&!t?o:0)]},getActives:function(){var i=eo(r||n,a,e);return Z(so(a).filter(function(t){var e=ro(t,a);return i<=e&&e+si(t).width<=si(a).width+i}),"offsetLeft")},updateTranslates:function(){var i=this.getActives();so(a).forEach(function(t){var e=b(i,t);oo(t,"itemtranslate"+(e?"in":"out"),{percent:e?1:0,dir:t.offsetLeft<=n.offsetLeft?1:-1})})}}}},computed:{avgWidth:function(){return no(this.list)/this.length},finite:function(t){return t.finite||Math.ceil(no(this.list))<si(this.list).width+so(this.list).reduce(function(t,e){return Math.max(t,si(e).width)},0)+this.center},maxIndex:function(){if(!this.finite||this.center&&!this.sets)return this.length-1;if(this.center)return K(this.sets);Re(this.slides,"order","");for(var t=io(this.list),e=this.length;e--;)if(ro(this.list.children[e],this.list)<t)return Math.min(e+1,this.length-1);return 0},sets:function(t){var o=this,e=t.sets,s=si(this.list).width/(this.center?2:1),a=0,h=s,u=0;return!O(e=e&&this.slides.reduce(function(t,e,i){var n,r=si(e).width;return a<u+r&&(!o.center&&i>o.maxIndex&&(i=o.maxIndex),b(t,i)||(n=o.slides[i+1],o.center&&n&&r<h-si(n).width/2?h-=r:(h=s,t.push(i),a=u+s+(o.center?r/2:0)))),u+=r,t},[]))&&e},transitionOptions:function(){return{center:this.center,list:this.list}}},connected:function(){Le(this.$el,this.clsContainer,!Me("."+this.clsContainer,this.$el))},update:{write:function(){var i=this;Ne("["+this.attrItem+"],[data-"+this.attrItem+"]",this.$el).forEach(function(t){var e=ht(t,i.attrItem);i.maxIndex&&Le(t,"uk-hidden",P(e)&&(i.sets&&!b(i.sets,j(e))||e>i.maxIndex))}),!this.length||this.dragging||this.stack.length||(this.reorder(),this._translate(1));var e=this._getTransitioner(this.index).getActives();this.slides.forEach(function(t){return Le(t,i.clsActive,b(e,t))}),this.sets&&!b(this.sets,j(this.index))||this.slides.forEach(function(t){return Le(t,i.clsActivated,b(e,t))})},events:["resize"]},events:{beforeitemshow:function(t){!this.dragging&&this.sets&&this.stack.length<2&&!b(this.sets,this.index)&&(this.index=this.getValidIndex());var e=Math.abs(this.index-this.prevIndex+(0<this.dir&&this.index<this.prevIndex||this.dir<0&&this.index>this.prevIndex?(this.maxIndex+1)*this.dir:0));if(!this.dragging&&1<e){for(var i=0;i<e;i++)this.stack.splice(1,0,0<this.dir?"next":"previous");t.preventDefault()}else this.duration=Wr(this.avgWidth/this.velocity)*(si(this.dir<0||!this.slides[this.prevIndex]?this.slides[this.index]:this.slides[this.prevIndex]).width/this.avgWidth),this.reorder()},itemshow:function(){~this.prevIndex&&De(this._getTransitioner().getItemIn(),this.clsActive)}},methods:{reorder:function(){var i=this;if(this.finite)Re(this.slides,"order","");else{var n=0<this.dir&&this.slides[this.prevIndex]?this.prevIndex:this.index;if(this.slides.forEach(function(t,e){return Re(t,"order",0<i.dir&&e<n?1:i.dir<0&&e>=i.index?-1:"")}),this.center)for(var t=this.slides[n],e=si(this.list).width/2-si(t).width/2,r=0;0<e;){var o=this.getIndex(--r+n,n),s=this.slides[o];Re(s,"order",n<o?-2:-1),e-=si(s).width}}},getValidIndex:function(t,e){if(void 0===t&&(t=this.index),void 0===e&&(e=this.prevIndex),t=this.getIndex(t,e),!this.sets)return t;var i;do{if(b(this.sets,t))return t;i=t,t=this.getIndex(t+this.dir,e)}while(t!==i);return t}}},ho={mixins:[Jr],data:{selItem:"!li"},computed:{item:function(t,e){return yt(t.selItem,e)}},events:[{name:"itemshown",self:!0,el:function(){return this.item},handler:function(){Re(this.$el,this.getCss(.5))}},{name:"itemin itemout",self:!0,el:function(){return this.item},handler:function(t){var e=t.type,i=t.detail,n=i.percent,r=i.duration,o=i.timing,s=i.dir;Qe.cancel(this.$el),Re(this.$el,this.getCss(co(e,s,n))),Qe.start(this.$el,this.getCss(uo(e)?.5:0<s?1:0),r,o).catch(et)}},{name:"transitioncanceled transitionend",self:!0,el:function(){return this.item},handler:function(){Qe.cancel(this.$el)}},{name:"itemtranslatein itemtranslateout",self:!0,el:function(){return this.item},handler:function(t){var e=t.type,i=t.detail,n=i.percent,r=i.dir;Qe.cancel(this.$el),Re(this.$el,this.getCss(co(e,r,n)))}}]};function uo(t){return u(t,"in")}function co(t,e,i){return i/=2,uo(t)?e<0?1-i:i:e<0?i:1-i}var lo,fo,po=G({},Br,{fade:{show:function(){return[{opacity:0,zIndex:0},{zIndex:-1}]},percent:function(t){return 1-Re(t,"opacity")},translate:function(t){return[{opacity:1-t,zIndex:0},{zIndex:-1}]}},scale:{show:function(){return[{opacity:0,transform:Hr(1.5),zIndex:0},{zIndex:-1}]},percent:function(t){return 1-Re(t,"opacity")},translate:function(t){return[{opacity:1-t,transform:Hr(1+.5*t),zIndex:0},{zIndex:-1}]}},pull:{show:function(t){return t<0?[{transform:Or(30),zIndex:-1},{transform:Or(),zIndex:0}]:[{transform:Or(-100),zIndex:0},{transform:Or(),zIndex:-1}]},percent:function(t,e,i){return i<0?1-Pr(e):Pr(t)},translate:function(t,e){return e<0?[{transform:Or(30*t),zIndex:-1},{transform:Or(-100*(1-t)),zIndex:0}]:[{transform:Or(100*-t),zIndex:0},{transform:Or(30*(1-t)),zIndex:-1}]}},push:{show:function(t){return t<0?[{transform:Or(100),zIndex:0},{transform:Or(),zIndex:-1}]:[{transform:Or(-30),zIndex:-1},{transform:Or(),zIndex:0}]},percent:function(t,e,i){return 0<i?1-Pr(e):Pr(t)},translate:function(t,e){return e<0?[{transform:Or(100*t),zIndex:0},{transform:Or(-30*(1-t)),zIndex:-1}]:[{transform:Or(-30*t),zIndex:-1},{transform:Or(100*(1-t)),zIndex:0}]}}}),mo={mixins:[sn,Vr,to],props:{ratio:String,minHeight:Number,maxHeight:Number},data:{ratio:"16:9",minHeight:!1,maxHeight:!1,selList:".uk-slideshow-items",attrItem:"uk-slideshow-item",selNav:".uk-slideshow-nav",Animations:po},update:{read:function(){var t=this.ratio.split(":").map(Number),e=t[0],i=(i=t[1])*this.list.offsetWidth/e||0;return this.minHeight&&(i=Math.max(this.minHeight,i)),this.maxHeight&&(i=Math.min(this.maxHeight,i)),{height:i-fi(this.list,"height","content-box")}},write:function(t){var e=t.height;0<e&&Re(this.list,"minHeight",e)},events:["resize"]}},go={mixins:[sn,_r],props:{group:String,threshold:Number,clsItem:String,clsPlaceholder:String,clsDrag:String,clsDragState:String,clsBase:String,clsNoDrag:String,clsEmpty:String,clsCustom:String,handle:String},data:{group:!1,threshold:5,clsItem:"uk-sortable-item",clsPlaceholder:"uk-sortable-placeholder",clsDrag:"uk-sortable-drag",clsDragState:"uk-drag",clsBase:"uk-sortable",clsNoDrag:"uk-sortable-nodrag",clsEmpty:"uk-sortable-empty",clsCustom:"",handle:!1,pos:{}},created:function(){var i=this;["init","start","move","end"].forEach(function(t){var e=i[t];i[t]=function(t){G(i.pos,oe(t)),e(t)}})},events:{name:mt,passive:!1,handler:"init"},computed:{target:function(){return(this.$el.tBodies||[this.$el])[0]},items:function(){return Yt(this.target)},isEmpty:{get:function(){return O(this.items)},watch:function(t){Le(this.target,this.clsEmpty,t)},immediate:!0},handles:{get:function(t,e){var i=t.handle;return i?Ne(i,e):this.items},watch:function(t,e){Re(e,{touchAction:"",userSelect:""}),Re(t,{touchAction:pt?"none":"",userSelect:"none"})},immediate:!0}},update:{write:function(){if(this.drag&&Pt(this.placeholder)){var t=this.pos,e=t.x,i=t.y,n=this.origin,r=n.offsetTop,o=n.offsetLeft,s=this.drag,a=s.offsetHeight,h=s.offsetWidth,u=si(window),c=u.right,l=u.bottom,d=document.elementFromPoint(e,i);Re(this.drag,{top:tt(i-r,0,l-a),left:tt(e-o,0,c-h)});var f=this.getSortable(d),p=this.getSortable(this.placeholder),m=f!==p;if(f&&!qt(d,this.placeholder)&&(!m||f.group&&f.group===p.group)){if(d=f.target===d.parentNode&&d||f.items.filter(function(t){return qt(d,t)})[0],m)p.remove(this.placeholder);else if(!d)return;f.insert(this.placeholder,d),b(this.touched,f)||this.touched.push(f)}}},events:["move"]},methods:{init:function(t){var e=t.target,i=t.button,n=t.defaultPrevented,r=this.items.filter(function(t){return qt(e,t)})[0];!r||n||0<i||Vt(e)||qt(e,"."+this.clsNoDrag)||this.handle&&!qt(e,this.handle)||(t.preventDefault(),this.touched=[this],this.placeholder=r,this.origin=G({target:e,index:me(r)},this.pos),Xt(document,gt,this.move),Xt(document,vt,this.end),this.threshold||this.start(t))},start:function(t){var e,i,n;this.drag=(e=this.$container,i=this.placeholder,ot(n=be(e,i.outerHTML.replace(/(^<)(?:li|tr)|(?:li|tr)(\/>$)/g,"$1div$2")),"style",ot(n,"style")+";margin:0!important"),Re(n,G({boxSizing:"border-box",width:i.offsetWidth,height:i.offsetHeight,overflow:"hidden"},Re(i,["paddingLeft","paddingRight","paddingTop","paddingBottom"]))),ci(n.firstElementChild,ci(i.firstElementChild)),n);var r,o,s=this.placeholder.getBoundingClientRect(),a=s.left,h=s.top;G(this.origin,{offsetLeft:this.pos.x-a,offsetTop:this.pos.y-h}),De(this.drag,this.clsDrag,this.clsCustom),De(this.placeholder,this.clsPlaceholder),De(this.items,this.clsItem),De(document.documentElement,this.clsDragState),Jt(this.$el,"start",[this,this.placeholder]),r=this.pos,o=Date.now(),lo=setInterval(function(){var t=r.x,a=r.y;a+=window.pageYOffset;var h=.3*(Date.now()-o);o=Date.now(),Li(document.elementFromPoint(t,r.y)).some(function(t){var e=t.scrollTop,i=t.scrollHeight,n=si(Fi(t)),r=n.top,o=n.bottom,s=n.height;if(r<a&&a<r+30)e-=h;else{if(!(a<o&&o-30<a))return;e+=h}if(0<e&&e<i-s)return Pi(t,e),!0})},15),this.move(t)},move:function(t){this.drag?this.$emit("move"):(Math.abs(this.pos.x-this.origin.x)>this.threshold||Math.abs(this.pos.y-this.origin.y)>this.threshold)&&this.start(t)},end:function(t){var e,i;Gt(document,gt,this.move),Gt(document,vt,this.end),Gt(window,"scroll",this.scroll),this.drag?(clearInterval(lo),e=this.getSortable(this.placeholder),this===e?this.origin.index!==me(this.placeholder)&&Jt(this.$el,"moved",[this,this.placeholder]):(Jt(e.$el,"added",[e,this.placeholder]),Jt(this.$el,"removed",[this,this.placeholder])),Jt(this.$el,"stop",[this,this.placeholder]),$e(this.drag),this.drag=null,i=this.touched.map(function(t){return t.clsPlaceholder+" "+t.clsItem}).join(" "),this.touched.forEach(function(t){return Be(t.items,i)}),Be(document.documentElement,this.clsDragState)):"touchend"===t.type&&t.target.click()},insert:function(i,n){var r=this;De(this.items,this.clsItem);function t(){var t,e;n?(!qt(i,r.target)||(e=n,(t=i).parentNode===e.parentNode&&me(t)>me(e))?xe:ye)(n,i):be(r.target,i)}this.animation?this.animate(t):t()},remove:function(t){qt(t,this.target)&&(this.animation?this.animate(function(){return $e(t)}):$e(t))},getSortable:function(t){return t&&(this.$getComponent(t,"sortable")||this.getSortable(t.parentNode))}}};var vo=[],wo={mixins:[nr,an,mn],args:"title",props:{delay:Number,title:String},data:{pos:"top",title:"",delay:0,animation:["uk-animation-scale-up"],duration:100,cls:"uk-active",clsPos:"uk-tooltip"},beforeConnect:function(){this._hasTitle=st(this.$el,"title"),ot(this.$el,{title:"","aria-expanded":!1})},disconnected:function(){this.hide(),ot(this.$el,{title:this._hasTitle?this.title:null,"aria-expanded":null})},methods:{show:function(){var e=this;!this.isActive()&&this.title&&(vo.forEach(function(t){return t.hide()}),vo.push(this),this._unbind=Xt(document,vt,function(t){return!qt(t.target,e.$el)&&e.hide()}),clearTimeout(this.showTimer),this.showTimer=setTimeout(this._show,this.delay))},hide:function(){var t=this;this.isActive()&&!zt(this.$el,"input:focus")&&this.toggleElement(this.tooltip,!1,!1).then(function(){vo.splice(vo.indexOf(t),1),clearTimeout(t.showTimer),t.tooltip=$e(t.tooltip),t._unbind()})},_show:function(){var e=this;this.tooltip=be(this.container,'<div class="'+this.clsPos+'"> <div class="'+this.clsPos+'-inner">'+this.title+"</div> </div>"),Xt(this.tooltip,"toggled",function(){var t=e.isToggled(e.tooltip);ot(e.$el,"aria-expanded",t),t&&(e.positionAt(e.tooltip,e.$el),e.origin="y"===e.getAxis()?vi(e.dir)+"-"+e.align:e.align+"-"+vi(e.dir))}),this.toggleElement(this.tooltip,!0)},isActive:function(){return b(vo,this)}},events:((fo={focus:"show",blur:"hide"})[wt+" "+bt]=function(t){re(t)||(t.type===wt?this.show():this.hide())},fo[mt]=function(t){re(t)&&(this.isActive()?this.hide():this.show())},fo)},bo={props:{allow:String,clsDragover:String,concurrent:Number,maxSize:Number,method:String,mime:String,msgInvalidMime:String,msgInvalidName:String,msgInvalidSize:String,multiple:Boolean,name:String,params:Object,type:String,url:String},data:{allow:!1,clsDragover:"uk-dragover",concurrent:1,maxSize:0,method:"POST",mime:!1,msgInvalidMime:"Invalid File Type: %s",msgInvalidName:"Invalid File Name: %s",msgInvalidSize:"Invalid File Size: %s Kilobytes Max",multiple:!1,name:"files[]",params:{},type:"",url:"",abort:et,beforeAll:et,beforeSend:et,complete:et,completeAll:et,error:et,fail:et,load:et,loadEnd:et,loadStart:et,progress:et},events:{change:function(t){zt(t.target,'input[type="file"]')&&(t.preventDefault(),t.target.files&&this.upload(t.target.files),t.target.value="")},drop:function(t){yo(t);var e=t.dataTransfer;e&&e.files&&(Be(this.$el,this.clsDragover),this.upload(e.files))},dragenter:function(t){yo(t)},dragover:function(t){yo(t),De(this.$el,this.clsDragover)},dragleave:function(t){yo(t),Be(this.$el,this.clsDragover)}},methods:{upload:function(t){var n=this;if(t.length){Jt(this.$el,"upload",[t]);for(var e=0;e<t.length;e++){if(this.maxSize&&1e3*this.maxSize<t[e].size)return void this.fail(this.msgInvalidSize.replace("%s",this.maxSize));if(this.allow&&!xo(this.allow,t[e].name))return void this.fail(this.msgInvalidName.replace("%s",this.allow));if(this.mime&&!xo(this.mime,t[e].type))return void this.fail(this.msgInvalidMime.replace("%s",this.mime))}this.multiple||(t=[t[0]]),this.beforeAll(this,t);var r=function(t,e){for(var i=[],n=0;n<t.length;n+=e){for(var r=[],o=0;o<e;o++)r.push(t[n+o]);i.push(r)}return i}(t,this.concurrent),o=function(t){var e=new FormData;for(var i in t.forEach(function(t){return e.append(n.name,t)}),n.params)e.append(i,n.params[i]);de(n.url,{data:e,method:n.method,responseType:n.type,beforeSend:function(t){var e=t.xhr;e.upload&&Xt(e.upload,"progress",n.progress),["loadStart","load","loadEnd","abort"].forEach(function(t){return Xt(e,t.toLowerCase(),n[t])}),n.beforeSend(t)}}).then(function(t){n.complete(t),r.length?o(r.shift()):n.completeAll(t)},function(t){return n.error(t)})};o(r.shift())}}}};function xo(t,e){return e.match(new RegExp("^"+t.replace(/\//g,"\\/").replace(/\*\*/g,"(\\/[^\\/]+)*").replace(/\*/g,"[^\\/]+").replace(/((?!\\))\?/g,"$1.")+"$","i"))}function yo(t){t.preventDefault(),t.stopPropagation()}return J(Object.freeze({__proto__:null,Countdown:Sr,Filter:Nr,Lightbox:Yr,LightboxPanel:Rr,Notification:Gr,Parallax:Qr,Slider:ao,SliderParallax:ho,Slideshow:mo,SlideshowParallax:ho,Sortable:go,Tooltip:wo,Upload:bo}),function(t,e){return qi.component(e,t)}),qi});
\ No newline at end of file