From: Banana Date: Wed, 30 Dec 2020 10:44:10 +0000 (+0100) Subject: inital commit. Creating own repo to unclutter things. X-Git-Tag: 1.0~50 X-Git-Url: http://91.132.146.200/gitweb/?a=commitdiff_plain;h=88868cc736f3d27441aea027af11a64ef8ad22ca;p=bibliotheca-php.git inital commit. Creating own repo to unclutter things. --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6974b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea/ +.buildpath +.project +.settings/ +*.iml +*.log diff --git a/README b/README new file mode 100644 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 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 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 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 index 0000000..a6ff029 --- /dev/null +++ b/documentation/bibliotheca.sql @@ -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 index 0000000..4567e83 --- /dev/null +++ b/documentation/setup/bibliotheca.sql @@ -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 index 0000000..2683cd0 --- /dev/null +++ b/documentation/setup/install.txt @@ -0,0 +1 @@ +Default admin user pw: test diff --git a/documentation/usermanagement.txt b/documentation/usermanagement.txt new file mode 100644 index 0000000..4ef2c89 --- /dev/null +++ b/documentation/usermanagement.txt @@ -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 index 0000000..981349b --- /dev/null +++ b/sources/imdb.class.php.txt @@ -0,0 +1,1758 @@ + + * @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 = '~]*>\s*Also\s*Known\s*As\s*\s*(.+)~Uis'; + const IMDB_ASPECT_RATIO = '~]*>Aspect\s*Ratio\s*(.+)~Uis'; + const IMDB_AWARDS = '~\s*Awards:(.+)~Uis'; + const IMDB_BUDGET = '~]*>Budget<\/td>\s*\s*(.*)(?:\(estimated\))\s*<\/td>~Ui'; + const IMDB_CAST = '~]*itemprop="actor"[^>]*>\s*]*>\s*(.+)~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 = '~]*>\s*Runtime\s*\s*(.+)~Ui'; + const IMDB_SEARCH = '~ (?:.*)<\/a>~Ui'; + const IMDB_SEASONS = '~episodes\?season=(?:\d+)">(\d+)<~Ui'; + const IMDB_SOUND_MIX = '~]*>\s*Sound\s*Mix\s*\s*(.+)~Ui'; + const IMDB_TAGLINE = '~]*>\s*Taglines\s*\s*(.+)~Ui'; + const IMDB_TITLE = '~itemprop="name">(.*)(<\/h3>|'; + } + 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 '
Using redirect: ' . basename($sRedirectFile) . '
'; + } + $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 '
Using cache: ' . basename($sCacheFile) . '
'; + } + $this->sSource = file_get_contents($sCacheFile); + $this->isReady = true; + + return true; + } + } + + // Run cURL on the URL. + if (true === self::IMDB_DEBUG) { + echo '
Running cURL: ' . $this->sUrl . '
'; + } + + $aCurlInfo = IMDBHelper::runCurl($this->sUrl); + $sSource = $aCurlInfo['contents']; + + if (false === $sSource) { + if (true === self::IMDB_DEBUG) { + echo '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + 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 '
New redirect saved: ' . basename($sRedirectFile) . ' => ' . $sUrl . '
'; + } + 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 '
Movie not found: ' . $sSearch . '
'; + } + + 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 '
Cache created: ' . basename($sCacheFile) . '
'; + } + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + return false; + } + + $aReturned = IMDBHelper::matchRegex($sSource, "~(.*?)<\/td>\s+(.*?)<\/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[] = '
' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + $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[] = '' . 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); + } + + /** + * @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 '' . IMDBHelper::cleanString( + $aMatch[2][0] + ) . ''; + } + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + return false; + } + + $aReturned = IMDBHelper::matchRegex( + $sSource, + '~>(.*)<\/a><\/td>\s+(.*)<\/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[] = '' . $sName . ''; + } + + 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[] = '' . IMDBHelper::cleanString( + $sName + ) . ''; + } + + 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 »', + 'Full synopsis »', + 'Add summary »', + 'Add synopsis »', + 'See more »', + 'See why on IMDbPro.', + "\n", + "\r", + ]; + $aReplace = [ + '', + '', + '', + '', + '', + '', + '', + '', + ]; + $sInput = str_replace('', ' | ', $sInput); + $sInput = strip_tags($sInput); + $sInput = str_replace(' ', ' ', $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 '
cURL returned wrong HTTP code “' . $aCurlInfo['http_code'] . '”, aborting.
'; + } + + 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 index 0000000..37e86f0 --- /dev/null +++ b/sources/moveinfos.txt @@ -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 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 index 0000000..ff3c3ba --- /dev/null +++ b/sources/version-names.txt @@ -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 index 0000000..8610ab1 --- /dev/null +++ b/webclient/api.php @@ -0,0 +1,229 @@ +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 index 0000000..cde8069 --- /dev/null +++ b/webclient/config/.gitignore @@ -0,0 +1 @@ +*.php diff --git a/webclient/config/database.php.default b/webclient/config/database.php.default new file mode 100644 index 0000000..450bcfd --- /dev/null +++ b/webclient/config/database.php.default @@ -0,0 +1,24 @@ +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 index 0000000..1d20d91 --- /dev/null +++ b/webclient/lib/doomguy.class.php @@ -0,0 +1,475 @@ + 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 index 0000000..cfd5cd8 --- /dev/null +++ b/webclient/lib/gorenest.class.php @@ -0,0 +1,106 @@ +_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 index 0000000..38ea398 --- /dev/null +++ b/webclient/lib/imdbwebparser.class.php @@ -0,0 +1,1808 @@ + + * @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 = '~]*>\s*Also\s*Known\s*As\s*\s*(.+)~Uis'; + const IMDB_ASPECT_RATIO = '~]*>Aspect\s*Ratio\s*(.+)~Uis'; + const IMDB_AWARDS = '~\s*Awards:(.+)~Uis'; + const IMDB_BUDGET = '~]*>Budget<\/td>\s*\s*(.*)(?:\(estimated\))\s*<\/td>~Ui'; + const IMDB_CAST = '~]*itemprop="actor"[^>]*>\s*]*>\s*(.+)~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 = '~]*>\s*Runtime\s*\s*(.+)~Ui'; + const IMDB_SEARCH = '~ (?:.*)<\/a>~Ui'; + const IMDB_SEASONS = '~episodes\?season=(?:\d+)">(\d+)<~Ui'; + const IMDB_SOUND_MIX = '~]*>\s*Sound\s*Mix\s*\s*(.+)~Ui'; + const IMDB_TAGLINE = '~]*>\s*Taglines\s*\s*(.+)~Ui'; + const IMDB_TITLE = '~itemprop="name">(.*)(<\/h3>|'; + } + + // 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 '
Using redirect: ' . basename($sRedirectFile) . '
'; + } + $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 '
Using cache: ' . basename($sCacheFile) . '
'; + } + $this->sSource = file_get_contents($sCacheFile); + $this->isReady = true; + + return true; + } + } + + // Run cURL on the URL. + if ($this->IMDB_DEBUG) { + echo '
Running cURL: ' . $this->sUrl . '
'; + } + + $aCurlInfo = $this->runCurl($this->sUrl); + $sSource = $aCurlInfo['contents']; + + if (false === $sSource) { + if ($this->IMDB_DEBUG) { + echo '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + 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 '
New redirect saved: ' . basename($sRedirectFile) . ' => ' . $sUrl . '
'; + } + 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 '
Movie not found: ' . $sSearch . '
'; + } + + return false; + } + + $this->sSource = str_replace( + [ + "\n", + "\r\n", + "\r", + ], + '', + $sSource + ); + $this->isReady = true; + + // Save cache. + if (false === $bSearch) { + if ($this->IMDB_DEBUG) { + echo '
Cache created: ' . basename($sCacheFile) . '
'; + } + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + return false; + } + + $aReturned = $this->matchRegex($sSource, "~(.*?)<\/td>\s+(.*?)<\/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[] = '
' . $this->cleanString( + $sName + ) . ''; + } + + $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[] = '' . $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); + } + + /** + * @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 '' . $this->cleanString( + $aMatch[2][0] + ) . ''; + } + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + 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 '
cURL error: ' . var_dump($aCurlInfo) . '
'; + } + + return false; + } + + $aReturned = $this->matchRegex( + $sSource, + '~>(.*)<\/a><\/td>\s+(.*)<\/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[] = '' . $sName . ''; + } + + 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[] = '' . $this->cleanString( + $sName + ) . ''; + } + + 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 »', + 'Full synopsis »', + 'Add summary »', + 'Add synopsis »', + 'See more »', + 'See why on IMDbPro.', + "\n", + "\r", + ]; + $aReplace = [ + '', + '', + '', + '', + '', + '', + '', + '', + ]; + $sInput = str_replace('', ' | ', $sInput); + $sInput = strip_tags($sInput); + $sInput = str_replace(' ', ' ', $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 '
cURL returned wrong HTTP code “' . $aCurlInfo['http_code'] . '”, aborting.
'; + } + + 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 index 0000000..af19d83 --- /dev/null +++ b/webclient/lib/managecollectionfields.class.php @@ -0,0 +1,260 @@ +_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 index 0000000..fc6104d --- /dev/null +++ b/webclient/lib/managecollections.class.php @@ -0,0 +1,489 @@ +_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 index 0000000..ef14375 --- /dev/null +++ b/webclient/lib/manageentry.class.php @@ -0,0 +1,689 @@ +_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 index 0000000..1d1682e --- /dev/null +++ b/webclient/lib/mancubus.class.php @@ -0,0 +1,626 @@ + 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 index 0000000..0be12c8 --- /dev/null +++ b/webclient/lib/possessed.class.php @@ -0,0 +1,377 @@ +_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 index 0000000..ced903f --- /dev/null +++ b/webclient/lib/spectre.class.php @@ -0,0 +1,108 @@ +_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 index 0000000..15ccefd --- /dev/null +++ b/webclient/lib/summoner.class.php @@ -0,0 +1,685 @@ +$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 index 0000000..398d220 --- /dev/null +++ b/webclient/lib/tentacle.class.php @@ -0,0 +1,88 @@ +_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 index 0000000..22a0e83 --- /dev/null +++ b/webclient/lib/trite.class.php @@ -0,0 +1,190 @@ + 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 index 0000000..d6b7ef3 --- /dev/null +++ b/webclient/storage/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/webclient/systemout/.gitignore b/webclient/systemout/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/webclient/systemout/.gitignore @@ -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 index 0000000..625e0f6 --- /dev/null +++ b/webclient/view/default/auth/auth.html @@ -0,0 +1,31 @@ +isSignedIn() === true) { ?> +

Logout

+ + Logout + + + +

Login

+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+ diff --git a/webclient/view/default/auth/auth.php b/webclient/view/default/auth/auth.php new file mode 100644 index 0000000..4747933 --- /dev/null +++ b/webclient/view/default/auth/auth.php @@ -0,0 +1,50 @@ +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 index 0000000..73ec71c --- /dev/null +++ b/webclient/view/default/collections/collections.html @@ -0,0 +1,55 @@ +

+ + +
+ +

Display result for:

+
+ + + + +
+ $entry) { ?> +
+
+
+ + <?php echo $entry['fields']['coverimage']['displayname']; ?> + + +
+
+ +

+ + + +

+ +
+ +
+
+ +
+ +

Collection overview

+
+
+
+ $v) { ?> +
+
+ +
+
+
+ diff --git a/webclient/view/default/collections/collections.php b/webclient/view/default/collections/collections.php new file mode 100644 index 0000000..b29698a --- /dev/null +++ b/webclient/view/default/collections/collections.php @@ -0,0 +1,92 @@ +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 index 0000000..6ad47e0 --- /dev/null +++ b/webclient/view/default/dashboard/dashboard.html @@ -0,0 +1,54 @@ + +
+ +

Display result for:

+
+ + + +
+$v) { ?> +
+
+ + + $entry) { ?> + +
+
+ + <?php echo $entry['fields']['coverimage']['displayname']; ?> + + +
+
+
+ +

+ + + +

+ +
+ +
+
+ + + +
+ +
diff --git a/webclient/view/default/dashboard/dashboard.php b/webclient/view/default/dashboard/dashboard.php new file mode 100644 index 0000000..a4a843f --- /dev/null +++ b/webclient/view/default/dashboard/dashboard.php @@ -0,0 +1,34 @@ +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 index 0000000..4c83cc1 --- /dev/null +++ b/webclient/view/default/entry/entry.html @@ -0,0 +1,55 @@ +

+
+
+ +
+
+ +
+
diff --git a/webclient/view/default/entry/entry.php b/webclient/view/default/entry/entry.php new file mode 100644 index 0000000..a554905 --- /dev/null +++ b/webclient/view/default/entry/entry.php @@ -0,0 +1,63 @@ +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 index 0000000..61f0e48 --- /dev/null +++ b/webclient/view/default/entry/field-date.html @@ -0,0 +1,4 @@ +

+ : + +

diff --git a/webclient/view/default/entry/field-lookupmultiple.html b/webclient/view/default/entry/field-lookupmultiple.html new file mode 100644 index 0000000..47d42e0 --- /dev/null +++ b/webclient/view/default/entry/field-lookupmultiple.html @@ -0,0 +1,8 @@ +

+ : + '.$_fv.', '; + } + ?> +

diff --git a/webclient/view/default/entry/field-selection.html b/webclient/view/default/entry/field-selection.html new file mode 100644 index 0000000..2872380 --- /dev/null +++ b/webclient/view/default/entry/field-selection.html @@ -0,0 +1,4 @@ +

+ : + +

diff --git a/webclient/view/default/entry/field-text-title.html b/webclient/view/default/entry/field-text-title.html new file mode 100644 index 0000000..216fac6 --- /dev/null +++ b/webclient/view/default/entry/field-text-title.html @@ -0,0 +1 @@ +

diff --git a/webclient/view/default/entry/field-text.html b/webclient/view/default/entry/field-text.html new file mode 100644 index 0000000..9f76b0e --- /dev/null +++ b/webclient/view/default/entry/field-text.html @@ -0,0 +1 @@ +

:

diff --git a/webclient/view/default/entry/field-text3-description.html b/webclient/view/default/entry/field-text3-description.html new file mode 100644 index 0000000..065ab0f --- /dev/null +++ b/webclient/view/default/entry/field-text3-description.html @@ -0,0 +1 @@ +

diff --git a/webclient/view/default/entry/field-text3.html b/webclient/view/default/entry/field-text3.html new file mode 100644 index 0000000..c663afb --- /dev/null +++ b/webclient/view/default/entry/field-text3.html @@ -0,0 +1 @@ +

:

diff --git a/webclient/view/default/entry/field-textarea-content.html b/webclient/view/default/entry/field-textarea-content.html new file mode 100644 index 0000000..6e5e340 --- /dev/null +++ b/webclient/view/default/entry/field-textarea-content.html @@ -0,0 +1 @@ +

diff --git a/webclient/view/default/entry/field-textarea.html b/webclient/view/default/entry/field-textarea.html new file mode 100644 index 0000000..7cd22c2 --- /dev/null +++ b/webclient/view/default/entry/field-textarea.html @@ -0,0 +1 @@ +

:

diff --git a/webclient/view/default/entry/field-unknown.html b/webclient/view/default/entry/field-unknown.html new file mode 100644 index 0000000..fa3ba54 --- /dev/null +++ b/webclient/view/default/entry/field-unknown.html @@ -0,0 +1 @@ +

Missing template for:

diff --git a/webclient/view/default/entry/field-upload-coverimage.html b/webclient/view/default/entry/field-upload-coverimage.html new file mode 100644 index 0000000..8e78315 --- /dev/null +++ b/webclient/view/default/entry/field-upload-coverimage.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/webclient/view/default/entry/field-upload.html b/webclient/view/default/entry/field-upload.html new file mode 100644 index 0000000..5acb876 --- /dev/null +++ b/webclient/view/default/entry/field-upload.html @@ -0,0 +1,3 @@ +

: + +

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 index 0000000..6145c89 --- /dev/null +++ b/webclient/view/default/entry/field-upload_multiple-attachment.html @@ -0,0 +1,9 @@ +
+ +
+ + <?php echo $_uEntry; ?> + +
+ +
diff --git a/webclient/view/default/entry/field-upload_multiple.html b/webclient/view/default/entry/field-upload_multiple.html new file mode 100644 index 0000000..955ccfd --- /dev/null +++ b/webclient/view/default/entry/field-upload_multiple.html @@ -0,0 +1,8 @@ +

: +

    + +
  • + +
+

+ diff --git a/webclient/view/default/entry/field-year.html b/webclient/view/default/entry/field-year.html new file mode 100644 index 0000000..7f04a91 --- /dev/null +++ b/webclient/view/default/entry/field-year.html @@ -0,0 +1,4 @@ +

+ : + +

diff --git a/webclient/view/default/main.php b/webclient/view/default/main.php new file mode 100644 index 0000000..ff5fec7 --- /dev/null +++ b/webclient/view/default/main.php @@ -0,0 +1,34 @@ + + + + + + + + + + + + + Bibliotheca + + +
+ +
+ +
+
+ + + +
+
+ +
+
+

 

+
+
+ + diff --git a/webclient/view/default/managecollectionfields/managecollectionfields.html b/webclient/view/default/managecollectionfields/managecollectionfields.html new file mode 100644 index 0000000..ddc23b0 --- /dev/null +++ b/webclient/view/default/managecollectionfields/managecollectionfields.html @@ -0,0 +1,60 @@ +

Manage your fields for:

+ +
+
+

Add or remove a field

+

+ Just use drag and drop below to add, remove or order your fields.
+ Removing a field will remove + the stored data from the collection.
+ Make sure at least the title + field is available. +

+
+ $v) { ?> +
+ + () +
+ +
+ +
+ +
+ +
+
+
+
+

Available fields

+
+ $v) { ?> +
+ + () +
+ +
+
+
+ + diff --git a/webclient/view/default/managecollectionfields/managecollectionfields.php b/webclient/view/default/managecollectionfields/managecollectionfields.php new file mode 100644 index 0000000..536f372 --- /dev/null +++ b/webclient/view/default/managecollectionfields/managecollectionfields.php @@ -0,0 +1,71 @@ +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 index 0000000..486957f --- /dev/null +++ b/webclient/view/default/managecolletions/managecolletions.html @@ -0,0 +1,166 @@ +

Manage your collections

+ +
+
+

Add or modify a collection

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
Rights
+
+ + + + + + + + + + + +
UserGroupOther
+ + + + + + + + + + + +
+
+
+
+ +
+ +
+
+ +
+
Delete
+
+ +
+
+ +
+ +
+ + The field is used in the global search. + Altering the default search field results in + a DB reindex. This could take some time, depending on the amount of data. +
+
+
+ +
+
+
+
+

Available collections

+ + + + + + + + + + + $v) { ?> + + + + + + + + +
NameDescriptionOwnership
+
+ +
+
+
+ +
+ + +
+
+
diff --git a/webclient/view/default/managecolletions/managecolletions.php b/webclient/view/default/managecolletions/managecolletions.php new file mode 100644 index 0000000..14d126d --- /dev/null +++ b/webclient/view/default/managecolletions/managecolletions.php @@ -0,0 +1,123 @@ +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 index 0000000..cb885e2 --- /dev/null +++ b/webclient/view/default/manageentry/field-lookupmultiple.html @@ -0,0 +1,49 @@ + +
+ +
+
+ + +
+ +
+ + +
+ +
+
+ + + + + + + + + + diff --git a/webclient/view/default/manageentry/field-selection.html b/webclient/view/default/manageentry/field-selection.html new file mode 100644 index 0000000..6dafc78 --- /dev/null +++ b/webclient/view/default/manageentry/field-selection.html @@ -0,0 +1,13 @@ +
+ +
+ +
+
diff --git a/webclient/view/default/manageentry/field-text.html b/webclient/view/default/manageentry/field-text.html new file mode 100644 index 0000000..a6c5c41 --- /dev/null +++ b/webclient/view/default/manageentry/field-text.html @@ -0,0 +1,9 @@ +
+ +
+ +
+
diff --git a/webclient/view/default/manageentry/field-text3.html b/webclient/view/default/manageentry/field-text3.html new file mode 100644 index 0000000..974b0da --- /dev/null +++ b/webclient/view/default/manageentry/field-text3.html @@ -0,0 +1,9 @@ +
+ +
+ +
+
+ diff --git a/webclient/view/default/manageentry/field-textarea.html b/webclient/view/default/manageentry/field-textarea.html new file mode 100644 index 0000000..0e20fdb --- /dev/null +++ b/webclient/view/default/manageentry/field-textarea.html @@ -0,0 +1,9 @@ +
+ +
+ +
+
+ diff --git a/webclient/view/default/manageentry/field-unknown.html b/webclient/view/default/manageentry/field-unknown.html new file mode 100644 index 0000000..a1cdcbf --- /dev/null +++ b/webclient/view/default/manageentry/field-unknown.html @@ -0,0 +1,3 @@ +
+ Missing template for: +
diff --git a/webclient/view/default/manageentry/field-upload.html b/webclient/view/default/manageentry/field-upload.html new file mode 100644 index 0000000..152a325 --- /dev/null +++ b/webclient/view/default/manageentry/field-upload.html @@ -0,0 +1,17 @@ +
+ +
+ + +
+ '.Summoner::ifset($TemplateData['editData'], $field['identifier']).''; ?> + +
+ +
+
diff --git a/webclient/view/default/manageentry/field-upload_multiple.html b/webclient/view/default/manageentry/field-upload_multiple.html new file mode 100644 index 0000000..52e64d2 --- /dev/null +++ b/webclient/view/default/manageentry/field-upload_multiple.html @@ -0,0 +1,24 @@ +
+ +
+ +
+ + + +
+ +
+
+
diff --git a/webclient/view/default/manageentry/field-year.html b/webclient/view/default/manageentry/field-year.html new file mode 100644 index 0000000..75b687e --- /dev/null +++ b/webclient/view/default/manageentry/field-year.html @@ -0,0 +1,10 @@ +
+ +
+ +
+
diff --git a/webclient/view/default/manageentry/manageentry.html b/webclient/view/default/manageentry/manageentry.html new file mode 100644 index 0000000..96fc698 --- /dev/null +++ b/webclient/view/default/manageentry/manageentry.html @@ -0,0 +1,74 @@ + +

Update an entry in:

+

View entry

+ +

Add an entry to:

+ +
+
+
+ + + +
+
Delete
+
+ +
+
+ + + +
+ +
+
+
+
+ +

Available tools

+ + +
+
+ + +

Add an entry to your collection

+
+
+

Please select a collection first:

+
+ $v) { ?> +
+
+ +
+
+
+ diff --git a/webclient/view/default/manageentry/manageentry.php b/webclient/view/default/manageentry/manageentry.php new file mode 100644 index 0000000..5cbb984 --- /dev/null +++ b/webclient/view/default/manageentry/manageentry.php @@ -0,0 +1,143 @@ +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: ".$do.""; + $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 index 0000000..4dc33d2 --- /dev/null +++ b/webclient/view/default/manageusers/manageusers.html @@ -0,0 +1,125 @@ +

User management

+
+
+

Add or modify a user

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
Can login
+
+ +
+
+ +
+
Delete
+
+ +
+
+
+
Create API Token
+
+ +
+
+ +
+ +
+
+
+
+

Available users

+ + + + + + + + + + + + $v) { ?> + + + + + + + + + +
LoginUsernameGroup(s)Status
+
+ +
+
    + $gv) { ?> +
  • + +
  • + +
+
+ + + +
+ + +
+
diff --git a/webclient/view/default/manageusers/manageusers.php b/webclient/view/default/manageusers/manageusers.php new file mode 100644 index 0000000..a7e1b89 --- /dev/null +++ b/webclient/view/default/manageusers/manageusers.php @@ -0,0 +1,111 @@ +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 index 0000000..53bab8c --- /dev/null +++ b/webclient/view/default/system/menu.php @@ -0,0 +1,74 @@ +get('show'); +$_menuManage = $Gorenest->get('manage'); +?> + diff --git a/webclient/view/default/system/message.php b/webclient/view/default/system/message.php new file mode 100644 index 0000000..fc8e008 --- /dev/null +++ b/webclient/view/default/system/message.php @@ -0,0 +1,42 @@ + +
+

+
+ diff --git a/webclient/view/default/system/pagination.html b/webclient/view/default/system/pagination.html new file mode 100644 index 0000000..5fdafa4 --- /dev/null +++ b/webclient/view/default/system/pagination.html @@ -0,0 +1,36 @@ + 1) { ?> +
    + 1) { + echo '
  • +
  • '; + } + + $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 '
  • '.$i.'
  • '; + } + else { + if($i < $TemplateData['pagination']['currentRangeStart'] && $ellipsisShown == 0) { + echo '
  • '; + $ellipsisShown = 1; + } + if($i > $TemplateData['pagination']['currentRangeEnd'] && ($ellipsisShown == 0 || $ellipsisShown == 1)) { + echo '
  • '; + $ellipsisShown = 2; + } + } + } + + if($TemplateData['pagination']['curPage'] < $TemplateData['pagination']['pages']) { + echo '
  • +
  • '; + } + ?> +
+ diff --git a/webclient/view/default/system/pagination_after.php b/webclient/view/default/system/pagination_after.php new file mode 100644 index 0000000..48a106b --- /dev/null +++ b/webclient/view/default/system/pagination_after.php @@ -0,0 +1,54 @@ + 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 index 0000000..ac24626 --- /dev/null +++ b/webclient/view/default/system/pagination_before.php @@ -0,0 +1,51 @@ + 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 index 0000000..16f10c1 --- /dev/null +++ b/webclient/view/default/tags/tags.html @@ -0,0 +1,37 @@ +
+
+ +

Selectable tags for:

+ + +
+ +

Display result for:

+
+ + + + $v) { ?> +

+
+ $ev) { ?> + , + +
+ + + +

Please select a collection first

+
+ $v) { ?> +
+
+ +
+ +
+
diff --git a/webclient/view/default/tags/tags.php b/webclient/view/default/tags/tags.php new file mode 100644 index 0000000..ecda30d --- /dev/null +++ b/webclient/view/default/tags/tags.php @@ -0,0 +1,64 @@ +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 index 0000000..cdc541b --- /dev/null +++ b/webclient/view/default/tool/tool-imdbweb.html @@ -0,0 +1,56 @@ +

Limitations

+

Picture: Use URL to manually save and upload.

+

Rating: Works only if the rating matches 1:1.

+

Data will be overwritten

+ +
+
+ +
+ +
+
+ +
+
+
+ + +
+ + $v) { + ?> + +
+

+
+ +

+
+
+ +
+ + + +
+ +
+ +
+ diff --git a/webclient/view/default/tool/tool-imdbweb.php b/webclient/view/default/tool/tool-imdbweb.php new file mode 100644 index 0000000..d04cd58 --- /dev/null +++ b/webclient/view/default/tool/tool-imdbweb.php @@ -0,0 +1,153 @@ + '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'] .= "\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: + Here"; + } + + 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 index 0000000..8cf10d4 --- /dev/null +++ b/webclient/view/default/tool/tool.html @@ -0,0 +1,12 @@ +

Using with collection:

+ +

+ +

+ + +
+
+ +
+
diff --git a/webclient/view/default/tool/tool.php b/webclient/view/default/tool/tool.php new file mode 100644 index 0000000..9f5e6f5 --- /dev/null +++ b/webclient/view/default/tool/tool.php @@ -0,0 +1,83 @@ +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 index 0000000..e71cb60 --- /dev/null +++ b/webclient/view/default/ui/css/style.css @@ -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 index 0000000..447f064 --- /dev/null +++ b/webclient/view/default/ui/css/uikit.min.css @@ -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 index 0000000..2cfdcef --- /dev/null +++ b/webclient/view/default/ui/js/suggest-tag.js @@ -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 index 0000000..2f980c0 --- /dev/null +++ b/webclient/view/default/ui/js/uikit-icons.min.js @@ -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":'',album:'',"arrow-down":'',"arrow-left":'',"arrow-right":'',"arrow-up":'',ban:'',behance:'',bell:'',bold:'',bolt:'',bookmark:'',calendar:'',camera:'',cart:'',check:'',"chevron-double-left":'',"chevron-double-right":'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',clock:'',close:'',"cloud-download":'',"cloud-upload":'',code:'',cog:'',comment:'',commenting:'',comments:'',copy:'',"credit-card":'',database:'',desktop:'',download:'',dribbble:'',etsy:'',expand:'',facebook:'',"file-edit":'',"file-pdf":'',"file-text":'',file:'',flickr:'',folder:'',forward:'',foursquare:'',future:'',"git-branch":'',"git-fork":'',"github-alt":'',github:'',gitter:'',"google-plus":'',google:'',grid:'',happy:'',hashtag:'',heart:'',history:'',home:'',image:'',info:'',instagram:'',italic:'',joomla:'',laptop:'',lifesaver:'',link:'',linkedin:'',list:'',location:'',lock:'',mail:'',menu:'',microphone:'',"minus-circle":'',minus:'',"more-vertical":'',more:'',move:'',nut:'',pagekit:'',"paint-bucket":'',pencil:'',"phone-landscape":'',phone:'',pinterest:'',"play-circle":'',play:'',"plus-circle":'',plus:'',print:'',pull:'',push:'',question:'',"quote-right":'',receiver:'',reddit:'',refresh:'',reply:'',rss:'',search:'',server:'',settings:'',shrink:'',"sign-in":'',"sign-out":'',social:'',soundcloud:'',star:'',strikethrough:'',table:'',"tablet-landscape":'',tablet:'',tag:'',thumbnails:'',trash:'',"triangle-down":'',"triangle-left":'',"triangle-right":'',"triangle-up":'',tripadvisor:'',tumblr:'',tv:'',twitter:'',uikit:'',unlock:'',upload:'',user:'',users:'',"video-camera":'',vimeo:'',warning:'',whatsapp:'',wordpress:'',world:'',xing:'',yelp:'',youtube:''})}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 index 0000000..5fddab3 --- /dev/null +++ b/webclient/view/default/ui/js/uikit.min.js @@ -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;ie.left&&t.tope.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]+~-]/,_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]*>/,_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,1n[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,kiMath.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 *",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,"")),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=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]"}return zn[t][e]}(t,e)||t);return(t=Me(t.substr(t.indexOf("/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:'',totop:'',marker:'',"close-icon":'',"close-large":'',"navbar-toggle-icon":'',"overlay-icon":'',"pagination-next":'',"pagination-previous":'',"search-icon":'',"search-large":'',"search-navbar":'',"slidenav-next":'',"slidenav-next-large":'',"slidenav-previous":'',"slidenav-previous-large":''},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,'}(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,'');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('
'+t+"
",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'
'+(D(i)?i:we(i))+'
"},t,function(t){return t.resolve()})},a.confirm=function(i,t){return e(function(t){var e=t.labels;return'
'+(D(i)?i:we(i))+'
"},t,function(t){return t.reject()})},a.prompt=function(i,n,t){return e(function(t){var e=t.labels;return'
"},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("
")):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"),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,'')}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('
'),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&&0this.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(e-n)?0
"}).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,"