diff --git a/app/.editorconfig b/app/.editorconfig
new file mode 100644
index 0000000..209e731
--- /dev/null
+++ b/app/.editorconfig
@@ -0,0 +1,23 @@
+; This file is for unifying the coding style for different editors and IDEs.
+; More information at http://editorconfig.org
+
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.bat]
+end_of_line = crlf
+
+[*.yml]
+indent_size = 2
+
+[*.twig]
+insert_final_newline = false
+
+[Makefile]
+indent_style = tab
diff --git a/app/.gitattributes b/app/.gitattributes
new file mode 100644
index 0000000..8a2cf52
--- /dev/null
+++ b/app/.gitattributes
@@ -0,0 +1,54 @@
+# Define the line ending behavior of the different file extensions
+# Set default behavior, in case users don't have core.autocrlf set.
+* text=auto
+* text eol=lf
+
+# Explicitly declare text files we want to always be normalized and converted
+# to native line endings on checkout.
+*.php text
+*.default text
+*.ctp text
+*.sql text
+*.md text
+*.po text
+*.js text
+*.css text
+*.ini text
+*.properties text
+*.txt text
+*.xml text
+*.svg text
+*.yml text
+.htaccess text
+
+# Declare files that will always have CRLF line endings on checkout.
+*.bat eol=crlf
+
+# Declare files that will always have LF line endings on checkout.
+*.pem eol=lf
+
+# Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpg binary
+*.gif binary
+*.webp binary
+*.ico binary
+*.mo binary
+*.pdf binary
+*.phar binary
+*.woff binary
+*.woff2 binary
+*.ttf binary
+*.otf binary
+*.eot binary
+*.gz binary
+*.bz2 binary
+*.7z binary
+*.zip binary
+*.webm binary
+*.mp4 binary
+*.ogv binary
+
+# Remove files for archives generated using `git archive`
+phpstan.neon export-ignore
+.github export-ignore
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..a20bb1f
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,43 @@
+# CakePHP specific files #
+##########################
+/config/app_local.php
+/config/.env
+/logs/*
+/tmp/*
+/vendor/*
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+Icon?
+ehthumbs.db
+Thumbs.db
+.directory
+
+# Tool specific files #
+#######################
+# PHPUnit
+.phpunit.result.cache
+# vim
+*~
+*.swp
+*.swo
+# sublime text & textmate
+*.sublime-*
+*.stTheme.cache
+*.tmlanguage.cache
+*.tmPreferences.cache
+# Eclipse
+.settings/*
+# JetBrains, aka PHPStorm, IntelliJ IDEA
+.idea/*
+# NetBeans
+nbproject/*
+# Visual Studio Code
+.vscode
+# Sass preprocessor
+.sass-cache/
diff --git a/app/.htaccess b/app/.htaccess
new file mode 100644
index 0000000..fc3aac4
--- /dev/null
+++ b/app/.htaccess
@@ -0,0 +1,5 @@
+
+ RewriteEngine on
+ RewriteRule ^$ webroot/ [L]
+ RewriteRule (.*) webroot/$1 [L]
+
\ No newline at end of file
diff --git a/app/INSTALL/MYSQL.sql b/app/INSTALL/MYSQL.sql
new file mode 100644
index 0000000..4fe38ca
--- /dev/null
+++ b/app/INSTALL/MYSQL.sql
@@ -0,0 +1,176 @@
+CREATE TABLE IF NOT EXISTS alignment_tags (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ alignment_id int(10) UNSIGNED NOT NULL,
+ tag_id int(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS alignments (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ individual_id int(10) UNSIGNED NOT NULL,
+ organisation_id int(10) UNSIGNED NOT NULL,
+ type varchar(191) DEFAULT 'member',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS authkeys (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ authkey varchar(40) CHARSET ascii COLLATE ascii_general_ci,
+ created int(10) UNSIGNED NOT NULL,
+ valid_until int(10) UNSIGNED NOT NULL,
+ user_id int(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (id),
+ INDEX (authkey),
+ INDEX (created),
+ INDEX (valid_until)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+
+CREATE TABLE IF NOT EXISTS broods (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ name varchar(191) NOT NULL,
+ url varchar(191) NOT NULL,
+ description text,
+ organisation_id int(10) UNSIGNED NOT NULL,
+ alignment_id int(10) UNSIGNED NOT NULL,
+ trusted tinyint(1),
+ pull tinyint(1),
+ authkey varchar(40) CHARSET ascii COLLATE ascii_general_ci,
+ PRIMARY KEY (id),
+ INDEX (uuid),
+ INDEX (name),
+ INDEX (url),
+ INDEX (authkey)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+
+CREATE TABLE IF NOT EXISTS individuals (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ email varchar(191) NOT NULL,
+ first_name varchar(191) NOT NULL,
+ last_name varchar(191) NOT NULL,
+ position text,
+ PRIMARY KEY (id),
+ INDEX (uuid),
+ INDEX (email),
+ INDEX (first_name),
+ INDEX (last_name)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS individual_encryption_keys (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ individual_id int(10) UNSIGNED NOT NULL,
+ encryption_key_id int(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS encryption_keys (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ type varchar(191) NOT NULL,
+ encryption_key text,
+ revoked tinyint(1),
+ expires int(10) UNSIGNED,
+ PRIMARY KEY (id),
+ INDEX (uuid),
+ INDEX (type),
+ INDEX (expires)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS organisation_encryption_keys (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ organisation_id int(10) UNSIGNED NOT NULL,
+ encryption_key_id int(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+
+CREATE TABLE IF NOT EXISTS organisations (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ name varchar(191) NOT NULL,
+ url varchar(191),
+ nationality varchar(191),
+ sector varchar(191),
+ type varchar(191),
+ contacts text,
+ PRIMARY KEY (id),
+ INDEX (uuid),
+ INDEX (name),
+ INDEX (url),
+ INDEX (nationality),
+ INDEX (sector),
+ INDEX (type)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS roles (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ name varchar(191) NOT NULL,
+ is_default tinyint(1),
+ perm_admin tinyint(1),
+ PRIMARY KEY (id),
+ INDEX (name),
+ INDEX (uuid)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS tags (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ name varchar(191) NOT NULL,
+ description text,
+ colour varchar(6) CHARSET ascii COLLATE ascii_general_ci NOT NULL,
+ PRIMARY KEY (id),
+ INDEX (name)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS user_keys (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ user_id int(10) UNSIGNED NOT NULL,
+ authkey_id int(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS users (
+ id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL,
+ email varchar(191) NOT NULL,
+ password varchar(191),
+ role_id int(11) UNSIGNED NOT NULL,
+ individual_id int(11) UNSIGNED NOT NULL,
+ PRIMARY KEY (id),
+ INDEX (uuid),
+ INDEX (email)
+) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+ALTER TABLE alignment_tags
+ ADD FOREIGN KEY (alignment_id) REFERENCES alignments(id),
+ ADD FOREIGN KEY (tag_id) REFERENCES tags(id);
+
+ALTER TABLE alignments
+ ADD FOREIGN KEY (individual_id) REFERENCES individuals(id),
+ ADD FOREIGN KEY (organisation_id) REFERENCES organisations(id);
+
+ALTER TABLE authkeys
+ ADD FOREIGN KEY (user_id) REFERENCES users(id);
+
+ALTER TABLE broods
+ ADD FOREIGN KEY (alignment_id) REFERENCES alignments(id);
+
+ALTER TABLE individual_encryption_keys
+ ADD FOREIGN KEY (individual_id) REFERENCES individuals(id),
+ ADD FOREIGN KEY (encryption_key_id) REFERENCES encryption_keys(id);
+
+ALTER TABLE organisation_encryption_keys
+ ADD FOREIGN KEY (organisation_id) REFERENCES organisations(id),
+ ADD FOREIGN KEY (encryption_key_id) REFERENCES encryption_keys(id);
+
+ALTER TABLE user_keys
+ ADD FOREIGN KEY (user_id) REFERENCES users(id),
+ ADD FOREIGN KEY (authkey_id) REFERENCES authkeys(id);
+
+ALTER TABLE users
+ ADD FOREIGN KEY (role_id) REFERENCES roles(id),
+ ADD FOREIGN KEY (individual_id) REFERENCES individuals(id);
+
diff --git a/app/INSTALL/clean.sql b/app/INSTALL/clean.sql
new file mode 100644
index 0000000..40cd9ef
--- /dev/null
+++ b/app/INSTALL/clean.sql
@@ -0,0 +1,14 @@
+SET FOREIGN_KEY_CHECKS=0;
+DROP TABLE IF EXISTS alignment_keys;
+DROP TABLE IF EXISTS alignments;
+DROP TABLE IF EXISTS authkeys;
+DROP TABLE IF EXISTS broods;
+DROP TABLE IF EXISTS individuals;
+DROP TABLE IF EXISTS encryption_keys;
+DROP TABLE IF EXISTS organisation_encryption_keys;
+DROP TABLE IF EXISTS organisations;
+DROP TABLE IF EXISTS roles;
+DROP TABLE IF EXISTS tags;
+DROP TABLE IF EXISTS user_keys;
+DROP TABLE IF EXISTS users;
+SET FOREIGN_KEY_CHECKS=1;
diff --git a/app/INSTALL/data.sql b/app/INSTALL/data.sql
new file mode 100644
index 0000000..7c6bef9
--- /dev/null
+++ b/app/INSTALL/data.sql
@@ -0,0 +1,6 @@
+INSERT INTO organisations (uuid, name, url, nationality, sector, type, contacts)
+VALUES ('11111111-1111-1111-1111-111111111111', 'foo', 'http://google.com', 'NO', '', '', '');
+
+INSERT INTO organisations (uuid, name, url, nationality, sector, type, contacts)
+VALUES ('11111111-1111-1111-1111-111111111112', 'bar', 'http://bing.com', 'HU', '', '', '');
+
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000..010b6b0
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,53 @@
+# CakePHP Application Skeleton
+
+[![Build Status](https://img.shields.io/travis/cakephp/app/master.svg?style=flat-square)](https://travis-ci.org/cakephp/app)
+[![Total Downloads](https://img.shields.io/packagist/dt/cakephp/app.svg?style=flat-square)](https://packagist.org/packages/cakephp/app)
+[![PHPStan](https://img.shields.io/badge/PHPStan-level%207-brightgreen.svg?style=flat-square)](https://github.com/phpstan/phpstan)
+
+A skeleton for creating applications with [CakePHP](https://cakephp.org) 4.x.
+
+The framework source code can be found here: [cakephp/cakephp](https://github.com/cakephp/cakephp).
+
+## Installation
+
+1. Download [Composer](https://getcomposer.org/doc/00-intro.md) or update `composer self-update`.
+2. Run `php composer.phar create-project --prefer-dist cakephp/app [app_name]`.
+
+If Composer is installed globally, run
+
+```bash
+composer create-project --prefer-dist cakephp/app
+```
+
+In case you want to use a custom app dir name (e.g. `/myapp/`):
+
+```bash
+composer create-project --prefer-dist cakephp/app myapp
+```
+
+You can now either use your machine's webserver to view the default home page, or start
+up the built-in webserver with:
+
+```bash
+bin/cake server -p 8765
+```
+
+Then visit `http://localhost:8765` to see the welcome page.
+
+## Update
+
+Since this skeleton is a starting point for your application and various files
+would have been modified as per your needs, there isn't a way to provide
+automated upgrades, so you have to do any updates manually.
+
+## Configuration
+
+Read and edit the environment specific `config/app_local.php` and setup the
+`'Datasources'` and any other configuration relevant for your application.
+Other environment agnostic settings can be changed in `config/app.php`.
+
+## Layout
+
+The app skeleton uses [Milligram](https://milligram.io/) (v1.3) minimalist CSS
+framework by default. You can, however, replace it with any other library or
+custom styles.
diff --git a/app/bin/cake b/app/bin/cake
new file mode 100755
index 0000000..4b696c8
--- /dev/null
+++ b/app/bin/cake
@@ -0,0 +1,75 @@
+#!/usr/bin/env sh
+################################################################################
+#
+# Cake is a shell script for invoking CakePHP shell commands
+#
+# CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+#
+# Licensed under The MIT License
+# For full copyright and license information, please see the LICENSE.txt
+# Redistributions of files must retain the above copyright notice.
+#
+# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+# @link https://cakephp.org CakePHP(tm) Project
+# @since 1.2.0
+# @license https://opensource.org/licenses/mit-license.php MIT License
+#
+################################################################################
+
+# Canonicalize by following every symlink of the given name recursively
+canonicalize() {
+ NAME="$1"
+ if [ -f "$NAME" ]
+ then
+ DIR=$(dirname -- "$NAME")
+ NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME")
+ fi
+ while [ -h "$NAME" ]; do
+ DIR=$(dirname -- "$NAME")
+ SYM=$(readlink "$NAME")
+ NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM")
+ done
+ echo "$NAME"
+}
+
+# Find a CLI version of PHP
+findCliPhp() {
+ for TESTEXEC in php php-cli /usr/local/bin/php
+ do
+ SAPI=$(echo "= PHP_SAPI ?>" | $TESTEXEC 2>/dev/null)
+ if [ "$SAPI" = "cli" ]
+ then
+ echo $TESTEXEC
+ return
+ fi
+ done
+ echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2
+ echo "php";
+}
+
+# If current path is a symlink, resolve to real path
+realname="$0"
+if [ -L "$realname" ]
+then
+ realname=$(readlink -f "$0")
+fi
+
+CONSOLE=$(dirname -- "$(canonicalize "$realname")")
+APP=$(dirname "$CONSOLE")
+
+# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment
+# variable with the correct path in it.
+if [ -z "$PHP" ]
+then
+ PHP=$(findCliPhp)
+fi
+
+if [ "$(basename "$realname")" != 'cake' ]
+then
+ exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@"
+else
+ exec "$PHP" "$CONSOLE"/cake.php "$@"
+fi
+
+exit
diff --git a/app/bin/cake.bat b/app/bin/cake.bat
new file mode 100644
index 0000000..ad13782
--- /dev/null
+++ b/app/bin/cake.bat
@@ -0,0 +1,27 @@
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Cake is a Windows batch script for invoking CakePHP shell commands
+::
+:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+::
+:: Licensed under The MIT License
+:: Redistributions of files must retain the above copyright notice.
+::
+:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+:: @link https://cakephp.org CakePHP(tm) Project
+:: @since 2.0.0
+:: @license https://opensource.org/licenses/mit-license.php MIT License
+::
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+@echo off
+
+SET app=%0
+SET lib=%~dp0
+
+php "%lib%cake.php" %*
+
+echo.
+
+exit /B %ERRORLEVEL%
diff --git a/app/bin/cake.php b/app/bin/cake.php
new file mode 100644
index 0000000..320ee36
--- /dev/null
+++ b/app/bin/cake.php
@@ -0,0 +1,12 @@
+#!/usr/bin/php -q
+run($argv));
diff --git a/app/composer.json b/app/composer.json
new file mode 100644
index 0000000..2dbfb71
--- /dev/null
+++ b/app/composer.json
@@ -0,0 +1,56 @@
+{
+ "name": "cakephp/app",
+ "description": "CakePHP skeleton app",
+ "homepage": "https://cakephp.org",
+ "type": "project",
+ "license": "MIT",
+ "require": {
+ "php": ">=7.2",
+ "cakephp/cakephp": "^4.0",
+ "cakephp/migrations": "^3.0",
+ "cakephp/plugin-installer": "^1.2",
+ "mobiledetect/mobiledetectlib": "^2.8"
+ },
+ "require-dev": {
+ "cakephp/bake": "^2.0.3",
+ "cakephp/cakephp-codesniffer": "~4.0.0",
+ "cakephp/debug_kit": "^4.0",
+ "josegonzalez/dotenv": "^3.2",
+ "phpunit/phpunit": "^8.5",
+ "psy/psysh": "@stable"
+ },
+ "suggest": {
+ "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.",
+ "dereuromark/cakephp-ide-helper": "After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.",
+ "phpstan/phpstan": "PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code."
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "App\\Test\\": "tests/",
+ "Cake\\Test\\": "vendor/cakephp/cakephp/tests/"
+ }
+ },
+ "scripts": {
+ "post-install-cmd": "App\\Console\\Installer::postInstall",
+ "post-create-project-cmd": "App\\Console\\Installer::postInstall",
+ "post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump",
+ "check": [
+ "@test",
+ "@cs-check"
+ ],
+ "cs-check": "phpcs --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
+ "cs-fix": "phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
+ "stan": "phpstan analyse src/",
+ "test": "phpunit --colors=always"
+ },
+ "prefer-stable": true,
+ "config": {
+ "sort-packages": true
+ },
+ "minimum-stability": "dev"
+}
diff --git a/app/composer.lock b/app/composer.lock
new file mode 100644
index 0000000..d60bd87
--- /dev/null
+++ b/app/composer.lock
@@ -0,0 +1,4548 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "78f0813d2e19252372610ff0834d4122",
+ "packages": [
+ {
+ "name": "aura/intl",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/auraphp/Aura.Intl.git",
+ "reference": "7fce228980b19bf4dee2d7bbd6202a69b0dde926"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/auraphp/Aura.Intl/zipball/7fce228980b19bf4dee2d7bbd6202a69b0dde926",
+ "reference": "7fce228980b19bf4dee2d7bbd6202a69b0dde926",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Aura\\Intl\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aura.Intl Contributors",
+ "homepage": "https://github.com/auraphp/Aura.Intl/contributors"
+ }
+ ],
+ "description": "The Aura Intl package provides internationalization tools, specifically message translation.",
+ "homepage": "https://github.com/auraphp/Aura.Intl",
+ "keywords": [
+ "g11n",
+ "globalization",
+ "i18n",
+ "internationalization",
+ "intl",
+ "l10n",
+ "localization"
+ ],
+ "time": "2017-01-20T05:00:11+00:00"
+ },
+ {
+ "name": "cakephp/cakephp",
+ "version": "4.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/cakephp.git",
+ "reference": "94435ab211196ce92014a83ec7bab4e385bf8ba3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/cakephp/zipball/94435ab211196ce92014a83ec7bab4e385bf8ba3",
+ "reference": "94435ab211196ce92014a83ec7bab4e385bf8ba3",
+ "shasum": ""
+ },
+ "require": {
+ "aura/intl": "^3.0.0",
+ "cakephp/chronos": "^2.0",
+ "composer/ca-bundle": "^1.2",
+ "ext-intl": "*",
+ "ext-mbstring": "*",
+ "laminas/laminas-diactoros": "^2.2.2",
+ "laminas/laminas-httphandlerrunner": "^1.1",
+ "php": ">=7.2.0",
+ "psr/http-client": "^1.0",
+ "psr/http-server-handler": "^1.0",
+ "psr/http-server-middleware": "^1.0",
+ "psr/log": "^1.0.0",
+ "psr/simple-cache": "^1.0.0"
+ },
+ "replace": {
+ "cakephp/cache": "self.version",
+ "cakephp/collection": "self.version",
+ "cakephp/console": "self.version",
+ "cakephp/core": "self.version",
+ "cakephp/database": "self.version",
+ "cakephp/datasource": "self.version",
+ "cakephp/event": "self.version",
+ "cakephp/filesystem": "self.version",
+ "cakephp/form": "self.version",
+ "cakephp/http": "self.version",
+ "cakephp/i18n": "self.version",
+ "cakephp/log": "self.version",
+ "cakephp/orm": "self.version",
+ "cakephp/utility": "self.version",
+ "cakephp/validation": "self.version"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^4.0",
+ "mikey179/vfsstream": "^1.6",
+ "paragonie/csp-builder": "^2.3",
+ "phpunit/phpunit": "~8.5.0"
+ },
+ "suggest": {
+ "ext-curl": "To enable more efficient network calls in Http\\Client.",
+ "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation.",
+ "lib-ICU": "The intl PHP library, to use Text::transliterate() or Text::slug()",
+ "paragonie/csp-builder": "CSP builder, to use the CSP Middleware"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Cake\\": "src/"
+ },
+ "files": [
+ "src/Core/functions.php",
+ "src/Collection/functions.php",
+ "src/I18n/functions.php",
+ "src/Utility/bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/cakephp/graphs/contributors"
+ }
+ ],
+ "description": "The CakePHP framework",
+ "homepage": "https://cakephp.org",
+ "keywords": [
+ "conventions over configuration",
+ "dry",
+ "form",
+ "framework",
+ "mvc",
+ "orm",
+ "psr-7",
+ "rapid-development",
+ "validation"
+ ],
+ "time": "2020-01-26T02:19:21+00:00"
+ },
+ {
+ "name": "cakephp/chronos",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/chronos.git",
+ "reference": "e1044d27cabf12d19097b436001aa96a3c2e4b0a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/chronos/zipball/e1044d27cabf12d19097b436001aa96a3c2e4b0a",
+ "reference": "e1044d27cabf12d19097b436001aa96a3c2e4b0a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^4.0",
+ "phpbench/phpbench": "^1.0@dev",
+ "phpunit/phpunit": "^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Cake\\Chronos\\": "src/"
+ },
+ "files": [
+ "src/carbon_compat.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Brian Nesbitt",
+ "email": "brian@nesbot.com",
+ "homepage": "http://nesbot.com"
+ },
+ {
+ "name": "The CakePHP Team",
+ "homepage": "http://cakephp.org"
+ }
+ ],
+ "description": "A simple API extension for DateTime.",
+ "homepage": "http://cakephp.org",
+ "keywords": [
+ "date",
+ "datetime",
+ "time"
+ ],
+ "time": "2020-02-08T02:38:43+00:00"
+ },
+ {
+ "name": "cakephp/migrations",
+ "version": "3.0.0-beta2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/migrations.git",
+ "reference": "4cc2222dbde87fa6827d76ede01e13ce3ff5c78f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/migrations/zipball/4cc2222dbde87fa6827d76ede01e13ce3ff5c78f",
+ "reference": "4cc2222dbde87fa6827d76ede01e13ce3ff5c78f",
+ "shasum": ""
+ },
+ "require": {
+ "cakephp/cache": "^4.0",
+ "cakephp/orm": "^4.0",
+ "php": ">=7.2.0",
+ "robmorgan/phinx": "0.next-dev"
+ },
+ "require-dev": {
+ "cakephp/bake": "^2.0",
+ "cakephp/cakephp": "^4.0",
+ "cakephp/cakephp-codesniffer": "dev-next",
+ "phpunit/phpunit": "^8.0"
+ },
+ "suggest": {
+ "cakephp/bake": "Required if you want to generate migrations."
+ },
+ "type": "cakephp-plugin",
+ "autoload": {
+ "psr-4": {
+ "Migrations\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/migrations/graphs/contributors"
+ }
+ ],
+ "description": "Database Migration plugin for CakePHP based on Phinx",
+ "homepage": "https://github.com/cakephp/migrations",
+ "keywords": [
+ "cakephp",
+ "migrations"
+ ],
+ "time": "2019-12-18T08:16:53+00:00"
+ },
+ {
+ "name": "cakephp/plugin-installer",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/plugin-installer.git",
+ "reference": "3be2ea116603341b196592053e973f4abe71e8b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/plugin-installer/zipball/3be2ea116603341b196592053e973f4abe71e8b2",
+ "reference": "3be2ea116603341b196592053e973f4abe71e8b2",
+ "shasum": ""
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "dev-master",
+ "composer/composer": "^1.0",
+ "phpunit/phpunit": "^4.8|^5.7|^6.0"
+ },
+ "type": "composer-installer",
+ "extra": {
+ "class": "Cake\\Composer\\Installer\\PluginInstaller"
+ },
+ "autoload": {
+ "psr-4": {
+ "Cake\\Composer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://cakephp.org"
+ }
+ ],
+ "description": "A composer installer for CakePHP 3.0+ plugins.",
+ "time": "2019-11-12T10:21:19+00:00"
+ },
+ {
+ "name": "composer/ca-bundle",
+ "version": "1.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/ca-bundle.git",
+ "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e",
+ "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-pcre": "*",
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
+ "psr/log": "^1.0",
+ "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\CaBundle\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
+ "keywords": [
+ "cabundle",
+ "cacert",
+ "certificate",
+ "ssl",
+ "tls"
+ ],
+ "time": "2020-01-13T10:02:55+00:00"
+ },
+ {
+ "name": "laminas/laminas-diactoros",
+ "version": "2.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-diactoros.git",
+ "reference": "95178c4751d737cdf9ab0a9f70a42754ac860e7b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/95178c4751d737cdf9ab0a9f70a42754ac860e7b",
+ "reference": "95178c4751d737cdf9ab0a9f70a42754ac860e7b",
+ "shasum": ""
+ },
+ "require": {
+ "laminas/laminas-zendframework-bridge": "^1.0",
+ "php": "^7.1",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.0"
+ },
+ "conflict": {
+ "phpspec/prophecy": "<1.9.0"
+ },
+ "provide": {
+ "psr/http-factory-implementation": "1.0",
+ "psr/http-message-implementation": "1.0"
+ },
+ "replace": {
+ "zendframework/zend-diactoros": "self.version"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "http-interop/http-factory-tests": "^0.5.0",
+ "laminas/laminas-coding-standard": "~1.0.0",
+ "php-http/psr7-integration-tests": "dev-master",
+ "phpunit/phpunit": "^7.5.18"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1.x-dev",
+ "dev-develop": "2.2.x-dev",
+ "dev-release-1.8": "1.8.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions/create_uploaded_file.php",
+ "src/functions/marshal_headers_from_sapi.php",
+ "src/functions/marshal_method_from_sapi.php",
+ "src/functions/marshal_protocol_version_from_sapi.php",
+ "src/functions/marshal_uri_from_sapi.php",
+ "src/functions/normalize_server.php",
+ "src/functions/normalize_uploaded_files.php",
+ "src/functions/parse_cookie_header.php",
+ "src/functions/create_uploaded_file.legacy.php",
+ "src/functions/marshal_headers_from_sapi.legacy.php",
+ "src/functions/marshal_method_from_sapi.legacy.php",
+ "src/functions/marshal_protocol_version_from_sapi.legacy.php",
+ "src/functions/marshal_uri_from_sapi.legacy.php",
+ "src/functions/normalize_server.legacy.php",
+ "src/functions/normalize_uploaded_files.legacy.php",
+ "src/functions/parse_cookie_header.legacy.php"
+ ],
+ "psr-4": {
+ "Laminas\\Diactoros\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "PSR HTTP Message implementations",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "http",
+ "laminas",
+ "psr",
+ "psr-7"
+ ],
+ "time": "2020-01-07T19:39:26+00:00"
+ },
+ {
+ "name": "laminas/laminas-httphandlerrunner",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-httphandlerrunner.git",
+ "reference": "296f5ff35074dd981d1570a66b95596c81808087"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/296f5ff35074dd981d1570a66b95596c81808087",
+ "reference": "296f5ff35074dd981d1570a66b95596c81808087",
+ "shasum": ""
+ },
+ "require": {
+ "laminas/laminas-zendframework-bridge": "^1.0",
+ "php": "^7.1",
+ "psr/http-message": "^1.0",
+ "psr/http-message-implementation": "^1.0",
+ "psr/http-server-handler": "^1.0"
+ },
+ "replace": {
+ "zendframework/zend-httphandlerrunner": "self.version"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~1.0.0",
+ "laminas/laminas-diactoros": "^1.7 || ^2.1.1",
+ "phpunit/phpunit": "^7.0.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev",
+ "dev-develop": "1.2.x-dev"
+ },
+ "laminas": {
+ "config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Laminas\\HttpHandlerRunner\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "components",
+ "laminas",
+ "mezzio",
+ "psr-15",
+ "psr-7"
+ ],
+ "time": "2019-12-31T17:06:16+00:00"
+ },
+ {
+ "name": "laminas/laminas-zendframework-bridge",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-zendframework-bridge.git",
+ "reference": "0fb9675b84a1666ab45182b6c5b29956921e818d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/0fb9675b84a1666ab45182b6c5b29956921e818d",
+ "reference": "0fb9675b84a1666ab45182b6c5b29956921e818d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev",
+ "dev-develop": "1.1.x-dev"
+ },
+ "laminas": {
+ "module": "Laminas\\ZendFrameworkBridge"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/autoload.php"
+ ],
+ "psr-4": {
+ "Laminas\\ZendFrameworkBridge\\": "src//"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Alias legacy ZF class names to Laminas Project equivalents.",
+ "keywords": [
+ "ZendFramework",
+ "autoloading",
+ "laminas",
+ "zf"
+ ],
+ "time": "2020-01-07T22:58:31+00:00"
+ },
+ {
+ "name": "mobiledetect/mobiledetectlib",
+ "version": "2.8.34",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/serbanghita/Mobile-Detect.git",
+ "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
+ "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8.35||~5.7"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "Mobile_Detect.php"
+ ],
+ "psr-0": {
+ "Detection": "namespaced/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Serban Ghita",
+ "email": "serbanghita@gmail.com",
+ "homepage": "http://mobiledetect.net",
+ "role": "Developer"
+ }
+ ],
+ "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
+ "homepage": "https://github.com/serbanghita/Mobile-Detect",
+ "keywords": [
+ "detect mobile devices",
+ "mobile",
+ "mobile detect",
+ "mobile detector",
+ "php mobile detect"
+ ],
+ "time": "2019-09-18T18:44:20+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "time": "2017-02-14T16:28:37+00:00"
+ },
+ {
+ "name": "psr/http-client",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "496a823ef742b632934724bf769560c2a5c7c44e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/496a823ef742b632934724bf769560c2a5c7c44e",
+ "reference": "496a823ef742b632934724bf769560c2a5c7c44e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "psr/http-message": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
+ "time": "2018-10-30T23:29:13+00:00"
+ },
+ {
+ "name": "psr/http-factory",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0",
+ "psr/http-message": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for PSR-7 HTTP message factories",
+ "keywords": [
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "time": "2019-04-30T12:38:16+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "time": "2016-08-06T14:39:51+00:00"
+ },
+ {
+ "name": "psr/http-server-handler",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-server-handler.git",
+ "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+ "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0",
+ "psr/http-message": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Server\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP server-side request handler",
+ "keywords": [
+ "handler",
+ "http",
+ "http-interop",
+ "psr",
+ "psr-15",
+ "psr-7",
+ "request",
+ "response",
+ "server"
+ ],
+ "time": "2018-10-30T16:46:14+00:00"
+ },
+ {
+ "name": "psr/http-server-middleware",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-server-middleware.git",
+ "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+ "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0",
+ "psr/http-message": "^1.0",
+ "psr/http-server-handler": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Server\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP server-side middleware",
+ "keywords": [
+ "http",
+ "http-interop",
+ "middleware",
+ "psr",
+ "psr-15",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "time": "2018-10-30T17:12:04+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2019-11-01T11:05:21+00:00"
+ },
+ {
+ "name": "psr/simple-cache",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/simple-cache.git",
+ "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+ "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\SimpleCache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for simple caching",
+ "keywords": [
+ "cache",
+ "caching",
+ "psr",
+ "psr-16",
+ "simple-cache"
+ ],
+ "time": "2017-10-23T01:57:42+00:00"
+ },
+ {
+ "name": "robmorgan/phinx",
+ "version": "dev-0.next",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/phinx.git",
+ "reference": "7b3ca6c0a97381d391a1ffb4b8a789415cfe8607"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/phinx/zipball/7b3ca6c0a97381d391a1ffb4b8a789415cfe8607",
+ "reference": "7b3ca6c0a97381d391a1ffb4b8a789415cfe8607",
+ "shasum": ""
+ },
+ "require": {
+ "cakephp/collection": "^4.0",
+ "cakephp/database": "^4.0",
+ "php": ">=7.2",
+ "symfony/config": "^3.4|^4.0|^5.0",
+ "symfony/console": "^3.4|^4.0|^5.0",
+ "symfony/yaml": "^3.4|^4.0|^5.0"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^3.0",
+ "phpunit/phpunit": "^8.5",
+ "sebastian/comparator": ">=1.2.3"
+ },
+ "bin": [
+ "bin/phinx"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Phinx\\": "src/Phinx/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Morgan",
+ "email": "robbym@gmail.com",
+ "homepage": "https://robmorgan.id.au",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Woody Gilk",
+ "email": "woody.gilk@gmail.com",
+ "homepage": "https://shadowhand.me",
+ "role": "Developer"
+ },
+ {
+ "name": "Richard Quadling",
+ "email": "rquadling@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/phinx/graphs/contributors",
+ "role": "Developer"
+ }
+ ],
+ "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.",
+ "homepage": "https://phinx.org",
+ "keywords": [
+ "database",
+ "database migrations",
+ "db",
+ "migrations",
+ "phinx"
+ ],
+ "time": "2020-01-03T23:12:36+00:00"
+ },
+ {
+ "name": "symfony/config",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/config.git",
+ "reference": "7640c6704f56bf64045066bc5d93fd9d664baa63"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/config/zipball/7640c6704f56bf64045066bc5d93fd9d664baa63",
+ "reference": "7640c6704f56bf64045066bc5d93fd9d664baa63",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/filesystem": "^4.4|^5.0",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/finder": "<4.4"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "^4.4|^5.0",
+ "symfony/finder": "^4.4|^5.0",
+ "symfony/messenger": "^4.4|^5.0",
+ "symfony/service-contracts": "^1.1|^2",
+ "symfony/yaml": "^4.4|^5.0"
+ },
+ "suggest": {
+ "symfony/yaml": "To use the yaml reference dumper"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Config\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Config Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-04T14:08:26+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/91c294166c38d8c0858a86fad76d8c14dc1144c8",
+ "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php73": "^1.8",
+ "symfony/service-contracts": "^1.1|^2"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<4.4",
+ "symfony/event-dispatcher": "<4.4",
+ "symfony/lock": "<4.4",
+ "symfony/process": "<4.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^4.4|^5.0",
+ "symfony/dependency-injection": "^4.4|^5.0",
+ "symfony/event-dispatcher": "^4.4|^5.0",
+ "symfony/lock": "^4.4|^5.0",
+ "symfony/process": "^4.4|^5.0",
+ "symfony/var-dumper": "^4.4|^5.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Console Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-25T15:56:29+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c",
+ "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Filesystem Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-21T08:40:24+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
+ "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "time": "2020-01-13T11:15:53+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2",
+ "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2020-01-13T11:15:53+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php73",
+ "version": "v1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php73.git",
+ "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675",
+ "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php73\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2020-01-13T11:15:53+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "144c5e51266b281231e947b51223ba14acf1a749"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749",
+ "reference": "144c5e51266b281231e947b51223ba14acf1a749",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "psr/container": "^1.0"
+ },
+ "suggest": {
+ "symfony/service-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "time": "2019-11-18T17:27:11+00:00"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a",
+ "reference": "69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/console": "<4.4"
+ },
+ "require-dev": {
+ "symfony/console": "^4.4|^5.0"
+ },
+ "suggest": {
+ "symfony/console": "For validating YAML files using the lint command"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Yaml\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Yaml Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-21T11:12:28+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "cakephp/bake",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/bake.git",
+ "reference": "113502b5687026adf158fde3132354f4dcd49ed4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/bake/zipball/113502b5687026adf158fde3132354f4dcd49ed4",
+ "reference": "113502b5687026adf158fde3132354f4dcd49ed4",
+ "shasum": ""
+ },
+ "require": {
+ "cakephp/cakephp": "^4.0",
+ "cakephp/plugin-installer": "^1.0",
+ "php": ">=7.2",
+ "wyrihaximus/twig-view": "^5.0.1"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^4.0",
+ "phpunit/phpunit": "~8.5.0"
+ },
+ "type": "cakephp-plugin",
+ "autoload": {
+ "psr-4": {
+ "Bake\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/bake/graphs/contributors"
+ }
+ ],
+ "description": "Bake plugin for CakePHP",
+ "homepage": "https://github.com/cakephp/bake",
+ "keywords": [
+ "bake",
+ "cakephp"
+ ],
+ "time": "2020-01-06T15:41:13+00:00"
+ },
+ {
+ "name": "cakephp/cakephp-codesniffer",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/cakephp-codesniffer.git",
+ "reference": "637e424134e6fc7c6c3ecddd750ef743eb7869fc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/637e424134e6fc7c6c3ecddd750ef743eb7869fc",
+ "reference": "637e424134e6fc7c6c3ecddd750ef743eb7869fc",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1",
+ "slevomat/coding-standard": "^6.0",
+ "squizlabs/php_codesniffer": "~3.5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "phpcodesniffer-standard",
+ "autoload": {
+ "psr-4": {
+ "CakePHP\\": "CakePHP/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/cakephp-codesniffer/graphs/contributors"
+ }
+ ],
+ "description": "CakePHP CodeSniffer Standards",
+ "homepage": "https://cakephp.org",
+ "keywords": [
+ "codesniffer",
+ "framework"
+ ],
+ "time": "2020-01-13T22:00:38+00:00"
+ },
+ {
+ "name": "cakephp/debug_kit",
+ "version": "4.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cakephp/debug_kit.git",
+ "reference": "56805287711dc81c081865250faeee80ce5eec50"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/56805287711dc81c081865250faeee80ce5eec50",
+ "reference": "56805287711dc81c081865250faeee80ce5eec50",
+ "shasum": ""
+ },
+ "require": {
+ "cakephp/cakephp": "^4.0",
+ "cakephp/chronos": "^2.0",
+ "cakephp/plugin-installer": "^1.0",
+ "composer/composer": "^1.3",
+ "jdorn/sql-formatter": "^1.2",
+ "php": ">=7.2"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^4.0",
+ "phpunit/phpunit": "^8.0"
+ },
+ "suggest": {
+ "ext-pdo_sqlite": "DebugKit needs to store panel data in a database. SQLite is simple and easy to use."
+ },
+ "type": "cakephp-plugin",
+ "autoload": {
+ "psr-4": {
+ "DebugKit\\": "src/",
+ "DebugKit\\Test\\Fixture\\": "tests/Fixture/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mark Story",
+ "homepage": "https://mark-story.com",
+ "role": "Author"
+ },
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/debug_kit/graphs/contributors"
+ }
+ ],
+ "description": "CakePHP Debug Kit",
+ "homepage": "https://github.com/cakephp/debug_kit",
+ "keywords": [
+ "cakephp",
+ "debug",
+ "kit"
+ ],
+ "time": "2020-01-16T14:50:30+00:00"
+ },
+ {
+ "name": "composer/composer",
+ "version": "1.10.0-RC",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/composer.git",
+ "reference": "ec39b4cbb5e012365d70cd95969ea11780d3c1fc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/composer/zipball/ec39b4cbb5e012365d70cd95969ea11780d3c1fc",
+ "reference": "ec39b4cbb5e012365d70cd95969ea11780d3c1fc",
+ "shasum": ""
+ },
+ "require": {
+ "composer/ca-bundle": "^1.0",
+ "composer/semver": "^1.0",
+ "composer/spdx-licenses": "^1.2",
+ "composer/xdebug-handler": "^1.1",
+ "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0",
+ "php": "^5.3.2 || ^7.0",
+ "psr/log": "^1.0",
+ "seld/jsonlint": "^1.4",
+ "seld/phar-utils": "^1.0",
+ "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0",
+ "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0",
+ "symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0",
+ "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0"
+ },
+ "conflict": {
+ "symfony/console": "2.8.38"
+ },
+ "require-dev": {
+ "phpspec/prophecy": "^1.10",
+ "symfony/phpunit-bridge": "^3.4"
+ },
+ "suggest": {
+ "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
+ "ext-zip": "Enabling the zip extension allows you to unzip archives",
+ "ext-zlib": "Allow gzip compression of HTTP requests"
+ },
+ "bin": [
+ "bin/composer"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\": "src/Composer"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
+ "homepage": "https://getcomposer.org/",
+ "keywords": [
+ "autoload",
+ "dependency",
+ "package"
+ ],
+ "time": "2020-02-14T14:11:30+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "1.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
+ "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.5 || ^5.0.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "time": "2020-01-13T12:06:48+00:00"
+ },
+ {
+ "name": "composer/spdx-licenses",
+ "version": "1.5.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/spdx-licenses.git",
+ "reference": "0c3e51e1880ca149682332770e25977c70cf9dae"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae",
+ "reference": "0c3e51e1880ca149682332770e25977c70cf9dae",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Spdx\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "SPDX licenses list and validation library.",
+ "keywords": [
+ "license",
+ "spdx",
+ "validator"
+ ],
+ "time": "2020-02-14T07:44:31+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "cbe23383749496fe0f373345208b79568e4bc248"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248",
+ "reference": "cbe23383749496fe0f373345208b79568e4bc248",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0",
+ "psr/log": "^1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "time": "2019-11-06T16:40:04+00:00"
+ },
+ {
+ "name": "dnoegel/php-xdg-base-dir",
+ "version": "v0.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
+ "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+ "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "XdgBaseDir\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "implementation of xdg base directory specification for php",
+ "time": "2019-12-04T15:06:13+00:00"
+ },
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
+ "reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^6.0",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.13",
+ "phpstan/phpstan-phpunit": "^0.11",
+ "phpstan/phpstan-shim": "^0.11",
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "time": "2019-10-21T16:45:58+00:00"
+ },
+ {
+ "name": "jakub-onderka/php-console-color",
+ "version": "v0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/JakubOnderka/PHP-Console-Color.git",
+ "reference": "d5deaecff52a0d61ccb613bb3804088da0307191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191",
+ "reference": "d5deaecff52a0d61ccb613bb3804088da0307191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "jakub-onderka/php-code-style": "1.0",
+ "jakub-onderka/php-parallel-lint": "1.0",
+ "jakub-onderka/php-var-dump-check": "0.*",
+ "phpunit/phpunit": "~4.3",
+ "squizlabs/php_codesniffer": "1.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "JakubOnderka\\PhpConsoleColor\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jakub Onderka",
+ "email": "jakub.onderka@gmail.com"
+ }
+ ],
+ "time": "2018-09-29T17:23:10+00:00"
+ },
+ {
+ "name": "jakub-onderka/php-console-highlighter",
+ "version": "v0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git",
+ "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547",
+ "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "jakub-onderka/php-console-color": "~0.2",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "jakub-onderka/php-code-style": "~1.0",
+ "jakub-onderka/php-parallel-lint": "~1.0",
+ "jakub-onderka/php-var-dump-check": "~0.1",
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~1.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "JakubOnderka\\PhpConsoleHighlighter\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jakub Onderka",
+ "email": "acci@acci.cz",
+ "homepage": "http://www.acci.cz/"
+ }
+ ],
+ "description": "Highlight PHP code in terminal",
+ "time": "2018-09-29T18:48:56+00:00"
+ },
+ {
+ "name": "jasny/twig-extensions",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jasny/twig-extensions.git",
+ "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/a694eb02f6fc14ff8e2fceb8b80882c0c926102b",
+ "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0",
+ "twig/twig": "^2.0 | ^3.0"
+ },
+ "require-dev": {
+ "ext-intl": "*",
+ "ext-pcre": "*",
+ "jasny/php-code-quality": "^2.5",
+ "php": ">=7.2.0"
+ },
+ "suggest": {
+ "ext-intl": "Required for the use of the LocalDate Twig extension",
+ "ext-pcre": "Required for the use of the PCRE Twig extension"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jasny\\Twig\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Arnold Daniels",
+ "email": "arnold@jasny.net",
+ "homepage": "http://www.jasny.net"
+ }
+ ],
+ "description": "A set of useful Twig filters",
+ "homepage": "http://github.com/jasny/twig-extensions#README",
+ "keywords": [
+ "PCRE",
+ "array",
+ "date",
+ "datetime",
+ "preg",
+ "regex",
+ "templating",
+ "text",
+ "time"
+ ],
+ "time": "2019-12-10T16:04:23+00:00"
+ },
+ {
+ "name": "jdorn/sql-formatter",
+ "version": "v1.2.17",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jdorn/sql-formatter.git",
+ "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc",
+ "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "lib"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jeremy Dorn",
+ "email": "jeremy@jeremydorn.com",
+ "homepage": "http://jeremydorn.com/"
+ }
+ ],
+ "description": "a PHP SQL highlighting library",
+ "homepage": "https://github.com/jdorn/sql-formatter/",
+ "keywords": [
+ "highlight",
+ "sql"
+ ],
+ "time": "2014-01-12T16:20:24+00:00"
+ },
+ {
+ "name": "josegonzalez/dotenv",
+ "version": "3.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/josegonzalez/php-dotenv.git",
+ "reference": "f19174d9d7213a6c20e8e5e268aa7dd042d821ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/josegonzalez/php-dotenv/zipball/f19174d9d7213a6c20e8e5e268aa7dd042d821ca",
+ "reference": "f19174d9d7213a6c20e8e5e268aa7dd042d821ca",
+ "shasum": ""
+ },
+ "require": {
+ "m1/env": "2.*",
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "php-mock/php-mock-phpunit": "^1.1",
+ "satooshi/php-coveralls": "1.*",
+ "squizlabs/php_codesniffer": "2.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "josegonzalez\\Dotenv": [
+ "src",
+ "tests"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jose Diaz-Gonzalez",
+ "email": "dotenv@josegonzalez.com",
+ "homepage": "http://josediazgonzalez.com",
+ "role": "Maintainer"
+ }
+ ],
+ "description": "dotenv file parsing for PHP",
+ "homepage": "https://github.com/josegonzalez/php-dotenv",
+ "keywords": [
+ "configuration",
+ "dotenv",
+ "php"
+ ],
+ "time": "2017-09-19T15:49:58+00:00"
+ },
+ {
+ "name": "justinrainbow/json-schema",
+ "version": "5.2.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/justinrainbow/json-schema.git",
+ "reference": "44c6787311242a979fa15c704327c20e7221a0e4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4",
+ "reference": "44c6787311242a979fa15c704327c20e7221a0e4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
+ "json-schema/json-schema-test-suite": "1.2.0",
+ "phpunit/phpunit": "^4.8.35"
+ },
+ "bin": [
+ "bin/validate-json"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "JsonSchema\\": "src/JsonSchema/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bruno Prieto Reis",
+ "email": "bruno.p.reis@gmail.com"
+ },
+ {
+ "name": "Justin Rainbow",
+ "email": "justin.rainbow@gmail.com"
+ },
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ },
+ {
+ "name": "Robert Schönthal",
+ "email": "seroscho@googlemail.com"
+ }
+ ],
+ "description": "A library to validate a json schema.",
+ "homepage": "https://github.com/justinrainbow/json-schema",
+ "keywords": [
+ "json",
+ "schema"
+ ],
+ "time": "2019-09-25T14:49:45+00:00"
+ },
+ {
+ "name": "m1/env",
+ "version": "2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/m1/Env.git",
+ "reference": "294addeedf15e1149eeb96ec829f2029d2017d39"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/m1/Env/zipball/294addeedf15e1149eeb96ec829f2029d2017d39",
+ "reference": "294addeedf15e1149eeb96ec829f2029d2017d39",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*",
+ "scrutinizer/ocular": "~1.1",
+ "squizlabs/php_codesniffer": "^2.3"
+ },
+ "suggest": {
+ "josegonzalez/dotenv": "For loading of .env",
+ "m1/vars": "For loading of configs"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "M1\\Env\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Miles Croxford",
+ "email": "hello@milescroxford.com",
+ "homepage": "http://milescroxford.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.",
+ "homepage": "https://github.com/m1/Env",
+ "keywords": [
+ ".env",
+ "config",
+ "dotenv",
+ "env",
+ "loader",
+ "m1",
+ "parser",
+ "support"
+ ],
+ "time": "2018-06-19T18:55:08+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.9.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef",
+ "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "time": "2020-01-17T21:11:47+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc",
+ "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "0.0.5",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "time": "2019-11-08T13:50:10+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "phar-io/version": "^2.0",
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "time": "2018-07-08T19:23:20+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "time": "2018-07-08T19:19:57+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "time": "2018-08-07T13:53:10+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/a48807183a4b819072f26e347bbd0b5199a9d15f",
+ "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "^7.1",
+ "php": "^7.2",
+ "phpdocumentor/reflection-common": "^2.0",
+ "phpdocumentor/type-resolver": "^1.0",
+ "webmozart/assert": "^1"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "^1",
+ "mockery/mockery": "^1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "account@ijaap.nl"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "time": "2020-02-09T09:16:15+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1",
+ "phpdocumentor/reflection-common": "^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "^7.1",
+ "mockery/mockery": "~1",
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "time": "2019-08-22T18:11:29+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.10.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9",
+ "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
+ "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5 || ^3.2",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "time": "2020-01-20T15:57:02+00:00"
+ },
+ {
+ "name": "phpstan/phpdoc-parser",
+ "version": "0.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpdoc-parser.git",
+ "reference": "928179efc5368145a8b03cb20d58cb3f3136afae"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/928179efc5368145a8b03cb20d58cb3f3136afae",
+ "reference": "928179efc5368145a8b03cb20d58cb3f3136afae",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~7.1"
+ },
+ "require-dev": {
+ "consistence/coding-standard": "^3.5",
+ "ergebnis/composer-normalize": "^2.0.2",
+ "jakub-onderka/php-parallel-lint": "^0.9.2",
+ "phing/phing": "^2.16.0",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-strict-rules": "^0.12",
+ "phpunit/phpunit": "^6.3",
+ "slevomat/coding-standard": "^4.7.2",
+ "symfony/process": "^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\PhpDocParser\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPDoc parser with support for nullable, intersection and generic types",
+ "time": "2020-01-25T20:42:48+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "7.0.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf",
+ "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2",
+ "phpunit/php-file-iterator": "^2.0.2",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-token-stream": "^3.1.1",
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
+ "sebastian/environment": "^4.2.2",
+ "sebastian/version": "^2.0.1",
+ "theseer/tokenizer": "^1.1.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.2.2"
+ },
+ "suggest": {
+ "ext-xdebug": "^2.7.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2019-11-20T13:55:58+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "050bedf145a257b1ff02746c31894800e5122946"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
+ "reference": "050bedf145a257b1ff02746c31894800e5122946",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2018-09-13T20:33:42+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2015-06-21T13:50:34+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e",
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2019-06-07T04:22:29+00:00"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff",
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2019-09-17T06:23:10+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "8.5.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0",
+ "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.2.0",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.9.1",
+ "phar-io/manifest": "^1.0.3",
+ "phar-io/version": "^2.0.1",
+ "php": "^7.2",
+ "phpspec/prophecy": "^1.8.1",
+ "phpunit/php-code-coverage": "^7.0.7",
+ "phpunit/php-file-iterator": "^2.0.2",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-timer": "^2.1.2",
+ "sebastian/comparator": "^3.0.2",
+ "sebastian/diff": "^3.0.2",
+ "sebastian/environment": "^4.2.2",
+ "sebastian/exporter": "^3.1.1",
+ "sebastian/global-state": "^3.0.0",
+ "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/resource-operations": "^2.0.1",
+ "sebastian/type": "^1.1.3",
+ "sebastian/version": "^2.0.1"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
+ },
+ "suggest": {
+ "ext-soap": "*",
+ "ext-xdebug": "*",
+ "phpunit/php-invoker": "^2.0.0"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "8.5-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2020-01-08T08:49:49+00:00"
+ },
+ {
+ "name": "psy/psysh",
+ "version": "v0.9.12",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bobthecow/psysh.git",
+ "reference": "90da7f37568aee36b116a030c5f99c915267edd4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/90da7f37568aee36b116a030c5f99c915267edd4",
+ "reference": "90da7f37568aee36b116a030c5f99c915267edd4",
+ "shasum": ""
+ },
+ "require": {
+ "dnoegel/php-xdg-base-dir": "0.1.*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*",
+ "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0",
+ "php": ">=5.4.0",
+ "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0",
+ "symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.2",
+ "hoa/console": "~2.15|~3.16",
+ "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0"
+ },
+ "suggest": {
+ "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
+ "ext-pdo-sqlite": "The doc command requires SQLite to work.",
+ "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
+ "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.",
+ "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit."
+ },
+ "bin": [
+ "bin/psysh"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.9.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Psy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Justin Hileman",
+ "email": "justin@justinhileman.info",
+ "homepage": "http://justinhileman.com"
+ }
+ ],
+ "description": "An interactive shell for modern PHP.",
+ "homepage": "http://psysh.org",
+ "keywords": [
+ "REPL",
+ "console",
+ "interactive",
+ "shell"
+ ],
+ "time": "2019-12-06T14:19:43+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "time": "2017-03-04T06:30:41+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
+ "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1",
+ "sebastian/diff": "^3.0",
+ "sebastian/exporter": "^3.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "time": "2018-07-12T15:12:46+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
+ "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5 || ^8.0",
+ "symfony/process": "^2 || ^3.3 || ^4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "time": "2019-02-04T06:01:07+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "4.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
+ "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "time": "2019-11-20T08:46:58+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "3.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "time": "2019-09-14T09:02:43+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
+ "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^8.0"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "time": "2019-02-01T05:30:01+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "time": "2017-08-03T12:35:26+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "time": "2017-03-29T09:07:27+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "time": "2017-03-03T06:23:57+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
+ "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "time": "2018-10-04T04:07:39+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "1.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3",
+ "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "time": "2019-07-02T08:10:15+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "time": "2016-10-03T07:35:21+00:00"
+ },
+ {
+ "name": "seld/jsonlint",
+ "version": "1.7.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/jsonlint.git",
+ "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19",
+ "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "bin": [
+ "bin/jsonlint"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Seld\\JsonLint\\": "src/Seld/JsonLint/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "JSON Linter",
+ "keywords": [
+ "json",
+ "linter",
+ "parser",
+ "validator"
+ ],
+ "time": "2019-10-24T14:27:39+00:00"
+ },
+ {
+ "name": "seld/phar-utils",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/phar-utils.git",
+ "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0",
+ "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Seld\\PharUtils\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be"
+ }
+ ],
+ "description": "PHAR file format utilities, for when PHP phars you up",
+ "keywords": [
+ "phar"
+ ],
+ "time": "2020-02-14T15:25:33+00:00"
+ },
+ {
+ "name": "slevomat/coding-standard",
+ "version": "6.1.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/slevomat/coding-standard.git",
+ "reference": "d767b5e302ff096327466c97fec3cb57f6d16086"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/d767b5e302ff096327466c97fec3cb57f6d16086",
+ "reference": "d767b5e302ff096327466c97fec3cb57f6d16086",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1",
+ "phpstan/phpdoc-parser": "0.3.5 - 0.4.3",
+ "squizlabs/php_codesniffer": "^3.5.4"
+ },
+ "require-dev": {
+ "dealerdirect/phpcodesniffer-composer-installer": "0.6.2",
+ "grogy/php-parallel-lint": "1.1.0",
+ "phing/phing": "2.16.3",
+ "phpstan/phpstan": "0.11.19|0.12.9",
+ "phpstan/phpstan-phpunit": "0.11.2|0.12.6",
+ "phpstan/phpstan-strict-rules": "0.11.1|0.12.2",
+ "phpunit/phpunit": "7.5.18|8.5.2"
+ },
+ "type": "phpcodesniffer-standard",
+ "autoload": {
+ "psr-4": {
+ "SlevomatCodingStandard\\": "SlevomatCodingStandard"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
+ "time": "2020-02-05T21:17:34+00:00"
+ },
+ {
+ "name": "squizlabs/php_codesniffer",
+ "version": "3.5.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
+ "reference": "dceec07328401de6211037abbb18bda423677e26"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26",
+ "reference": "dceec07328401de6211037abbb18bda423677e26",
+ "shasum": ""
+ },
+ "require": {
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "bin": [
+ "bin/phpcs",
+ "bin/phpcbf"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "lead"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards"
+ ],
+ "time": "2020-01-30T22:20:29+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
+ "reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-04T14:08:26+00:00"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/process.git",
+ "reference": "f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/process/zipball/f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1",
+ "reference": "f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-01-09T09:53:06+00:00"
+ },
+ {
+ "name": "symfony/var-dumper",
+ "version": "v5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-dumper.git",
+ "reference": "923591cfb78a935f0c98968fedfad05bfda9d01f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/923591cfb78a935f0c98968fedfad05bfda9d01f",
+ "reference": "923591cfb78a935f0c98968fedfad05bfda9d01f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<5.4.3",
+ "symfony/console": "<4.4"
+ },
+ "require-dev": {
+ "ext-iconv": "*",
+ "symfony/console": "^4.4|^5.0",
+ "symfony/process": "^4.4|^5.0",
+ "twig/twig": "^2.4|^3.0"
+ },
+ "suggest": {
+ "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
+ "ext-intl": "To show region name in time zone dump",
+ "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+ },
+ "bin": [
+ "Resources/bin/var-dump-server"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "Resources/functions/dump.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\VarDumper\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony mechanism for exploring and dumping PHP variables",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "debug",
+ "dump"
+ ],
+ "time": "2020-01-25T15:56:29+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "time": "2019-06-13T22:48:21+00:00"
+ },
+ {
+ "name": "twig/markdown-extra",
+ "version": "v3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/markdown-extra.git",
+ "reference": "c9d09a12024febcb6976886794d095a31f1ce6fa"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/c9d09a12024febcb6976886794d095a31f1ce6fa",
+ "reference": "c9d09a12024febcb6976886794d095a31f1ce6fa",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3",
+ "twig/twig": "^2.4|^3.0"
+ },
+ "require-dev": {
+ "erusev/parsedown": "^1.7",
+ "league/commonmark": "^1.0",
+ "league/html-to-markdown": "^4.8",
+ "michelf/php-markdown": "^1.8",
+ "symfony/phpunit-bridge": "^4.4|^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Twig\\Extra\\Markdown\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ }
+ ],
+ "description": "A Twig extension for Markdown",
+ "homepage": "https://twig.symfony.com",
+ "keywords": [
+ "html",
+ "markdown",
+ "twig"
+ ],
+ "time": "2020-01-01T17:11:09+00:00"
+ },
+ {
+ "name": "twig/twig",
+ "version": "v3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/Twig.git",
+ "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b88ccd180a6b61ebb517aea3b1a8906762a1dc2",
+ "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-mbstring": "^1.3"
+ },
+ "require-dev": {
+ "psr/container": "^1.0",
+ "symfony/phpunit-bridge": "^4.4|^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Twig\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Twig Team",
+ "role": "Contributors"
+ },
+ {
+ "name": "Armin Ronacher",
+ "email": "armin.ronacher@active-4.com",
+ "role": "Project Founder"
+ }
+ ],
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
+ "homepage": "https://twig.symfony.com",
+ "keywords": [
+ "templating"
+ ],
+ "time": "2020-02-11T15:33:47+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "aed98a490f9a8f78468232db345ab9cf606cf598"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598",
+ "reference": "aed98a490f9a8f78468232db345ab9cf606cf598",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "vimeo/psalm": "<3.6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.36 || ^7.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "time": "2020-02-14T12:15:55+00:00"
+ },
+ {
+ "name": "wyrihaximus/twig-view",
+ "version": "5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WyriHaximus/TwigView.git",
+ "reference": "ec1d3091d56a0da9b1756692fa0bf99846a4eb20"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WyriHaximus/TwigView/zipball/ec1d3091d56a0da9b1756692fa0bf99846a4eb20",
+ "reference": "ec1d3091d56a0da9b1756692fa0bf99846a4eb20",
+ "shasum": ""
+ },
+ "require": {
+ "cakephp/cakephp": "^4.0",
+ "jasny/twig-extensions": "^1.3",
+ "php": "^7.2",
+ "twig/markdown-extra": "^3.0",
+ "twig/twig": "^3.0"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^4.0",
+ "cakephp/debug_kit": "^4.0",
+ "jakub-onderka/php-console-highlighter": "^0.4.0",
+ "jakub-onderka/php-parallel-lint": "^1.0",
+ "phpunit/phpunit": "^8.0",
+ "wyrihaximus/phpunit-class-reflection-helpers": "dev-master"
+ },
+ "type": "cakephp-plugin",
+ "autoload": {
+ "psr-4": {
+ "WyriHaximus\\TwigView\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "ceesjank@gmail.com",
+ "homepage": "http://wyrihaximus.net/"
+ }
+ ],
+ "description": "Twig powered View for CakePHP",
+ "keywords": [
+ "cakephp",
+ "template",
+ "twig",
+ "twig2",
+ "view"
+ ],
+ "time": "2019-12-30T11:29:47+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "dev",
+ "stability-flags": {
+ "psy/psysh": 0
+ },
+ "prefer-stable": true,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=7.2"
+ },
+ "platform-dev": []
+}
diff --git a/app/config/.env.example b/app/config/.env.example
new file mode 100644
index 0000000..15060f7
--- /dev/null
+++ b/app/config/.env.example
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Used as a default to seed config/.env which
+# enables you to use environment variables to configure
+# the aspects of your application that vary by
+# environment.
+#
+# Having this file in production is considered a **SECURITY RISK** and also decreases
+# the boostrap performance of your application.
+#
+# To use this file, first copy it into `config/.env`. Also ensure the related
+# code block for loading this file is uncommented in `config/boostrap.php`
+#
+# In development .env files are parsed by PHP
+# and set into the environment. This provides a simpler
+# development workflow over standard environment variables.
+export APP_NAME="__APP_NAME__"
+export DEBUG="true"
+export APP_ENCODING="UTF-8"
+export APP_DEFAULT_LOCALE="en_US"
+export APP_DEFAULT_TIMEZONE="UTC"
+export SECURITY_SALT="__SALT__"
+
+# Uncomment these to define cache configuration via environment variables.
+#export CACHE_DURATION="+2 minutes"
+#export CACHE_DEFAULT_URL="file://tmp/cache/?prefix=${APP_NAME}_default&duration=${CACHE_DURATION}"
+#export CACHE_CAKECORE_URL="file://tmp/cache/persistent?prefix=${APP_NAME}_cake_core&serialize=true&duration=${CACHE_DURATION}"
+#export CACHE_CAKEMODEL_URL="file://tmp/cache/models?prefix=${APP_NAME}_cake_model&serialize=true&duration=${CACHE_DURATION}"
+
+# Uncomment these to define email transport configuration via environment variables.
+#export EMAIL_TRANSPORT_DEFAULT_URL=""
+
+# Uncomment these to define database configuration via environment variables.
+#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false"
+#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false"
+
+# Uncomment these to define logging configuration via environment variables.
+#export LOG_DEBUG_URL="file://logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug"
+#export LOG_ERROR_URL="file://logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error"
diff --git a/app/config/app.php b/app/config/app.php
new file mode 100644
index 0000000..d91d49f
--- /dev/null
+++ b/app/config/app.php
@@ -0,0 +1,401 @@
+ filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN),
+
+ /*
+ * Configure basic information about the application.
+ *
+ * - namespace - The namespace to find app classes under.
+ * - defaultLocale - The default locale for translation, formatting currencies and numbers, date and time.
+ * - encoding - The encoding used for HTML + database connections.
+ * - base - The base directory the app resides in. If false this
+ * will be auto detected.
+ * - dir - Name of app directory.
+ * - webroot - The webroot directory.
+ * - wwwRoot - The file path to webroot.
+ * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to
+ * use CakePHP pretty URLs, remove these .htaccess
+ * files:
+ * /.htaccess
+ * /webroot/.htaccess
+ * And uncomment the baseUrl key below.
+ * - fullBaseUrl - A base URL to use for absolute links. When set to false (default)
+ * CakePHP generates required value based on `HTTP_HOST` environment variable.
+ * However, you can define it manually to optimize performance or if you
+ * are concerned about people manipulating the `Host` header.
+ * - imageBaseUrl - Web path to the public images directory under webroot.
+ * - cssBaseUrl - Web path to the public css directory under webroot.
+ * - jsBaseUrl - Web path to the public js directory under webroot.
+ * - paths - Configure paths for non class based resources. Supports the
+ * `plugins`, `templates`, `locales` subkeys, which allow the definition of
+ * paths for plugins, view templates and locale files respectively.
+ */
+ 'App' => [
+ 'namespace' => 'App',
+ 'encoding' => env('APP_ENCODING', 'UTF-8'),
+ 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'),
+ 'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'UTC'),
+ 'base' => false,
+ 'dir' => 'src',
+ 'webroot' => 'webroot',
+ 'wwwRoot' => WWW_ROOT,
+ //'baseUrl' => env('SCRIPT_NAME'),
+ 'fullBaseUrl' => false,
+ 'imageBaseUrl' => 'img/',
+ 'cssBaseUrl' => 'css/',
+ 'jsBaseUrl' => 'js/',
+ 'paths' => [
+ 'plugins' => [ROOT . DS . 'plugins' . DS],
+ 'templates' => [ROOT . DS . 'templates' . DS],
+ 'locales' => [RESOURCES . 'locales' . DS],
+ ],
+ ],
+
+ /*
+ * Security and encryption configuration
+ *
+ * - salt - A random string used in security hashing methods.
+ * The salt value is also used as the encryption key.
+ * You should treat it as extremely sensitive data.
+ */
+ 'Security' => [
+ 'salt' => env('SECURITY_SALT'),
+ ],
+
+ /*
+ * Apply timestamps with the last modified time to static assets (js, css, images).
+ * Will append a querystring parameter containing the time the file was modified.
+ * This is useful for busting browser caches.
+ *
+ * Set to true to apply timestamps when debug is true. Set to 'force' to always
+ * enable timestamping regardless of debug value.
+ */
+ 'Asset' => [
+ //'timestamp' => true,
+ // 'cacheTime' => '+1 year'
+ ],
+
+ /*
+ * Configure the cache adapters.
+ */
+ 'Cache' => [
+ 'default' => [
+ 'className' => FileEngine::class,
+ 'path' => CACHE,
+ 'url' => env('CACHE_DEFAULT_URL', null),
+ ],
+
+ /*
+ * Configure the cache used for general framework caching.
+ * Translation cache files are stored with this configuration.
+ * Duration will be set to '+2 minutes' in bootstrap.php when debug = true
+ * If you set 'className' => 'Null' core cache will be disabled.
+ */
+ '_cake_core_' => [
+ 'className' => FileEngine::class,
+ 'prefix' => 'myapp_cake_core_',
+ 'path' => CACHE . 'persistent' . DS,
+ 'serialize' => true,
+ 'duration' => '+1 years',
+ 'url' => env('CACHE_CAKECORE_URL', null),
+ ],
+
+ /*
+ * Configure the cache for model and datasource caches. This cache
+ * configuration is used to store schema descriptions, and table listings
+ * in connections.
+ * Duration will be set to '+2 minutes' in bootstrap.php when debug = true
+ */
+ '_cake_model_' => [
+ 'className' => FileEngine::class,
+ 'prefix' => 'myapp_cake_model_',
+ 'path' => CACHE . 'models' . DS,
+ 'serialize' => true,
+ 'duration' => '+1 years',
+ 'url' => env('CACHE_CAKEMODEL_URL', null),
+ ],
+
+ /*
+ * Configure the cache for routes. The cached routes collection is built the
+ * first time the routes are processed through `config/routes.php`.
+ * Duration will be set to '+2 seconds' in bootstrap.php when debug = true
+ */
+ '_cake_routes_' => [
+ 'className' => FileEngine::class,
+ 'prefix' => 'myapp_cake_routes_',
+ 'path' => CACHE,
+ 'serialize' => true,
+ 'duration' => '+1 years',
+ 'url' => env('CACHE_CAKEROUTES_URL', null),
+ ],
+ ],
+
+ /*
+ * Configure the Error and Exception handlers used by your application.
+ *
+ * By default errors are displayed using Debugger, when debug is true and logged
+ * by Cake\Log\Log when debug is false.
+ *
+ * In CLI environments exceptions will be printed to stderr with a backtrace.
+ * In web environments an HTML page will be displayed for the exception.
+ * With debug true, framework errors like Missing Controller will be displayed.
+ * When debug is false, framework errors will be coerced into generic HTTP errors.
+ *
+ * Options:
+ *
+ * - `errorLevel` - int - The level of errors you are interested in capturing.
+ * - `trace` - boolean - Whether or not backtraces should be included in
+ * logged errors/exceptions.
+ * - `log` - boolean - Whether or not you want exceptions logged.
+ * - `exceptionRenderer` - string - The class responsible for rendering
+ * uncaught exceptions. If you choose a custom class you should place
+ * the file for that class in src/Error. This class needs to implement a
+ * render method.
+ * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that
+ * extend one of the listed exceptions will also be skipped for logging.
+ * E.g.:
+ * `'skipLog' => ['Cake\Http\Exception\NotFoundException', 'Cake\Http\Exception\UnauthorizedException']`
+ * - `extraFatalErrorMemory` - int - The number of megabytes to increase
+ * the memory limit by when a fatal error is encountered. This allows
+ * breathing room to complete logging or error handling.
+ */
+ 'Error' => [
+ 'errorLevel' => E_ALL,
+ 'exceptionRenderer' => ExceptionRenderer::class,
+ 'skipLog' => [],
+ 'log' => true,
+ 'trace' => true,
+ ],
+
+ /*
+ * Email configuration.
+ *
+ * By defining transports separately from delivery profiles you can easily
+ * re-use transport configuration across multiple profiles.
+ *
+ * You can specify multiple configurations for production, development and
+ * testing.
+ *
+ * Each transport needs a `className`. Valid options are as follows:
+ *
+ * Mail - Send using PHP mail function
+ * Smtp - Send using SMTP
+ * Debug - Do not send the email, just return the result
+ *
+ * You can add custom transports (or override existing transports) by adding the
+ * appropriate file to src/Mailer/Transport. Transports should be named
+ * 'YourTransport.php', where 'Your' is the name of the transport.
+ */
+ 'EmailTransport' => [
+ 'default' => [
+ 'className' => MailTransport::class,
+ /*
+ * The keys host, port, timeout, username, password, client and tls
+ * are used in SMTP transports
+ */
+ 'host' => 'localhost',
+ 'port' => 25,
+ 'timeout' => 30,
+ /*
+ * It is recommended to set these options through your environment or app_local.php
+ */
+ //'username' => null,
+ //'password' => null,
+ 'client' => null,
+ 'tls' => false,
+ 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
+ ],
+ ],
+
+ /*
+ * Email delivery profiles
+ *
+ * Delivery profiles allow you to predefine various properties about email
+ * messages from your application and give the settings a name. This saves
+ * duplication across your application and makes maintenance and development
+ * easier. Each profile accepts a number of keys. See `Cake\Mailer\Email`
+ * for more information.
+ */
+ 'Email' => [
+ 'default' => [
+ 'transport' => 'default',
+ 'from' => 'you@localhost',
+ /*
+ * Will by default be set to config value of App.encoding, if that exists otherwise to UTF-8.
+ */
+ //'charset' => 'utf-8',
+ //'headerCharset' => 'utf-8',
+ ],
+ ],
+
+ /*
+ * Connection information used by the ORM to connect
+ * to your application's datastores.
+ *
+ * ### Notes
+ * - Drivers include Mysql Postgres Sqlite Sqlserver
+ * See vendor\cakephp\cakephp\src\Database\Driver for complete list
+ * - Do not use periods in database name - it may lead to error.
+ * See https://github.com/cakephp/cakephp/issues/6471 for details.
+ * - 'encoding' is recommended to be set to full UTF-8 4-Byte support.
+ * E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any
+ * other RDBMS.
+ */
+ 'Datasources' => [
+ /**
+ * These configurations should contain permanent settings used
+ * by all environments.
+ *
+ * The values in app_local.php will override any values set here
+ * and should be used for local and per-environment configurations.
+ *
+ * Environment variable based configurations can be loaded here or
+ * in app_local.php depending on the applications needs.
+ */
+ 'default' => [
+ 'className' => Connection::class,
+ 'driver' => Mysql::class,
+ 'persistent' => false,
+ 'timezone' => 'UTC',
+
+ /**
+ * For MariaDB/MySQL the internal default changed from utf8 to utf8mb4, aka full utf-8 support, in CakePHP 3.6
+ */
+ //'encoding' => 'utf8mb4',
+
+ /**
+ * If your MySQL server is configured with `skip-character-set-client-handshake`
+ * then you MUST use the `flags` config to set your charset encoding.
+ * For e.g. `'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']`
+ */
+ 'flags' => [],
+ 'cacheMetadata' => true,
+ 'log' => false,
+
+ /*
+ * Set identifier quoting to true if you are using reserved words or
+ * special characters in your table or column names. Enabling this
+ * setting will result in queries built using the Query Builder having
+ * identifiers quoted when creating SQL. It should be noted that this
+ * decreases performance because each query needs to be traversed and
+ * manipulated before being executed.
+ */
+ 'quoteIdentifiers' => false,
+
+ /*
+ * During development, if using MySQL < 5.6, uncommenting the
+ * following line could boost the speed at which schema metadata is
+ * fetched from the database. It can also be set directly with the
+ * mysql configuration directive 'innodb_stats_on_metadata = 0'
+ * which is the recommended value in production environments
+ */
+ //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
+ ],
+ /*
+ * The test connection is used during the test suite.
+ */
+ 'test' => [
+ 'className' => Connection::class,
+ 'driver' => Mysql::class,
+ 'persistent' => false,
+ 'timezone' => 'UTC',
+ //'encoding' => 'utf8mb4',
+ 'flags' => [],
+ 'cacheMetadata' => true,
+ 'quoteIdentifiers' => false,
+ 'log' => false,
+ //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
+ ],
+ ],
+
+ /*
+ * Configures logging options
+ */
+ 'Log' => [
+ 'debug' => [
+ 'className' => FileLog::class,
+ 'path' => LOGS,
+ 'file' => 'debug',
+ 'url' => env('LOG_DEBUG_URL', null),
+ 'scopes' => false,
+ 'levels' => ['notice', 'info', 'debug'],
+ ],
+ 'error' => [
+ 'className' => FileLog::class,
+ 'path' => LOGS,
+ 'file' => 'error',
+ 'url' => env('LOG_ERROR_URL', null),
+ 'scopes' => false,
+ 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
+ ],
+ // To enable this dedicated query log, you need set your datasource's log flag to true
+ 'queries' => [
+ 'className' => FileLog::class,
+ 'path' => LOGS,
+ 'file' => 'queries',
+ 'url' => env('LOG_QUERIES_URL', null),
+ 'scopes' => ['queriesLog'],
+ ],
+ ],
+
+ /*
+ * Session configuration.
+ *
+ * Contains an array of settings to use for session configuration. The
+ * `defaults` key is used to define a default preset to use for sessions, any
+ * settings declared here will override the settings of the default config.
+ *
+ * ## Options
+ *
+ * - `cookie` - The name of the cookie to use. Defaults to value set for `session.name` php.ini config.
+ * Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name.
+ * - `cookiePath` - The url path for which session cookie is set. Maps to the
+ * `session.cookie_path` php.ini config. Defaults to base path of app.
+ * - `timeout` - The time in minutes the session should be valid for.
+ * Pass 0 to disable checking timeout.
+ * Please note that php.ini's session.gc_maxlifetime must be equal to or greater
+ * than the largest Session['timeout'] in all served websites for it to have the
+ * desired effect.
+ * - `defaults` - The default configuration set to use as a basis for your session.
+ * There are four built-in options: php, cake, cache, database.
+ * - `handler` - Can be used to enable a custom session handler. Expects an
+ * array with at least the `engine` key, being the name of the Session engine
+ * class to use for managing the session. CakePHP bundles the `CacheSession`
+ * and `DatabaseSession` engines.
+ * - `ini` - An associative array of additional ini values to set.
+ *
+ * The built-in `defaults` options are:
+ *
+ * - 'php' - Uses settings defined in your php.ini.
+ * - 'cake' - Saves session files in CakePHP's /tmp directory.
+ * - 'database' - Uses CakePHP's database sessions.
+ * - 'cache' - Use the Cache class to save sessions.
+ *
+ * To define a custom session handler, save it at src/Network/Session/.php.
+ * Make sure the class implements PHP's `SessionHandlerInterface` and set
+ * Session.handler to
+ *
+ * To use database sessions, load the SQL file located at config/schema/sessions.sql
+ */
+ 'Session' => [
+ 'defaults' => 'php',
+ ],
+];
diff --git a/app/config/app_local.example.php b/app/config/app_local.example.php
new file mode 100644
index 0000000..affb8e2
--- /dev/null
+++ b/app/config/app_local.example.php
@@ -0,0 +1,92 @@
+ filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN),
+
+ /*
+ * Security and encryption configuration
+ *
+ * - salt - A random string used in security hashing methods.
+ * The salt value is also used as the encryption key.
+ * You should treat it as extremely sensitive data.
+ */
+ 'Security' => [
+ 'salt' => env('SECURITY_SALT', '__SALT__'),
+ ],
+
+ /*
+ * Connection information used by the ORM to connect
+ * to your application's datastores.
+ *
+ * See app.php for more configuration options.
+ */
+ 'Datasources' => [
+ 'default' => [
+ 'host' => 'localhost',
+ /*
+ * CakePHP will use the default DB port based on the driver selected
+ * MySQL on MAMP uses port 8889, MAMP users will want to uncomment
+ * the following line and set the port accordingly
+ */
+ //'port' => 'non_standard_port_number',
+
+ 'username' => 'my_app',
+ 'password' => 'secret',
+
+ 'database' => 'my_app',
+ /**
+ * If not using the default 'public' schema with the PostgreSQL driver
+ * set it here.
+ */
+ //'schema' => 'myapp',
+
+ /**
+ * You can use a DSN string to set the entire configuration
+ */
+ 'url' => env('DATABASE_URL', null),
+ ],
+ /*
+ * The test connection is used during the test suite.
+ */
+ 'test' => [
+ 'host' => 'localhost',
+ //'port' => 'non_standard_port_number',
+ 'username' => 'my_app',
+ 'password' => 'secret',
+ 'database' => 'test_myapp',
+ //'schema' => 'myapp',
+ ],
+ ],
+
+ /*
+ * Email configuration.
+ *
+ * Host and credential configuration in case you are using SmtpTransport
+ *
+ * See app.php for more configuration options.
+ */
+ 'EmailTransport' => [
+ 'default' => [
+ 'host' => 'localhost',
+ 'port' => 25,
+ 'username' => null,
+ 'password' => null,
+ 'client' => null,
+ 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
+ ],
+ ],
+];
diff --git a/app/config/bootstrap.php b/app/config/bootstrap.php
new file mode 100644
index 0000000..615df3d
--- /dev/null
+++ b/app/config/bootstrap.php
@@ -0,0 +1,215 @@
+parse()
+// ->putenv()
+// ->toEnv()
+// ->toServer();
+// }
+
+/*
+ * Read configuration file and inject configuration into various
+ * CakePHP classes.
+ *
+ * By default there is only one configuration file. It is often a good
+ * idea to create multiple configuration files, and separate the configuration
+ * that changes from configuration that does not. This makes deployment simpler.
+ */
+try {
+ Configure::config('default', new PhpConfig());
+ Configure::load('app', 'default', false);
+} catch (\Exception $e) {
+ exit($e->getMessage() . "\n");
+}
+
+/*
+ * Load an environment local configuration file to provide overrides to your configuration.
+ * Notice: For security reasons app_local.php **should not** be included in your git repo.
+ */
+if (file_exists(CONFIG . 'app_local.php')) {
+ Configure::load('app_local', 'default');
+}
+
+/*
+ * When debug = true the metadata cache should only last
+ * for a short time.
+ */
+if (Configure::read('debug')) {
+ Configure::write('Cache._cake_model_.duration', '+2 minutes');
+ Configure::write('Cache._cake_core_.duration', '+2 minutes');
+ // disable router cache during development
+ Configure::write('Cache._cake_routes_.duration', '+2 seconds');
+}
+
+/*
+ * Set the default server timezone. Using UTC makes time calculations / conversions easier.
+ * Check http://php.net/manual/en/timezones.php for list of valid timezone strings.
+ */
+date_default_timezone_set(Configure::read('App.defaultTimezone'));
+
+/*
+ * Configure the mbstring extension to use the correct encoding.
+ */
+mb_internal_encoding(Configure::read('App.encoding'));
+
+/*
+ * Set the default locale. This controls how dates, number and currency is
+ * formatted and sets the default language to use for translations.
+ */
+ini_set('intl.default_locale', Configure::read('App.defaultLocale'));
+
+/*
+ * Register application error and exception handlers.
+ */
+$isCli = PHP_SAPI === 'cli';
+if ($isCli) {
+ (new ConsoleErrorHandler(Configure::read('Error')))->register();
+} else {
+ (new ErrorHandler(Configure::read('Error')))->register();
+}
+
+/*
+ * Include the CLI bootstrap overrides.
+ */
+if ($isCli) {
+ require __DIR__ . '/bootstrap_cli.php';
+}
+
+/*
+ * Set the full base URL.
+ * This URL is used as the base of all absolute links.
+ */
+$fullBaseUrl = Configure::read('App.fullBaseUrl');
+if (!$fullBaseUrl) {
+ $s = null;
+ if (env('HTTPS')) {
+ $s = 's';
+ }
+
+ $httpHost = env('HTTP_HOST');
+ if (isset($httpHost)) {
+ $fullBaseUrl = 'http' . $s . '://' . $httpHost;
+ }
+ unset($httpHost, $s);
+}
+if ($fullBaseUrl) {
+ Router::fullBaseUrl($fullBaseUrl);
+}
+unset($fullBaseUrl);
+
+Cache::setConfig(Configure::consume('Cache'));
+ConnectionManager::setConfig(Configure::consume('Datasources'));
+TransportFactory::setConfig(Configure::consume('EmailTransport'));
+Mailer::setConfig(Configure::consume('Email'));
+Log::setConfig(Configure::consume('Log'));
+Security::setSalt(Configure::consume('Security.salt'));
+
+/*
+ * Setup detectors for mobile and tablet.
+ */
+ServerRequest::addDetector('mobile', function ($request) {
+ $detector = new \Detection\MobileDetect();
+
+ return $detector->isMobile();
+});
+ServerRequest::addDetector('tablet', function ($request) {
+ $detector = new \Detection\MobileDetect();
+
+ return $detector->isTablet();
+});
+
+/*
+ * You can set whether the ORM uses immutable or mutable Time types.
+ * The default changed in 4.0 to immutable types. You can uncomment
+ * below to switch back to mutable types.
+ *
+ * You can enable default locale format parsing by adding calls
+ * to `useLocaleParser()`. This enables the automatic conversion of
+ * locale specific date formats. For details see
+ * @link https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data
+ */
+// TypeFactory::build('time')
+// ->useMutable();
+// TypeFactory::build('date')
+// ->useMutable();
+// TypeFactory::build('datetime')
+// ->useMutable();
+// TypeFactory::build('timestamp')
+// ->useMutable();
+// TypeFactory::build('datetimefractional')
+// ->useMutable();
+// TypeFactory::build('timestampfractional')
+// ->useMutable();
+// TypeFactory::build('datetimetimezone')
+// ->useMutable();
+// TypeFactory::build('timestamptimezone')
+// ->useMutable();
+
+/*
+ * Custom Inflector rules, can be set to correctly pluralize or singularize
+ * table, model, controller names or whatever other string is passed to the
+ * inflection functions.
+ */
+//Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']);
+//Inflector::rules('irregular', ['red' => 'redlings']);
+//Inflector::rules('uninflected', ['dontinflectme']);
+//Inflector::rules('transliteration', ['/Ã¥/' => 'aa']);
diff --git a/app/config/bootstrap_cli.php b/app/config/bootstrap_cli.php
new file mode 100644
index 0000000..7cece95
--- /dev/null
+++ b/app/config/bootstrap_cli.php
@@ -0,0 +1,31 @@
+ '{{text}} ',
+ 'prevActive' => '{{text}} ',
+ 'nextDisabled' => '{{text}} ',
+ 'nextActive' => '{{text}} ',
+ 'number' => '{{text}} ',
+ 'sortAsc' => '{{text}} ',
+ 'sortDesc' => '{{text}} '
+
+];
diff --git a/app/config/paths.php b/app/config/paths.php
new file mode 100644
index 0000000..7e40e9c
--- /dev/null
+++ b/app/config/paths.php
@@ -0,0 +1,94 @@
+= 50.1 is needed to use CakePHP. Please update the `libicu` package of your system.' . PHP_EOL, E_USER_ERROR);
+}
+
+/*
+ * You can remove this if you are confident you have mbstring installed.
+ */
+if (!extension_loaded('mbstring')) {
+ trigger_error('You must enable the mbstring extension to use CakePHP.', E_USER_ERROR);
+}
diff --git a/app/config/routes.php b/app/config/routes.php
new file mode 100644
index 0000000..46b8a9a
--- /dev/null
+++ b/app/config/routes.php
@@ -0,0 +1,99 @@
+setRouteClass(DashedRoute::class);
+
+$routes->scope('/', function (RouteBuilder $builder) {
+ $builder->setExtensions(['json']);
+ // Register scoped middleware for in scopes.
+ $builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([
+ 'httpOnly' => true,
+ ]));
+
+ /*
+ * Apply a middleware to the current route scope.
+ * Requires middleware to be registered through `Application::routes()` with `registerMiddleware()`
+ */
+ $builder->applyMiddleware('csrf');
+
+ /*
+ * Here, we are connecting '/' (base path) to a controller called 'Pages',
+ * its action called 'display', and we pass a param to select the view file
+ * to use (in this case, templates/Pages/home.php)...
+ */
+ $builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
+
+ /*
+ * ...and connect the rest of 'Pages' controller's URLs.
+ */
+ $builder->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
+
+ /*
+ * Connect catchall routes for all controllers.
+ *
+ * The `fallbacks` method is a shortcut for
+ *
+ * ```
+ * $builder->connect('/:controller', ['action' => 'index']);
+ * $builder->connect('/:controller/:action/*', []);
+ * ```
+ *
+ * You can remove these routes once you've connected the
+ * routes you want in your application.
+ */
+ $builder->fallbacks();
+});
+
+/*
+ * If you need a different set of middleware or none at all,
+ * open new scope and define routes there.
+ *
+ * ```
+ * $routes->scope('/api', function (RouteBuilder $builder) {
+ * // No $builder->applyMiddleware() here.
+ * // Connect API actions here.
+ * });
+ * ```
+ */
diff --git a/app/config/schema/i18n.sql b/app/config/schema/i18n.sql
new file mode 100644
index 0000000..e59d1e6
--- /dev/null
+++ b/app/config/schema/i18n.sql
@@ -0,0 +1,18 @@
+# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+#
+# Licensed under The MIT License
+# For full copyright and license information, please see the LICENSE.txt
+# Redistributions of files must retain the above copyright notice.
+# MIT License (https://opensource.org/licenses/mit-license.php)
+
+CREATE TABLE i18n (
+ id int NOT NULL auto_increment,
+ locale varchar(6) NOT NULL,
+ model varchar(255) NOT NULL,
+ foreign_key int(10) NOT NULL,
+ field varchar(255) NOT NULL,
+ content text,
+ PRIMARY KEY (id),
+ UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field),
+ INDEX I18N_FIELD(model, foreign_key, field)
+);
diff --git a/app/config/schema/sessions.sql b/app/config/schema/sessions.sql
new file mode 100644
index 0000000..1aa0a0f
--- /dev/null
+++ b/app/config/schema/sessions.sql
@@ -0,0 +1,15 @@
+# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+#
+# Licensed under The MIT License
+# For full copyright and license information, please see the LICENSE.txt
+# Redistributions of files must retain the above copyright notice.
+# MIT License (https://opensource.org/licenses/mit-license.php)
+
+CREATE TABLE `sessions` (
+ `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
+ `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+
+ `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+
+ `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob
+ `expires` int(10) unsigned DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/app/index.php b/app/index.php
new file mode 100644
index 0000000..4591769
--- /dev/null
+++ b/app/index.php
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+ tests/TestCase/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ src/
+ plugins/*/src/
+
+ src/Console/Installer.php
+
+
+
+
diff --git a/app/plugins/.gitkeep b/app/plugins/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/resources/.gitkeep b/app/resources/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/Application.php b/app/src/Application.php
new file mode 100644
index 0000000..6c47b27
--- /dev/null
+++ b/app/src/Application.php
@@ -0,0 +1,108 @@
+bootstrapCli();
+ }
+
+ /*
+ * Only try to load DebugKit in development mode
+ * Debug Kit should not be installed on a production system
+ */
+ if (Configure::read('debug')) {
+ $this->addPlugin('DebugKit');
+ }
+
+ // Load more plugins here
+ }
+
+ /**
+ * Setup the middleware queue your application will use.
+ *
+ * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup.
+ * @return \Cake\Http\MiddlewareQueue The updated middleware queue.
+ */
+ public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
+ {
+ $middlewareQueue
+ // Catch any exceptions in the lower layers,
+ // and make an error page/response
+ ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
+
+ // Handle plugin/theme assets like CakePHP normally does.
+ ->add(new AssetMiddleware([
+ 'cacheTime' => Configure::read('Asset.cacheTime'),
+ ]))
+
+ // Add routing middleware.
+ // If you have a large number of routes connected, turning on routes
+ // caching in production could improve performance. For that when
+ // creating the middleware instance specify the cache config name by
+ // using it's second constructor argument:
+ // `new RoutingMiddleware($this, '_cake_routes_')`
+ ->add(new RoutingMiddleware($this));
+
+ return $middlewareQueue;
+ }
+
+ /**
+ * Bootrapping for CLI application.
+ *
+ * That is when running commands.
+ *
+ * @return void
+ */
+ protected function bootstrapCli(): void
+ {
+ try {
+ $this->addPlugin('Bake');
+ } catch (MissingPluginException $e) {
+ // Do not halt if the plugin is missing
+ }
+
+ $this->addPlugin('Migrations');
+
+ // Load more plugins here
+ }
+}
diff --git a/app/src/Command/ConsoleCommand.php b/app/src/Command/ConsoleCommand.php
new file mode 100644
index 0000000..e65fe09
--- /dev/null
+++ b/app/src/Command/ConsoleCommand.php
@@ -0,0 +1,86 @@
+err('Unable to load Psy\Shell. ');
+ $io->err('');
+ $io->err('Make sure you have installed psysh as a dependency,');
+ $io->err('and that Psy\Shell is registered in your autoloader.');
+ $io->err('');
+ $io->err('If you are using composer run');
+ $io->err('');
+ $io->err('$ php composer.phar require --dev psy/psysh ');
+ $io->err('');
+
+ return static::CODE_ERROR;
+ }
+
+ $io->out("You can exit with `CTRL-C` or `exit` ");
+ $io->out('');
+
+ Log::drop('debug');
+ Log::drop('error');
+ $io->setLoggers(false);
+ restore_error_handler();
+ restore_exception_handler();
+
+ $psy = new PsyShell();
+ $psy->run();
+ }
+
+ /**
+ * Display help for this console.
+ *
+ * @param \Cake\Console\ConsoleOptionParser $parser The parser to update
+ * @return \Cake\Console\ConsoleOptionParser
+ */
+ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
+ {
+ $parser->setDescription(
+ 'This shell provides a REPL that you can use to interact with ' .
+ 'your application in a command line designed to run PHP code. ' .
+ 'You can use it to run adhoc queries with your models, or ' .
+ 'explore the features of CakePHP and your application.' .
+ "\n\n" .
+ 'You will need to have psysh installed for this Shell to work.'
+ );
+
+ return $parser;
+ }
+}
diff --git a/app/src/Console/Installer.php b/app/src/Console/Installer.php
new file mode 100644
index 0000000..8d98c77
--- /dev/null
+++ b/app/src/Console/Installer.php
@@ -0,0 +1,246 @@
+getIO();
+
+ $rootDir = dirname(dirname(__DIR__));
+
+ static::createAppLocalConfig($rootDir, $io);
+ static::createWritableDirectories($rootDir, $io);
+
+ static::setFolderPermissions($rootDir, $io);
+ static::setSecuritySalt($rootDir, $io);
+
+ $class = 'Cake\Codeception\Console\Installer';
+ if (class_exists($class)) {
+ $class::customizeCodeceptionBinary($event);
+ }
+ }
+
+ /**
+ * Create config/app_local.php file if it does not exist.
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @return void
+ */
+ public static function createAppLocalConfig($dir, $io)
+ {
+ $appLocalConfig = $dir . '/config/app_local.php';
+ $appLocalConfigTemplate = $dir . '/config/app_local.example.php';
+ if (!file_exists($appLocalConfig)) {
+ copy($appLocalConfigTemplate, $appLocalConfig);
+ $io->write('Created `config/app_local.php` file');
+ }
+ }
+
+ /**
+ * Create the `logs` and `tmp` directories.
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @return void
+ */
+ public static function createWritableDirectories($dir, $io)
+ {
+ foreach (static::WRITABLE_DIRS as $path) {
+ $path = $dir . '/' . $path;
+ if (!file_exists($path)) {
+ mkdir($path);
+ $io->write('Created `' . $path . '` directory');
+ }
+ }
+ }
+
+ /**
+ * Set globally writable permissions on the "tmp" and "logs" directory.
+ *
+ * This is not the most secure default, but it gets people up and running quickly.
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @return void
+ */
+ public static function setFolderPermissions($dir, $io)
+ {
+ // ask if the permissions should be changed
+ if ($io->isInteractive()) {
+ $validator = function ($arg) {
+ if (in_array($arg, ['Y', 'y', 'N', 'n'])) {
+ return $arg;
+ }
+ throw new Exception('This is not a valid answer. Please choose Y or n.');
+ };
+ $setFolderPermissions = $io->askAndValidate(
+ 'Set Folder Permissions ? (Default to Y) [Y,n ]? ',
+ $validator,
+ 10,
+ 'Y'
+ );
+
+ if (in_array($setFolderPermissions, ['n', 'N'])) {
+ return;
+ }
+ }
+
+ // Change the permissions on a path and output the results.
+ $changePerms = function ($path) use ($io) {
+ $currentPerms = fileperms($path) & 0777;
+ $worldWritable = $currentPerms | 0007;
+ if ($worldWritable == $currentPerms) {
+ return;
+ }
+
+ $res = chmod($path, $worldWritable);
+ if ($res) {
+ $io->write('Permissions set on ' . $path);
+ } else {
+ $io->write('Failed to set permissions on ' . $path);
+ }
+ };
+
+ $walker = function ($dir) use (&$walker, $changePerms) {
+ $files = array_diff(scandir($dir), ['.', '..']);
+ foreach ($files as $file) {
+ $path = $dir . '/' . $file;
+
+ if (!is_dir($path)) {
+ continue;
+ }
+
+ $changePerms($path);
+ $walker($path);
+ }
+ };
+
+ $walker($dir . '/tmp');
+ $changePerms($dir . '/tmp');
+ $changePerms($dir . '/logs');
+ }
+
+ /**
+ * Set the security.salt value in the application's config file.
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @return void
+ */
+ public static function setSecuritySalt($dir, $io)
+ {
+ $newKey = hash('sha256', Security::randomBytes(64));
+ static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php');
+ }
+
+ /**
+ * Set the security.salt value in a given file
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @param string $newKey key to set in the file
+ * @param string $file A path to a file relative to the application's root
+ * @return void
+ */
+ public static function setSecuritySaltInFile($dir, $io, $newKey, $file)
+ {
+ $config = $dir . '/config/' . $file;
+ $content = file_get_contents($config);
+
+ $content = str_replace('__SALT__', $newKey, $content, $count);
+
+ if ($count == 0) {
+ $io->write('No Security.salt placeholder to replace.');
+
+ return;
+ }
+
+ $result = file_put_contents($config, $content);
+ if ($result) {
+ $io->write('Updated Security.salt value in config/' . $file);
+
+ return;
+ }
+ $io->write('Unable to update Security.salt value.');
+ }
+
+ /**
+ * Set the APP_NAME value in a given file
+ *
+ * @param string $dir The application's root directory.
+ * @param \Composer\IO\IOInterface $io IO interface to write to console.
+ * @param string $appName app name to set in the file
+ * @param string $file A path to a file relative to the application's root
+ * @return void
+ */
+ public static function setAppNameInFile($dir, $io, $appName, $file)
+ {
+ $config = $dir . '/config/' . $file;
+ $content = file_get_contents($config);
+ $content = str_replace('__APP_NAME__', $appName, $content, $count);
+
+ if ($count == 0) {
+ $io->write('No __APP_NAME__ placeholder to replace.');
+
+ return;
+ }
+
+ $result = file_put_contents($config, $content);
+ if ($result) {
+ $io->write('Updated __APP_NAME__ value in config/' . $file);
+
+ return;
+ }
+ $io->write('Unable to update __APP_NAME__ value.');
+ }
+}
diff --git a/app/src/Controller/AlignmentsController.php b/app/src/Controller/AlignmentsController.php
new file mode 100644
index 0000000..d025cf0
--- /dev/null
+++ b/app/src/Controller/AlignmentsController.php
@@ -0,0 +1,130 @@
+Alignments->find();
+ if (!empty($organisation_id)) {
+ $query->where(['organisation_id' => $organisation_id]);
+ }
+ if ($this->_isRest()) {
+ $alignments = $query->all();
+ return $this->RestResponse->viewData($alignments, 'json');
+ } else {
+ $this->loadComponent('Paginator');
+ $alignments = $this->Paginator->paginate($query);
+ $this->set('data', $alignments);
+ $this->set('metaGroup', 'ContactDB');
+ }
+ }
+
+ public function view($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid alignment.'));
+ }
+ $individual = $this->Alignments->get($id);
+ if ($this->_isRest()) {
+ return $this->RestResponse->viewData($individual, 'json');
+ } else {
+
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('alignment', $individual);
+ }
+
+ public function delete($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid alignment.'));
+ }
+ $individual = $this->Alignments->get($id);
+ if ($this->request->is('post') || $this->request->is('delete')) {
+ if ($this->Alignments->delete($individual)) {
+ $message = __('Individual deleted.');
+ if ($this->_isRest()) {
+ $individual = $this->Alignments->get($id);
+ return $this->RestResponse->saveSuccessResponse('Alignments', 'delete', $id, 'json', $message);
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect($this->referer());
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('scope', 'alignments');
+ $this->set('id', $individual['id']);
+ $this->set('alignment', $individual);
+ $this->viewBuilder()->setLayout('ajax');
+ $this->render('/genericTemplates/delete');
+ }
+
+ public function add($scope, $source_id)
+ {
+ if (empty($scope) || empty($source_id)) {
+ throw new NotAcceptableException(__('Invalid input. scope and source_id expected as URL parameters in the format /alignments/add/[scope]/[source_id].'));
+ }
+ $this->loadModel('Individuals');
+ $this->loadModel('Organisations');
+ $alignment = $this->Alignments->newEmptyEntity();
+ if ($this->request->is('post')) {
+ $this->Alignments->patchEntity($alignment, $this->request->getData());
+ if ($scope === 'individuals') {
+ $alignment['individual_id'] = $source_id;
+ } else {
+ $alignment['organisation_id'] = $source_id;
+ }
+ if ($this->Alignments->save($alignment)) {
+ $message = __('Alignment added.');
+ if ($this->_isRest()) {
+ $alignment = $this->Alignments->get($this->Alignments->id);
+ return $this->RestResponse->viewData($alignment, 'json');
+ } else {
+ $this->Flash->success($message);
+ $this->redirect($this->referer());
+ }
+ } else {
+ $message = __('Alignment could not be added.');
+ if ($this->_isRest()) {
+ return $this->RestResponse->saveFailResponse('Individuals', 'addAlignment', false, $message);
+ } else {
+ $this->Flash->error($message);
+ //$this->redirect($this->referer());
+ }
+ }
+ }
+ if ($scope === 'organisations') {
+ $individuals = $this->Individuals->find('list', ['valueField' => 'email']);
+ $this->set('individuals', $individuals);
+ $organisation = $this->Organisations->find()->where(['id' => $source_id])->first();
+ if (empty($organisation)) {
+ throw new NotFoundException(__('Invalid organisation'));
+ }
+ $this->set(compact('organisation'));
+ } else {
+ $organisations = $this->Organisations->find('list', ['valueField' => 'name']);
+ $this->set('organisations', $organisations);
+ $individual = $this->Individuals->find()->where(['id' => $source_id])->first();
+ if (empty($individual)) {
+ throw new NotFoundException(__('Invalid individual'));
+ }
+ $this->set(compact('individual'));
+ }
+ $this->set(compact('alignment'));
+ $this->set('scope', $scope);
+ $this->set('source_id', $source_id);
+ $this->set('metaGroup', 'ContactDB');
+ }
+}
diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php
new file mode 100644
index 0000000..bc52bde
--- /dev/null
+++ b/app/src/Controller/AppController.php
@@ -0,0 +1,104 @@
+loadComponent('FormProtection');`
+ *
+ * @return void
+ */
+ public function initialize(): void
+ {
+ parent::initialize();
+
+ $this->loadComponent('RequestHandler');
+ $this->loadComponent('Flash');
+ $this->loadComponent('RestResponse');
+ $this->loadComponent('ACL');
+
+ if (Configure::read('debug')) {
+ Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]);
+ Configure::write('DebugKit.forceEnable', true);
+ }
+
+ /*
+ * Enable the following component for recommended CakePHP form protection settings.
+ * see https://book.cakephp.org/4/en/controllers/components/form-protection.html
+ */
+ //$this->loadComponent('FormProtection');
+ }
+
+ public function beforeFilter(EventInterface $event)
+ {
+ $this->set('ajax', $this->request->is('ajax'));
+ }
+
+ protected function _isRest()
+ {
+ // This method is surprisingly slow and called many times for one request, so it make sense to cache the result.
+ if ($this->isRest !== null) {
+ return $this->isRest;
+ }
+ if ($this->request->is('json')) {
+ if (!empty($this->request->input()) && empty($this->request->input('json_decode'))) {
+ throw new MethodNotAllowedException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.');
+ }
+ $this->isRest = true;
+ return true;
+ } else {
+ $this->isRest = false;
+ return false;
+ }
+ }
+
+ protected function _isJson($data)
+ {
+ return (json_decode($data) != null) ? true : false;
+ }
+
+ public function generateUUID()
+ {
+ $uuid = Text::uuid();
+ return $this->RestResponse->viewData(['uuid' => $uuid], 'json');
+ }
+}
diff --git a/app/src/Controller/Component/.gitkeep b/app/src/Controller/Component/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/Controller/Component/ACLComponent.php b/app/src/Controller/Component/ACLComponent.php
new file mode 100644
index 0000000..8fddcdf
--- /dev/null
+++ b/app/src/Controller/Component/ACLComponent.php
@@ -0,0 +1,875 @@
+ array()) - any role in the array has access
+ // $action == array('AND' => array()) - roles with all permissions in the array have access
+ // If we add any new functionality to MISP and we don't add it to this list, it will only be visible to site admins.
+ private $__aclList = array(
+ '*' => array(
+ 'blackhole' => array(),
+ 'checkAction' => array(),
+ 'checkAuthUser' => array(),
+ 'checkExternalAuthUser' => array(),
+ 'cleanModelCaches' => array(),
+ 'debugACL' => array(),
+ 'generateCount' => array(),
+ 'getActions' => array(),
+ 'pruneDuplicateUUIDs' => array(),
+ 'queryACL' => array(),
+ 'removeDuplicateEvents' => array(),
+ 'restSearch' => array('*'),
+ 'updateDatabase' => array(),
+ 'upgrade2324' => array(),
+ ),
+ 'attributes' => array(
+ 'add' => array('perm_add'),
+ 'add_attachment' => array('perm_add'),
+ 'add_threatconnect' => array('perm_add'),
+ 'addTag' => array('perm_tagger'),
+ 'attributeReplace' => array('perm_add'),
+ 'attributeStatistics' => array('*'),
+ 'bro' => array('*'),
+ 'checkAttachments' => array(),
+ 'checkComposites' => array('perm_admin'),
+ 'checkOrphanedAttributes' => array(),
+ 'delete' => array('perm_add'),
+ 'deleteSelected' => array('perm_add'),
+ 'describeTypes' => array('*'),
+ 'download' => array('*'),
+ 'downloadAttachment' => array('*'),
+ 'downloadSample' => array('*'),
+ 'edit' => array('perm_add'),
+ 'editField' => array('perm_add'),
+ 'editSelected' => array('perm_add'),
+ 'exportSearch' => array('*'),
+ 'fetchEditForm' => array('perm_add'),
+ 'fetchViewValue' => array('*'),
+ 'generateCorrelation' => array(),
+ 'hoverEnrichment' => array('perm_add'),
+ 'index' => array('*'),
+ 'pruneOrphanedAttributes' => array(),
+ 'removeTag' => array('perm_tagger'),
+ 'reportValidationIssuesAttributes' => array(),
+ 'restore' => array('perm_add'),
+ 'restSearch' => array('*'),
+ 'returnAttributes' => array('*'),
+ 'rpz' => array('*'),
+ 'search' => array('*'),
+ 'searchAlternate' => array('*'),
+ 'toggleCorrelation' => array('perm_add'),
+ 'text' => array('*'),
+ 'toggleToIDS' => array('perm_add'),
+ 'updateAttributeValues' => array('perm_add'),
+ 'view' => array('*'),
+ 'viewPicture' => array('*'),
+ ),
+ 'dashboards' => array(
+ 'getForm' => array('*'),
+ 'index' => array('*'),
+ 'updateSettings' => array('*'),
+ 'getEmptyWidget' => array('*'),
+ 'renderWidget' => array('*'),
+ 'listTemplates' => array('*'),
+ 'saveTemplate' => array('*'),
+ 'export' => array('*'),
+ 'import' => array('*'),
+ 'deleteTemplate' => array('*')
+ ),
+ 'decayingModel' => array(
+ "update" => array(),
+ "export" => array('*'),
+ "import" => array('*'),
+ "view" => array('*'),
+ "index" => array('*'),
+ "add" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "edit" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "delete" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "enable" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "disable" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "decayingTool" => array( 'OR' => array('perm_admin', 'perm_decaying')),
+ "getAllDecayingModels" => array('*'),
+ "decayingToolBasescore" => array('*'),
+ "decayingToolSimulation" => array('*'),
+ "decayingToolRestSearch" => array('*'),
+ "decayingToolComputeSimulation" => array('*')
+ ),
+ 'decayingModelMapping' => array(
+ "viewAssociatedTypes" => array('*'),
+ "linkAttributeTypeToModel" => array( 'OR' => array('perm_admin', 'perm_decaying'))
+ ),
+ 'communities' => array(
+ 'index' => array(),
+ 'requestAccess' => array(),
+ 'view' => array()
+ ),
+ 'eventBlacklists' => array(
+ 'add' => array(),
+ 'delete' => array(),
+ 'edit' => array(),
+ 'index' => array(),
+ 'massDelete' => array()
+ ),
+ 'eventDelegations' => array(
+ 'acceptDelegation' => array('perm_add'),
+ 'delegateEvent' => array('perm_delegate'),
+ 'deleteDelegation' => array('perm_add'),
+ 'index' => array('*'),
+ 'view' => array('*'),
+ ),
+ 'events' => array(
+ 'add' => array('perm_add'),
+ 'addIOC' => array('perm_add'),
+ 'addTag' => array('perm_tagger'),
+ 'add_misp_export' => array('perm_modify'),
+ 'alert' => array('perm_publish'),
+ 'automation' => array('perm_auth'),
+ 'checkLocks' => array('perm_add'),
+ 'checkPublishedStatus' => array('*'),
+ 'checkuuid' => array('perm_sync'),
+ 'contact' => array('*'),
+ 'csv' => array('*'),
+ 'cullEmptyEvents' => array(),
+ 'delegation_index' => array('*'),
+ 'delete' => array('perm_add'),
+ 'deleteNode' => array('*'),
+ 'dot' => array(),
+ 'downloadExport' => array('*'),
+ 'downloadOpenIOCEvent' => array('*'),
+ 'edit' => array('perm_add'),
+ 'enrichEvent' => array('perm_add'),
+ 'export' => array('*'),
+ 'exportChoice' => array('*'),
+ 'exportModule' => array('*'),
+ 'filterEventIdsForPush' => array('perm_sync'),
+ 'filterEventIndex' => array('*'),
+ 'freeTextImport' => array('perm_add'),
+ 'getEditStrategy' => array('perm_add'),
+ 'getEventInfoById' => array('*'),
+ 'getEventGraphReferences' => array('*'),
+ 'getEventGraphTags' => array('*'),
+ 'getEventGraphGeneric' => array('*'),
+ 'getEventTimeline' => array('*'),
+ 'genDistributionGraph' => array('*'),
+ 'getDistributionGraph' => array('*'),
+ 'getReferenceData' => array('*'),
+ 'getReferences' => array('*'),
+ 'getObjectTemplate' => array('*'),
+ 'handleModuleResults' => array('*'),
+ 'hids' => array('*'),
+ 'index' => array('*'),
+ 'importChoice' => array('*'),
+ 'importModule' => array('*'),
+ 'massDelete' => array('perm_site_admin'),
+ 'merge' => array('perm_modify'),
+ 'nids' => array('*'),
+ 'proposalEventIndex' => array('*'),
+ 'publish' => array('perm_publish'),
+ 'publishSightings' => array('perm_sighting'),
+ 'pushEventToZMQ' => array('perm_publish_zmq'),
+ 'pushEventToKafka' => array('perm_publish_kafka'),
+ 'pushProposals' => array('perm_sync'),
+ 'queryEnrichment' => array('perm_add'),
+ 'removePivot' => array('*'),
+ 'removeTag' => array('perm_tagger'),
+ 'reportValidationIssuesEvents' => array(),
+ 'restSearch' => array('*'),
+ 'saveFreeText' => array('perm_add'),
+ 'stix' => array('*'),
+ 'stix2' => array('*'),
+ 'strposarray' => array(),
+ 'toggleCorrelation' => array('perm_add'),
+ 'unpublish' => array('perm_modify'),
+ 'updateGraph' => array('*'),
+ 'upload_analysis_file' => array('perm_add'),
+ 'upload_sample' => array('AND' => array('perm_auth', 'perm_add')),
+ 'upload_stix' => array('perm_add'),
+ 'view' => array('*'),
+ 'viewEventAttributes' => array('*'),
+ 'viewEventGraph' => array('*'),
+ 'viewGraph' => array('*'),
+ 'viewGalaxyMatrix' => array('*'),
+ 'xml' => array('*')
+ ),
+ 'favouriteTags' => array(
+ 'toggle' => array('*'),
+ 'getToggleField' => array('*')
+ ),
+ 'feeds' => array(
+ 'add' => array(),
+ 'cacheFeeds' => array(),
+ 'compareFeeds' => array('*'),
+ 'delete' => array(),
+ 'disable' => array(),
+ 'edit' => array(),
+ 'enable' => array(),
+ 'feedCoverage' => array('*'),
+ 'fetchFromAllFeeds' => array(),
+ 'fetchFromFeed' => array(),
+ 'fetchSelectedFromFreetextIndex' => array(),
+ 'getEvent' => array(),
+ 'importFeeds' => array(),
+ 'index' => array('*'),
+ 'loadDefaultFeeds' => array('perm_site_admin'),
+ 'previewEvent' => array('*'),
+ 'previewIndex' => array('*'),
+ 'searchCaches' => array('*'),
+ 'toggleSelected' => array('perm_site_admin'),
+ 'view' => array('*'),
+ ),
+ 'galaxies' => array(
+ 'attachCluster' => array('perm_tagger'),
+ 'attachMultipleClusters' => array('perm_tagger'),
+ 'delete' => array(),
+ 'index' => array('*'),
+ 'selectGalaxy' => array('perm_tagger'),
+ 'selectGalaxyNamespace' => array('perm_tagger'),
+ 'selectCluster' => array('perm_tagger'),
+ 'showGalaxies' => array('*'),
+ 'update' => array(),
+ 'view' => array('*'),
+ 'viewGraph' => array('*')
+ ),
+ 'galaxyClusters' => array(
+ 'attachToEvent' => array('perm_tagger'),
+ 'delete' => array('perm_site_admin'),
+ 'detach' => array('perm_tagger'),
+ 'index' => array('*'),
+ 'view' => array('*'),
+ 'viewGalaxyMatrix' => array('*')
+ ),
+ 'galaxyElements' => array(
+ 'index' => array('*')
+ ),
+ 'jobs' => array(
+ 'cache' => array('*'),
+ 'getError' => array(),
+ 'getGenerateCorrelationProgress' => array('*'),
+ 'getProgress' => array('*'),
+ 'index' => array(),
+ 'clearJobs' => array()
+ ),
+ 'logs' => array(
+ 'admin_index' => array('perm_audit'),
+ 'admin_search' => array('perm_audit'),
+ 'event_index' => array('*'),
+ 'maxDateActivity' => array('*'),
+ 'returnDates' => array('*'),
+ 'testForStolenAttributes' => array(),
+ 'pruneUpdateLogs' => array()
+ ),
+ 'modules' => array(
+ 'index' => array('perm_auth'),
+ 'queryEnrichment' => array('perm_auth'),
+ ),
+ 'news' => array(
+ 'add' => array(),
+ 'edit' => array(),
+ 'delete' => array(),
+ 'index' => array('*'),
+ ),
+ 'noticelists' => array(
+ 'delete' => array(),
+ 'enableNoticelist' => array(),
+ 'getToggleField' => array(),
+ 'index' => array('*'),
+ 'toggleEnable' => array(),
+ 'update' => array(),
+ 'view' => array('*')
+ ),
+ 'objects' => array(
+ 'add' => array('perm_add'),
+ 'addValueField' => array('perm_add'),
+ 'delete' => array('perm_add'),
+ 'edit' => array('perm_add'),
+ 'get_row' => array('perm_add'),
+ 'orphanedObjectDiagnostics' => array(),
+ 'editField' => array('perm_add'),
+ 'fetchEditForm' => array('perm_add'),
+ 'fetchViewValue' => array('*'),
+ 'quickAddAttributeForm' => array('perm_add'),
+ 'quickFetchTemplateWithValidObjectAttributes' => array('perm_add'),
+ 'restSearch' => array('*'),
+ 'proposeObjectsFromAttributes' => array('*'),
+ 'groupAttributesIntoObject' => array('perm_add'),
+ 'revise_object' => array('perm_add'),
+ 'view' => array('*'),
+ ),
+ 'objectReferences' => array(
+ 'add' => array('perm_add'),
+ 'delete' => array('perm_add'),
+ 'view' => array('*'),
+ ),
+ 'objectTemplates' => array(
+ 'activate' => array(),
+ 'add' => array('perm_object_template'),
+ 'edit' => array('perm_object_template'),
+ 'delete' => array('perm_object_template'),
+ 'getToggleField' => array(),
+ 'objectChoice' => array('*'),
+ 'objectMetaChoice' => array('perm_add'),
+ 'view' => array('*'),
+ 'viewElements' => array('*'),
+ 'index' => array('*'),
+ 'update' => array('perm_site_admin')
+ ),
+ 'objectTemplateElements' => array(
+ 'viewElements' => array('*')
+ ),
+ 'orgBlacklists' => array(
+ 'add' => array(),
+ 'delete' => array(),
+ 'edit' => array(),
+ 'index' => array(),
+ ),
+ 'organisations' => array(
+ 'admin_add' => array(),
+ 'admin_delete' => array(),
+ 'admin_edit' => array(),
+ 'admin_generateuuid' => array(),
+ 'admin_merge' => array(),
+ 'fetchOrgsForSG' => array('*'),
+ 'fetchSGOrgRow' => array('*'),
+ 'getUUIDs' => array('perm_sync'),
+ 'index' => array('*'),
+ 'landingpage' => array('*'),
+ 'view' => array('*'),
+ ),
+ 'pages' => array(
+ 'display' => array('*'),
+ ),
+ 'posts' => array(
+ 'add' => array('*'),
+ 'delete' => array('*'),
+ 'edit' => array('*'),
+ 'pushMessageToZMQ' => array('perm_site_admin')
+ ),
+ 'regexp' => array(
+ 'admin_add' => array('perm_regexp_access'),
+ 'admin_clean' => array('perm_regexp_access'),
+ 'admin_delete' => array('perm_regexp_access'),
+ 'admin_edit' => array('perm_regexp_access'),
+ 'admin_index' => array('perm_regexp_access'),
+ 'cleanRegexModifiers' => array('perm_regexp_access'),
+ 'index' => array('*'),
+ ),
+ 'restClientHistory' => array(
+ 'delete' => array('*'),
+ 'index' => array('*')
+ ),
+ 'roles' => array(
+ 'admin_add' => array(),
+ 'admin_delete' => array(),
+ 'admin_edit' => array(),
+ 'admin_index' => array('perm_admin'),
+ 'admin_set_default' => array(),
+ 'index' => array('*'),
+ 'view' => array('*'),
+ ),
+ 'servers' => array(
+ 'add' => array(),
+ 'dbSchemaDiagnostic' => array(),
+ 'cache' => array(),
+ 'changePriority' => array(),
+ 'checkout' => array(),
+ 'clearWorkerQueue' => array(),
+ 'createSync' => array('perm_sync'),
+ 'delete' => array(),
+ 'deleteFile' => array(),
+ 'edit' => array(),
+ 'fetchServersForSG' => array('*'),
+ 'filterEventIndex' => array(),
+ 'getApiInfo' => array('*'),
+ 'getGit' => array(),
+ 'getInstanceUUID' => array('perm_sync'),
+ 'getPyMISPVersion' => array('*'),
+ 'getRemoteUser' => array(),
+ 'getSetting' => array(),
+ 'getSubmodulesStatus' => array(),
+ 'getSubmoduleQuickUpdateForm' => array(),
+ 'getWorkers' => array(),
+ 'getVersion' => array('*'),
+ 'import' => array(),
+ 'index' => array(),
+ 'ondemandAction' => array(),
+ 'postTest' => array('perm_sync'),
+ 'previewEvent' => array(),
+ 'previewIndex' => array(),
+ 'pull' => array(),
+ 'purgeSessions' => array(),
+ 'push' => array(),
+ 'releaseUpdateLock' => array(),
+ 'resetRemoteAuthKey' => array(),
+ 'rest' => array('perm_auth'),
+ 'restartDeadWorkers' => array(),
+ 'restartWorkers' => array(),
+ 'serverSettings' => array(),
+ 'serverSettingsEdit' => array(),
+ 'serverSettingsReloadSetting' => array(),
+ 'startWorker' => array(),
+ 'startZeroMQServer' => array(),
+ 'statusZeroMQServer' => array(),
+ 'stopWorker' => array(),
+ 'stopZeroMQServer' => array(),
+ 'testConnection' => array(),
+ 'update' => array(),
+ 'updateJSON' => array(),
+ 'updateProgress' => array(),
+ 'updateSubmodule' => array(),
+ 'uploadFile' => array(),
+ 'viewDeprecatedFunctionUse' => array()
+ ),
+ 'shadowAttributes' => array(
+ 'accept' => array('perm_add'),
+ 'acceptSelected' => array('perm_add'),
+ 'add' => array('perm_add'),
+ 'add_attachment' => array('perm_add'),
+ 'delete' => array('perm_add'),
+ 'discard' => array('perm_add'),
+ 'discardSelected' => array('perm_add'),
+ 'download' => array('*'),
+ 'edit' => array('perm_add'),
+ 'editField' => array('perm_add'),
+ 'fetchEditForm' => array('perm_add'),
+ 'generateCorrelation' => array(),
+ 'getProposalsByUuid' => array('perm_sync'),
+ 'getProposalsByUuidList' => array('perm_sync'),
+ 'index' => array('*'),
+ 'view' => array('*'),
+ ),
+ 'sharingGroups' => array(
+ 'add' => array('perm_sharing_group'),
+ 'addServer' => array('perm_sharing_group'),
+ 'addOrg' => array('perm_sharing_group'),
+ 'delete' => array('perm_sharing_group'),
+ 'edit' => array('perm_sharing_group'),
+ 'index' => array('*'),
+ 'removeServer' => array('perm_sharing_group'),
+ 'removeOrg' => array('perm_sharing_group'),
+ 'view' => array('*'),
+ ),
+ 'sightings' => array(
+ 'add' => array('perm_sighting'),
+ 'restSearch' => array('perm_sighting'),
+ 'advanced' => array('perm_sighting'),
+ 'delete' => array('perm_sighting'),
+ 'index' => array('*'),
+ 'listSightings' => array('*'),
+ 'quickDelete' => array('perm_sighting'),
+ 'viewSightings' => array('*'),
+ 'bulkSaveSightings' => array('OR' => array('perm_sync', 'perm_sighting')),
+ 'quickAdd' => array('perm_sighting')
+ ),
+ 'sightingdb' => array(
+ 'add' => array(),
+ 'edit' => array(),
+ 'delete' => array(),
+ 'index' => array(),
+ 'requestStatus' => array(),
+ 'search' => array()
+ ),
+ 'tagCollections' => array(
+ 'add' => array('perm_tag_editor'),
+ 'addTag' => array('perm_tag_editor'),
+ 'delete' => array('perm_tag_editor'),
+ 'edit' => array('perm_tag_editor'),
+ 'getRow' => array('perm_tag_editor'),
+ 'import' => array('perm_tag_editor'),
+ 'index' => array('*'),
+ 'removeTag' => array('perm_tag_editor'),
+ 'view' => array('*')
+ ),
+ 'tags' => array(
+ 'add' => array('perm_tag_editor'),
+ 'attachTagToObject' => array('perm_tagger'),
+ 'delete' => array(),
+ 'edit' => array(),
+ 'index' => array('*'),
+ 'quickAdd' => array('perm_tag_editor'),
+ 'removeTagFromObject' => array('perm_tagger'),
+ 'search' => array('*'),
+ 'selectTag' => array('perm_tagger'),
+ 'selectTaxonomy' => array('perm_tagger'),
+ 'showEventTag' => array('*'),
+ 'showAttributeTag' => array('*'),
+ 'showTagControllerTag' => array('*'),
+ 'tagStatistics' => array('*'),
+ 'view' => array('*'),
+ 'viewGraph' => array('*'),
+ 'viewTag' => array('*')
+ ),
+ 'tasks' => array(
+ 'index' => array(),
+ 'setTask' => array(),
+ ),
+ 'taxonomies' => array(
+ 'addTag' => array(),
+ 'delete' => array(),
+ 'disable' => array(),
+ 'disableTag' => array(),
+ 'enable' => array(),
+ 'index' => array('*'),
+ 'taxonomyMassConfirmation' => array('perm_tagger'),
+ 'taxonomyMassHide' => array('perm_tagger'),
+ 'taxonomyMassUnhide' => array('perm_tagger'),
+ 'toggleRequired' => array('perm_site_admin'),
+ 'update' => array(),
+ 'view' => array('*'),
+ 'unhideTag' => array('perm_tagger'),
+ 'hideTag' => array('perm_tagger'),
+ ),
+ 'templateElements' => array(
+ 'add' => array('perm_template'),
+ 'delete' => array('perm_template'),
+ 'edit' => array('perm_template'),
+ 'index' => array('*'),
+ 'templateElementAddChoices' => array('perm_template'),
+ ),
+ 'templates' => array(
+ 'add' => array('perm_template'),
+ 'delete' => array('perm_template'),
+ 'deleteTemporaryFile' => array('perm_add'),
+ 'edit' => array('perm_template'),
+ 'index' => array('*'),
+ 'populateEventFromTemplate' => array('perm_add'),
+ 'saveElementSorting' => array('perm_template'),
+ 'submitEventPopulation' => array('perm_add'),
+ 'templateChoices' => array('*'),
+ 'uploadFile' => array('*'),
+ 'view' => array('*'),
+ ),
+ 'threads' => array(
+ 'index' => array('*'),
+ 'view' => array('*'),
+ 'viewEvent' => array('*'),
+ ),
+ 'users' => array(
+ 'acceptRegistrations' => array('perm_site_admin'),
+ 'admin_add' => array('perm_admin'),
+ 'admin_delete' => array('perm_admin'),
+ 'admin_edit' => array('perm_admin'),
+ 'admin_email' => array('perm_admin'),
+ 'admin_filterUserIndex' => array('perm_admin'),
+ 'admin_index' => array('perm_admin'),
+ 'admin_monitor' => array('perm_site_admin'),
+ 'admin_quickEmail' => array('perm_admin'),
+ 'admin_view' => array('perm_admin'),
+ 'attributehistogram' => array('*'),
+ 'change_pw' => array('*'),
+ 'checkAndCorrectPgps' => array(),
+ 'checkIfLoggedIn' => array('*'),
+ 'dashboard' => array('*'),
+ 'delete' => array('perm_admin'),
+ 'discardRegistrations' => array('perm_site_admin'),
+ 'downloadTerms' => array('*'),
+ 'edit' => array('*'),
+ 'email_otp' => array('*'),
+ 'searchGpgKey' => array('*'),
+ 'fetchGpgKey' => array('*'),
+ 'histogram' => array('*'),
+ 'initiatePasswordReset' => array('perm_admin'),
+ 'login' => array('*'),
+ 'logout' => array('*'),
+ 'register' => array('*'),
+ 'registrations' => array('perm_site_admin'),
+ 'resetAllSyncAuthKeys' => array(),
+ 'resetauthkey' => array('*'),
+ 'request_API' => array('*'),
+ 'routeafterlogin' => array('*'),
+ 'statistics' => array('*'),
+ 'tagStatisticsGraph' => array('*'),
+ 'terms' => array('*'),
+ 'updateLoginTime' => array('*'),
+ 'verifyCertificate' => array(),
+ 'verifyGPG' => array(),
+ 'view' => array('*'),
+ ),
+ 'userSettings' => array(
+ 'index' => array('*'),
+ 'view' => array('*'),
+ 'setSetting' => array('*'),
+ 'getSetting' => array('*'),
+ 'delete' => array('*'),
+ 'setHomePage' => array('*')
+ ),
+ 'warninglists' => array(
+ 'checkValue' => array('perm_auth'),
+ 'delete' => array(),
+ 'enableWarninglist' => array(),
+ 'getToggleField' => array(),
+ 'index' => array('*'),
+ 'toggleEnable' => array(),
+ 'update' => array(),
+ 'view' => array('*')
+ ),
+ 'whitelists' => array(
+ 'admin_add' => array('perm_regexp_access'),
+ 'admin_delete' => array('perm_regexp_access'),
+ 'admin_edit' => array('perm_regexp_access'),
+ 'admin_index' => array('perm_regexp_access'),
+ 'index' => array('*'),
+ ),
+ 'eventGraph' => array(
+ 'view' => array('*'),
+ 'add' => array('perm_add'),
+ 'delete' => array('perm_modify'),
+ )
+ );
+
+ private function __checkLoggedActions($user, $controller, $action)
+ {
+ $loggedActions = array(
+ 'servers' => array(
+ 'index' => array(
+ 'role' => array(
+ 'NOT' => array(
+ 'perm_site_admin'
+ )
+ ),
+ 'message' => __('This could be an indication of an attempted privilege escalation on older vulnerable versions of MISP (<2.4.115)')
+ )
+ )
+ );
+ foreach ($loggedActions as $k => $v) {
+ $loggedActions[$k] = array_change_key_case($v);
+ }
+ $message = '';
+ if (!empty($loggedActions[$controller])) {
+ if (!empty($loggedActions[$controller][$action])) {
+ $message = $loggedActions[$controller][$action]['message'];
+ $hit = false;
+ if (empty($loggedActions[$controller][$action]['role'])) {
+ $hit = true;
+ } else {
+ $role_req = $loggedActions[$controller][$action]['role'];
+ if (empty($role_req['OR']) && empty($role_req['AND']) && empty($role_req['NOT'])) {
+ $role_req = array('OR' => $role_req);
+ }
+ if (!empty($role_req['NOT'])) {
+ foreach ($role_req['NOT'] as $k => $v) {
+ if (!$user['Role'][$v]) {
+ $hit = true;
+ continue;
+ }
+ }
+ }
+ if (!$hit && !empty($role_req['AND'])) {
+ $subhit = true;
+ foreach ($role_req['AND'] as $k => $v) {
+ $subhit = $subhit && $user['Role'][$v];
+ }
+ if ($subhit) {
+ $hit = true;
+ }
+ }
+ if (!$hit && !empty($role_req['OR'])) {
+ foreach ($role_req['OR'] as $k => $v) {
+ if ($user['Role'][$v]) {
+ $hit = true;
+ continue;
+ }
+ }
+ }
+ if ($hit) {
+ $this->Log = ClassRegistry::init('Log');
+ $this->Log->create();
+ $this->Log->save(array(
+ 'org' => 'SYSTEM',
+ 'model' => 'User',
+ 'model_id' => $user['id'],
+ 'email' => $user['email'],
+ 'action' => 'security',
+ 'user_id' => $user['id'],
+ 'title' => __('User triggered security alert by attempting to access /%s/%s. Reason why this endpoint is of interest: %s', $controller, $action, $message),
+ ));
+ }
+ }
+ }
+ }
+ }
+
+ // The check works like this:
+ // If the user is a site admin, return true
+ // If the requested action has an OR-d list, iterate through the list. If any of the permissions are set for the user, return true
+ // If the requested action has an AND-ed list, iterate through the list. If any of the permissions for the user are not set, turn the check to false. Otherwise return true.
+ // If the requested action has a permission, check if the user's role has it flagged. If yes, return true
+ // If we fall through all of the checks, return an exception.
+ public function checkAccess($user, $controller, $action, $soft = false)
+ {
+ $controller = lcfirst(Inflector::camelize($controller));
+ $action = strtolower($action);
+ $aclList = $this->__aclList;
+ foreach ($aclList as $k => $v) {
+ $aclList[$k] = array_change_key_case($v);
+ }
+ $this->__checkLoggedActions($user, $controller, $action);
+ if ($user['Role']['perm_site_admin']) {
+ return true;
+ }
+ if (!isset($aclList[$controller])) {
+ return $this->__error(404, 'Invalid controller.', $soft);
+ }
+ if ($user['Role']['perm_site_admin']) {
+ return true;
+ }
+ if (isset($aclList[$controller][$action]) && !empty($aclList[$controller][$action])) {
+ if (in_array('*', $aclList[$controller][$action])) {
+ return true;
+ }
+ if (isset($aclList[$controller][$action]['OR'])) {
+ foreach ($aclList[$controller][$action]['OR'] as $permission) {
+ if ($user['Role'][$permission]) {
+ return true;
+ }
+ }
+ } elseif (isset($aclList[$controller][$action]['AND'])) {
+ $allConditionsMet = true;
+ foreach ($aclList[$controller][$action]['AND'] as $permission) {
+ if (!$user['Role'][$permission]) {
+ $allConditionsMet = false;
+ }
+ }
+ if ($allConditionsMet) {
+ return true;
+ }
+ } elseif ($user['Role'][$aclList[$controller][$action][0]]) {
+ return true;
+ }
+ }
+ return $this->__error(403, 'You do not have permission to use this functionality.', $soft);
+ }
+
+ private function __error($code, $message, $soft = false)
+ {
+ if ($soft) {
+ return $code;
+ }
+ switch ($code) {
+ case 404:
+ throw new NotFoundException($message);
+ break;
+ case 403:
+ throw new MethodNotAllowedException($message);
+ default:
+ throw new InternalErrorException('Unknown error: ' . $message);
+ }
+ }
+
+ private function __findAllFunctions()
+ {
+ $functionFinder = '/function[\s\n]+(\S+)[\s\n]*\(/';
+ $dir = new Folder(APP . 'Controller');
+ $files = $dir->find('.*\.php');
+ $results = array();
+ foreach ($files as $file) {
+ $controllerName = lcfirst(str_replace('Controller.php', "", $file));
+ if ($controllerName === 'app') {
+ $controllerName = '*';
+ }
+ $functionArray = array();
+ $fileContents = file_get_contents(APP . 'Controller' . DS . $file);
+ $fileContents = preg_replace('/\/\*[^\*]+?\*\//', '', $fileContents);
+ preg_match_all($functionFinder, $fileContents, $functionArray);
+ foreach ($functionArray[1] as $function) {
+ if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter' && $function !== 'afterFilter') {
+ $results[$controllerName][] = $function;
+ }
+ }
+ }
+ return $results;
+ }
+
+ public function printAllFunctionNames($content = false)
+ {
+ $results = $this->__findAllFunctions();
+ ksort($results);
+ return $results;
+ }
+
+ public function findMissingFunctionNames($content = false)
+ {
+ $results = $this->__findAllFunctions();
+ $missing = array();
+ foreach ($results as $controller => $functions) {
+ foreach ($functions as $function) {
+ if (!isset($this->__aclList[$controller])
+ || !in_array($function, array_keys($this->__aclList[$controller]))) {
+ $missing[$controller][] = $function;
+ }
+ }
+ }
+ return $missing;
+ }
+
+ public function printRoleAccess($content = false)
+ {
+ $results = array();
+ $this->Role = ClassRegistry::init('Role');
+ $conditions = array();
+ if (is_numeric($content)) {
+ $conditions = array('Role.id' => $content);
+ }
+ $roles = $this->Role->find('all', array(
+ 'recursive' => -1,
+ 'conditions' => $conditions
+ ));
+ if (empty($roles)) {
+ throw new NotFoundException('Role not found.');
+ }
+ foreach ($roles as $role) {
+ $urls = $this->__checkRoleAccess($role['Role']);
+ $results[$role['Role']['id']] = array('name' => $role['Role']['name'], 'urls' => $urls);
+ }
+ return $results;
+ }
+
+ private function __checkRoleAccess($role)
+ {
+ $result = array();
+ foreach ($this->__aclList as $controller => $actions) {
+ $controllerNames = Inflector::variable($controller) == Inflector::underscore($controller) ? array(Inflector::variable($controller)) : array(Inflector::variable($controller), Inflector::underscore($controller));
+ foreach ($controllerNames as $controllerName) {
+ foreach ($actions as $action => $permissions) {
+ if ($role['perm_site_admin']) {
+ $result[] = DS . $controllerName . DS . $action;
+ } elseif (in_array('*', $permissions)) {
+ $result[] = DS . $controllerName . DS . $action . DS . '*';
+ } elseif (isset($permissions['OR'])) {
+ $access = false;
+ foreach ($permissions['OR'] as $permission) {
+ if ($role[$permission]) {
+ $access = true;
+ }
+ }
+ if ($access) {
+ $result[] = DS . $controllerName . DS . $action . DS . '*';
+ }
+ } elseif (isset($permissions['AND'])) {
+ $access = true;
+ foreach ($permissions['AND'] as $permission) {
+ if ($role[$permission]) {
+ $access = false;
+ }
+ }
+ if ($access) {
+ $result[] = DS . $controllerName . DS . $action . DS . '*';
+ }
+ } elseif (isset($permissions[0]) && $role[$permissions[0]]) {
+ $result[] = DS . $controllerName . DS . $action . DS . '*';
+ }
+ }
+ }
+ }
+ return $result;
+ }
+}
diff --git a/app/src/Controller/Component/RestResponseComponent.php b/app/src/Controller/Component/RestResponseComponent.php
new file mode 100644
index 0000000..d433358
--- /dev/null
+++ b/app/src/Controller/Component/RestResponseComponent.php
@@ -0,0 +1,1782 @@
+ array(
+ 'addOrg' => 'add Organisation to',
+ 'removeOrg' => 'remove Organisation from',
+ 'addServer' => 'add Server to',
+ 'removeServer' => 'remove Server from'
+ )
+ );
+
+ private $___setup = false;
+
+ private $__descriptions = array(
+ 'Attribute' => array(
+ 'add' => array(
+ 'description' => "POST a MISP Attribute JSON to this API to create an Attribute.",
+ 'mandatory' => array('value', 'type'),
+ 'optional' => array('category', 'to_ids', 'uuid', 'distribution', 'sharing_group_id', 'timestamp', 'comment', 'data', 'encrypt', 'first_seen', 'last_seen'),
+ 'params' => array('event_id')
+ ),
+ 'edit' => array(
+ 'description' => "POST a MISP Attribute JSON to this API to update an Attribute. If the timestamp is set, it has to be newer than the existing Attribute.",
+ 'mandatory' => array(),
+ 'optional' => array('value', 'type', 'category', 'to_ids', 'uuid', 'distribution', 'sharing_group_id', 'timestamp', 'comment', 'date', 'encrypt', 'first_seen', 'last_seen'),
+ 'params' => array('attribute_id')
+ ),
+ 'deleteSelected' => array(
+ 'description' => "POST a list of attribute IDs in JSON format to this API to delete the given attributes. This API also expects an event ID passed via the URL or via the event_id key. The id key also takes 'all' as a parameter for a wildcard search to mass delete attributes. If you want the function to also hard-delete already soft-deleted attributes, pass the allow_hard_delete key.",
+ 'mandatory' => array('id'),
+ 'optional' => array('event_id', 'allow_hard_delete'),
+ 'params' => array('event_id')
+ ),
+ 'restSearch' => array(
+ 'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.",
+ 'mandatory' => array('returnFormat'),
+ 'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'attribute_timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'score', 'first_seen', 'last_seen'),
+ 'params' => array()
+ )
+ ),
+ 'Community' => array(
+ 'requestAccess' => array(
+ 'description' => "POST a request object describing yourself and your organisation to request access to the desired community.",
+ 'mandatory' => array(),
+ 'optional' => array('org_name', 'org_uuid', 'sync', 'org_description', 'email', 'message', 'anonymise', 'gpgkey', 'mock'),
+ 'params' => array('uuid')
+ )
+ ),
+ 'Event' => array(
+ 'add' => array(
+ 'description' => "POST a MISP Event JSON to this API to create an Event. Contained objects can also be included (such as attributes, objects, tags, etc).",
+ 'mandatory' => array('info'),
+ 'optional' => array('threat_level_id', 'analysis', 'distribution', 'sharing_group_id', 'uuid', 'published', 'timestamp', 'date', 'Attribute', 'Object', 'Shadow_Attribute', 'EventTag'),
+ 'params' => array()
+ ),
+ 'edit' => array(
+ 'description' => "POST a MISP Event JSON to this API to update an Event. Contained objects can also be included (such as attributes, objects, tags, etc). If the timestamp is set, it has to be newer than the existing Attribute.",
+ 'mandatory' => array(),
+ 'optional' => array('info', 'threat_level_id', 'analysis', 'distribution', 'sharing_group_id', 'uuid', 'published', 'timestamp', 'date', 'Attribute', 'Object', 'Shadow_Attribute', 'EventTag'),
+ 'params' => array('event_id')
+ ),
+ 'index' => array(
+ 'description' => 'POST a JSON filter object to this API to get the meta-data about matching events.',
+ 'optional' => array('all', 'attribute', 'published', 'eventid', 'datefrom', 'dateuntil', 'org', 'eventinfo', 'tag', 'tags', 'distribution', 'sharinggroup', 'analysis', 'threatlevel', 'email', 'hasproposal', 'timestamp', 'publishtimestamp', 'publish_timestamp', 'minimal')
+ ),
+ 'restSearch' => array(
+ 'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.",
+ 'mandatory' => array('returnFormat'),
+ 'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'date', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo', 'excludeLocalTags', 'threat_level_id'),
+ 'params' => array()
+ )
+ ),
+ 'EventGraph' => array(
+ 'add' => array(
+ 'description' => "POST a network in JSON format to this API to to keep an history of it",
+ 'mandatory' => array('event_id', 'network_json'),
+ 'optional' => array('network_name')
+ )
+ ),
+ 'Feed' => array(
+ 'add' => array(
+ 'description' => "POST a MISP Feed descriptor JSON to this API to add a Feed.",
+ 'mandatory' => array('source_format', 'url', 'name', 'input_source', 'provider'),
+ 'optional' => array('enabled', 'caching_enabled', 'lookup_visible', 'delete_local_file', 'headers', 'fixed_event', 'target_event', 'settings', 'publish', 'override_ids', 'delta_merge', 'distribution', 'sharing_group_id', 'tag_id', 'pull_rules', 'rules', 'event_id'),
+ 'params' => array()
+ ),
+ 'edit' => array(
+ 'description' => "POST a MISP Feed descriptor JSON to this API to edit a Feed.",
+ 'mandatory' => array(),
+ 'optional' => array('source_format', 'url', 'name', 'enabled', 'caching_enabled', 'lookup_visible', 'provider', 'input_source', 'delete_local_file', 'headers', 'fixed_event', 'target_event', 'settings', 'publish', 'override_ids', 'delta_merge', 'distribution', 'sharing_group_id', 'tag_id', 'pull_rules', 'rules', 'event_id'),
+ 'params' => array('feed_id')
+ ),
+ 'previewIndex' => array(
+ 'description' => 'Sending a GET request to this endpoint will show the parsed feed in JSON format.',
+ 'mandatory' => array(),
+ 'optional' => array(),
+ 'params' => array('feed_id'),
+ 'http_method' => 'GET'
+ )
+ ),
+ 'Log' => array(
+ 'admin_index' => array(
+ 'description' => "POST a filter object to receive a JSON with the log entries matching the query. A simple get request will return the entire DB. You can use the filter parameters as url parameters with a GET request such as: https://path.to.my.misp/admin/logs/page:1/limit:200 - to run substring queries simply append/prepend/encapsulate the search term with %. All restSearch rules apply.",
+ "optional" => array('id', 'title', 'created', 'model', 'model_id', 'action', 'user_id', 'change', 'email', 'org', 'description', 'ip')
+ ),
+ 'event_index' => array(
+ 'description' => "Simply run a get request on this endpoint to get the relevant log entries for a given event. This functionality is open to any user having access to a given event."
+ )
+ ),
+ 'Organisation' => array(
+ 'admin_add' => array(
+ 'description' => "POST an Organisation object in JSON format to this API to create a new organsiation.",
+ 'mandatory' => array('name'),
+ 'optional' => array('description', 'type', 'nationality', 'sector', 'uuid', 'contacts', 'local')
+ ),
+ 'admin_edit' => array(
+ 'description' => "POST an Organisation object in JSON format to this API to create a new organsiation.",
+ 'mandatory' => array('name'),
+ 'optional' => array('description', 'type', 'nationality', 'sector', 'uuid', 'contacts', 'local')
+ )
+ ),
+ 'Role' => array(
+ 'admin_add' => array(
+ 'description' => "POST a Role object in JSON format to this API to create a new role. 'permission' sets the data access permission (0 => read only, 1 => add/edit own, 2 => add/edit org, 3 => publish)",
+ 'mandatory' => array('name'),
+ 'optional' => array(
+ 'perm_delegate',
+ 'perm_sync',
+ 'perm_admin',
+ 'perm_audit',
+ 'perm_auth',
+ 'perm_site_admin',
+ 'perm_regexp_access',
+ 'perm_tagger',
+ 'perm_template',
+ 'perm_sharing_group',
+ 'perm_tag_editor',
+ 'default_role',
+ 'perm_sighting',
+ 'permission'
+ )
+ ),
+ 'admin_edit' => array(
+ 'description' => "POST a Role object in JSON format to this API to edit a role. 'permission' sets the data access permission (0 => read only, 1 => add/edit own, 2 => add/edit org, 3 => publish)",
+ 'mandatory' => array('name'),
+ 'optional' => array(
+ 'perm_delegate',
+ 'perm_sync',
+ 'perm_admin',
+ 'perm_audit',
+ 'perm_auth',
+ 'perm_site_admin',
+ 'perm_regexp_access',
+ 'perm_tagger',
+ 'perm_template',
+ 'perm_sharing_group',
+ 'perm_tag_editor',
+ 'default_role',
+ 'perm_sighting',
+ 'permission'
+ )
+ )
+ ),
+ 'Server' => array(
+ 'add' => array(
+ 'description' => "POST an Server object in JSON format to this API to add a server.",
+ 'mandatory' => array('url', 'name', 'remote_org_id', 'authkey'),
+ 'optional' => array('push', 'pull', 'push_sightings', 'push_rules', 'pull_rules', 'submitted_cert', 'submitted_client_cert', 'json')
+ ),
+ 'edit' => array(
+ 'description' => "POST an Server object in JSON format to this API to edit a server.",
+ 'optional' => array('url', 'name', 'authkey', 'json', 'push', 'pull', 'push_sightings', 'push_rules', 'pull_rules', 'submitted_cert', 'submitted_client_cert', 'remote_org_id')
+ ),
+ 'serverSettings' => array(
+ 'description' => "Send a GET request to this endpoint to get a full diagnostic along with all currently set settings of the current instance. This will also include the worker status"
+ )
+ ),
+ 'Sighting' => array(
+ 'add' => array(
+ 'description' => "POST a simplified sighting object in JSON format to this API to add a or a list of sightings. Pass either value(s) or attribute IDs (can be uuids) to identify the target sightings.",
+ 'mandatory' => array('OR' => array('values', 'id')),
+ 'optional' => array('type', 'source', 'timestamp', 'date', 'time')
+ ),
+ 'restSearch' => array(
+ 'description' => "Search MISP sightings using a list of filter parameters and return the data in the JSON format. The search is available on an event, attribute or instance level, just select the scope via the URL (/sighting/restSearch/event vs /sighting/restSearch/attribute vs /sighting/restSearch/). id MUST be provided if context is set.",
+ 'mandatory' => array('returnFormat'),
+ 'optional' => array('id', 'type', 'from', 'to', 'last', 'org_id', 'source', 'includeAttribute', 'includeEvent'),
+ 'params' => array('context')
+ ),
+ ),
+ 'SharingGroup' => array(
+ 'add' => array(
+ 'description' => "POST a Sharing Group object in JSON format to this API to add a Sharing Group. The API will also try to capture attached organisations and servers if applicable to the current user.",
+ 'mandatory' => array('name', 'releasability'),
+ 'optional' => array('description', 'uuid', 'organisation_uuid', 'active', 'created', 'modified', 'roaming', 'Server' => array('url', 'name', 'all_orgs'), 'Organisation' => array('uuid', 'name', 'extend'))
+ ),
+ 'edit' => array(
+ 'description' => "POST a Sharing Group object in JSON format to this API to edit a Sharing Group. The API will also try to capture attached organisations and servers if applicable to the current user.",
+ 'mandatory' => array(),
+ 'optional' => array('name', 'releasability', 'description', 'uuid', 'organisation_uuid', 'active', 'created', 'modified', 'roaming', 'SharingGroupServer' => array('url', 'name', 'all_orgs'), 'SharingGroupOrg' => array('uuid', 'name', 'extend'))
+ )
+ ),
+ 'Tag' => array(
+ 'add' => array(
+ 'description' => "POST a Tag object in JSON format to this API to create a new tag.",
+ 'mandatory' => array('name'),
+ 'optional' => array('colour', 'exportable', 'hide_tag', 'org_id', 'user_id')
+ ),
+ 'edit' => array(
+ 'description' => "POST or PUT a Tag object in JSON format to this API to create a edit an existing tag.",
+ 'optional' => array('name', 'colour', 'exportable', 'hide_tag', 'org_id', 'user_id'),
+ 'params' => array('tag_id')
+ ),
+ 'removeTag' => array(
+ 'description' => "POST a request object in JSON format to this API to create detach a tag from an event. #FIXME Function does not exists",
+ 'mandatory' => array('event', 'tag'),
+ 'params' => array('tag_id')
+ ),
+ 'attachTagToObject' => array(
+ 'description' => "Attach a Tag to an object, refenced by an UUID. Tag can either be a tag id or a tag name.",
+ 'mandatory' => array('uuid', 'tag'),
+ )
+ ),
+ 'User' => array(
+ 'admin_add' => array(
+ 'description' => "POST a User object in JSON format to this API to create a new user.",
+ 'mandatory' => array('email', 'org_id', 'role_id'),
+ 'optional' => array('password', 'external_auth_required', 'external_auth_key', 'enable_password', 'nids_sid', 'server_id', 'gpgkey', 'certif_public', 'autoalert', 'contactalert', 'disabled', 'change_pw', 'termsaccepted', 'newsread')
+ ),
+ 'admin_edit' => array(
+ 'description' => "POST a User object in JSON format to this API to edit a user.",
+ 'optional' => array('email', 'org_id', 'role_id', 'password', 'external_auth_required', 'external_auth_key', 'enable_password', 'nids_sid', 'server_id', 'gpgkey', 'certif_public', 'autoalert', 'contactalert', 'disabled', 'change_pw', 'termsaccepted', 'newsread')
+ ),
+ 'admin_quickEmail' => array(
+ 'description' => "POST a body and a subject in a JSON to send an e-mail through MISP to the user ID given in the URL",
+ 'mandatory' => array('subject', 'body')
+ ),
+ 'change_pw' => array(
+ 'description' => "POST a password via a JSON object containing the password key to reset the given user\'s password.",
+ 'mandatory' => array('password')
+ ),
+ 'statistics' => array(
+ 'description' => 'Simply GET the url endpoint to view the API output of the statistics API. Additional statistics are available via the following tab-options similar to the UI: data, orgs, users, tags, attributehistogram, sightings, attackMatrix',
+ 'params' => array('tab'),
+ 'http_method' => 'GET'
+ )
+ ),
+ 'UserSetting' => array(
+ 'setSetting' => array(
+ 'description' => "POST a User setting object in JSON format to this API to create a new setting or update the equivalent existing setting. Admins/site admins can specify a user ID besides their own.",
+ 'mandatory' => array('setting', 'value'),
+ 'optional' => array('user_id')
+ ),
+ 'delete' => array(
+ 'description' => "POST or DELETE to this API to delete an existing setting.",
+ 'params' => array('id')
+ )
+ ),
+ 'Warninglist' => array(
+ 'checkValue' => array(
+ 'description' => "POST a JSON list with value(s) to check against the warninglists to get a JSON dictionary as a response with any hits, if there are any (with the key being the passed value triggering a warning).",
+ 'mandatory' => array('[]')
+ ),
+ 'toggleEnable' => array(
+ 'description' => "POST a json object with a single or a list of warninglist IDsIDs, or alternatively a (list of) substring(s) that match the names of warninglist(s) to toggle whether they're enabled or disabled. Specify the optional enabled boolean flag if you would like to enforce the outcome state. Not setting this flag will just toggle the current state.",'mandatory' => array('id'),
+ 'optional' => array('id', 'name', 'enabled')
+ )
+ )
+ );
+
+ private $__scopedFieldsConstraint = array();
+
+ public function initialize(array $config): void {
+ $this->__configureFieldConstraints();
+ $this->Controller = $this->getController();
+ }
+
+ public function getAllApisFieldsConstraint($user)
+ {
+ $this->__setup();
+ $result = array();
+ foreach ($this->__scopedFieldsConstraint as $controller => $actions) {
+ $controller = Inflector::tableize($controller);
+ foreach ($actions as $action => $data) {
+ if ($this->ACL->checkAccess($user, $controller, $action, true) === true) {
+ $admin_routing = '';
+ if (substr($action, 0, 6) === 'admin_') {
+ $action = substr($action, 6);
+ $admin_routing = 'admin/';
+ }
+ $url = '/' . $admin_routing . $controller . '/' . $action;
+ $result[$url] = $data;
+ }
+ }
+ }
+ return $result;
+ }
+
+ public function getAllApis($user)
+ {
+ $this->__setup();
+ $result = array();
+ foreach ($this->__descriptions as $controller => $actions) {
+ $controller = Inflector::tableize($controller);
+ foreach ($actions as $action => $data) {
+ if ($this->ACL->checkAccess($user, $controller, $action, true) === true) {
+ $admin_routing = '';
+ if (substr($action, 0, 6) === 'admin_') {
+ $action = substr($action, 6);
+ $admin_routing = 'admin/';
+ }
+ $data['api_name'] = '[' . $controller . '] ' . $action;
+ $data['controller'] = $controller;
+ $data['action'] = $action;
+ $data['body'] = array();
+ $filter_types = array('mandatory', 'optional');
+ foreach ($filter_types as $filter_type) {
+ if (!empty($data[$filter_type])) {
+ foreach ($data[$filter_type] as $filter_items) {
+ if (!is_array($filter_items)) {
+ $filter_items = array($filter_items);
+ }
+ foreach ($filter_items as $filter) {
+ if ($filter === lcfirst($filter)) {
+ $data['body'][$filter] = $filter_type;
+ } else {
+ $data['body'][$filter] = array($filter_type);
+ }
+ }
+ }
+ }
+ }
+ $data['body'] = json_encode($data['body'], JSON_PRETTY_PRINT);
+ $url = '/' . $admin_routing . $controller . '/' . $action;
+ $data['url'] = $url;
+ if (!empty($data['params'])) {
+ foreach ($data['params'] as $param) {
+ $data['url'] .= '/[' . $param . ']';
+ }
+ }
+ $result[$url] = $data;
+ }
+ }
+ }
+ return $result;
+ }
+
+ // use a relative path to check if the current api has a description
+ public function getApiInfo($relative_path)
+ {
+ $this->__setup();
+ $relative_path = trim($relative_path, '/');
+ $relative_path = explode('/', $relative_path);
+ $admin = false;
+ if (count($relative_path) >= 2) {
+ if ($relative_path[0] == 'admin') {
+ if (count($relative_path) < 3) {
+ return '[]';
+ }
+ $admin = true;
+ $relative_path = array_slice($relative_path, 1);
+ }
+ $relative_path[0] = Inflector::camelize(Inflector::singularize($relative_path[0]));
+ if ($admin) {
+ $relative_path[1] = 'admin_' . $relative_path[1];
+ }
+ if (isset($this->__descriptions[$relative_path[0]][$relative_path[1]])) {
+ $temp = $this->__descriptions[$relative_path[0]][$relative_path[1]];
+ } else {
+ $temp = array();
+ }
+ if (empty($temp)) {
+ return '[]';
+ }
+ return json_encode(array('api_info' => $temp), JSON_PRETTY_PRINT);
+ }
+ return '[]';
+ }
+
+ public function saveFailResponse($controller, $action, $id = false, $validationErrors, $format = false)
+ {
+ $this->autoRender = false;
+ $response = array();
+ $action = $this->__dissectAdminRouting($action);
+ $stringifiedAction = $action['action'];
+ if (isset($this->__convertActionToMessage[$controller][$action['action']])) {
+ $stringifiedAction = $this->__convertActionToMessage[$controller][$action['action']];
+ }
+ $response['saved'] = false;
+ $response['name'] = 'Could not ' . $stringifiedAction . ' ' . Inflector::singularize($controller);
+ $response['message'] = $response['name'];
+ $response['url'] = $this->__generateURL($action, $controller, $id);
+ $response['errors'] = $validationErrors;
+ return $this->__sendResponse($response, 403, $format);
+ }
+
+ public function saveSuccessResponse($controller, $action, $id = false, $format = false, $message = false)
+ {
+ $action = $this->__dissectAdminRouting($action);
+ if (!$message) {
+ $message = Inflector::singularize($controller) . ' ' . $action['action'] . ((substr($action['action'], -1) == 'e') ? 'd' : 'ed');
+ }
+ $response['saved'] = true;
+ $response['success'] = true;
+ $response['name'] = $message;
+ $response['message'] = $response['name'];
+ $response['url'] = $this->__generateURL($action, $controller, $id);
+ return $this->__sendResponse($response, 200, $format);
+ }
+
+ private function __sendResponse($response, $code, $format = false, $raw = false, $download = false, $headers = array())
+ {
+ if (strtolower($format) === 'application/xml' || strtolower($format) === 'xml') {
+ if (!$raw) {
+ if (isset($response[0])) {
+ if (count(array_keys($response[0])) == 1) {
+ $key = array_keys($response[0])[0];
+ $rearrange = array();
+ foreach ($response as $k => $v) {
+ $rearrange[$key][] = $v[$key];
+ }
+ $response = $rearrange;
+ }
+ }
+ $response = array('response' => $response);
+ $response = Xml::fromArray($response, array('format' => 'tags'));
+ $response = $response->asXML();
+ }
+ $type = 'xml';
+ } elseif (strtolower($format) == 'openioc') {
+ $type = 'xml';
+ } elseif (strtolower($format) == 'csv') {
+ $type = 'csv';
+ } else {
+ if (empty($format)) {
+ $type = 'json';
+ } else {
+ $type = $format;
+ }
+ if (!$raw) {
+ if (is_string($response)) {
+ $response = array('message' => $response);
+ }
+ if (Configure::read('debug') > 1 && !empty($this->Controller->sql_dump)) {
+ $this->Log = ClassRegistry::init('Log');
+ if ($this->Controller->sql_dump === 2) {
+ $response = array('sql_dump' => $this->Log->getDataSource()->getLog(false, false));
+ } else {
+ $response['sql_dump'] = $this->Log->getDataSource()->getLog(false, false);
+ }
+ }
+ $response = json_encode($response, JSON_PRETTY_PRINT);
+ } else {
+ if (Configure::read('debug') > 1 && !empty($this->Controller->sql_dump)) {
+ $this->Log = ClassRegistry::init('Log');
+ if ($this->Controller->sql_dump === 2) {
+ $response = json_encode(array('sql_dump' => $this->Log->getDataSource()->getLog(false, false)));
+ } else {
+ $response = substr_replace(
+ $response,
+ sprintf(', "sql_dump": %s}', json_encode($this->Log->getDataSource()->getLog(false, false))),
+ -2
+ );
+ }
+ }
+ }
+ }
+ $cakeResponse = new \Cake\Http\Response();
+ $cakeResponse = $cakeResponse->withType($type);
+ $cakeResponse = $cakeResponse->withStatus($code);
+ $cakeResponse = $cakeResponse->withStringBody($response);
+
+ if (Configure::read('Security.allow_cors')) {
+ $headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Authorization, Accept";
+ $headers["Access-Control-Allow-Methods"] = "*";
+ $headers["Access-Control-Allow-Origin"] = explode(',', Configure::read('Security.cors_origins'));
+ $headers["Access-Control-Expose-Headers"] = ["X-Result-Count"];
+ }
+ if (!empty($this->headers)) {
+ foreach ($this->headers as $key => $value) {
+ $cakeResponse = $cakeResponse->withHeader($key, $value);
+ }
+ }
+ if (!empty($headers)) {
+ foreach ($headers as $key => $value) {
+ $cakeResponse = $cakeResponse->withHeader($key, $value);
+ }
+ }
+ if (!empty($deprecationWarnings)) {
+ $cakeResponse = $cakeResponse->withHeader('X-Deprecation-Warning', $deprecationWarnings);
+ }
+ if ($download) {
+ $cakeResponse = $cakeResponse->withDownload($download);
+ }
+
+ return $cakeResponse;
+ }
+
+ private function __generateURL($action, $controller, $id)
+ {
+ $controller = Inflector::underscore(Inflector::pluralize($controller));
+ return ($action['admin'] ? '/admin' : '') . '/' . $controller . '/' . $action['action'] . ($id ? '/' . $id : '');
+ }
+
+ private function __dissectAdminRouting($action)
+ {
+ $admin = false;
+ if (strlen($action) > 6 && substr($action, 0, 6) == 'admin_') {
+ $action = substr($action, 6);
+ $admin = true;
+ }
+ return array('action' => $action, 'admin' => $admin);
+ }
+
+ public function viewData($data, $format = false, $errors = false, $raw = false, $download = false, $headers = array())
+ {
+ if (!empty($errors)) {
+ $data['errors'] = $errors;
+ }
+ return $this->__sendResponse($data, 200, $format, $raw, $download, $headers);
+ }
+
+ public function sendFile($path, $format = false, $download = false, $name = 'download')
+ {
+ $cakeResponse = new \Cake\Http\Response();
+ $cakeResponse = $cakeResponse->withStatus = 200;
+ $cakeResponse = $cakeResponse->withType = $format;
+ $cakeResponse = $cakeResponse->withDownload($path, array('download' => true, 'name' => $name));
+ return $cakeResponse;
+ }
+
+ public function throwException($code, $message, $url = '', $format = false, $raw = false, $headers = array())
+ {
+ $message = array(
+ 'name' => $message,
+ 'message' => $message,
+ 'url' => $url
+ );
+ return $this->__sendResponse($message, $code, $format, $raw, false, $headers);
+ }
+
+ public function setHeader($header, $value)
+ {
+ $this->headers[$header] = $value;
+ }
+
+ public function describe($controller, $action, $id = false, $format = false)
+ {
+ $this->__setup();
+ $actionArray = $this->__dissectAdminRouting($action);
+ $response['name'] = $this->__generateURL($actionArray, $controller, false) . ' API description';
+ $response['description'] = isset($this->__descriptions[Inflector::singularize($controller)][$action]['description']) ? $this->__descriptions[Inflector::singularize($controller)][$action]['description'] : 'This API is not accessible via GET requests.';
+ if (isset($this->__descriptions[Inflector::singularize($controller)][$action]['mandatory'])) {
+ $response['mandatory_fields'] = $this->__descriptions[Inflector::singularize($controller)][$action]['mandatory'];
+ }
+ if (isset($this->__descriptions[Inflector::singularize($controller)][$action]['optional'])) {
+ $response['optional_fields'] = $this->__descriptions[Inflector::singularize($controller)][$action]['optional'];
+ }
+ $params = '';
+ if (!empty($this->__descriptions[Inflector::singularize($controller)][$action]['params'])) {
+ foreach ($this->__descriptions[Inflector::singularize($controller)][$action]['params'] as $k => $param) {
+ $params .= ($k > 0 ? '/': '') . '[' . $param . ']';
+ }
+ }
+ $response['url'] = $this->__generateURL($actionArray, $controller, $params);
+ return $this->__sendResponse($response, 200, $format);
+ }
+
+ private function __setup()
+ {
+ if (!$this->__setup) {
+ $scopes = array('Event', 'Attribute', 'Sighting');
+ foreach ($scopes as $scope) {
+ $this->{$scope} = ClassRegistry::init($scope);
+ $this->__descriptions[$scope]['restSearch'] = array(
+ 'description' => $this->__descriptions[$scope]['restSearch']['description'],
+ 'returnFormat' => array_keys($this->{$scope}->validFormats),
+ 'mandatory' => $this->__descriptions[$scope]['restSearch']['mandatory'],
+ 'optional' => $this->__descriptions[$scope]['restSearch']['optional'],
+ 'params' => $this->__descriptions[$scope]['restSearch']['params']
+ );
+ }
+ $this->__setupFieldsConstraint();
+ }
+ return true;
+ }
+
+ private $__fieldConstraint = array();
+
+ // default value and input for API field
+ private function __configureFieldConstraints()
+ {
+ $this->__fieldsConstraint = array(
+ 'action' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array('action1'),
+ 'help' => __('The action that the user performed')
+ ),
+ 'active' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Is the sharing group selectable (active) when chosing distribution')
+ ),
+ 'all' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'help' => __('Search for a full or a substring (delimited by % for substrings) in the event info, event tags, attribute tags, attribute values or attribute comment fields')
+ ),
+ 'all_orgs' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('All organisations contained on the instance will be part of the sharing group')
+ ),
+ 'allow_hard_delete' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('hard-delete already soft-deleted attributes')
+ ),
+ 'analysis' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'values' => array( 0 => 'Initial', 1 => 'Ongoing', 2 => 'Completed'),
+ 'help' => __('Maturity of the event')
+ ),
+ 'anonymise' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'operators' => array('equal'),
+ 'help' => __('Anonymise the information regarding the server on which the request was issued')
+ ),
+ 'attribute' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Filter on attribute value')
+ ),
+ 'authkey' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The authorisation key found on the external server')
+ ),
+ 'autoalert' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The user receive alerts when events are published')
+ ),
+ 'body' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The email\'s body')
+ ),
+ 'caching_enabled' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The feed is cached')
+ ),
+ 'category' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'values' => array('categ1'),
+ ),
+ 'certif_public' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('A valid x509 certificate ')
+ ),
+ 'change' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The text contained in the change field')
+ ),
+ 'change_pw' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The user will be prompted the change the password')
+ ),
+ 'colour' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('A valid hexadecimal colour `#ffffff`')
+ ),
+ 'comment' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal')
+ ),
+ 'contacts' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Contact details for the organisation')
+ ),
+ 'contactalert' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The user receive alerts from `contact reporter` requests')
+ ),
+ 'created' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ ),
+ 'data' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Base64 encoded file contents')
+ ),
+ 'date' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ 'help' => __('The user set date field on the event level. If you are using restSearch, you can use any of the valid time related filters (examples: 7d, timestamps, [14d, 7d] for ranges, etc.)')
+ ),
+ 'datefrom' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ ),
+ 'dateuntil' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ ),
+ 'decayingModel' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'unique' => true,
+ 'help' => 'Specify the decaying model from which the decaying score should be calculated'
+ ),
+ 'default_role' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The role is a default role (selected by default)')
+ ),
+ 'delete_local_file' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Remove file after ingestion')
+ ),
+ 'deleted' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include deleted elements')
+ ),
+ 'delta_merge' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Merge attributes (only add new attribute, remove revoked attributes)')
+ ),
+ 'description' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ ),
+ 'disabled' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Disable the user account')
+ ),
+ 'distribution' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => ['equal', 'not_equal'],
+ 'values' => array(0 => 'dist1'),
+ ),
+ 'email' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Filter on user email')
+ ),
+ 'enable_password' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Set the password manually')
+ ),
+ 'enabled' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'encrypt' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('When uploading malicious samples, set this flag to tell MISP to encrpyt the sample and extract the file hashes. This will create a MISP object with the appropriate attributes.')
+ ),
+ //'enforceWarningList' => array(
+ // 'input' => 'radio',
+ // 'type' => 'integer',
+ // 'values' => array(1 => 'True', 0 => 'False' )
+ //),
+ 'enforceWarninglist' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Should the warning list be enforced. Adds `blocked` field for matching attributes')
+ ),
+ 'event_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'event_timestamp' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('The timestamp at which the event was last modified')
+ ),
+ 'attribute_timestamp' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('The timestamp at which the attribute was last modified')
+ ),
+ 'eventid' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'eventinfo' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Quick event description')
+ ),
+ 'exportable' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The tag is exported when synchronising with other instances')
+ ),
+ 'excludeDecayed' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => 'Should the decayed elements by excluded'
+ ),
+ 'excludeLocalTags' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Exclude local tags from the export')
+ ),
+ 'extend' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The organisation have write access to this sharing group (they can add/remove other organisation)')
+ ),
+ 'external_auth_required' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('An external authorisation is required for this user')
+ ),
+ 'external_auth_key' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('A valid external auth key')
+ ),
+ 'first_seen' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => 'A valid ISO 8601 datetime format, up to milli-seconds. i.e.: 2019-06-13T15:56:56.856074+02:00'
+ ),
+ 'fixed_event' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'values' => array( 0 => 'New Event Each Pull', 1 => 'Fixed Event'),
+ 'help' => __('target_event option might be considered')
+ ),
+ 'from' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ 'help' => __('The date from which the event was published')
+ ),
+ 'gpgkey' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('A valid GPG key')
+ ),
+ 'hasproposal' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The event contains proposals')
+ ),
+ 'headers' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Headers to be passed with the requests. All separated by `\n`')
+ ),
+ 'hide_tag' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The tag is hidden (not selectable)')
+ ),
+ 'id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'includeAttribute' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include matching attributes in the response')
+ ),
+ 'includeDecayScore' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => 'Include all enabled decaying score'
+ ),
+ 'includeEvent' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include matching events in the response')
+ ),
+ 'includeEventUuid' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include matching eventUuids in the response')
+ ),
+ 'includeEventTags' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include tags of matching events in the response')
+ ),
+ 'includeFullModel' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => 'Include all model information of matching events in the response'
+ ),
+ 'includeProposals' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Include proposals of matching events in the response')
+ ),
+ 'info' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Quick event description')
+ ),
+ 'input_source' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array( 'network' => 'Network', 'local' => 'Local'),
+ 'help' => __('Specify whether the source (url field) is a directory (local) or an geniun url (network)')
+ ),
+ 'ip' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The IP of a login attempt')
+ ),
+ 'json' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('JSON containing ID, UUID and name')
+ ),
+ 'last' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Events published within the last x amount of time, where x can be defined in days, hours, minutes (for example 5d or 12h or 30m)')
+ ),
+ 'last_seen' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => 'A valid ISO 8601 datetime format, up to milli-seconds. i.e.: 2019-06-13T15:56:56.856074+02:00'
+ ),
+ 'limit' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('Limit on the pagination')
+ ),
+ 'local' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('If the organisation should have access to this instance, make sure that the Local organisation setting is checked. If you would only like to add a known external organisation for inclusion in sharing groups, uncheck the Local organisation setting.')
+ ),
+ 'lookup_visible' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The lookup will not be visible in the feed correlation')
+ ),
+ 'message' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Message to be included')
+ ),
+ 'metadata' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Will only return the metadata of the given query scope, contained data is omitted.')
+ ),
+ 'minimal' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Will only return id, timestamp, published and uuid')
+ ),
+ 'mock' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'operators' => array('equal'),
+ 'help' => __('Mock the query')
+ ),
+ 'model' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array('Attribute', 'Event', 'EventBlacklist', 'EventTag', 'MispObject', 'Organisation', 'Post', 'Regexp', 'Role', 'Server', 'ShadowAttribute', 'SharingGroup', 'Tag', 'Task', 'Taxonomy', 'Template', 'Thread', 'User', 'Whitelist'),
+ ),
+ 'model_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ ),
+ 'modified' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ 'help' => __('The last time the sharing group was modified')
+ ),
+ 'name' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ ),
+ 'nationality' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array('nat1'),
+ ),
+ 'newsread' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('The news are read')
+ ),
+ 'nids_sid' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('The unique Signature Identification')
+ ),
+ 'org' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Can be either the ORG_ID or the ORG_NAME')
+ ),
+ 'org_description' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Describe the organisation')
+ ),
+ 'org_name' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('Organisation identifier (name)')
+ ),
+ 'org_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ ),
+ 'org_uuid' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Globally used uuid of an organisation')
+ ),
+ 'organisation_uuid' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Globally used uuid of an organisation')
+ ),
+ 'override_ids' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The IDS flags will be set to off for this feed')
+ ),
+ 'page' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 1, 'step' => 1),
+ 'help' => __('Page number for the pagination')
+ ),
+ 'password' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The hardcoded password')
+ ),
+ 'perm_admin' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_audit' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_auth' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_delegate' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_regexp_access' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_sharing_group' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_sighting' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_site_admin' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_sync' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_tag_editor' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_tagger' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'perm_template' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'permission' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array(0 =>'Read Only', 1 => 'Manage Own Events', 2 => 'Manage Organisation Events', 3 => 'Manage and Publish Organisation Events'),
+ ),
+ 'provider' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('The name of the feed provider')
+ ),
+ 'publish' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('The event will be published')
+ ),
+ 'publish_timestamp' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'published' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'publishtimestamp' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'pull' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Allow the download of events and their attribute from the server')
+ ),
+ 'push' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Allow the upload of events and their attribute to the server')
+ ),
+ 'push_sightings' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Allow the upload of sightings to the server')
+ ),
+ 'releasability' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Concise summary for who this sharing group is releasable to')
+ ),
+ 'remote_org_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ ),
+ 'returnFormat' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array('json', 'openioc', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix', 'stix2'),
+ ),
+ 'roaming' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Pass the event to any connected instance where the sync connection is tied to an organisation contained in the SG organisation list')
+ ),
+ 'role_id' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array(0 => 'role1'),
+ ),
+ 'score' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1, 'max' => 100),
+ 'help' => 'An alias to override on-the-fly the threshold of the decaying model'
+ ),
+ 'searchall' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Search for a full or a substring (delimited by % for substrings) in the event info, event tags, attribute tags, attribute values or attribute comment fields')
+ ),
+ 'sector' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The sector of the organisation')
+ ),
+ 'server_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ ),
+ 'sgReferenceOnly' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'help' => __('Will only return the sharing group ID')
+ ),
+ 'sharing_group_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'sharinggroup' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('Sharing group ID')
+ ),
+ 'source' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The source of the Sighting (e.g. honeypot_1)')
+ ),
+ 'source_format' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'values' => array( 'misp' => 'MISP Feed', 'freetext' => 'Freetext Parsed Feed', 'csv' => 'CSV Parsed Feed')
+ ),
+ 'subject' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The email\'s subject')
+ ),
+ 'submitted_cert' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Base64 encoded certificate')
+ ),
+ 'submitted_client_cert' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Base64 encoded certificate')
+ ),
+ 'sync' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' ),
+ 'operators' => array('equal')
+ ),
+ 'tag' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ ),
+ 'tag_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('A tad ID to attach to created events')
+ ),
+ 'tags' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'unique' => false,
+ ),
+ 'target_event' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ 'help' => __('The provided ID will be reused as an existing event')
+ ),
+ 'termsaccepted' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+ 'threat_level_id' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => ['equal', 'not_equal'],
+ 'values' => array( 1 => 'High', 2 => 'Medium', 3 => 'Low', 4 => 'Undefined')
+ ),
+ 'threatlevel' => array(
+ 'input' => 'select',
+ 'type' => 'integer',
+ 'operators' => ['equal', 'not_equal'],
+ 'values' => array( 1 => 'High', 2 => 'Medium', 3 => 'Low', 4 => 'Undefined')
+ ),
+ 'time' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Time of the sighting with the form `h:i:s`')
+ ),
+ 'timestamp' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal', 'not_equal'),
+ 'validation' => array('min' => 0, 'step' => 1)
+ ),
+ 'title' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('The title of the log')
+ ),
+ 'to' => array(
+ 'type' => 'date',
+ 'validation' => array( 'format' => 'YYYY-MM-DD' ),
+ 'plugin' => 'datepicker',
+ 'plugin_config' => array(
+ 'format' => 'yyyy/mm/dd',
+ 'todayBtn' => 'linked',
+ 'todayHighlight' => true,
+ 'autoclose' => true
+ ),
+ 'help' => __('The date to which the event was published')
+ ),
+ 'to_ids' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False'),
+ 'help' => __('The state of the `to_ids` flag')
+ ),
+ 'type' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ 'help' => __('The type of the attribute')
+ ),
+ 'url' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal'),
+ ),
+ 'user_id' => array(
+ 'input' => 'number',
+ 'type' => 'integer',
+ 'operators' => array('equal'),
+ 'validation' => array('min' => 0, 'step' => 1),
+ ),
+ 'uuid' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal')
+ ),
+ 'value' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal', 'not_equal')
+ ),
+ 'values' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'unique' => false,
+ 'help' => __('Placeholder containing values to sight')
+ ),
+ 'withAttachments' => array(
+ 'input' => 'radio',
+ 'type' => 'integer',
+ 'values' => array(1 => 'True', 0 => 'False' )
+ ),
+
+ // Not supported yet
+ '[]' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported (warninglist->checkvalues) expect an array')
+ ),
+ 'event' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported (removeTag)')
+ ),
+ 'push_rules' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'pull_rules' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'rules' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+
+ 'settings' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'network_name' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'network_json' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'Attribute' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'Object' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ 'EventTag' => array(
+ 'input' => 'select',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ ),
+ 'Shadow_Attribute' => array(
+ 'input' => 'text',
+ 'type' => 'string',
+ 'operators' => array('equal'),
+ 'help' => __('Not supported')
+ ),
+ );
+ }
+
+ // create dictionnary mapping between fields constraints and scope->action
+ private function __setupFieldsConstraint() {
+ foreach ($this->__descriptions as $scope => $desc) {
+ foreach ($desc as $action => $params) {
+ $fieldsConstraint = array();
+ foreach ($params as $paramType => $field) {
+ if ($paramType == 'optional' || $paramType == 'mandatory') {
+ $fields = array_values($field);
+ if (!empty($fields)) {
+ foreach($fields as $field) {
+ if (is_array($field)) {
+ foreach($field as $sf) {
+ $fieldsConstraint[$sf] = $this->__fieldsConstraint[$sf];
+ $label = $scope . '.' . $sf;
+ $fieldsConstraint[$sf]['id'] = $label;
+ $fieldsConstraint[$sf]['label'] = $label;
+ }
+ } else {
+ if (!empty($this->__fieldsConstraint[$field])) {
+ $fieldsConstraint[$field] = $this->__fieldsConstraint[$field];
+ $label = $scope . '.' . $field;
+ $fieldsConstraint[$field]['id'] = $label;
+ $fieldsConstraint[$field]['label'] = $label;
+ }
+ }
+
+ // add dynamic data and overwrite name collisions
+ switch($field) {
+ case "returnFormat":
+ $this->__overwriteReturnFormat($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "type":
+ $this->__overwriteType($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "category":
+ $this->__overwriteCategory($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "decayingModel":
+ $this->__overwriteDecayingModel($scope, $fieldsConstraint[$field]);
+ break;
+ case "distribution":
+ $this->__overwriteDistribution($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "tag":
+ case "tags":
+ case "EventTag":
+ $this->__overwriteTags($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "nationality":
+ $this->__overwriteNationality($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "action":
+ $this->__overwriteAction($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "role_id":
+ $this->__overwriteRoleId($scope, $action, $fieldsConstraint[$field]);
+ break;
+ case "first_seen":
+ case "last_seen":
+ $this->__overwriteSeen($scope, $action, $fieldsConstraint[$field]);
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+ }
+ }
+ $this->__scopedFieldsConstraint[$scope][$action] = $fieldsConstraint;
+ }
+ }
+ }
+
+ // Fetch the correct values based on the scope, then overwrite default value
+ private function __overwriteReturnFormat($scope, $action, &$field) {
+ switch($scope) {
+ case "Attribute":
+ $field['values'] = array_keys(ClassRegistry::init($scope)->validFormats);
+ break;
+ case "Event":
+ $field['values'] = array_keys(ClassRegistry::init($scope)->validFormats);
+ break;
+ }
+ }
+ private function __overwriteType($scope, $action, &$field) {
+ $field['input'] = 'select';
+ switch($scope) {
+ case "Attribute":
+ $field['values'] = array_keys(ClassRegistry::init($scope)->typeDefinitions);
+ break;
+ case "Event":
+ $field['values'] = array_keys(ClassRegistry::init("Attribute")->typeDefinitions);
+ break;
+ case "Sighting":
+ $field['values'] = ClassRegistry::init($scope)->type;
+ break;
+ default:
+ $field['input'] = 'text';
+ break;
+ }
+ }
+
+ private function __overwriteCategory($scope, $action, &$field) {
+ $field['values'] = array_keys(ClassRegistry::init("Attribute")->categoryDefinitions);
+ }
+ private function __overwriteDistribution($scope, $action, &$field) {
+ $field['values'] = array();
+ foreach(ClassRegistry::init("Attribute")->distributionLevels as $d => $text) {
+ $field['values'][] = array('label' => $text, 'value' => $d);
+ }
+ }
+ private function __overwriteDecayingModel($scope, &$field) {
+ $this->{$scope} = ClassRegistry::init("DecayingModel");
+ $models = $this->{$scope}->find('list', array(
+ 'recursive' => -1,
+ 'fields' => array('name')
+ ));
+ $field['values'] = array();
+ foreach($models as $i => $model_name) {
+ $field['values'][] = array('label' => h($model_name), 'value' => $i);
+ }
+ }
+ private function __overwriteTags($scope, $action, &$field) {
+ $this->{$scope} = ClassRegistry::init("Tag");
+ $tags = $this->{$scope}->find('list', array(
+ 'recursive' => -1,
+ 'fields' => array('name')
+ ));
+ foreach($tags as $i => $tag) {
+ $tagname = htmlspecialchars($tag);
+ $tags[$tagname] = $tagname;
+ unset($tags[$i]);
+ }
+ $field['values'] = $tags;
+ }
+ private function __overwriteNationality($scope, $action, &$field) {
+ $field['values'] = ClassRegistry::init("Organisation")->countries;
+ }
+ private function __overwriteAction($scope, $action, &$field) {
+ $field['values'] = array_keys(ClassRegistry::init("Log")->actionDefinitions);
+ }
+ private function __overwriteRoleId($scope, $action, &$field) {
+ $this->{$scope} = ClassRegistry::init("Role");
+ $roles = $this->{$scope}->find('list', array(
+ 'recursive' => -1,
+ 'fields' => array('name')
+ ));
+ $field['values'] = $roles;
+ }
+ private function __overwriteSeen($scope, $action, &$field) {
+ if ($action == 'restSearch') {
+ $field['help'] = __('Seen within the last x amount of time, where x can be defined in days, hours, minutes (for example 5d or 12h or 30m)');
+ }
+ }
+
+}
diff --git a/app/src/Controller/EncryptionKeysController.php b/app/src/Controller/EncryptionKeysController.php
new file mode 100644
index 0000000..412c117
--- /dev/null
+++ b/app/src/Controller/EncryptionKeysController.php
@@ -0,0 +1,117 @@
+EncryptionKeys->find();
+ if (!empty($owner_type)) {
+ $query->where(['owner_type' => $owner_type]);
+ }
+ if (!empty($owner_id)) {
+ $query->where(['owner_id' => $owner_id]);
+ }
+ if ($this->_isRest()) {
+ $alignments = $query->all();
+ return $this->RestResponse->viewData($alignments, 'json');
+ } else {
+ $this->loadComponent('Paginator');
+ $encrpyion_keys = $this->Paginator->paginate($query);
+ $this->set('data', $encrpyion_keys);
+ $this->set('metaGroup', 'ContactDB');
+ }
+ }
+
+ public function delete($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid encrpyion keys.'));
+ }
+ $individual = $this->Alignments->get($id);
+ if ($this->request->is('post') || $this->request->is('delete')) {
+ if ($this->Alignments->delete($individual)) {
+ $message = __('Individual deleted.');
+ if ($this->_isRest()) {
+ $individual = $this->Alignments->get($id);
+ return $this->RestResponse->saveSuccessResponse('Alignments', 'delete', $id, 'json', $message);
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect($this->referer());
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('scope', 'alignments');
+ $this->set('id', $individual['id']);
+ $this->set('alignment', $individual);
+ $this->viewBuilder()->setLayout('ajax');
+ $this->render('/genericTemplates/delete');
+ }
+
+ public function add($owner_type = false, $owner_id = false)
+ {
+ if (empty($owner_type) && !empty($this->request->getData('owner_type'))) {
+ $owner_type = $this->request->getData('owner_type');
+ }
+ if (empty($owner_id) && !empty($this->request->getData('owner_id'))) {
+ $owner_id = $this->request->getData('owner_id');
+ }
+ if (empty($owner_type) || empty($owner_id)) {
+ throw new NotAcceptableException(__('Invalid input. owner_type and owner_id expected as parameters in the format /encryption_keys/add/[owner_type]/[owner_id] or passed as a JSON.'));
+ }
+ if ($owner_type === 'individual') {
+ $this->loadModel('Individuals');
+ $owner = $this->Individuals->find()->where(['id' => $owner_id])->first();
+ if (empty($owner)) {
+ throw new NotFoundException(__('Invalid owner individual.'));
+ }
+ } else {
+ $this->loadModel('Organisations');
+ $owner = $this->Organisations->find()->where(['id' => $owner_id])->first();
+ if (empty($owner)) {
+ throw new NotFoundException(__('Invalid owner individual.'));
+ }
+ }
+ $encryptionKey = $this->EncryptionKeys->newEmptyEntity();
+ if ($this->request->is('post')) {
+ $this->EncryptionKeys->patchEntity($encryptionKey, $this->request->getData());
+ $encrypionKey['owner_type'] = $owner_type;
+ if ($this->EncryptionKeys->save($encryptionKey)) {
+ $message = __('EncryptionKey added.');
+ if ($this->_isRest()) {
+ $encryptionKey = $this->EncryptionKeys->get($this->EncryptionKeys->id);
+ return $this->RestResponse->viewData($encryptionKey, 'json');
+ } else {
+ $this->Flash->success($message);
+ $this->redirect($this->referer());
+ }
+ } else {
+ $message = __('EncryptionKey could not be added.');
+ if ($this->_isRest()) {
+ return $this->RestResponse->saveFailResponse('EncryptionKeys', 'add', false, $message);
+ } else {
+ $this->Flash->error($message);
+ $this->redirect($this->referer());
+ }
+ }
+ }
+
+ $this->set(compact('owner'));
+ $this->set(compact('encryptionKey'));
+ $this->set(compact('owner_id'));
+ $this->set(compact('owner_type'));
+ $this->set('metaGroup', 'ContactDB');
+ }
+}
diff --git a/app/src/Controller/ErrorController.php b/app/src/Controller/ErrorController.php
new file mode 100644
index 0000000..27dfde5
--- /dev/null
+++ b/app/src/Controller/ErrorController.php
@@ -0,0 +1,70 @@
+loadComponent('RequestHandler');
+ }
+
+ /**
+ * beforeFilter callback.
+ *
+ * @param \Cake\Event\EventInterface $event Event.
+ * @return \Cake\Http\Response|null|void
+ */
+ public function beforeFilter(EventInterface $event)
+ {
+ }
+
+ /**
+ * beforeRender callback.
+ *
+ * @param \Cake\Event\EventInterface $event Event.
+ * @return \Cake\Http\Response|null|void
+ */
+ public function beforeRender(EventInterface $event)
+ {
+ parent::beforeRender($event);
+
+ $this->viewBuilder()->setTemplatePath('Error');
+ }
+
+ /**
+ * afterFilter callback.
+ *
+ * @param \Cake\Event\EventInterface $event Event.
+ * @return \Cake\Http\Response|null|void
+ */
+ public function afterFilter(EventInterface $event)
+ {
+ }
+}
diff --git a/app/src/Controller/IndividualsController.php b/app/src/Controller/IndividualsController.php
new file mode 100644
index 0000000..ed87702
--- /dev/null
+++ b/app/src/Controller/IndividualsController.php
@@ -0,0 +1,155 @@
+Individuals->find();
+ $filterFields = ['uuid', 'email', 'first_name', 'last_name', 'position'];
+ if (!empty($this->request->getQuery('quickFilter'))) {
+ $quickFilter = $this->request->getQuery('quickFilter');
+ $conditions = [];
+ foreach ($filterFields as $field) {
+ $conditions[] = [$field . ' LIKE' => '%' . $quickFilter . '%'];
+ }
+ }
+ $quickFilter = $this->request->getQuery('quickFilter');
+ foreach ($filterFields as $filterField) {
+ $tempFilter = $this->request->getQuery($filterField);
+ if (!empty($tempFilter)) {
+ if (strpos($tempFilter, '%') !== false) {
+ $conditions[] = [$filterField . ' LIKE' => $tempFilter];
+ } else {
+ $conditions[] = [$filterField => $tempFilter];
+ }
+ }
+ }
+ $query->contain(['Alignments' => 'Organisations']);
+ if (!empty($this->request->getQuery('organisation_id'))) {
+ $query->matching('Alignments', function($q) {
+ return $q->where(['Alignments.organisation_id' => $this->request->getQuery('organisation_id')]);
+ });
+ }
+ if (!empty($conditions)) {
+ $query->where($conditions);
+ }
+ if ($this->_isRest()) {
+ $individuals = $query->all();
+ return $this->RestResponse->viewData($individuals, 'json');
+ } else {
+ $this->loadComponent('Paginator');
+ $individuals = $this->Paginator->paginate($query);
+ $this->set('data', $individuals);
+ $this->set('alignmentScope', 'individuals');
+ $this->set('metaGroup', 'ContactDB');
+ }
+ }
+
+ public function add()
+ {
+ $individual = $this->Individuals->newEmptyEntity();
+ if ($this->request->is('post')) {
+ $individual = $this->Individuals->patchEntity($individual, $this->request->getData());
+ if ($this->Individuals->save($individual)) {
+ $message = __('Individual added.');
+ if ($this->_isRest()) {
+ $individual = $this->Individuals->get($id);
+ return $this->RestResponse->viewData($individual, 'json');
+ } else {
+ $this->Flash->success($message);
+ $this->redirect(['action' => 'index']);
+ }
+ } else {
+ $message = __('Individual could not be added.');
+ if ($this->_isRest()) {
+
+ } else {
+ $this->Flash->error($message);
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('individual', $individual);
+ }
+
+ public function view($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $individual = $this->Individuals->get($id, [
+ 'contain' => ['Alignments' => 'Organisations']
+ ]);
+ if ($this->_isRest()) {
+ return $this->RestResponse->viewData($individual, 'json');
+ } else {
+
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('individual', $individual);
+ }
+
+ public function edit($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $individual = $this->Individuals->get($id);
+ if ($this->request->is(['post', 'put'])) {
+ $this->Individuals->patchEntity($individual, $this->request->getData());
+ if ($this->Individuals->save($individual)) {
+ $message = __('Individual updated.');
+ if ($this->_isRest()) {
+ $individual = $this->Individuals->get($id);
+ return $this->RestResponse->viewData($individual, 'json');
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect(['action' => 'index']);
+ }
+ } else {
+ if ($this->_isRest()) {
+
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('individual', $individual);
+ $this->render('add');
+ }
+
+ public function delete($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $individual = $this->Individuals->get($id);
+ if ($this->request->is('post') || $this->request->is('delete')) {
+ if ($this->Individuals->delete($individual)) {
+ $message = __('Individual deleted.');
+ if ($this->_isRest()) {
+ $individual = $this->Individuals->get($id);
+ return $this->RestResponse->saveSuccessResponse('Individuals', 'delete', $id, 'json', $message);
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect($this->referer());
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('scope', 'individuals');
+ $this->set('id', $individual['id']);
+ $this->set('individual', $individual);
+ $this->viewBuilder()->setLayout('ajax');
+ $this->render('/genericTemplates/delete');
+ }
+}
diff --git a/app/src/Controller/OrganisationsController.php b/app/src/Controller/OrganisationsController.php
new file mode 100644
index 0000000..f7704ca
--- /dev/null
+++ b/app/src/Controller/OrganisationsController.php
@@ -0,0 +1,153 @@
+request->getQuery('quickFilter'))) {
+ $quickFilter = $this->request->getQuery('quickFilter');
+ $conditions = [];
+ foreach ($filterFields as $field) {
+ $conditions[] = [$field . ' LIKE' => '%' . $quickFilter . '%'];
+ }
+ }
+ $quickFilter = $this->request->getQuery('quickFilter');
+ foreach ($filterFields as $filterField) {
+ $tempFilter = $this->request->getQuery($filterField);
+ if (!empty($tempFilter)) {
+ if (strpos($tempFilter, '%') !== false) {
+ $conditions[] = [$filterField . ' LIKE' => $tempFilter];
+ } else {
+ $conditions[] = [$filterField => $tempFilter];
+ }
+ }
+ }
+ $query = $this->Organisations->find();
+ $query->contain(['Alignments' => 'Individuals']);
+ if (!empty($this->request->getQuery('individual_id'))) {
+ $query->matching('Alignments', function($q) {
+ return $q->where(['Alignments.individual_id' => $this->request->getQuery('individual_id')]);
+ });
+ }
+ if (!empty($conditions)) {
+ $query->where([
+ 'OR' => $conditions
+ ]);
+ }
+ if ($this->_isRest()) {
+ $organisations = $query->all();
+ return $this->RestResponse->viewData($organisations, 'json');
+ } else {
+ $this->loadComponent('Paginator');
+ $organisations = $this->Paginator->paginate($query);
+ $this->set('data', $organisations);
+ $this->set('metaGroup', 'ContactDB');
+ }
+ }
+
+ public function add()
+ {
+ $organisation = $this->Organisations->newEmptyEntity();
+ if ($this->request->is('post')) {
+ $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData());
+ if ($this->Organisations->save($organisation)) {
+ $message = __('Organisation added.');
+ if ($this->_isRest()) {
+ $organisation = $this->Organisations->get($id);
+ return $this->RestResponse->viewData($organisation, 'json');
+ } else {
+ $this->Flash->success($message);
+ $this->redirect(['action' => 'index']);
+ }
+ } else {
+ $message = __('Organisation could not be added.');
+ if ($this->_isRest()) {
+
+ } else {
+ $this->Flash->error($message);
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('organisation', $organisation);
+ }
+
+ public function view($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $organisation = $this->Organisations->get($id, [
+ 'contain' => ['Alignments' => 'Individuals']
+ ]);
+ if ($this->_isRest()) {
+ return $this->RestResponse->viewData($organisation, 'json');
+ } else {
+
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('organisation', $organisation);
+ }
+
+ public function edit($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $organisation = $this->Organisations->get($id);
+ if ($this->request->is(['post', 'put'])) {
+ $this->Organisations->patchEntity($organisation, $this->request->getData());
+ if ($this->Organisations->save($organisation)) {
+ $message = __('Organisation updated.');
+ if ($this->_isRest()) {
+ $organisation = $this->Organisations->get($id);
+ return $this->RestResponse->viewData($organisation, 'json');
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect(['action' => 'index']);
+ }
+ } else {
+ if ($this->_isRest()) {
+
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('organisation', $organisation);
+ $this->render('add');
+ }
+
+ public function delete($id)
+ {
+ if (empty($id)) {
+ throw new NotFoundException(__('Invalid organisation.'));
+ }
+ $organisation = $this->Organisations->get($id);
+ if ($this->request->is('post') || $this->request->is('delete')) {
+ if ($this->Organisations->delete($organisation)) {
+ $message = __('Organisation deleted.');
+ if ($this->_isRest()) {
+ $organisation = $this->Organisations->get($id);
+ return $this->RestResponse->saveSuccessResponse('Organisations', 'delete', $id, 'json', $message);
+ } else {
+ $this->Flash->success($message);
+ return $this->redirect($this->referer());
+ }
+ }
+ }
+ $this->set('metaGroup', 'ContactDB');
+ $this->set('scope', 'organisations');
+ $this->set('id', $organisation['id']);
+ $this->set('organisation', $organisation);
+ $this->viewBuilder()->setLayout('ajax');
+ $this->render('/genericTemplates/delete');
+ }
+}
diff --git a/app/src/Controller/PagesController.php b/app/src/Controller/PagesController.php
new file mode 100644
index 0000000..5ad4740
--- /dev/null
+++ b/app/src/Controller/PagesController.php
@@ -0,0 +1,75 @@
+redirect('/');
+ }
+ if (in_array('..', $path, true) || in_array('.', $path, true)) {
+ throw new ForbiddenException();
+ }
+ $page = $subpage = null;
+
+ if (!empty($path[0])) {
+ $page = $path[0];
+ }
+ if (!empty($path[1])) {
+ $subpage = $path[1];
+ }
+ $this->set(compact('page', 'subpage'));
+
+ try {
+ return $this->render(implode('/', $path));
+ } catch (MissingTemplateException $exception) {
+ if (Configure::read('debug')) {
+ throw $exception;
+ }
+ throw new NotFoundException();
+ }
+
+ return $this->render();
+ }
+}
diff --git a/app/src/Model/Behavior/.gitkeep b/app/src/Model/Behavior/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/Model/Entity/.gitkeep b/app/src/Model/Entity/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/Model/Entity/Alignment.php b/app/src/Model/Entity/Alignment.php
new file mode 100644
index 0000000..a969770
--- /dev/null
+++ b/app/src/Model/Entity/Alignment.php
@@ -0,0 +1,11 @@
+belongsTo('Individuals');
+ $this->belongsTo('Organisations');
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ $validator
+ ->notEmptyString('individual_id')
+ ->notEmptyString('organisation_id')
+ ->requirePresence(['individual_id', 'organisation_id'], 'create');
+ return $validator;
+ }
+}
diff --git a/app/src/Model/Table/AppTable.php b/app/src/Model/Table/AppTable.php
new file mode 100644
index 0000000..09a5669
--- /dev/null
+++ b/app/src/Model/Table/AppTable.php
@@ -0,0 +1,13 @@
+belongsTo(
+ 'Individuals',
+ [
+ 'foreignKey' => 'owner_id',
+ 'conditions' => ['owner_type' => 'individual']
+ ]
+ );
+ $this->belongsTo(
+ 'Organisations',
+ [
+ 'foreignKey' => 'owner_id',
+ 'conditions' => ['owner_type' => 'organisation']
+ ]
+ );
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ $validator
+ ->notEmptyString('type')
+ ->notEmptyString('encryption_key')
+ ->notEmptyString('uuid')
+ ->notEmptyString('owner_id')
+ ->notEmptyString('owner_type')
+ ->requirePresence(['type', 'encryption_key', 'uuid', 'owner_id', 'owner_type'], 'create');
+ return $validator;
+ }
+}
diff --git a/app/src/Model/Table/IndividualsTable.php b/app/src/Model/Table/IndividualsTable.php
new file mode 100644
index 0000000..743909c
--- /dev/null
+++ b/app/src/Model/Table/IndividualsTable.php
@@ -0,0 +1,32 @@
+hasMany('Alignments');
+ $this->hasMany(
+ 'EncryptionKeys',
+ [
+ 'foreignKey' => 'owner_id',
+ 'conditions' => ['owner_type' => 'individual']
+ ]
+ );
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ $validator
+ ->notEmptyString('email')
+ ->notEmptyString('uuid')
+ ->requirePresence(['email', 'uuid'], 'create');
+ return $validator;
+ }
+}
diff --git a/app/src/Model/Table/OrganisationsTable.php b/app/src/Model/Table/OrganisationsTable.php
new file mode 100644
index 0000000..a7c5439
--- /dev/null
+++ b/app/src/Model/Table/OrganisationsTable.php
@@ -0,0 +1,32 @@
+hasMany('Alignments');
+ $this->hasMany(
+ 'EncryptionKeys',
+ [
+ 'foreignKey' => 'owner_id',
+ 'conditions' => ['owner_type' => 'organisation']
+ ]
+ );
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ $validator
+ ->notEmptyString('name')
+ ->notEmptyString('uuid')
+ ->requirePresence(['name', 'uuid'], 'create');
+ return $validator;
+ }
+}
diff --git a/app/src/Model/Validation/ValidationCollection.php b/app/src/Model/Validation/ValidationCollection.php
new file mode 100644
index 0000000..6d8f84f
--- /dev/null
+++ b/app/src/Model/Validation/ValidationCollection.php
@@ -0,0 +1,13 @@
+response = $this->response->withType('ajax');
+ }
+}
diff --git a/app/src/View/AppView.php b/app/src/View/AppView.php
new file mode 100644
index 0000000..6abc2b1
--- /dev/null
+++ b/app/src/View/AppView.php
@@ -0,0 +1,45 @@
+loadHelper('Html');`
+ *
+ * @return void
+ */
+ public function initialize(): void
+ {
+ parent::initialize();
+ $this->loadHelper('Hash');
+ $this->loadHelper('Paginator', ['templates' => 'cerebrate-pagination-templates']);
+ }
+}
diff --git a/app/src/View/Cell/.gitkeep b/app/src/View/Cell/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/View/Helper/.gitkeep b/app/src/View/Helper/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/View/Helper/FontAwesomeHelper.php b/app/src/View/Helper/FontAwesomeHelper.php
new file mode 100644
index 0000000..9b34bce
--- /dev/null
+++ b/app/src/View/Helper/FontAwesomeHelper.php
@@ -0,0 +1,450 @@
+findNamespace($icon) . ' fa-' . $icon;
+ }
+
+ public function findNamespace($icon)
+ {
+ $fab_icons = array(
+ '500px',
+ 'accessible-icon',
+ 'accusoft',
+ 'acquisitions-incorporated',
+ 'adn',
+ 'adobe',
+ 'adversal',
+ 'affiliatetheme',
+ 'airbnb',
+ 'algolia',
+ 'alipay',
+ 'amazon',
+ 'amazon-pay',
+ 'amilia',
+ 'android',
+ 'angellist',
+ 'angrycreative',
+ 'angular',
+ 'app-store',
+ 'app-store-ios',
+ 'apper',
+ 'apple',
+ 'apple-pay',
+ 'artstation',
+ 'asymmetrik',
+ 'atlassian',
+ 'audible',
+ 'autoprefixer',
+ 'avianex',
+ 'aviato',
+ 'aws',
+ 'bandcamp',
+ 'battle-net',
+ 'behance',
+ 'behance-square',
+ 'bimobject',
+ 'bitbucket',
+ 'bitcoin',
+ 'bity',
+ 'black-tie',
+ 'blackberry',
+ 'blogger',
+ 'blogger-b',
+ 'bluetooth',
+ 'bluetooth-b',
+ 'bootstrap',
+ 'btc',
+ 'buffer',
+ 'buromobelexperte',
+ 'canadian-maple-leaf',
+ 'cc-amazon-pay',
+ 'cc-amex',
+ 'cc-apple-pay',
+ 'cc-diners-club',
+ 'cc-discover',
+ 'cc-jcb',
+ 'cc-mastercard',
+ 'cc-paypal',
+ 'cc-stripe',
+ 'cc-visa',
+ 'centercode',
+ 'centos',
+ 'chrome',
+ 'chromecast',
+ 'cloudscale',
+ 'cloudsmith',
+ 'cloudversify',
+ 'codepen',
+ 'codiepie',
+ 'confluence',
+ 'connectdevelop',
+ 'contao',
+ 'cpanel',
+ 'creative-commons',
+ 'creative-commons-by',
+ 'creative-commons-nc',
+ 'creative-commons-nc-eu',
+ 'creative-commons-nc-jp',
+ 'creative-commons-nd',
+ 'creative-commons-pd',
+ 'creative-commons-pd-alt',
+ 'creative-commons-remix',
+ 'creative-commons-sa',
+ 'creative-commons-sampling',
+ 'creative-commons-sampling-plus',
+ 'creative-commons-share',
+ 'creative-commons-zero',
+ 'critical-role',
+ 'css3',
+ 'css3-alt',
+ 'cuttlefish',
+ 'd-and-d',
+ 'd-and-d-beyond',
+ 'dashcube',
+ 'delicious',
+ 'deploydog',
+ 'deskpro',
+ 'dev',
+ 'deviantart',
+ 'dhl',
+ 'diaspora',
+ 'digg',
+ 'digital-ocean',
+ 'discord',
+ 'discourse',
+ 'dochub',
+ 'docker',
+ 'draft2digital',
+ 'dribbble',
+ 'dribbble-square',
+ 'dropbox',
+ 'drupal',
+ 'dyalog',
+ 'earlybirds',
+ 'ebay',
+ 'edge',
+ 'elementor',
+ 'ello',
+ 'ember',
+ 'empire',
+ 'envira',
+ 'erlang',
+ 'ethereum',
+ 'etsy',
+ 'evernote',
+ 'expeditedssl',
+ 'facebook',
+ 'facebook-f',
+ 'facebook-messenger',
+ 'facebook-square',
+ 'fantasy-flight-games',
+ 'fedex',
+ 'fedora',
+ 'figma',
+ 'firefox',
+ 'first-order',
+ 'first-order-alt',
+ 'firstdraft',
+ 'flickr',
+ 'flipboard',
+ 'fly',
+ 'font-awesome',
+ 'font-awesome-alt',
+ 'font-awesome-flag',
+ 'fonticons',
+ 'fonticons-fi',
+ 'fort-awesome',
+ 'fort-awesome-alt',
+ 'forumbee',
+ 'foursquare',
+ 'free-code-camp',
+ 'freebsd',
+ 'fulcrum',
+ 'galactic-republic',
+ 'galactic-senate',
+ 'get-pocket',
+ 'gg',
+ 'gg-circle',
+ 'git',
+ 'git-square',
+ 'github',
+ 'github-alt',
+ 'github-square',
+ 'gitkraken',
+ 'gitlab',
+ 'gitter',
+ 'glide',
+ 'glide-g',
+ 'gofore',
+ 'goodreads',
+ 'goodreads-g',
+ 'google',
+ 'google-drive',
+ 'google-play',
+ 'google-plus',
+ 'google-plus-g',
+ 'google-plus-square',
+ 'google-wallet',
+ 'gratipay',
+ 'grav',
+ 'gripfire',
+ 'grunt',
+ 'gulp',
+ 'hacker-news',
+ 'hacker-news-square',
+ 'hackerrank',
+ 'hips',
+ 'hire-a-helper',
+ 'hooli',
+ 'hornbill',
+ 'hotjar',
+ 'houzz',
+ 'html5',
+ 'hubspot',
+ 'imdb',
+ 'instagram',
+ 'intercom',
+ 'internet-explorer',
+ 'invision',
+ 'ioxhost',
+ 'itch-io',
+ 'itunes',
+ 'itunes-note',
+ 'java',
+ 'jedi-order',
+ 'jenkins',
+ 'jira',
+ 'joget',
+ 'joomla',
+ 'js',
+ 'js-square',
+ 'jsfiddle',
+ 'kaggle',
+ 'keybase',
+ 'keycdn',
+ 'kickstarter',
+ 'kickstarter-k',
+ 'korvue',
+ 'laravel',
+ 'lastfm',
+ 'lastfm-square',
+ 'leanpub',
+ 'less',
+ 'line',
+ 'linkedin',
+ 'linkedin-in',
+ 'linode',
+ 'linux',
+ 'lyft',
+ 'magento',
+ 'mailchimp',
+ 'mandalorian',
+ 'markdown',
+ 'mastodon',
+ 'maxcdn',
+ 'medapps',
+ 'medium',
+ 'medium-m',
+ 'medrt',
+ 'meetup',
+ 'megaport',
+ 'mendeley',
+ 'microsoft',
+ 'mix',
+ 'mixcloud',
+ 'mizuni',
+ 'modx',
+ 'monero',
+ 'napster',
+ 'neos',
+ 'nimblr',
+ 'nintendo-switch',
+ 'node',
+ 'node-js',
+ 'npm',
+ 'ns8',
+ 'nutritionix',
+ 'odnoklassniki',
+ 'odnoklassniki-square',
+ 'old-republic',
+ 'opencart',
+ 'openid',
+ 'opera',
+ 'optin-monster',
+ 'osi',
+ 'page4',
+ 'pagelines',
+ 'palfed',
+ 'patreon',
+ 'paypal',
+ 'penny-arcade',
+ 'periscope',
+ 'phabricator',
+ 'phoenix-framework',
+ 'phoenix-squadron',
+ 'php',
+ 'pied-piper',
+ 'pied-piper-alt',
+ 'pied-piper-hat',
+ 'pied-piper-pp',
+ 'pinterest',
+ 'pinterest-p',
+ 'pinterest-square',
+ 'playstation',
+ 'product-hunt',
+ 'pushed',
+ 'python',
+ 'qq',
+ 'quinscape',
+ 'quora',
+ 'r-project',
+ 'raspberry-pi',
+ 'ravelry',
+ 'react',
+ 'reacteurope',
+ 'readme',
+ 'rebel',
+ 'red-river',
+ 'reddit',
+ 'reddit-alien',
+ 'reddit-square',
+ 'redhat',
+ 'renren',
+ 'replyd',
+ 'researchgate',
+ 'resolving',
+ 'rev',
+ 'rocketchat',
+ 'rockrms',
+ 'safari',
+ 'salesforce',
+ 'sass',
+ 'schlix',
+ 'scribd',
+ 'searchengin',
+ 'sellcast',
+ 'sellsy',
+ 'servicestack',
+ 'shirtsinbulk',
+ 'shopware',
+ 'simplybuilt',
+ 'sistrix',
+ 'sith',
+ 'sketch',
+ 'skyatlas',
+ 'skype',
+ 'slack',
+ 'slack-hash',
+ 'slideshare',
+ 'snapchat',
+ 'snapchat-ghost',
+ 'snapchat-square',
+ 'soundcloud',
+ 'sourcetree',
+ 'speakap',
+ 'speaker-deck',
+ 'spotify',
+ 'squarespace',
+ 'stack-exchange',
+ 'stack-overflow',
+ 'staylinked',
+ 'steam',
+ 'steam-square',
+ 'steam-symbol',
+ 'sticker-mule',
+ 'strava',
+ 'stripe',
+ 'stripe-s',
+ 'studiovinari',
+ 'stumbleupon',
+ 'stumbleupon-circle',
+ 'superpowers',
+ 'supple',
+ 'suse',
+ 'symfony',
+ 'teamspeak',
+ 'telegram',
+ 'telegram-plane',
+ 'tencent-weibo',
+ 'the-red-yeti',
+ 'themeco',
+ 'themeisle',
+ 'think-peaks',
+ 'trade-federation',
+ 'trello',
+ 'tripadvisor',
+ 'tumblr',
+ 'tumblr-square',
+ 'twitch',
+ 'twitter',
+ 'twitter-square',
+ 'typo3',
+ 'uber',
+ 'ubuntu',
+ 'uikit',
+ 'uniregistry',
+ 'untappd',
+ 'ups',
+ 'usb',
+ 'usps',
+ 'ussunnah',
+ 'vaadin',
+ 'viacoin',
+ 'viadeo',
+ 'viadeo-square',
+ 'viber',
+ 'vimeo',
+ 'vimeo-square',
+ 'vimeo-v',
+ 'vine',
+ 'vk',
+ 'vnv',
+ 'vuejs',
+ 'waze',
+ 'weebly',
+ 'weibo',
+ 'weixin',
+ 'whatsapp',
+ 'whatsapp-square',
+ 'whmcs',
+ 'wikipedia-w',
+ 'windows',
+ 'wix',
+ 'wizards-of-the-coast',
+ 'wolf-pack-battalion',
+ 'wordpress',
+ 'wordpress-simple',
+ 'wpbeginner',
+ 'wpexplorer',
+ 'wpforms',
+ 'wpressr',
+ 'xbox',
+ 'xing',
+ 'xing-square',
+ 'y-combinator',
+ 'yahoo',
+ 'yammer',
+ 'yandex',
+ 'yandex-international',
+ 'yarn',
+ 'yelp',
+ 'yoast',
+ 'youtube',
+ 'youtube-square',
+ 'zhihu'
+ );
+ if (in_array($icon, $fab_icons)) {
+ return 'fab';
+ } else {
+ return 'fas';
+ }
+ }
+ }
diff --git a/app/src/View/Helper/HashHelper.php b/app/src/View/Helper/HashHelper.php
new file mode 100644
index 0000000..5a2cbef
--- /dev/null
+++ b/app/src/View/Helper/HashHelper.php
@@ -0,0 +1,14 @@
+element('genericElements/Form/genericForm', array(
+ 'form' => $this->Form,
+ 'data' => array(
+ 'entity' => $alignment,
+ 'title' => __('Add new alignment for {0} #{1}', \Cake\Utility\Inflector::singularize(h($scope)), h($source_id)),
+ 'description' => __('Alignments indicate that an individual belongs to an organisation in one way or another. The type of relationship is defined by the type field.'),
+ 'model' => 'Organisations',
+ 'fields' => array(
+ array(
+ 'field' => ($scope === 'individuals' ? 'organisation_id' : 'individual_id'),
+ 'options' => ($scope === 'individuals' ? $organisations : $individuals),
+ 'type' => 'select'
+ ),
+ array(
+ 'field' => 'type'
+ )
+ ),
+ 'submit' => array(
+ 'action' => $this->request->getParam('action')
+ )
+ )
+));
diff --git a/app/templates/EncryptionKeys/add.php b/app/templates/EncryptionKeys/add.php
new file mode 100644
index 0000000..0a7afb1
--- /dev/null
+++ b/app/templates/EncryptionKeys/add.php
@@ -0,0 +1,30 @@
+ 'email', 'organisation' => 'name'];
+echo $this->element('genericElements/Form/genericForm', array(
+ 'form' => $this->Form,
+ 'data' => array(
+ 'entity' => $encryptionKey,
+ 'title' => __('Add new encryption key for {0} #{1} ({2})', h($owner_type), h($owner_id), h($owner[$primaryIdentifiers[$owner_type]])),
+ 'description' => __('Alignments indicate that an individual belongs to an organisation in one way or another. The type of relationship is defined by the type field.'),
+ 'model' => 'Organisations',
+ 'fields' => array(
+ array(
+ 'field' => 'uuid',
+ 'type' => 'uuid'
+ ),
+ array(
+ 'field' => 'type',
+ 'options' => array('pgp' => 'PGP', 'smime' => 'S/MIME')
+ ),
+ array(
+ 'field' => 'encryption_key',
+ 'label' => __('Public key'),
+ 'type' => 'textarea',
+ 'rows' => 8
+ )
+ ),
+ 'submit' => array(
+ 'action' => $this->request->getParam('action')
+ )
+ )
+));
diff --git a/app/templates/Error/error400.php b/app/templates/Error/error400.php
new file mode 100644
index 0000000..8096901
--- /dev/null
+++ b/app/templates/Error/error400.php
@@ -0,0 +1,38 @@
+layout = 'error';
+
+if (Configure::read('debug')) :
+ $this->layout = 'dev_error';
+
+ $this->assign('title', $message);
+ $this->assign('templateName', 'error400.php');
+
+ $this->start('file');
+?>
+queryString)) : ?>
+
+ SQL Query:
+ = h($error->queryString) ?>
+
+
+params)) : ?>
+ SQL Query Params:
+ params) ?>
+
+= $this->element('auto_table_warning') ?>
+end();
+endif;
+?>
+= h($message) ?>
+
+ = __d('cake', 'Error') ?>:
+ = __d('cake', 'The requested address {0} was not found on this server.', "'{$url}' ") ?>
+
diff --git a/app/templates/Error/error500.php b/app/templates/Error/error500.php
new file mode 100644
index 0000000..4ade4dd
--- /dev/null
+++ b/app/templates/Error/error500.php
@@ -0,0 +1,42 @@
+layout = 'error';
+
+if (Configure::read('debug')) :
+ $this->layout = 'dev_error';
+
+ $this->assign('title', $message);
+ $this->assign('templateName', 'error500.php');
+
+ $this->start('file');
+?>
+queryString)) : ?>
+
+ SQL Query:
+ = h($error->queryString) ?>
+
+
+params)) : ?>
+ SQL Query Params:
+ params) ?>
+
+
+ Error in:
+ = sprintf('%s, line %s', str_replace(ROOT, 'ROOT', $error->getFile()), $error->getLine()) ?>
+
+element('auto_table_warning');
+
+ $this->end();
+endif;
+?>
+= __d('cake', 'An Internal Error Has Occurred') ?>
+
+ = __d('cake', 'Error') ?>:
+ = h($message) ?>
+
diff --git a/app/templates/Individuals/add.php b/app/templates/Individuals/add.php
new file mode 100644
index 0000000..dbb2f17
--- /dev/null
+++ b/app/templates/Individuals/add.php
@@ -0,0 +1,35 @@
+element('genericElements/Form/genericForm', array(
+ 'form' => $this->Form,
+ 'data' => array(
+ 'entity' => $individual,
+ 'title' => __('Add new individual'),
+ 'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'),
+ 'model' => 'Organisations',
+ 'fields' => array(
+ array(
+ 'field' => 'email'
+ ),
+ array(
+ 'field' => 'first_name'
+ ),
+ array(
+ 'field' => 'last_name'
+ ),
+ array(
+ 'field' => 'position'
+ ),
+ array(
+ 'field' => 'uuid',
+ 'label' => 'UUID',
+ 'type' => 'uuid'
+ )
+ ),
+ 'submit' => array(
+ 'action' => $this->request->getParam('action')
+ )
+ )
+ ));
+?>
+
diff --git a/app/templates/Individuals/index.php b/app/templates/Individuals/index.php
new file mode 100644
index 0000000..491a9fb
--- /dev/null
+++ b/app/templates/Individuals/index.php
@@ -0,0 +1,74 @@
+element('genericElements/IndexTable/index_table', [
+ 'data' => [
+ 'data' => $data,
+ 'top_bar' => [
+ 'pull' => 'right',
+ 'children' => [
+ [
+ 'type' => 'search',
+ 'button' => __('Filter'),
+ 'placeholder' => __('Enter value to search'),
+ 'data' => '',
+ 'searchKey' => 'value'
+ ]
+ ]
+ ],
+ 'fields' => [
+ [
+ 'name' => '#',
+ 'sort' => 'id',
+ 'data_path' => 'id',
+ ],
+ [
+ 'name' => __('Email'),
+ 'sort' => 'email',
+ 'data_path' => 'email',
+ ],
+ [
+ 'name' => __('First Name'),
+ 'sort' => 'first_name',
+ 'data_path' => 'first_name',
+ ],
+ [
+ 'name' => __('Last Name'),
+ 'sort' => 'last_name',
+ 'data_path' => 'last_name',
+ ],
+ [
+ 'name' => __('Alignments'),
+ 'data_path' => 'alignments',
+ 'element' => 'alignments',
+ 'scope' => $alignmentScope
+ ],
+ [
+ 'name' => __('UUID'),
+ 'sort' => 'uuid',
+ 'data_path' => 'uuid',
+ 'placeholder' => __('Leave empty to auto generate')
+ ],
+ ],
+ 'title' => __('ContactDB Individuals Index'),
+ 'description' => __('A list of individuals known by your Cerebrate instance. This list can get populated either directly, by adding new individuals or by fetching them from trusted remote sources. Additionally, users created for the platform will always have an individual identity.'),
+ 'pull' => 'right',
+ 'actions' => [
+ [
+ 'url' => '/individuals/view',
+ 'url_params_data_paths' => ['id'],
+ 'icon' => 'eye'
+ ],
+ [
+ 'url' => '/individuals/edit',
+ 'url_params_data_paths' => ['id'],
+ 'icon' => 'edit'
+ ],
+ [
+ 'onclick' => 'populateAndLoadModal(\'/individuals/delete/[onclick_params_data_path]\');',
+ 'onclick_params_data_path' => 'id',
+ 'icon' => 'trash'
+ ]
+ ]
+ ]
+]);
+echo '';
+?>
diff --git a/app/templates/Individuals/view.php b/app/templates/Individuals/view.php
new file mode 100644
index 0000000..510c142
--- /dev/null
+++ b/app/templates/Individuals/view.php
@@ -0,0 +1,41 @@
+element(
+ '/genericElements/SingleViews/single_view',
+ [
+ 'title' => __('Individual View'),
+ 'data' => $individual,
+ 'fields' => [
+ [
+ 'key' => __('ID'),
+ 'path' => 'id'
+ ],
+ [
+ 'key' => __('Email'),
+ 'path' => 'email'
+ ],
+ [
+ 'key' => __('UUID'),
+ 'path' => 'uuid'
+ ],
+ [
+ 'key' => __('First Name'),
+ 'path' => 'first_name'
+ ],
+ [
+ 'key' => __('Last Name'),
+ 'path' => 'last_name'
+ ],
+ [
+ 'key' => __('Position'),
+ 'path' => 'position'
+ ],
+ [
+ 'key' => __('Alignments'),
+ 'type' => 'alignment',
+ 'path' => 'alignments',
+ 'scope' => 'individuals'
+ ]
+ ],
+ 'children' => []
+ ]
+);
diff --git a/app/templates/Organisations/add.php b/app/templates/Organisations/add.php
new file mode 100644
index 0000000..203c9ce
--- /dev/null
+++ b/app/templates/Organisations/add.php
@@ -0,0 +1,42 @@
+element('genericElements/Form/genericForm', array(
+ 'form' => $this->Form,
+ 'data' => array(
+ 'entity' => $organisation,
+ 'title' => __('Add new organisation'),
+ 'description' => __('Organisations can be equivalent to legal entities or specific individual teams within such entities. Their purpose is to relate individuals to their affiliations and for release control of information using the Trust Circles.'),
+ 'model' => 'Organisations',
+ 'fields' => array(
+ array(
+ 'field' => 'name'
+ ),
+ array(
+ 'field' => 'description',
+ 'type' => 'textarea'
+ ),
+ array(
+ 'field' => 'uuid',
+ 'label' => 'UUID',
+ 'type' => 'uuid'
+ ),
+ array(
+ 'field' => 'URL'
+ ),
+ array(
+ 'field' => 'nationality'
+ ),
+ array(
+ 'field' => 'sector'
+ ),
+ array(
+ 'field' => 'type'
+ )
+ ),
+ 'submit' => array(
+ 'action' => $this->request->getParam('action')
+ )
+ )
+ ));
+?>
+
diff --git a/app/templates/Organisations/index.php b/app/templates/Organisations/index.php
new file mode 100644
index 0000000..2644953
--- /dev/null
+++ b/app/templates/Organisations/index.php
@@ -0,0 +1,84 @@
+element('genericElements/IndexTable/index_table', [
+ 'data' => [
+ 'data' => $data,
+ 'top_bar' => [
+ 'pull' => 'right',
+ 'children' => [
+ [
+ 'type' => 'search',
+ 'button' => __('Filter'),
+ 'placeholder' => __('Enter value to search'),
+ 'data' => '',
+ 'searchKey' => 'value'
+ ]
+ ]
+ ],
+ 'fields' => [
+ [
+ 'name' => '#',
+ 'sort' => 'id',
+ 'class' => 'short',
+ 'data_path' => 'id',
+ ],
+ [
+ 'name' => __('Name'),
+ 'class' => 'short',
+ 'data_path' => 'name',
+ ],
+ [
+ 'name' => __('UUID'),
+ 'sort' => 'uuid',
+ 'class' => 'short',
+ 'data_path' => 'uuid',
+ ],
+ [
+ 'name' => __('Members'),
+ 'data_path' => 'alignments',
+ 'element' => 'count_summary',
+ 'url' => '/individuals/index/?organisation_id={{url_data}}',
+ 'url_data_path' => 'id'
+ ],
+ [
+ 'name' => __('URL'),
+ 'sort' => 'url',
+ 'class' => 'short',
+ 'data_path' => 'url',
+ ],
+ [
+ 'name' => __('Nationality'),
+ 'data_path' => 'nationality',
+ ],
+ [
+ 'name' => __('Sector'),
+ 'data_path' => 'sector',
+ ],
+ [
+ 'name' => __('Type'),
+ 'data_path' => 'type',
+ ]
+ ],
+ 'title' => __('ContactDB Organisation Index'),
+ 'description' => __('A list of organisations known by your Cerebrate instance. This list can get populated either directly, by adding new organisations or by fetching them from trusted remote sources.'),
+ 'pull' => 'right',
+ 'actions' => [
+ [
+ 'url' => '/organisations/view',
+ 'url_params_data_paths' => ['id'],
+ 'icon' => 'eye'
+ ],
+ [
+ 'url' => '/organisations/edit',
+ 'url_params_data_paths' => ['id'],
+ 'icon' => 'edit'
+ ],
+ [
+ 'onclick' => 'populateAndLoadModal(\'/organisations/delete/[onclick_params_data_path]\');',
+ 'onclick_params_data_path' => 'id',
+ 'icon' => 'trash'
+ ]
+ ]
+ ]
+]);
+echo '';
+?>
diff --git a/app/templates/Organisations/view.php b/app/templates/Organisations/view.php
new file mode 100644
index 0000000..d63655b
--- /dev/null
+++ b/app/templates/Organisations/view.php
@@ -0,0 +1,49 @@
+element(
+ '/genericElements/SingleViews/single_view',
+ array(
+ 'title' => __('Organisation View'),
+ 'data' => $organisation,
+ 'fields' => array(
+ [
+ 'key' => __('ID'),
+ 'path' => 'id'
+ ],
+ [
+ 'key' => __('Name'),
+ 'path' => 'name'
+ ],
+ [
+ 'key' => __('UUID'),
+ 'path' => 'uuid'
+ ],
+ [
+ 'key' => __('URL'),
+ 'path' => 'url'
+ ],
+ [
+ 'key' => __('Nationality'),
+ 'path' => 'nationality'
+ ],
+ [
+ 'key' => __('Sector'),
+ 'path' => 'sector'
+ ],
+ [
+ 'key' => __('Type'),
+ 'path' => 'type'
+ ],
+ [
+ 'key' => __('Contacts'),
+ 'path' => 'contacts'
+ ],
+ [
+ 'key' => __('Alignments'),
+ 'type' => 'alignment',
+ 'path' => 'alignments',
+ 'scope' => 'organisations'
+ ]
+ ),
+ 'children' => []
+ )
+);
diff --git a/app/templates/Pages/home.php b/app/templates/Pages/home.php
new file mode 100644
index 0000000..0b50457
--- /dev/null
+++ b/app/templates/Pages/home.php
@@ -0,0 +1,222 @@
+disableAutoLayout();
+
+if (!Configure::read('debug')) :
+ throw new NotFoundException(
+ 'Please replace templates/Pages/home.php with your own version or re-enable debug mode.'
+ );
+endif;
+
+$cakeDescription = 'CakePHP: the rapid development PHP framework';
+?>
+
+
+
+ = $this->Html->charset() ?>
+
+
+ = $cakeDescription ?>:
+ = $this->fetch('title') ?>
+
+ = $this->Html->meta('icon') ?>
+
+
+
+
+ = $this->Html->css('milligram.min.css') ?>
+ = $this->Html->css('cake.css') ?>
+ = $this->Html->css('home.css') ?>
+
+ = $this->fetch('meta') ?>
+ = $this->fetch('css') ?>
+ = $this->fetch('script') ?>
+
+
+
+
+
+
+
+
+ Welcome to CakePHP Strawberry
+
+
+
+
+
+
+
+
+
+ Please be aware that this page will not be shown if you turn off debug mode unless you replace templates/Pages/home.php with your own version.
+
+
+
+
+
+
+
+
Environment
+
+ =')) : ?>
+ Your version of PHP is 7.2.0 or higher (detected ).
+
+ Your version of PHP is too low. You need PHP 7.2.0 or higher to use CakePHP (detected ).
+
+
+
+ Your version of PHP has the mbstring extension loaded.
+
+ Your version of PHP does NOT have the mbstring extension loaded.
+
+
+
+ Your version of PHP has the openssl extension loaded.
+
+ Your version of PHP has the mcrypt extension loaded.
+
+ Your version of PHP does NOT have the openssl or mcrypt extension loaded.
+
+
+
+ Your version of PHP has the intl extension loaded.
+
+ Your version of PHP does NOT have the intl extension loaded.
+
+
+
+
+
Filesystem
+
+
+ Your tmp directory is writable.
+
+ Your tmp directory is NOT writable.
+
+
+
+ Your logs directory is writable.
+
+ Your logs directory is NOT writable.
+
+
+
+
+ The Engine is being used for core caching. To change the config edit config/app.php
+
+ Your cache is NOT working. Please check the settings in config/app.php
+
+
+
+
+
+
+
+
Database
+ connect();
+ } catch (Exception $connectionError) {
+ $connected = false;
+ $errorMsg = $connectionError->getMessage();
+ if (method_exists($connectionError, 'getAttributes')) :
+ $attributes = $connectionError->getAttributes();
+ if (isset($errorMsg['message'])) :
+ $errorMsg .= '
' . $attributes['message'];
+ endif;
+ endif;
+ }
+ ?>
+
+
+ CakePHP is able to connect to the database.
+
+ CakePHP is NOT able to connect to the database.
+
+
+
+
+
DebugKit
+
+
+ DebugKit is loaded.
+
+ DebugKit is NOT loaded. You need to either install pdo_sqlite, or define the "debug_kit" connection name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/templates/cell/.gitkeep b/app/templates/cell/.gitkeep
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/app/templates/cell/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/app/templates/element/flash/default.php b/app/templates/element/flash/default.php
new file mode 100644
index 0000000..f86e90f
--- /dev/null
+++ b/app/templates/element/flash/default.php
@@ -0,0 +1,20 @@
+
+
+ = $message ?>
+
+ ×
+
+
diff --git a/app/templates/element/flash/error.php b/app/templates/element/flash/error.php
new file mode 100644
index 0000000..09d03ec
--- /dev/null
+++ b/app/templates/element/flash/error.php
@@ -0,0 +1,16 @@
+
+
+ = $message ?>
+
+ ×
+
+
diff --git a/app/templates/element/flash/success.php b/app/templates/element/flash/success.php
new file mode 100644
index 0000000..edf11ca
--- /dev/null
+++ b/app/templates/element/flash/success.php
@@ -0,0 +1,16 @@
+
+
+ = $message ?>
+
+ ×
+
+
diff --git a/app/templates/element/genericElements/Form/Fields/checkboxField.php b/app/templates/element/genericElements/Form/Fields/checkboxField.php
new file mode 100644
index 0000000..9354f0f
--- /dev/null
+++ b/app/templates/element/genericElements/Form/Fields/checkboxField.php
@@ -0,0 +1,8 @@
+control($fieldData['field'], $params);
+ if (!empty($fieldData['hidden'])) {
+ $temp = '' . $temp . ' ';
+ }
+ echo $temp;
+?>
diff --git a/app/templates/element/genericElements/Form/Fields/genericField.php b/app/templates/element/genericElements/Form/Fields/genericField.php
new file mode 100644
index 0000000..ccee3e2
--- /dev/null
+++ b/app/templates/element/genericElements/Form/Fields/genericField.php
@@ -0,0 +1,9 @@
+control($fieldData['field'], $params);
+ if (!empty($fieldData['hidden'])) {
+ $temp = '' . $temp . ' ';
+ }
+ echo $temp;
+?>
diff --git a/app/templates/element/genericElements/Form/Fields/uuidField.php b/app/templates/element/genericElements/Form/Fields/uuidField.php
new file mode 100644
index 0000000..6600bd3
--- /dev/null
+++ b/app/templates/element/genericElements/Form/Fields/uuidField.php
@@ -0,0 +1,42 @@
+Form->setTemplates([
+ 'inputContainer' => '{{content}}',
+ 'inputContainerError' => '{{content}}',
+ 'formGroup' => '{{input}}',
+ ]);
+ $label = $fieldData['label'];
+ $temp = sprintf(
+ '',
+ h($label),
+ $form->control($fieldData['field'], $params),
+ sprintf(
+ '%s ',
+ $random,
+ __('Generate')
+ )
+ );
+ echo $temp;
+?>
+
diff --git a/app/templates/element/genericElements/Form/formInfo.php b/app/templates/element/genericElements/Form/formInfo.php
new file mode 100644
index 0000000..419bdec
--- /dev/null
+++ b/app/templates/element/genericElements/Form/formInfo.php
@@ -0,0 +1,47 @@
+ $fieldDesc);
+ $default = 'info';
+ } else {
+ if (!empty($field['options'])) {
+ if (isset($this->request->data[$modelForForm][$field['field']])) {
+ $default = $this->request->data[$modelForForm][$field['field']];
+ } else {
+ reset($field['options']);
+ $default = key($field['options']);
+ }
+ } else {
+ reset($fieldDesc);
+ $fieldDesc = array('info' => key($fieldDesc));
+ $default = 'info';
+ }
+ }
+ echo sprintf(
+ ' ',
+ h($field['field'])
+ );
+?>
+
diff --git a/app/templates/element/genericElements/Form/genericForm.php b/app/templates/element/genericElements/Form/genericForm.php
new file mode 100644
index 0000000..47b8b19
--- /dev/null
+++ b/app/templates/element/genericElements/Form/genericForm.php
@@ -0,0 +1,160 @@
+Form->input(),
+ * - requirements: boolean, if false is passed the field is skipped
+ * - metafields: fields that are outside of the scope of the form itself
+ - use these to define dynamic form fields, or anything that will feed into the regular fields via JS population
+ * - submit: The submit button itself. By default it will simply submit to the form as defined via the 'model' field
+ */
+ $modelForForm = empty($data['model']) ?
+ h(\Cake\Utility\Inflector::singularize(\Cake\Utility\Inflector::classify($this->request->getParam('controller')))) :
+ h($data['model']);
+ $fieldsString = '';
+ $simpleFieldWhitelist = array(
+ 'default', 'type', 'options', 'placeholder', 'label', 'empty', 'rows', 'div', 'required'
+ );
+ $fieldsArrayForPersistence = array();
+ if (empty($data['url'])) {
+ $data['url'] = ["controller" => $this->request->getParam('controller'), "action" => $this->request->getParam('url')];
+ }
+ $formRandomValue = Cake\Utility\Security::randomString(8);
+ $formCreate = $this->Form->create($data['entity'], ['id' => 'form-' . $formRandomValue]);
+ $default_template = [
+ 'inputContainer' => '{{content}}
',
+ 'inputContainerError' => '{{content}}
',
+ 'label' => '{{text}}',
+ 'input' => ' ',
+ 'textarea' => '',
+ 'select' => '{{content}} ',
+ 'checkbox' => ' ',
+ 'checkboxFormGroup' => '{{label}}',
+ 'checkboxWrapper' => '{{label}}
',
+ 'formGroup' => '{{label}}
{{input}}
',
+ 'nestingLabel' => '{{hidden}}{{text}}
{{input}}
',
+ ];
+ if (!empty($data['fields'])) {
+ foreach ($data['fields'] as $fieldData) {
+ // we reset the template each iteration as individual fields might override the defaults.
+ $this->Form->setTemplates($default_template);
+ if (isset($fieldData['requirements']) && !$fieldData['requirements']) {
+ continue;
+ }
+ if (is_array($fieldData)) {
+ if (empty($fieldData['type'])) {
+ $fieldData['type'] = 'text';
+ }
+ $fieldTemplate = 'genericField';
+ if (file_exists(ROOT . '/templates/element/genericElements/Form/Fields/' . $fieldData['type'] . 'Field.php')) {
+ $fieldTemplate = $fieldData['type'] . 'Field';
+ }
+ if (empty($fieldData['label'])) {
+ $fieldData['label'] = \Cake\Utility\Inflector::humanize($fieldData['field']);
+ }
+ if (!empty($fieldDesc[$fieldData['field']])) {
+ $fieldData['label'] .= $this->element(
+ 'genericElements/Form/formInfo', array(
+ 'field' => $fieldData,
+ 'fieldDesc' => $fieldDesc[$fieldData['field']],
+ 'modelForForm' => $modelForForm
+ )
+ );
+ }
+ $params = array();
+ if (!empty($fieldData['class'])) {
+ if (is_array($fieldData['class'])) {
+ $class = implode(' ', $fieldData['class']);
+ } else {
+ $class = $fieldData['class'];
+ }
+ $params['class'] = $class;
+ } else {
+ $params['class'] = '';
+ }
+ if (empty($fieldData['type']) || $fieldData['type'] !== 'checkbox' ) {
+ $params['class'] .= ' form-control';
+ }
+ //$params['class'] = sprintf('form-control %s', $params['class']);
+ foreach ($simpleFieldWhitelist as $f) {
+ if (!empty($fieldData[$f])) {
+ $params[$f] = $fieldData[$f];
+ }
+ }
+ $temp = $this->element('genericElements/Form/Fields/' . $fieldTemplate, array(
+ 'fieldData' => $fieldData,
+ 'params' => $params,
+ 'form' => $this->Form
+ ));
+ if (!empty($fieldData['hidden'])) {
+ $temp = '' . $temp . ' ';
+ }
+ $fieldsString .= $temp;
+ $fieldsArrayForPersistence []= $modelForForm . \Cake\Utility\Inflector::camelize($fieldData['field']);
+ } else {
+ $fieldsString .= $fieldData;
+ }
+ }
+ }
+ $metaFieldString = '';
+ if (!empty($data['metaFields'])) {
+ foreach ($data['metaFields'] as $metaField) {
+ $metaFieldString .= $metaField;
+ }
+ }
+ $submitButtonData = array('model' => $modelForForm, 'formRandomValue' => $formRandomValue);
+ if (!empty($data['submit'])) {
+ $submitButtonData = array_merge($submitButtonData, $data['submit']);
+ }
+ if (!empty($data['ajaxSubmit'])) {
+ $submitButtonData['ajaxSubmit'] = $ajaxSubmit;
+ }
+ $ajaxFlashMessage = '';
+ if ($ajax) {
+ $ajaxFlashMessage = sprintf(
+ '',
+ $this->Flash->render()
+ );
+ }
+ $formEnd = $this->Form->end();
+ if (!empty($ajax)) {
+ echo $this->element('genericElements/genericModal', array(
+ 'title' => empty($data['title']) ? h(\Cake\Utility\Inflector::humanize($this->request->params['action'])) . ' ' . $modelForForm : h($data['title']),
+ 'body' => sprintf(
+ '%s%s%s%s%s%s',
+ empty($data['description']) ? '' : sprintf(
+ '%s
',
+ $data['description']
+ ),
+ $ajaxFlashMessage,
+ $formCreate,
+ $fieldsString,
+ $formEnd,
+ $metaFieldString
+ ),
+ 'actionButton' => $this->element('genericElements/Form/submitButton', $submitButtonData),
+ 'class' => 'modal-lg'
+ ));
+ } else {
+ echo sprintf(
+ '%s%s %s%s%s%s%s%s%s%s',
+ empty($ajax) ? '' : '',
+ empty($data['title']) ? h(\Cake\Utility\Inflector::humanize($this->request->params['action'])) . ' ' . $modelForForm : h($data['title']),
+ $formCreate,
+ $ajaxFlashMessage,
+ empty($data['description']) ? '' : sprintf(
+ '
%s
',
+ $data['description']
+ ),
+ $fieldsString,
+ $this->element('genericElements/Form/submitButton', $submitButtonData),
+ $formEnd,
+ $metaFieldString,
+ empty($ajax) ? '
' : ''
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/Form/submitButton.php b/app/templates/element/genericElements/Form/submitButton.php
new file mode 100644
index 0000000..e09fd13
--- /dev/null
+++ b/app/templates/element/genericElements/Form/submitButton.php
@@ -0,0 +1,17 @@
+%s',
+ "$('#form-" . h($formRandomValue) . "').submit()",
+ __('Submit')
+ )
+ );
+ } else {
+ echo $this->Form->button(empty($text) ? __('Submit') : h($text), [
+ 'class' => 'btn btn-' . (empty($type) ? 'primary' : h($type)),
+ 'type' => 'submit'
+ ]);
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/actions.php b/app/templates/element/genericElements/IndexTable/Fields/actions.php
new file mode 100644
index 0000000..3122f78
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/actions.php
@@ -0,0 +1,96 @@
+';
+ foreach ($actions as $action) {
+ if (isset($action['requirement']) && !$action['requirement']) {
+ continue;
+ }
+ if (isset($action['complex_requirement'])) {
+ if (isset($action['complex_requirement']['options']['datapath'])) {
+ foreach ($action['complex_requirement']['options']['datapath'] as $name => $path) {
+ $action['complex_requirement']['options']['datapath'][$name] = empty($this->Hash->extract($row, $path)[0]) ? null : $this->Hash->extract($row, $path)[0];
+ }
+ }
+ $options = isset($action['complex_requirement']['options']) ? $action['complex_requirement']['options'] : array();
+ $requirementMet = $action['complex_requirement']['function']($row, $options);
+ if (!$requirementMet) {
+ continue;
+ }
+ }
+ $url_param_data_paths = '';
+ $url = empty($action['url']) ? '#' : h($action['url']);
+ if (!empty($action['url_params_data_paths'])) {
+ if (is_array($action['url_params_data_paths'])) {
+ $temp = array();
+ foreach ($action['url_params_data_paths'] as $path) {
+ $temp[] = h(Cake\Utility\Hash::extract($row, $path)[0]);
+ }
+ $url_param_data_paths = implode('/', $temp);
+ } else {
+ $url_param_data_paths = h(Cake\Utility\Hash::extract($row, $action['url_params_data_paths'])[0]);
+ }
+ $url .= '/' . $url_param_data_paths;
+ }
+ if (!empty($action['url_named_params_data_paths'])) {
+ if (is_array($action['url_named_params_data_paths'])) {
+ $temp = array();
+ foreach ($action['url_named_params_data_paths'] as $namedParam => $path) {
+ $temp[] = sprintf('%s:%s', h($namedParam), h($this->Hash->extract($row, $path)[0]));
+ }
+ $url_param_data_paths = implode('/', $temp);
+ }
+ $url .= '/' . $url_param_data_paths;
+ }
+ if (!empty($action['url_extension'])) {
+ $url .= '.' . $action['url_extension'];
+ }
+ if (isset($action['postLink'])) {
+ echo $this->Form->postLink(
+ '',
+ $url,
+ array(
+ 'class' => $this->FontAwesome->getClass($action['icon']) . ' black ' . (empty($action['class']) ? '' : h($action['class'])),
+ 'title' => empty($action['title']) ? '' : h($action['title']),
+ 'aria-label' => empty($action['aria-label']) ? '' : h($action['aria-label']),
+ ),
+ empty($action['postLinkConfirm'])? '' : $action['postLinkConfirm']
+ );
+ } else {
+ if (!empty($action['onclick']) && !empty($action['onclick_params_data_path'])) {
+ $action['onclick'] = str_replace(
+ '[onclick_params_data_path]',
+ h(Cake\Utility\Hash::extract($row, $action['onclick_params_data_path'])[0]),
+ $action['onclick']
+ );
+
+ }
+ echo sprintf(
+ ' ',
+ $url,
+ empty($action['title']) ? '' : h($action['title']),
+ empty($action['title']) ? '' : h($action['title']),
+ empty($action['dbclickAction']) ? '' : 'class="dblclickActionElement"',
+ empty($action['onclick']) ? '' : sprintf('onClick="%s"', $action['onclick']),
+ $this->FontAwesome->getClass($action['icon'])
+ );
+ }
+ }
+ echo '';
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/alignments.php b/app/templates/element/genericElements/IndexTable/Fields/alignments.php
new file mode 100644
index 0000000..aabc106
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/alignments.php
@@ -0,0 +1,43 @@
+Hash->extract($row, $field['data_path']);
+$alignments = '';
+if ($field['scope'] === 'individuals') {
+ foreach ($raw_alignments as $alignment) {
+ $alignments .= sprintf(
+ '',
+ h($alignment['type']),
+ sprintf(
+ '%s ',
+ h($alignment['organisation']['id']),
+ h($alignment['organisation']['name'])
+ ),
+ sprintf(
+ "populateAndLoadModal(%s);",
+ sprintf(
+ "'/alignments/delete/%s'",
+ $alignment['id']
+ )
+ )
+ );
+ }
+} else if ($field['scope'] === 'organisations') {
+ foreach ($raw_alignments as $alignment) {
+ $alignments .= sprintf(
+ '',
+ h($alignment['type']),
+ sprintf(
+ '%s ',
+ h($alignment['individual']['id']),
+ h($alignment['individual']['email'])
+ ),
+ sprintf(
+ "populateAndLoadModal(%s);",
+ sprintf(
+ "'/alignments/delete/%s'",
+ $alignment['id']
+ )
+ )
+ );
+ }
+}
+echo $alignments;
diff --git a/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php b/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php
new file mode 100644
index 0000000..9f929f2
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php
@@ -0,0 +1,4 @@
+Hash->extract($row, $field['data_path'])[0]]);
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/boolean.php b/app/templates/element/genericElements/IndexTable/Fields/boolean.php
new file mode 100644
index 0000000..b017046
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/boolean.php
@@ -0,0 +1,57 @@
+ array(
+ 'colour' => 'green',
+ 'text' => 'allowed'
+ ),
+ 'NOT' => array(
+ 'colour' => 'red',
+ 'text' => 'blocked'
+ )
+ );
+ if (
+ !empty($this->Hash->extract($row, $field['data_path'])[0]) &&
+ !empty($field['rule_path'][0]) &&
+ !empty($this->Hash->extract($row, $field['rule_path'])[0])
+ ) {
+ $rules = $this->Hash->extract($row, $field['rule_path'])[0];
+ $rules = json_decode($rules, true);
+ foreach ($rules as $rule => $rule_data) {
+ if (is_array($rule_data)) {
+ foreach ($rule_data as $boolean => $values) {
+ if (!empty($values)) {
+ if (is_array($values)) {
+ $values = implode(', ', $values);
+ }
+ $rules_raw[] = sprintf(
+ '%s %s : %s ',
+ h(\Cake\Utility\Inflector::humanize($rule)),
+ $typeOptions[$boolean]['text'],
+ $typeOptions[$boolean]['colour'],
+ h($values)
+ );
+ }
+ }
+ } else if (!empty($rule_data)){
+ $rules_raw[] = sprintf(
+ '%s : %s ',
+ h(\Cake\Utility\Inflector::humanize($rule)),
+ h($rule_data)
+ );
+ }
+ }
+ $rules_raw = implode(' ', $rules_raw);
+ }
+ echo sprintf(
+ ' %s',
+ (!empty($this->Hash->extract($row, $field['data_path'])[0])) ? 'check' : 'times',
+ empty($rules_raw) ? '' :
+ sprintf(
+ ' (%s) ',
+ __('Filter rules'),
+ $rules_raw,
+ __('Rules')
+ )
+ );
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/caching.php b/app/templates/element/genericElements/IndexTable/Fields/caching.php
new file mode 100644
index 0000000..3f6dca4
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/caching.php
@@ -0,0 +1,32 @@
+Hash->extract($row, $field['data_path'])[0];
+ $enabled = isset($field['enabled_path']) ? $this->Hash->extract($row, $field['enabled_path'])[0] : true;
+ if (!empty($timestamp)):
+ $units = array('m', 'h', 'd');
+ $intervals = array(60, 60, 24);
+ $unit = 's';
+ $last = time() - $timestamp;
+ foreach ($units as $k => $v) {
+ if ($last > $intervals[$k]) {
+ $unit = $v;
+ $last = floor($last / $intervals[$k]);
+ } else {
+ break;
+ }
+ }
+ $ageString = __('Age: ') . $last . $unit;
+ else:
+ $ageString = __('Not cached');
+ endif;
+ echo sprintf(
+ '%s %s',
+ empty($timestamp) ? 'red bold' : '',
+ h($ageString),
+ (!$enabled || !$isSiteAdmin) ? '' : sprintf(
+ ' ',
+ $baseurl . '/feeds/cacheFeeds/' . h($primary),
+ __('Cache feed'),
+ __('Cache feed')
+ )
+ );
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/correlations.php b/app/templates/element/genericElements/IndexTable/Fields/correlations.php
new file mode 100644
index 0000000..b5cc013
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/correlations.php
@@ -0,0 +1,20 @@
+Hash->extract($row, $field['data_path']);
+ $scope_to_url = array(
+ 'event' => $baseurl . '/events/view'
+ );
+ $correlations_html = array();
+ foreach ($correlations as $id => $name) {
+ $correlations_html[] = sprintf(
+ '%s ',
+ sprintf(
+ '%s/%s',
+ $scope_to_url[empty($scope) ? 'event' : $scope],
+ h($id)
+ ),
+ h($name),
+ h($id)
+ );
+ }
+ echo implode(' ', $correlations_html);
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/count_summary.php b/app/templates/element/genericElements/IndexTable/Fields/count_summary.php
new file mode 100644
index 0000000..69162cd
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/count_summary.php
@@ -0,0 +1,25 @@
+ __('Members'),
+'data_path' => 'alignments',
+'element' => 'count_summary',
+'url' => '/individuals/index/?organisation_id={{url_data}}',
+'url_data_path' => 'id'
+*/
+ $data = $this->Hash->extract($row, $field['data_path']);
+ if (!empty($field['url_data_path'])) {
+ $url_data_path = $this->Hash->extract($row, $field['url_data_path'])[0];
+ }
+ if (!empty($field['url']) && count($data) > 0) {
+ if (!empty($url_data_path)) {
+ $field['url'] = str_replace('{{url_data}}', $url_data_path, $field['url']);
+ }
+ echo sprintf(
+ '%s ',
+ h($field['url']),
+ count($data)
+ );
+ } else {
+ echo count($data);
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/datetime.php b/app/templates/element/genericElements/IndexTable/Fields/datetime.php
new file mode 100644
index 0000000..2988e83
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/datetime.php
@@ -0,0 +1,26 @@
+Hash->extract($row, $field['data_path']);
+ if (is_array($data)) {
+ if (count($data) > 1) {
+ $data = implode(', ', $data);
+ } else {
+ if (count($data) > 0) {
+ $data = $data[0];
+ } else {
+ $data = '';
+ }
+ }
+ }
+ $data = h($data);
+ if (is_numeric($data)) {
+ $data = date('Y-m-d H:i:s', $data);
+ }
+ if (!empty($field['onClick'])) {
+ $data = sprintf(
+ '%s ',
+ $field['onClick'],
+ $data
+ );
+ }
+ echo $data;
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php b/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php
new file mode 100644
index 0000000..912ffef
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php
@@ -0,0 +1,15 @@
+Hash->extract($row, $field['data_path'])[0]);
+ echo sprintf(
+ '%s ',
+ $distributionLevel == 0 ? 'red' : '',
+ $distributionLevel != 4 ? $distributionLevels[$distributionLevel] :
+ sprintf(
+ '%s ',
+ $baseurl,
+ h($row['SharingGroup']['id']),
+ h($row['SharingGroup']['name'])
+ )
+ );
+
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/generic_field.php b/app/templates/element/genericElements/IndexTable/Fields/generic_field.php
new file mode 100644
index 0000000..afdcfc0
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/generic_field.php
@@ -0,0 +1,37 @@
+Hash->extract($row, $field['data_path']);
+ if (is_array($data)) {
+ if (count($data) > 1) {
+ $data = implode(', ', $data);
+ } else {
+ if (count($data) > 0) {
+ $data = $data[0];
+ } else {
+ $data = '';
+ }
+ }
+ }
+ if (is_bool($data)) {
+ $data = sprintf(
+ ' ',
+ $data ? 'check' : 'times'
+ );
+ $data = '';
+ } else {
+ $data = h($data);
+ if (!empty($field['privacy'])) {
+ $data = sprintf(
+ '**************************************** ',
+ $data
+ );
+ }
+ }
+ if (!empty($field['onClick'])) {
+ $data = sprintf(
+ '%s ',
+ $field['onClick'],
+ $data
+ );
+ }
+ echo $data;
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/icon.php b/app/templates/element/genericElements/IndexTable/Fields/icon.php
new file mode 100644
index 0000000..4f724f8
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/icon.php
@@ -0,0 +1,5 @@
+',
+ $this->FontAwesome->getClass($this->Hash->extract($row, $field['data_path'])[0])
+);
\ No newline at end of file
diff --git a/app/templates/element/genericElements/IndexTable/Fields/json.php b/app/templates/element/genericElements/IndexTable/Fields/json.php
new file mode 100644
index 0000000..6c14248
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/json.php
@@ -0,0 +1,16 @@
+Hash->extract($row, $field['data_path']));
+ // I feed dirty for this...
+ if (is_array($data) && count($data) === 1 && isset($data[0])) {
+ $data = $data[0];
+ }
+ echo sprintf(
+ '
',
+ h($k)
+ );
+?>
+
diff --git a/app/templates/element/genericElements/IndexTable/Fields/links.php b/app/templates/element/genericElements/IndexTable/Fields/links.php
new file mode 100644
index 0000000..7953d2f
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/links.php
@@ -0,0 +1,47 @@
+Hash->extract($row, $field['data_path']);
+ $url_param_data_paths = '';
+ $urlWithData = empty($field['url']) ? '#' : h($field['url']);
+ if (!empty($field['url_params_data_paths'])) {
+ if (is_array($field['url_params_data_paths'])) {
+ $temp = array();
+ foreach ($field['url_params_data_paths'] as $path) {
+ $temp[] = h($this->Hash->extract($row, $path)[0]);
+ }
+ $url_param_data_paths = implode('/', $temp);
+ } else {
+ $url_param_data_paths = h($this->Hash->extract($row, $field['url_params_data_paths'])[0]);
+ }
+ $urlWithData .= '/' . $url_param_data_paths;
+ }
+ $links = array();
+ foreach ($data_elements as $data) {
+ if (!empty($data['name'])) {
+ $field['title'] = $data['name'];
+ }
+ if (!empty($data['url'])) {
+ $data = $data['url'];
+ }
+ if (isset($field['url']) && strpos($field['url'], '%s') !== false) {
+ $url = sprintf(
+ $field['url'],
+ $data
+ );
+ } elseif (!empty($field['url_params_data_paths'])) {
+ $url = $urlWithData;
+ } else {
+ $url = $data;
+ }
+ $links[] = sprintf(
+ '%s ',
+ h($url),
+ empty($field['title']) ? h($data) : h($field['title']),
+ empty($field['title']) ? h($data) : h($field['title'])
+ );
+ }
+ echo implode(' ', $links);
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/list.php b/app/templates/element/genericElements/IndexTable/Fields/list.php
new file mode 100644
index 0000000..a524dc8
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/list.php
@@ -0,0 +1,16 @@
+Hash->extract($row, $field['data_path']);
+ foreach ($data as $key => $element) {
+ if (!is_numeric($key)) {
+ $data[$key] = sprintf(
+ '%s : %s',
+ h($key),
+ h($element)
+ );
+ } else {
+ $data[$key] = h($element);
+ }
+ }
+ $data = implode(' ', $data);
+ echo $data;
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/org.php b/app/templates/element/genericElements/IndexTable/Fields/org.php
new file mode 100644
index 0000000..7243d3b
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/org.php
@@ -0,0 +1,38 @@
+Hash->extract($row, $field['data_path']);
+ if (!isset($field['fields']['allow_picture'])) {
+ $field['fields']['allow_picture'] = true;
+ }
+ if (!isset($field['fields']['default_org'])) {
+ $field['fields']['default_org'] = '';
+ }
+ if (!empty($orgs)) {
+ if (!isset($orgs[0])) {
+ $orgs = array($orgs);
+ }
+ $count = count($orgs);
+ $i = 0;
+ foreach ($orgs as $org) {
+ $i++;
+ if (!empty($org['id']) || !empty($org['name'])) {
+ if ($field['fields']['allow_picture'] && !empty($org['id'])) {
+ echo $this->OrgImg->getOrgImg(array('name' => $org['name'], 'id' => $org['id'], 'size' => 24));
+ } else {
+ echo sprintf(
+ '%s ',
+ $baseurl,
+ empty($org['id']) ? h($org['uuid']) : h($org['id']),
+ h($org['name'])
+ );
+ }
+ if ($i < $count) {
+ echo ' ';
+ }
+ } else {
+ if ($field['fields']['allow_picture']) {
+ echo $this->OrgImg->getOrgImg(array('name' => $field['fields']['default_org'], 'size' => 24));
+ }
+ }
+ }
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/role.php b/app/templates/element/genericElements/IndexTable/Fields/role.php
new file mode 100644
index 0000000..377dfef
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/role.php
@@ -0,0 +1,22 @@
+Hash->extract($row, $field['data_path']);
+ if (!empty($roles)) {
+ if (!isset($roles[0])) {
+ $roles = array($roles);
+ }
+ $count = count($roles);
+ $i = 0;
+ foreach ($roles as $role) {
+ $i++;
+ echo sprintf(
+ '%s ',
+ $baseurl,
+ h($role['id']),
+ h($role['name'])
+ );
+ if ($i < $count) {
+ echo ' ';
+ }
+ }
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/selector.php b/app/templates/element/genericElements/IndexTable/Fields/selector.php
new file mode 100644
index 0000000..f7c6530
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/selector.php
@@ -0,0 +1,20 @@
+ $dataValue) {
+ $value = '';
+ if (!empty($dataValue['value'])) {
+ $value = $dataValue['value'];
+ }
+ if (!empty($dataValue['value_path']) && !empty($this->Hash->extract($row, $dataValue['value_path'])[0])) {
+ $value = $this->Hash->extract($row, $dataValue['value_path'])[0];
+ }
+ $data[] = 'data-' . h($dataField) . '="' . h($value) . '"';
+ }
+ }
+ echo sprintf(
+ ' ',
+ h($k),
+ empty($data) ? '' : implode(' ', $data)
+ );
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/self_registration.php b/app/templates/element/genericElements/IndexTable/Fields/self_registration.php
new file mode 100644
index 0000000..44efff9
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/self_registration.php
@@ -0,0 +1,17 @@
+Hash->extract($row, $field['data_path_requirement']);
+ if (empty($self_registration_flag[0])) {
+ echo ' ';
+ } else {
+ $url = $this->Hash->extract($row, $field['data_path'])[0];
+ echo sprintf(
+ ' %s',
+ (!empty($self_registration_flag[0])) ? 'check' : 'times',
+ (empty($self_registration_flag[0])) ? '' :
+ sprintf(
+ ' (' . __('click here') . ' )',
+ h($url)
+ )
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/sparkline.php b/app/templates/element/genericElements/IndexTable/Fields/sparkline.php
new file mode 100644
index 0000000..0119093
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/sparkline.php
@@ -0,0 +1,4 @@
+Hash->extract($row, $field['data_path'])[0];
+ echo $this->element('sparkline', array('scope' => $field['csv']['scope'], 'id' => $elementId, 'csv' => $field['csv']['data'][$k]));
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/tags.php b/app/templates/element/genericElements/IndexTable/Fields/tags.php
new file mode 100644
index 0000000..b3dd0d8
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/tags.php
@@ -0,0 +1,17 @@
+Hash->extract($row, $field['data_path']);
+ if (!empty($tags)) {
+ if (empty($tags[0])) {
+ $tags = array($tags);
+ }
+ echo $this->element(
+ 'ajaxTags',
+ array(
+ 'attributeId' => 0,
+ 'tags' => $tags,
+ 'tagAccess' => false,
+ 'static_tags_only' => 1
+ )
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/target_event.php b/app/templates/element/genericElements/IndexTable/Fields/target_event.php
new file mode 100644
index 0000000..0422c88
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/target_event.php
@@ -0,0 +1,33 @@
+DataPathCollector->extract($row, $field['data_path']);
+ if ($data['Feed.enabled']) {
+ if (in_array($data['Feed.source_format'], array('freetext', 'csv'))) {
+ if ($data['Feed.fixed_event']) {
+ if (!empty($data['Feed.event_error'])) {
+ echo sprintf(
+ '%s ',
+ __('Error: Invalid event!')
+ );
+ } else {
+ if ($data['Feed.event_id']) {
+ echo sprintf(
+ '%s ',
+ $baseurl,
+ h($data['Feed.event_id']),
+ __('Fixed event %s', h($data['Feed.event_id']))
+ );
+ } else {
+ echo __('New fixed event');
+ }
+ }
+ } else {
+ echo sprintf(
+ '%s ',
+ __('New event each pull can lead to potentially endlessly growing correlation tables. Only use this setting if you are sure that the data in the feed will mostly be completely distinct between each individual pull, otherwise use fixed events. Generally this setting is NOT recommended.'),
+ __('New event each pull')
+ );
+ }
+ }
+ } else {
+ echo __('Feed not enabled');
+ }
diff --git a/app/templates/element/genericElements/IndexTable/Fields/tester.php b/app/templates/element/genericElements/IndexTable/Fields/tester.php
new file mode 100644
index 0000000..d6447cf
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/tester.php
@@ -0,0 +1,30 @@
+%s%s
',
+ h($k),
+ h($column),
+ empty($field['textInput']) ? '' : sprintf(
+ ' ',
+ h($k),
+ h($column)
+ ),
+ !empty($field['button_class']) ? $field['button_class'] : 'btn-inverse',
+ empty($field['button_icon']) ? '' : $this->FontAwesome->getClass($field['button_icon']) . ' white',
+ !empty($field['button_style']) ? $field['button_style'] : 'line-height:20px;',
+ empty($field['textInput']) ? '' : 'border-radius: 0px 3px 3px 0px;',
+ empty($field['url']) ? '' : sprintf(
+ 'onClick="runOnDemandAction(this, \'%s%s\', \'onDemandButtonResult%s-%s\', \'%s\');"',
+ h($field['url']),
+ h($this->Hash->extract($row, $field['data_path'])[0]),
+ h($k),
+ h($column),
+ empty($field['textInput']) ? '' : sprintf(
+ 'onDemandTextEntry%s-%s',
+ h($k),
+ h($column)
+ )
+ ),
+ !empty($field['button']) ? h($field['button']) : ''
+ );
+
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/timestamp.php b/app/templates/element/genericElements/IndexTable/Fields/timestamp.php
new file mode 100644
index 0000000..5916178
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/timestamp.php
@@ -0,0 +1,7 @@
+Hash->extract($row, $field['data_path'])[0];
+ if (!empty($field['time_format'])) {
+ $timestamp = date($field['time_format'], $timestamp);
+ }
+ echo h($timestamp);
+?>
diff --git a/app/templates/element/genericElements/IndexTable/Fields/toggle.php b/app/templates/element/genericElements/IndexTable/Fields/toggle.php
new file mode 100644
index 0000000..cd17d9d
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/Fields/toggle.php
@@ -0,0 +1,59 @@
+Hash->extract($row, $field['data_path']);
+ $seed = rand();
+ $checkboxId = 'GenericToggle-' . $seed;
+ $tempboxId = 'TempBox-' . $seed;
+ echo sprintf(
+ '',
+ $checkboxId,
+ empty($data[0]) ? '' : 'checked',
+ $tempboxId
+ );
+?>
+
diff --git a/app/templates/element/genericElements/IndexTable/headers.php b/app/templates/element/genericElements/IndexTable/headers.php
new file mode 100644
index 0000000..c518b11
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/headers.php
@@ -0,0 +1,51 @@
+ $header) {
+ if (!isset($header['requirement']) || $header['requirement']) {
+ $header_data = '';
+ if (!empty($header['sort'])) {
+ if (!empty($header['name'])) {
+ $header_data = $paginator->sort($header['sort'], $header['name']);
+ } else {
+ $header_data = $paginator->sort($header['sort']);
+ }
+ } else {
+ if (!empty($header['element']) && $header['element'] === 'selector') {
+ $header_data = sprintf(
+ ' ',
+ empty($header['select_all_class']) ? 'select_all' : $header['select_all_class'],
+ empty($header['select_all_function']) ? 'onclick="toggleAllAttributeCheckboxes();"' : 'onclick="' . $header['select_all_function'] . '"'
+ );
+ } else {
+ $header_data = h($header['name']);
+ }
+
+ }
+ $headersHtml .= sprintf(
+ ' %s ',
+ $header_data
+ );
+ }
+ }
+ if ($actions) {
+ $headersHtml .= sprintf(
+ '%s ',
+ __('Actions')
+ );
+ }
+ $thead = '';
+ $thead .= $headersHtml;
+ $thead .= ' ';
+ echo $thead;
+?>
+
diff --git a/app/templates/element/genericElements/IndexTable/index_table.php b/app/templates/element/genericElements/IndexTable/index_table.php
new file mode 100644
index 0000000..cd61d04
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/index_table.php
@@ -0,0 +1,125 @@
+element('/genericElements/IndexTable/index_table', array(
+ * 'top_bar' => (
+ * // search/filter bar information compliant with ListTopBar
+ * ),
+ * 'data' => array(
+ // the actual data to be used
+ * ),
+ * 'fields' => array(
+ * // field list with information for the paginator, the elements used for the individual cells, etc
+ * ),
+ * 'title' => optional title,
+ * 'description' => optional description,
+ * 'primary_id_path' => path to each primary ID (extracted and passed as $primary to fields)
+ * ));
+ *
+ */
+ $tableRandomValue = Cake\Utility\Security::randomString(8);
+ echo '';
+ if (!empty($data['title'])) {
+ echo sprintf('
%s ', h($data['title']));
+ }
+ if (!empty($data['description'])) {
+ echo sprintf(
+ '
%s
',
+ empty($data['description']) ? '' : h($data['description'])
+ );
+ }
+ if (!empty($data['html'])) {
+ echo sprintf('
%s
', $data['html']);
+ }
+ $skipPagination = isset($data['skip_pagination']) ? $data['skip_pagination'] : 0;
+ if (!$skipPagination) {
+ $paginationData = !empty($data['paginatorOptions']) ? $data['paginatorOptions'] : array();
+ echo $this->element(
+ '/genericElements/IndexTable/pagination',
+ array(
+ 'paginationOptions' => $paginationData,
+ 'tableRandomValue' => $tableRandomValue
+ )
+ );
+ echo $this->element(
+ '/genericElements/IndexTable/pagination_links'
+ );
+ }
+ if (!empty($data['top_bar'])) {
+ echo $this->element(
+ '/genericElements/ListTopBar/scaffold',
+ array(
+ 'data' => $data['top_bar'],
+ 'tableRandomValue' => $tableRandomValue
+ )
+ );
+ }
+ $rows = '';
+ $row_element = isset($data['row_element']) ? $data['row_element'] : 'row';
+ $options = isset($data['options']) ? $data['options'] : array();
+ $actions = isset($data['actions']) ? $data['actions'] : array();
+ $dblclickActionArray = isset($data['actions']) ? $this->Hash->extract($data['actions'], '{n}[dbclickAction]') : array();
+ $dbclickAction = '';
+ foreach ($data['data'] as $k => $data_row) {
+ $primary = null;
+ if (!empty($data['primary_id_path'])) {
+ $primary = $this->Hash->extract($data_row, $data['primary_id_path'])[0];
+ }
+ if (!empty($dblclickActionArray)) {
+ $dbclickAction = sprintf("changeLocationFromIndexDblclick(%s)", $k);
+ }
+ $rows .= sprintf(
+ '
%s ',
+ h($k),
+ empty($dbclickAction) ? '' : 'ondblclick="' . $dbclickAction . '"',
+ empty($primary) ? '' : 'data-primary-id="' . $primary . '"',
+ $this->element(
+ '/genericElements/IndexTable/' . $row_element,
+ array(
+ 'k' => $k,
+ 'row' => $data_row,
+ 'fields' => $data['fields'],
+ 'options' => $options,
+ 'actions' => $actions,
+ 'primary' => $primary,
+ 'tableRandomValue' => $tableRandomValue
+ )
+ )
+ );
+ }
+ $tbody = '
' . $rows . ' ';
+ echo sprintf(
+ '
',
+ $tableRandomValue,
+ $this->element(
+ '/genericElements/IndexTable/headers',
+ array(
+ 'fields' => $data['fields'],
+ 'paginator' => $this->Paginator,
+ 'actions' => (empty($data['actions']) ? false : true),
+ 'tableRandomValue' => $tableRandomValue
+ )
+ ),
+ $tbody
+ );
+ if (!$skipPagination) {
+ echo $this->element('/genericElements/IndexTable/pagination_counter', $paginationData);
+ echo $this->element('/genericElements/IndexTable/pagination_links');
+ }
+ echo '
';
+?>
+
diff --git a/app/templates/element/genericElements/IndexTable/pagination.php b/app/templates/element/genericElements/IndexTable/pagination.php
new file mode 100644
index 0000000..9a06021
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/pagination.php
@@ -0,0 +1,36 @@
+ '#table-container-' . h($tableRandomValue),
+ 'evalScripts' => true
+ );
+ if (!empty($paginationOptions)) {
+ $options = array_merge($options, $paginationOptions);
+ }
+ $onClick = sprintf(
+ 'onClick="executePagination(%s, %s);"',
+ "'" . h($tableRandomValue) . "'",
+ "'{{url}}'"
+
+ );
+ $this->Paginator->setTemplates(
+ [
+ 'nextActive' => '{{text}} ',
+ 'nextDisabled' => '{{text}} ',
+ 'prevActive' => '{{text}} ',
+ 'prevDisabled' => '{{text}} ',
+ 'counterRange' => '{{start}} - {{end}} of {{count}}',
+ 'counterPages' => '{{page}} of {{pages}}',
+ 'first' => '{{text}} ',
+ 'last' => '{{text}} ',
+ 'number' => '{{text}} ',
+ 'current' => '{{text}} ',
+ 'ellipsis' => '… ',
+ 'sort' => '{{text}} ',
+ 'sortAsc' => '{{text}} ',
+ 'sortDesc' => '{{text}} ',
+ 'sortAscLocked' => '{{text}} ',
+ 'sortDescLocked' => '{{text}} '
+ ]
+ );
+ echo $this->Paginator->options($options);
+?>
diff --git a/app/templates/element/genericElements/IndexTable/pagination_counter.php b/app/templates/element/genericElements/IndexTable/pagination_counter.php
new file mode 100644
index 0000000..a08e917
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/pagination_counter.php
@@ -0,0 +1,17 @@
+%s
',
+ $this->Paginator->counter(
+ sprintf(
+ __('Page %s of %s, showing %s %s out of %s total, starting on record %s, ending on %s'),
+ '{{page}}',
+ '{{pages}}',
+ '{{current}}',
+ '{{model}}',
+ '{{count}}',
+ '{{start}}',
+ '{{end}}'
+ )
+ )
+ );
+?>
diff --git a/app/templates/element/genericElements/IndexTable/pagination_limiter.php b/app/templates/element/genericElements/IndexTable/pagination_limiter.php
new file mode 100644
index 0000000..7284964
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/pagination_limiter.php
@@ -0,0 +1,11 @@
+ 10, 25 => 25, 50 => 50];
+}
+
+if (empty($selectedOption)) {
+ $selectedOption = false;
+}
+
+echo $this->Paginator->limitControl($limits, $selectedOption);
diff --git a/app/templates/element/genericElements/IndexTable/pagination_links.php b/app/templates/element/genericElements/IndexTable/pagination_links.php
new file mode 100644
index 0000000..6641e1a
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/pagination_links.php
@@ -0,0 +1,8 @@
+',
+ __(''),
+ $this->Paginator->prev(__('Previous')),
+ $this->Paginator->numbers(['first' => 1, 'last' => 1]),
+ $this->Paginator->next(__('Next'))
+ );
diff --git a/app/templates/element/genericElements/IndexTable/row.php b/app/templates/element/genericElements/IndexTable/row.php
new file mode 100644
index 0000000..5422790
--- /dev/null
+++ b/app/templates/element/genericElements/IndexTable/row.php
@@ -0,0 +1,63 @@
+ $field) {
+ $field['data_path'] = empty($field['data_path']) ? '' : $field['data_path'];
+ if (!isset($field['requirement']) || $field['requirement']) {
+ if (empty($field['element'])) {
+ $valueField = $this->element('/genericElements/IndexTable/Fields/generic_field', array('field' => $field, 'row' => $row, 'data_path' => empty($field['data_path']) ? '' : $field['data_path'], 'k' => $k, 'column' => $column));
+ } else {
+ $valueField = $this->element(
+ '/genericElements/IndexTable/Fields/' . $field['element'],
+ array(
+ 'field' => $field,
+ 'row' => $row,
+ 'column' => $column,
+ 'data_path' => empty($field['data_path']) ? '' : $field['data_path'],
+ 'k' => $k,
+ 'primary' => $primary,
+ 'tableRandomValue' => $tableRandomValue
+ )
+ );
+ }
+ $rowHtml .= sprintf(
+ '%s ',
+ (empty($field['id'])) ? '' : sprintf('id="%s"', $field['id']),
+ (empty($field['class'])) ? '' : sprintf(' class="%s"', $field['class']),
+ (empty($field['style'])) ? '' : sprintf(' style="%s"', $field['style']),
+ (empty($field['title'])) ? '' : sprintf(' title="%s"', $field['title']),
+ (empty($field['name'])) ? '' : sprintf(
+ ' data-path="%s"',
+ is_array($field['data_path']) ?
+ h(implode(', ', $field['data_path'])) :
+ (h($field['data_path']))
+ ),
+ (empty($field['encode_raw_value']) || empty($field['data_path'])) ? '' : sprintf(' data-value="%s"', (h($this->Hash->extract($row, $field['data_path'])[0]))),
+ (empty($field['ondblclick'])) ? '' : sprintf(' ondblclick="%s"', $field['ondblclick']),
+ $valueField
+ );
+ }
+ }
+ if (!empty($actions)) {
+ $rowHtml .= $this->element(
+ '/genericElements/IndexTable/Fields/actions',
+ array(
+ 'actions' => $actions,
+ 'row' => $row,
+ 'column' => $column,
+ 'primary' => $primary,
+ 'tableRandomValue' => $tableRandomValue
+ )
+ );
+ }
+ echo ($rowHtml);
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/element_embedded.php b/app/templates/element/genericElements/ListTopBar/element_embedded.php
new file mode 100644
index 0000000..a3b540b
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/element_embedded.php
@@ -0,0 +1,47 @@
+ $dataValue) {
+ $dataFields[] = sprintf(
+ 'data-%s="%s"',
+ h($dataKey),
+ h($dataValue)
+ );
+ }
+ }
+ $dataFields = implode(' ', $dataFields);
+ echo sprintf(
+ '%s%s%s ',
+ empty($data['class']) ? '' : h($data['class']),
+ empty($data['active']) ? '' : 'background-blue', // Change the default class for highlighted/active toggles here
+ empty($data['id']) ? '' : h($data['id']),
+ empty($data['url']) ? '#' : h($data['url']), // prevent default is passed if the url is not set
+ empty($onClick) ? '' : $onClick, // pass $data['onClick'] for the function name to call and $data['onClickParams'] for the parameter list
+ empty($dataFields) ? '' : $dataFields,
+ empty($data['title']) ? '' : sprintf('title="%s"', h($data['title'])),
+ !empty($data['text']) ? '' : !empty($data['title']) ? sprintf('aria-label="%s"', h($data['title'])) : '',
+ empty($data['fa-icon']) ? '' : sprintf(' ', $data['fa-icon']), // this has to be sanitised beforehand!
+ empty($data['html']) ? '' : $data['html'], // this has to be sanitised beforehand!
+ empty($data['text']) ? '' : h($data['text'])
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/element_group.php b/app/templates/element/genericElements/ListTopBar/element_group.php
new file mode 100644
index 0000000..b24956d
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/element_group.php
@@ -0,0 +1,33 @@
+ $dataValue) {
+ $dataFields[] = sprintf(
+ 'data-%s="%s"',
+ h($dataKey),
+ h($dataValue)
+ );
+ }
+ }
+ $dataFields = implode(' ', $dataFields);
+ if (!empty($data['children'])) {
+ $child_data = '';
+ foreach ($data['children'] as $child) {
+ $child_data .= $this->element('/genericElements/ListTopBar/element_embedded', array('data' => $child));
+ }
+ }
+ echo sprintf(
+ '%s%s%s ',
+ empty($data['class']) ? '' : h($data['class']),
+ empty($data['active']) ? 'btn-inverse' : 'btn-primary', // Change the default class for highlighted/active toggles here
+ empty($data['id']) ? '' : 'id="' . h($data['id']) . '"',
+ empty($data['title']) ? '' : sprintf('title="%s"', h($data['title'])),
+ !empty($data['text']) ? '' : !empty($data['title']) ? sprintf('aria-label="%s"', h($data['title'])) : '',
+ empty($data['fa-icon']) ? '' : sprintf(' ', $data['fa-icon']), // this has to be sanitised beforehand!
+ empty($data['html']) ? '' : $data['html'], // this has to be sanitised beforehand!
+ empty($data['text']) ? '' : h($data['text']),
+ empty($data['children']) ? '' : $child_data
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/element_simple.php b/app/templates/element/genericElements/ListTopBar/element_simple.php
new file mode 100644
index 0000000..bf3091a
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/element_simple.php
@@ -0,0 +1,56 @@
+ $dataValue) {
+ $dataFields[] = sprintf(
+ 'data-%s="%s"',
+ h($dataKey),
+ h($dataValue)
+ );
+ }
+ }
+ $dataFields = implode(' ', $dataFields);
+ echo sprintf(
+ '%s%s%s ',
+ empty($data['class']) ? '' : h($data['class']),
+ empty($data['active']) ? 'btn-inverse' : 'btn-primary', // Change the default class for highlighted/active toggles here
+ empty($data['id']) ? '' : 'id="' . h($data['id']) . '"',
+ empty($data['url']) ? '#' : h($data['url']), // prevent default is passed if the url is not set
+ empty($onClick) ? '' : $onClick, // pass $data['onClick'] for the function name to call and $data['onClickParams'] for the parameter list
+ empty($dataFields) ? '' : $dataFields,
+ empty($data['title']) ? '' : sprintf('title="%s"', h($data['title'])),
+ empty($data['style']) ? '' : sprintf('style="%s"', h($data['style'])),
+ !empty($data['text']) ? '' : (!empty($data['title']) ? sprintf('aria-label="%s"', h($data['title'])) : ''),
+ empty($data['fa-icon']) ? '' : sprintf(
+ ' ',
+ empty($data['fa-source']) ? 'fas' : h($data['fa-source']),
+ $data['fa-icon']
+ ), // this has to be sanitised beforehand!
+ empty($data['html']) ? '' : $data['html'], // this has to be sanitised beforehand!
+ empty($data['text']) ? '' : h($data['text'])
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/group_live_search.php b/app/templates/element/genericElements/ListTopBar/group_live_search.php
new file mode 100644
index 0000000..e20509b
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/group_live_search.php
@@ -0,0 +1,13 @@
+',
+ empty($data['placeholder']) ? '' : h($data['placeholder']),
+ empty($data['placeholder']) ? '' : h($data['placeholder'])
+ );
+ echo sprintf(
+ '%s
',
+ $input
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/group_search.php b/app/templates/element/genericElements/ListTopBar/group_search.php
new file mode 100644
index 0000000..cf74859
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/group_search.php
@@ -0,0 +1,58 @@
+%s%s ',
+ empty($data['data']) ? '' : h($data['data']),
+ h($tableRandomValue),
+ empty($data['fa-icon']) ? '' : sprintf(' ', h($data['fa-icon'])),
+ empty($data['button']) ? '' : h($data['button'])
+ );
+ if (!empty($data['cancel'])) {
+ $button .= $this->element('/genericElements/ListTopBar/element_simple', array('data' => $data['cancel']));
+ }
+ $input = sprintf(
+ ' ',
+ h($tableRandomValue),
+ empty($data['placeholder']) ? '' : h($data['placeholder']),
+ empty($data['placeholder']) ? '' : h($data['placeholder']),
+ empty($data['id']) ? 'quickFilterField' : h($data['id']),
+ empty($data['searchKey']) ? 'searchall' : h($data['searchKey']),
+ empty($data['value']) ? '' : h($data['value'])
+ );
+ echo sprintf(
+ '%s%s
',
+ h($tableRandomValue),
+ $input,
+ $button
+ );
+ }
+?>
+
diff --git a/app/templates/element/genericElements/ListTopBar/group_simple.php b/app/templates/element/genericElements/ListTopBar/group_simple.php
new file mode 100644
index 0000000..cdc87d7
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/group_simple.php
@@ -0,0 +1,13 @@
+element('/genericElements/ListTopBar/element_' . (empty($element['type']) ? 'simple' : h($element['type'])), array('data' => $element));
+ }
+ echo sprintf(
+ '%s
',
+ (!empty($data['id'])) ? 'id="' . h($data['id']) . '"' : '',
+ $elements
+ );
+ }
+?>
diff --git a/app/templates/element/genericElements/ListTopBar/scaffold.php b/app/templates/element/genericElements/ListTopBar/scaffold.php
new file mode 100644
index 0000000..81c0a25
--- /dev/null
+++ b/app/templates/element/genericElements/ListTopBar/scaffold.php
@@ -0,0 +1,17 @@
+element('/genericElements/ListTopBar/group_' . (empty($group['type']) ? 'simple' : h($group['type'])), array('data' => $group, 'tableRandomValue' => $tableRandomValue));
+ }
+ $tempClass = "btn-toolbar";
+ if (count($data['children']) > 1) {
+ $tempClass .= ' justify-content-between';
+ } else if (!empty($data['pull'])) {
+ $tempClass .= ' float-' . h($data['pull']);
+ }
+ echo sprintf(
+ '%s
',
+ $tempClass,
+ $groups
+ );
+?>
diff --git a/app/templates/element/genericElements/SideMenu/side_menu.php b/app/templates/element/genericElements/SideMenu/side_menu.php
new file mode 100644
index 0000000..aaa8ac0
--- /dev/null
+++ b/app/templates/element/genericElements/SideMenu/side_menu.php
@@ -0,0 +1,106 @@
+ [
+ 'Individuals' => [
+ 'label' => __('Individuals'),
+ 'url' => '/individuals/index',
+ 'children' => [
+ 'index' => [
+ 'url' => '/individuals/index',
+ 'label' => __('List individuals')
+ ],
+ 'add' => [
+ 'url' => '/individuals/add',
+ 'label' => __('Add individual')
+ ],
+ 'view' => [
+ 'url' => '/individuals/view/{{id}}',
+ 'label' => __('View individual'),
+ 'actions' => ['delete', 'edit', 'view']
+ ],
+ 'edit' => [
+ 'url' => '/individuals/edit/{{id}}',
+ 'label' => __('Edit individual'),
+ 'actions' => ['edit', 'delete', 'view']
+ ],
+ 'delete' => [
+ 'url' => '/individuals/delete/{{id}}',
+ 'label' => __('Delete individual'),
+ 'actions' => ['delete', 'edit', 'view']
+ ]
+ ]
+ ],
+ 'Organisations' => [
+ 'label' => __('Organisations'),
+ 'url' => '/organisations/index',
+ 'children' => [
+ 'index' => [
+ 'url' => '/organisations/index',
+ 'label' => __('List organisations')
+ ],
+ 'add' => [
+ 'url' => '/organisations/add',
+ 'label' => __('Add organisation')
+ ],
+ 'view' => [
+ 'url' => '/organisations/view/{{id}}',
+ 'label' => __('View organisation'),
+ 'actions' => ['delete', 'edit', 'view']
+ ],
+ 'edit' => [
+ 'url' => '/organisations/edit/{{id}}',
+ 'label' => __('Edit organisation'),
+ 'actions' => ['edit', 'delete', 'view']
+ ],
+ 'delete' => [
+ 'url' => '/organisations/delete/{{id}}',
+ 'label' => __('Delete organisation'),
+ 'actions' => ['delete', 'edit', 'view']
+ ]
+ ]
+ ]
+ ]
+];
+$children = '';
+if (isset($menu[$metaGroup])) {
+ foreach ($menu[$metaGroup] as $scope => $scopeData) {
+ $children .= sprintf(
+ '',
+ empty($scopeData['url']) ? '#' : h($scopeData['url']),
+ empty($scopeData['class']) ? '' : h($scopeData['class']),
+ empty($scopeData['label']) ? h($scope) : $scopeData['label']
+ );
+ foreach ($scopeData['children'] as $action => $data) {
+ if (
+ (!empty($data['requirements']) && !$data['requirements']) ||
+ (
+ !empty($data['actions']) &&
+ !in_array($this->request->getParam('action'), $data['actions'])
+ ) ||
+ !empty($data['actions']) && $scope !== $this->request->getParam('controller')
+ ) {
+ continue;
+ }
+ $matches = [];
+ preg_match_all('/\{\{.*?\}\}/', $data['url'], $matches);
+ if (!empty($matches[0])) {
+ $mainEntity = \Cake\Utility\Inflector::underscore(\Cake\Utility\Inflector::singularize($scope));
+ foreach ($matches as $match) {
+ $data['url'] = str_replace($match[0], ${$mainEntity}[substr($match[0], 2, 2)], $data['url']);
+ }
+ }
+ $children .= sprintf(
+ '',
+ ($scope === $this->request->getParam('controller') && $action === $this->request->getParam('action')) ? 'active' : '',
+ empty($data['url']) ? '#' : h($data['url']),
+ empty($data['class']) ? '' : h($data['class']),
+ empty($data['label']) ? h($action) : $data['label']
+ );
+ }
+ }
+}
+echo sprintf(
+ '',
+ $children
+);
diff --git a/app/templates/element/genericElements/SingleViews/Fields/alignmentField.php b/app/templates/element/genericElements/SingleViews/Fields/alignmentField.php
new file mode 100644
index 0000000..8a80203
--- /dev/null
+++ b/app/templates/element/genericElements/SingleViews/Fields/alignmentField.php
@@ -0,0 +1,51 @@
+%s @ %s ',
+ h($alignment['type']),
+ sprintf(
+ '%s ',
+ h($alignment['organisation']['id']),
+ h($alignment['organisation']['name'])
+ ),
+ sprintf(
+ "populateAndLoadModal(%s);",
+ sprintf(
+ "'/alignments/delete/%s'",
+ $alignment['id']
+ )
+ )
+ );
+ }
+} else if ($field['scope'] === 'organisations') {
+ foreach ($data['alignments'] as $alignment) {
+ $alignments .= sprintf(
+ '',
+ h($alignment['type']),
+ sprintf(
+ '%s ',
+ h($alignment['individual']['id']),
+ h($alignment['individual']['email'])
+ ),
+ sprintf(
+ "populateAndLoadModal(%s);",
+ sprintf(
+ "'/alignments/delete/%s'",
+ $alignment['id']
+ )
+ )
+ );
+ }
+}
+echo sprintf(
+ '%s
%s
',
+ $alignments,
+ sprintf(
+ "populateAndLoadModal('/alignments/add/%s/%s');",
+ h($field['scope']),
+ h($data['id'])
+ ),
+ $field['scope'] === 'individuals' ? __('Add organisation') : __('Add individual')
+);
diff --git a/app/templates/element/genericElements/SingleViews/Fields/genericField.php b/app/templates/element/genericElements/SingleViews/Fields/genericField.php
new file mode 100644
index 0000000..d4b5c1d
--- /dev/null
+++ b/app/templates/element/genericElements/SingleViews/Fields/genericField.php
@@ -0,0 +1,3 @@
+%s',
+ sprintf(
+ '',
+ $randomId,
+ sprintf(
+ '%s ',
+ h($title)
+ )
+ ),
+ sprintf(
+ '
',
+ empty($collapsed) ? 'show' : 'collapsed',
+ $randomId,
+ $randomId,
+ h($url)
+ ),
+ empty($loadOn) ? 'ready' : h($loadOn)
+ );
diff --git a/app/templates/element/genericElements/SingleViews/single_view.php b/app/templates/element/genericElements/SingleViews/single_view.php
new file mode 100644
index 0000000..b37e762
--- /dev/null
+++ b/app/templates/element/genericElements/SingleViews/single_view.php
@@ -0,0 +1,64 @@
+element('/genericElements/SingleViews/single_view', [
+ * 'title' => '' //page title,
+ * 'description' => '' //description,
+ * 'description_html' => '' //html description, unsanitised,
+ * 'data' => $data, // the raw data passed for display
+ * 'fields' => [
+ * elements passed as to be displayed in the
element.
+ * format:
+ * [
+ 'key' => '' // key to be displayed
+ * 'path' => '' // path for the value to be parsed
+ * 'type' => '' // generic assumed if not filled, uses SingleViews/Fields/* elements
+ * ]
+ * ],
+ * 'children' => [
+ * // Additional elements attached to the currently viewed object. index views will be appended via ajax calls below.
+ [
+ * 'title' => '',
+ * 'url' => '', //cakephp compatible url, can be actual url or array for the constructor
+ * 'collapsed' => 0|1 // defaults to 0, whether to display it by default or not
+ * 'loadOn' => 'ready|expand' // load the data directly or only when expanded from a collapsed state
+ *
+ * ],
+ * ]
+ * ]);
+ *
+ */
+ $listElements = '';
+ if (!empty($fields)) {
+ foreach ($fields as $field) {
+ if (empty($field['type'])) {
+ $field['type'] = 'generic';
+ }
+ $listElements .= sprintf(
+ '%s %s ',
+ h($field['key']),
+ $this->element(
+ '/genericElements/SingleViews/Fields/' . $field['type'] . 'Field',
+ ['data' => $data, 'field' => $field]
+ )
+ );
+ }
+ }
+ $ajaxLists = '';
+ if (!empty($children)) {
+ foreach ($children as $child) {
+ $listElements .= $this->element(
+ '/genericElements/SingleViews/child',
+ array(
+ 'value' => $child
+ )
+ );
+ }
+ }
+ echo sprintf(
+ '',
+ empty($title) ? __('%s View', h(\Cake\Utility\Inflector::humanize($this->request->getParam('controller')))) : h($title),
+ empty($description) ? '' : sprintf('%s
', h($description)),
+ empty($description_html) ? '' : sprintf('%s
', $description_html),
+ $listElements,
+ $ajaxLists
+ );
diff --git a/app/templates/element/genericElements/footer.php b/app/templates/element/genericElements/footer.php
new file mode 100644
index 0000000..3e0c2af
--- /dev/null
+++ b/app/templates/element/genericElements/footer.php
@@ -0,0 +1,3 @@
+
diff --git a/app/templates/element/genericElements/genericModal.php b/app/templates/element/genericElements/genericModal.php
new file mode 100644
index 0000000..d49f881
--- /dev/null
+++ b/app/templates/element/genericElements/genericModal.php
@@ -0,0 +1,24 @@
+
+
diff --git a/app/templates/element/genericElements/header.php b/app/templates/element/genericElements/header.php
new file mode 100644
index 0000000..b0df381
--- /dev/null
+++ b/app/templates/element/genericElements/header.php
@@ -0,0 +1,146 @@
+ array(
+ 'url' => '#',
+ 'class' => 'navbar-brand',
+ 'text' => 'Cerebrate'
+ ),
+ 'collapse' => array(
+ array(
+ 'type' => 'group',
+ 'name' => 'ContactDB',
+ 'children' => array(
+ array(
+ 'text' => __('List Organisations'),
+ 'url' => '/organisations/index'
+ ),
+ array(
+ 'text' => __('Add Organisation'),
+ 'url' => '/organisations/add'
+ ),
+ array(
+ 'type' => 'divider'
+ ),
+ array(
+ 'text' => __('List Individuals'),
+ 'url' => '/individuals/index'
+ ),
+ array(
+ 'text' => __('Add Individual'),
+ 'url' => '/individuals/add'
+ ),
+ )
+ ),
+ array(
+ 'type' => 'group',
+ 'name' => 'Trust Circles',
+ 'children' => array(
+ array(
+ 'text' => __('List Sharing Groups'),
+ 'url' => '/sharing_groups/index'
+ ),
+ array(
+ 'text' => __('Add Sharing Group'),
+ 'url' => '/sharing_groups/add'
+ )
+ )
+ ),
+ array(
+ 'type' => 'group',
+ 'name' => __('Toolbox'),
+ 'children' => array(
+ array(
+ 'text' => __('List All'),
+ 'url' => '/tools/index'
+ ),
+ array(
+ 'text' => __('Add Tool'),
+ 'url' => '/tools/add'
+ )
+ )
+ ),
+ array(
+ 'type' => 'group',
+ 'name' => __('Admnistration'),
+ 'children' => array(
+ array(
+ 'text' => __('List Sharing Groups'),
+ 'url' => '/sharing_groups/index'
+ ),
+ array(
+ 'text' => __('Add Sharing Group'),
+ 'url' => '/sharing_groups/add'
+ )
+ )
+ ),
+ array(
+ 'type' => 'group',
+ 'name' => __('My Profile'),
+ 'children' => array(
+ array(
+ 'text' => __('View My Profile'),
+ 'url' => '/users/view/me'
+ ),
+ array(
+ 'text' => __('Modify My Profile'),
+ 'url' => '/users/edit/me'
+ )
+ )
+ )
+ )
+ );
+ $navdata = '';
+ foreach ($menu['collapse'] as $k => $menuElement) {
+ if ($menuElement['type'] === 'single') {
+ $navdata .= sprintf(
+ '%s ',
+ empty($menuElement['class']) ? '' : h($menuElement['class']),
+ empty($menuElement['url']) ? '' : h($menuElement['url']),
+ empty($menuElement['text']) ? '' : h($menuElement['text'])
+ );
+ } else if ($menuElement['type'] === 'group') {
+ $navdataElements = '';
+ foreach ($menuElement['children'] as $child) {
+ if (!empty($child['type']) && $child['type'] === 'divider') {
+ $navdataElements .= '
';
+ } else {
+ $navdataElements .= sprintf(
+ '%s ',
+ empty($child['class']) ? '' : h($child['class']),
+ empty($child['url']) ? '' : h($child['url']),
+ empty($child['text']) ? '' : h($child['text'])
+ );
+ }
+ }
+ $navdata .= sprintf(
+ '%s%s ',
+ sprintf(
+ '%s ',
+ 'dropdown-label-' . h($k),
+ h($menuElement['name'])
+ ),
+ sprintf(
+ '',
+ $navdataElements
+ )
+ );
+ }
+ }
+ $navdata = sprintf(
+ '',
+ $navdata
+ );
+ $homeButton = sprintf(
+ '%s ',
+ empty($menu['home']['class']) ? '' : h($menu['home']['class']),
+ empty($menu['home']['url']) ? '' : h($menu['home']['url']),
+ empty($menu['home']['text']) ? '' : h($menu['home']['text'])
+
+ );
+ echo sprintf(
+ '%s%s%s ',
+ $homeButton,
+ ' ',
+ $navdata
+ );
+?>
diff --git a/app/templates/email/html/default.php b/app/templates/email/html/default.php
new file mode 100644
index 0000000..a7b65d6
--- /dev/null
+++ b/app/templates/email/html/default.php
@@ -0,0 +1,21 @@
+ ' . $line . "\n";
+endforeach;
diff --git a/app/templates/email/text/default.php b/app/templates/email/text/default.php
new file mode 100644
index 0000000..ccebbfc
--- /dev/null
+++ b/app/templates/email/text/default.php
@@ -0,0 +1,17 @@
+
+
+
+
+
= __('Are you sure you want to delete {0} #{1}?', h(Cake\Utility\Inflector::singularize($scope)), h($id)) ?>
+
+
+
+
+
diff --git a/app/templates/layout/ajax.php b/app/templates/layout/ajax.php
new file mode 100644
index 0000000..cd51169
--- /dev/null
+++ b/app/templates/layout/ajax.php
@@ -0,0 +1,17 @@
+fetch('content');
diff --git a/app/templates/layout/default.php b/app/templates/layout/default.php
new file mode 100644
index 0000000..3eb32aa
--- /dev/null
+++ b/app/templates/layout/default.php
@@ -0,0 +1,63 @@
+
+
+
+
+ = $this->Html->charset() ?>
+
+
+ = $cakeDescription ?>:
+ = $this->fetch('title') ?>
+
+ = $this->Html->meta('icon') ?>
+ = $this->Html->css('bootstrap.css') ?>
+ = $this->Html->css('main.css') ?>
+ = $this->Html->css('font-awesome') ?>
+ = $this->Html->script('jquery-3.5.1.min.js') ?>
+ = $this->Html->script('popper.min.js') ?>
+ = $this->Html->script('bootstrap.bundle.js') ?>
+ = $this->Html->script('main.js') ?>
+ = $this->fetch('meta') ?>
+ = $this->fetch('css') ?>
+ = $this->fetch('script') ?>
+ = $this->Html->meta('favicon.ico', '/img/favicon.ico', ['type' => 'icon']); ?>
+
+
+
+ = $this->element('genericElements/header') ?>
+
+
+
+
+
+
+ = $this->Flash->render() ?>
+ = $this->fetch('content') ?>
+
+
+
+
+
+
+
+
diff --git a/app/templates/layout/email/html/default.php b/app/templates/layout/email/html/default.php
new file mode 100644
index 0000000..96b0e73
--- /dev/null
+++ b/app/templates/layout/email/html/default.php
@@ -0,0 +1,25 @@
+
+
+
+
+ = $this->fetch('title') ?>
+
+
+ = $this->fetch('content') ?>
+
+
diff --git a/app/templates/layout/email/text/default.php b/app/templates/layout/email/text/default.php
new file mode 100644
index 0000000..cd51169
--- /dev/null
+++ b/app/templates/layout/email/text/default.php
@@ -0,0 +1,17 @@
+fetch('content');
diff --git a/app/templates/layout/error.php b/app/templates/layout/error.php
new file mode 100644
index 0000000..dcb5f1c
--- /dev/null
+++ b/app/templates/layout/error.php
@@ -0,0 +1,43 @@
+
+
+
+
+ = $this->Html->charset() ?>
+
+ = $this->fetch('title') ?>
+
+ = $this->Html->meta('icon') ?>
+
+
+
+
+ = $this->Html->css('milligram.min.css') ?>
+ = $this->Html->css('cake.css') ?>
+
+ = $this->fetch('meta') ?>
+ = $this->fetch('css') ?>
+ = $this->fetch('script') ?>
+
+
+
+ = $this->Flash->render() ?>
+ = $this->fetch('content') ?>
+ = $this->Html->link(__('Back'), 'javascript:history.back()') ?>
+
+
+
diff --git a/app/tests/Fixture/.gitkeep b/app/tests/Fixture/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/tests/TestCase/ApplicationTest.php b/app/tests/TestCase/ApplicationTest.php
new file mode 100644
index 0000000..cd09f1e
--- /dev/null
+++ b/app/tests/TestCase/ApplicationTest.php
@@ -0,0 +1,87 @@
+bootstrap();
+ $plugins = $app->getPlugins();
+
+ $this->assertCount(3, $plugins);
+ $this->assertSame('Bake', $plugins->get('Bake')->getName());
+ $this->assertSame('DebugKit', $plugins->get('DebugKit')->getName());
+ $this->assertSame('Migrations', $plugins->get('Migrations')->getName());
+ }
+
+ /**
+ * testBootstrapPluginWitoutHalt
+ *
+ * @return void
+ */
+ public function testBootstrapPluginWithoutHalt()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $app = $this->getMockBuilder(Application::class)
+ ->setConstructorArgs([dirname(dirname(__DIR__)) . '/config'])
+ ->setMethods(['addPlugin'])
+ ->getMock();
+
+ $app->method('addPlugin')
+ ->will($this->throwException(new InvalidArgumentException('test exception.')));
+
+ $app->bootstrap();
+ }
+
+ /**
+ * testMiddleware
+ *
+ * @return void
+ */
+ public function testMiddleware()
+ {
+ $app = new Application(dirname(dirname(__DIR__)) . '/config');
+ $middleware = new MiddlewareQueue();
+
+ $middleware = $app->middleware($middleware);
+
+ $this->assertInstanceOf(ErrorHandlerMiddleware::class, $middleware->current());
+ $middleware->seek(1);
+ $this->assertInstanceOf(AssetMiddleware::class, $middleware->current());
+ $middleware->seek(2);
+ $this->assertInstanceOf(RoutingMiddleware::class, $middleware->current());
+ }
+}
diff --git a/app/tests/TestCase/Controller/Component/.gitkeep b/app/tests/TestCase/Controller/Component/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/tests/TestCase/Controller/PagesControllerTest.php b/app/tests/TestCase/Controller/PagesControllerTest.php
new file mode 100644
index 0000000..f2958f9
--- /dev/null
+++ b/app/tests/TestCase/Controller/PagesControllerTest.php
@@ -0,0 +1,126 @@
+get('/');
+ $this->assertResponseOk();
+ $this->get('/');
+ $this->assertResponseOk();
+ }
+
+ /**
+ * testDisplay method
+ *
+ * @return void
+ */
+ public function testDisplay()
+ {
+ $this->get('/pages/home');
+ $this->assertResponseOk();
+ $this->assertResponseContains('CakePHP');
+ $this->assertResponseContains('');
+ }
+
+ /**
+ * Test that missing template renders 404 page in production
+ *
+ * @return void
+ */
+ public function testMissingTemplate()
+ {
+ Configure::write('debug', false);
+ $this->get('/pages/not_existing');
+
+ $this->assertResponseError();
+ $this->assertResponseContains('Error');
+ }
+
+ /**
+ * Test that missing template in debug mode renders missing_template error page
+ *
+ * @return void
+ */
+ public function testMissingTemplateInDebug()
+ {
+ Configure::write('debug', true);
+ $this->get('/pages/not_existing');
+
+ $this->assertResponseFailure();
+ $this->assertResponseContains('Missing Template');
+ $this->assertResponseContains('Stacktrace');
+ $this->assertResponseContains('not_existing.php');
+ }
+
+ /**
+ * Test directory traversal protection
+ *
+ * @return void
+ */
+ public function testDirectoryTraversalProtection()
+ {
+ $this->get('/pages/../Layout/ajax');
+ $this->assertResponseCode(403);
+ $this->assertResponseContains('Forbidden');
+ }
+
+ /**
+ * Test that CSRF protection is applied to page rendering.
+ *
+ * @reutrn void
+ */
+ public function testCsrfAppliedError()
+ {
+ $this->post('/pages/home', ['hello' => 'world']);
+
+ $this->assertResponseCode(403);
+ $this->assertResponseContains('CSRF');
+ }
+
+ /**
+ * Test that CSRF protection is applied to page rendering.
+ *
+ * @reutrn void
+ */
+ public function testCsrfAppliedOk()
+ {
+ $this->enableCsrfToken();
+ $this->post('/pages/home', ['hello' => 'world']);
+
+ $this->assertResponseCode(200);
+ $this->assertResponseContains('CakePHP');
+ }
+}
diff --git a/app/tests/TestCase/Model/Behavior/.gitkeep b/app/tests/TestCase/Model/Behavior/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/tests/TestCase/View/Helper/.gitkeep b/app/tests/TestCase/View/Helper/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/tests/bootstrap.php b/app/tests/bootstrap.php
new file mode 100644
index 0000000..962815c
--- /dev/null
+++ b/app/tests/bootstrap.php
@@ -0,0 +1,52 @@
+ 'Cake\Database\Connection',
+ 'driver' => 'Cake\Database\Driver\Sqlite',
+ 'database' => TMP . 'debug_kit.sqlite',
+ 'encoding' => 'utf8',
+ 'cacheMetadata' => true,
+ 'quoteIdentifiers' => false,
+]);
+
+ConnectionManager::alias('test_debug_kit', 'debug_kit');
+
+// Fixate sessionid early on, as php7.2+
+// does not allow the sessionid to be set after stdout
+// has been written to.
+session_id('cli');
diff --git a/app/webroot/.htaccess b/app/webroot/.htaccess
new file mode 100644
index 0000000..85e3ae2
--- /dev/null
+++ b/app/webroot/.htaccess
@@ -0,0 +1,12 @@
+
+ RewriteEngine On
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^(.*)$ index.php?/$1 [QSA,L]
+
+ # Adds AUTH support to Rest Plugin:
+ RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
+
+
+ RequestHeader unset Proxy
+
diff --git a/app/webroot/bootstrap b/app/webroot/bootstrap
new file mode 160000
index 0000000..c9cd3e4
--- /dev/null
+++ b/app/webroot/bootstrap
@@ -0,0 +1 @@
+Subproject commit c9cd3e4a083a69bcd2eefb1d1b62e6106e2ce469
diff --git a/app/webroot/css/bootstrap.css b/app/webroot/css/bootstrap.css
new file mode 100644
index 0000000..8eac957
--- /dev/null
+++ b/app/webroot/css/bootstrap.css
@@ -0,0 +1,10224 @@
+/*!
+ * Bootstrap v4.4.1 (https://getbootstrap.com/)
+ * Copyright 2011-2019 The Bootstrap Authors
+ * Copyright 2011-2019 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+:root {
+ --blue: #007bff;
+ --indigo: #6610f2;
+ --purple: #6f42c1;
+ --pink: #e83e8c;
+ --red: #dc3545;
+ --orange: #fd7e14;
+ --yellow: #ffc107;
+ --green: #28a745;
+ --teal: #20c997;
+ --cyan: #17a2b8;
+ --white: #fff;
+ --gray: #6c757d;
+ --gray-dark: #343a40;
+ --primary: #007bff;
+ --secondary: #6c757d;
+ --success: #28a745;
+ --info: #17a2b8;
+ --warning: #ffc107;
+ --danger: #dc3545;
+ --light: #f8f9fa;
+ --dark: #343a40;
+ --breakpoint-xs: 0;
+ --breakpoint-sm: 576px;
+ --breakpoint-md: 768px;
+ --breakpoint-lg: 992px;
+ --breakpoint-xl: 1200px;
+ --font-family-sans-serif: -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-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: sans-serif;
+ line-height: 1.15;
+ -webkit-text-size-adjust: 100%;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
+ display: block;
+}
+
+body {
+ margin: 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-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ text-align: left;
+ background-color: #fff;
+}
+
+[tabindex="-1"]:focus:not(:focus-visible) {
+ outline: 0 !important;
+}
+
+hr {
+ box-sizing: content-box;
+ height: 0;
+ overflow: visible;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+}
+
+p {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+abbr[title],
+abbr[data-original-title] {
+ text-decoration: underline;
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+ cursor: help;
+ border-bottom: 0;
+ -webkit-text-decoration-skip-ink: none;
+ text-decoration-skip-ink: none;
+}
+
+address {
+ margin-bottom: 1rem;
+ font-style: normal;
+ line-height: inherit;
+}
+
+ol,
+ul,
+dl {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: 700;
+}
+
+dd {
+ margin-bottom: .5rem;
+ margin-left: 0;
+}
+
+blockquote {
+ margin: 0 0 1rem;
+}
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+small {
+ font-size: 80%;
+}
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -.25em;
+}
+
+sup {
+ top: -.5em;
+}
+
+a {
+ color: #007bff;
+ text-decoration: none;
+ background-color: transparent;
+}
+
+a:hover {
+ color: #0056b3;
+ text-decoration: underline;
+}
+
+a:not([href]) {
+ color: inherit;
+ text-decoration: none;
+}
+
+a:not([href]):hover {
+ color: inherit;
+ text-decoration: none;
+}
+
+pre,
+code,
+kbd,
+samp {
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ font-size: 1em;
+}
+
+pre {
+ margin-top: 0;
+ margin-bottom: 1rem;
+ overflow: auto;
+}
+
+figure {
+ margin: 0 0 1rem;
+}
+
+img {
+ vertical-align: middle;
+ border-style: none;
+}
+
+svg {
+ overflow: hidden;
+ vertical-align: middle;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+caption {
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+ color: #6c757d;
+ text-align: left;
+ caption-side: bottom;
+}
+
+th {
+ text-align: inherit;
+}
+
+label {
+ display: inline-block;
+ margin-bottom: 0.5rem;
+}
+
+button {
+ border-radius: 0;
+}
+
+button:focus {
+ outline: 1px dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+button,
+input {
+ overflow: visible;
+}
+
+button,
+select {
+ text-transform: none;
+}
+
+select {
+ word-wrap: normal;
+}
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+button:not(:disabled),
+[type="button"]:not(:disabled),
+[type="reset"]:not(:disabled),
+[type="submit"]:not(:disabled) {
+ cursor: pointer;
+}
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+input[type="date"],
+input[type="time"],
+input[type="datetime-local"],
+input[type="month"] {
+ -webkit-appearance: listbox;
+}
+
+textarea {
+ overflow: auto;
+ resize: vertical;
+}
+
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+legend {
+ display: block;
+ width: 100%;
+ max-width: 100%;
+ padding: 0;
+ margin-bottom: .5rem;
+ font-size: 1.5rem;
+ line-height: inherit;
+ color: inherit;
+ white-space: normal;
+}
+
+progress {
+ vertical-align: baseline;
+}
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+[type="search"] {
+ outline-offset: -2px;
+ -webkit-appearance: none;
+}
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+::-webkit-file-upload-button {
+ font: inherit;
+ -webkit-appearance: button;
+}
+
+output {
+ display: inline-block;
+}
+
+summary {
+ display: list-item;
+ cursor: pointer;
+}
+
+template {
+ display: none;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+h1, h2, h3, h4, h5, h6,
+.h1, .h2, .h3, .h4, .h5, .h6 {
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ line-height: 1.2;
+}
+
+h1, .h1 {
+ font-size: 2.5rem;
+}
+
+h2, .h2 {
+ font-size: 2rem;
+}
+
+h3, .h3 {
+ font-size: 1.75rem;
+}
+
+h4, .h4 {
+ font-size: 1.5rem;
+}
+
+h5, .h5 {
+ font-size: 1.25rem;
+}
+
+h6, .h6 {
+ font-size: 1rem;
+}
+
+.lead {
+ font-size: 1.25rem;
+ font-weight: 300;
+}
+
+.display-1 {
+ font-size: 6rem;
+ font-weight: 300;
+ line-height: 1.2;
+}
+
+.display-2 {
+ font-size: 5.5rem;
+ font-weight: 300;
+ line-height: 1.2;
+}
+
+.display-3 {
+ font-size: 4.5rem;
+ font-weight: 300;
+ line-height: 1.2;
+}
+
+.display-4 {
+ font-size: 3.5rem;
+ font-weight: 300;
+ line-height: 1.2;
+}
+
+hr {
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ border: 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+small,
+.small {
+ font-size: 80%;
+ font-weight: 400;
+}
+
+mark,
+.mark {
+ padding: 0.2em;
+ background-color: #fcf8e3;
+}
+
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline-item {
+ display: inline-block;
+}
+
+.list-inline-item:not(:last-child) {
+ margin-right: 0.5rem;
+}
+
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+
+.blockquote {
+ margin-bottom: 1rem;
+ font-size: 1.25rem;
+}
+
+.blockquote-footer {
+ display: block;
+ font-size: 80%;
+ color: #6c757d;
+}
+
+.blockquote-footer::before {
+ content: "\2014\00A0";
+}
+
+.img-fluid {
+ max-width: 100%;
+ height: auto;
+}
+
+.img-thumbnail {
+ padding: 0.25rem;
+ background-color: #fff;
+ border: 1px solid #dee2e6;
+ border-radius: 0.25rem;
+ max-width: 100%;
+ height: auto;
+}
+
+.figure {
+ display: inline-block;
+}
+
+.figure-img {
+ margin-bottom: 0.5rem;
+ line-height: 1;
+}
+
+.figure-caption {
+ font-size: 90%;
+ color: #6c757d;
+}
+
+code {
+ font-size: 87.5%;
+ color: #e83e8c;
+ word-wrap: break-word;
+}
+
+a > code {
+ color: inherit;
+}
+
+kbd {
+ padding: 0.2rem 0.4rem;
+ font-size: 87.5%;
+ color: #fff;
+ background-color: #212529;
+ border-radius: 0.2rem;
+}
+
+kbd kbd {
+ padding: 0;
+ font-size: 100%;
+ font-weight: 700;
+}
+
+pre {
+ display: block;
+ font-size: 87.5%;
+ color: #212529;
+}
+
+pre code {
+ font-size: inherit;
+ color: inherit;
+ word-break: normal;
+}
+
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+
+.container {
+ width: 100%;
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+@media (min-width: 576px) {
+ .container {
+ max-width: 540px;
+ }
+}
+
+@media (min-width: 768px) {
+ .container {
+ max-width: 720px;
+ }
+}
+
+@media (min-width: 992px) {
+ .container {
+ max-width: 960px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .container {
+ max-width: 1140px;
+ }
+}
+
+.container-fluid, .container-sm, .container-md, .container-lg, .container-xl {
+ width: 100%;
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+@media (min-width: 576px) {
+ .container, .container-sm {
+ max-width: 540px;
+ }
+}
+
+@media (min-width: 768px) {
+ .container, .container-sm, .container-md {
+ max-width: 720px;
+ }
+}
+
+@media (min-width: 992px) {
+ .container, .container-sm, .container-md, .container-lg {
+ max-width: 960px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .container, .container-sm, .container-md, .container-lg, .container-xl {
+ max-width: 1140px;
+ }
+}
+
+.row {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ margin-right: -15px;
+ margin-left: -15px;
+}
+
+.no-gutters {
+ margin-right: 0;
+ margin-left: 0;
+}
+
+.no-gutters > .col,
+.no-gutters > [class*="col-"] {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,
+.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,
+.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,
+.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,
+.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,
+.col-xl-auto {
+ position: relative;
+ width: 100%;
+ padding-right: 15px;
+ padding-left: 15px;
+}
+
+.col {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ max-width: 100%;
+}
+
+.row-cols-1 > * {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+}
+
+.row-cols-2 > * {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+}
+
+.row-cols-3 > * {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+}
+
+.row-cols-4 > * {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+}
+
+.row-cols-5 > * {
+ -ms-flex: 0 0 20%;
+ flex: 0 0 20%;
+ max-width: 20%;
+}
+
+.row-cols-6 > * {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+}
+
+.col-auto {
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: auto;
+ max-width: 100%;
+}
+
+.col-1 {
+ -ms-flex: 0 0 8.333333%;
+ flex: 0 0 8.333333%;
+ max-width: 8.333333%;
+}
+
+.col-2 {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+}
+
+.col-3 {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+}
+
+.col-4 {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+}
+
+.col-5 {
+ -ms-flex: 0 0 41.666667%;
+ flex: 0 0 41.666667%;
+ max-width: 41.666667%;
+}
+
+.col-6 {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+}
+
+.col-7 {
+ -ms-flex: 0 0 58.333333%;
+ flex: 0 0 58.333333%;
+ max-width: 58.333333%;
+}
+
+.col-8 {
+ -ms-flex: 0 0 66.666667%;
+ flex: 0 0 66.666667%;
+ max-width: 66.666667%;
+}
+
+.col-9 {
+ -ms-flex: 0 0 75%;
+ flex: 0 0 75%;
+ max-width: 75%;
+}
+
+.col-10 {
+ -ms-flex: 0 0 83.333333%;
+ flex: 0 0 83.333333%;
+ max-width: 83.333333%;
+}
+
+.col-11 {
+ -ms-flex: 0 0 91.666667%;
+ flex: 0 0 91.666667%;
+ max-width: 91.666667%;
+}
+
+.col-12 {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+}
+
+.order-first {
+ -ms-flex-order: -1;
+ order: -1;
+}
+
+.order-last {
+ -ms-flex-order: 13;
+ order: 13;
+}
+
+.order-0 {
+ -ms-flex-order: 0;
+ order: 0;
+}
+
+.order-1 {
+ -ms-flex-order: 1;
+ order: 1;
+}
+
+.order-2 {
+ -ms-flex-order: 2;
+ order: 2;
+}
+
+.order-3 {
+ -ms-flex-order: 3;
+ order: 3;
+}
+
+.order-4 {
+ -ms-flex-order: 4;
+ order: 4;
+}
+
+.order-5 {
+ -ms-flex-order: 5;
+ order: 5;
+}
+
+.order-6 {
+ -ms-flex-order: 6;
+ order: 6;
+}
+
+.order-7 {
+ -ms-flex-order: 7;
+ order: 7;
+}
+
+.order-8 {
+ -ms-flex-order: 8;
+ order: 8;
+}
+
+.order-9 {
+ -ms-flex-order: 9;
+ order: 9;
+}
+
+.order-10 {
+ -ms-flex-order: 10;
+ order: 10;
+}
+
+.order-11 {
+ -ms-flex-order: 11;
+ order: 11;
+}
+
+.order-12 {
+ -ms-flex-order: 12;
+ order: 12;
+}
+
+.offset-1 {
+ margin-left: 8.333333%;
+}
+
+.offset-2 {
+ margin-left: 16.666667%;
+}
+
+.offset-3 {
+ margin-left: 25%;
+}
+
+.offset-4 {
+ margin-left: 33.333333%;
+}
+
+.offset-5 {
+ margin-left: 41.666667%;
+}
+
+.offset-6 {
+ margin-left: 50%;
+}
+
+.offset-7 {
+ margin-left: 58.333333%;
+}
+
+.offset-8 {
+ margin-left: 66.666667%;
+}
+
+.offset-9 {
+ margin-left: 75%;
+}
+
+.offset-10 {
+ margin-left: 83.333333%;
+}
+
+.offset-11 {
+ margin-left: 91.666667%;
+}
+
+@media (min-width: 576px) {
+ .col-sm {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ max-width: 100%;
+ }
+ .row-cols-sm-1 > * {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .row-cols-sm-2 > * {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .row-cols-sm-3 > * {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .row-cols-sm-4 > * {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .row-cols-sm-5 > * {
+ -ms-flex: 0 0 20%;
+ flex: 0 0 20%;
+ max-width: 20%;
+ }
+ .row-cols-sm-6 > * {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-sm-auto {
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: auto;
+ max-width: 100%;
+ }
+ .col-sm-1 {
+ -ms-flex: 0 0 8.333333%;
+ flex: 0 0 8.333333%;
+ max-width: 8.333333%;
+ }
+ .col-sm-2 {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-sm-3 {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .col-sm-4 {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .col-sm-5 {
+ -ms-flex: 0 0 41.666667%;
+ flex: 0 0 41.666667%;
+ max-width: 41.666667%;
+ }
+ .col-sm-6 {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .col-sm-7 {
+ -ms-flex: 0 0 58.333333%;
+ flex: 0 0 58.333333%;
+ max-width: 58.333333%;
+ }
+ .col-sm-8 {
+ -ms-flex: 0 0 66.666667%;
+ flex: 0 0 66.666667%;
+ max-width: 66.666667%;
+ }
+ .col-sm-9 {
+ -ms-flex: 0 0 75%;
+ flex: 0 0 75%;
+ max-width: 75%;
+ }
+ .col-sm-10 {
+ -ms-flex: 0 0 83.333333%;
+ flex: 0 0 83.333333%;
+ max-width: 83.333333%;
+ }
+ .col-sm-11 {
+ -ms-flex: 0 0 91.666667%;
+ flex: 0 0 91.666667%;
+ max-width: 91.666667%;
+ }
+ .col-sm-12 {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .order-sm-first {
+ -ms-flex-order: -1;
+ order: -1;
+ }
+ .order-sm-last {
+ -ms-flex-order: 13;
+ order: 13;
+ }
+ .order-sm-0 {
+ -ms-flex-order: 0;
+ order: 0;
+ }
+ .order-sm-1 {
+ -ms-flex-order: 1;
+ order: 1;
+ }
+ .order-sm-2 {
+ -ms-flex-order: 2;
+ order: 2;
+ }
+ .order-sm-3 {
+ -ms-flex-order: 3;
+ order: 3;
+ }
+ .order-sm-4 {
+ -ms-flex-order: 4;
+ order: 4;
+ }
+ .order-sm-5 {
+ -ms-flex-order: 5;
+ order: 5;
+ }
+ .order-sm-6 {
+ -ms-flex-order: 6;
+ order: 6;
+ }
+ .order-sm-7 {
+ -ms-flex-order: 7;
+ order: 7;
+ }
+ .order-sm-8 {
+ -ms-flex-order: 8;
+ order: 8;
+ }
+ .order-sm-9 {
+ -ms-flex-order: 9;
+ order: 9;
+ }
+ .order-sm-10 {
+ -ms-flex-order: 10;
+ order: 10;
+ }
+ .order-sm-11 {
+ -ms-flex-order: 11;
+ order: 11;
+ }
+ .order-sm-12 {
+ -ms-flex-order: 12;
+ order: 12;
+ }
+ .offset-sm-0 {
+ margin-left: 0;
+ }
+ .offset-sm-1 {
+ margin-left: 8.333333%;
+ }
+ .offset-sm-2 {
+ margin-left: 16.666667%;
+ }
+ .offset-sm-3 {
+ margin-left: 25%;
+ }
+ .offset-sm-4 {
+ margin-left: 33.333333%;
+ }
+ .offset-sm-5 {
+ margin-left: 41.666667%;
+ }
+ .offset-sm-6 {
+ margin-left: 50%;
+ }
+ .offset-sm-7 {
+ margin-left: 58.333333%;
+ }
+ .offset-sm-8 {
+ margin-left: 66.666667%;
+ }
+ .offset-sm-9 {
+ margin-left: 75%;
+ }
+ .offset-sm-10 {
+ margin-left: 83.333333%;
+ }
+ .offset-sm-11 {
+ margin-left: 91.666667%;
+ }
+}
+
+@media (min-width: 768px) {
+ .col-md {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ max-width: 100%;
+ }
+ .row-cols-md-1 > * {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .row-cols-md-2 > * {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .row-cols-md-3 > * {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .row-cols-md-4 > * {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .row-cols-md-5 > * {
+ -ms-flex: 0 0 20%;
+ flex: 0 0 20%;
+ max-width: 20%;
+ }
+ .row-cols-md-6 > * {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-md-auto {
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: auto;
+ max-width: 100%;
+ }
+ .col-md-1 {
+ -ms-flex: 0 0 8.333333%;
+ flex: 0 0 8.333333%;
+ max-width: 8.333333%;
+ }
+ .col-md-2 {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-md-3 {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .col-md-4 {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .col-md-5 {
+ -ms-flex: 0 0 41.666667%;
+ flex: 0 0 41.666667%;
+ max-width: 41.666667%;
+ }
+ .col-md-6 {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .col-md-7 {
+ -ms-flex: 0 0 58.333333%;
+ flex: 0 0 58.333333%;
+ max-width: 58.333333%;
+ }
+ .col-md-8 {
+ -ms-flex: 0 0 66.666667%;
+ flex: 0 0 66.666667%;
+ max-width: 66.666667%;
+ }
+ .col-md-9 {
+ -ms-flex: 0 0 75%;
+ flex: 0 0 75%;
+ max-width: 75%;
+ }
+ .col-md-10 {
+ -ms-flex: 0 0 83.333333%;
+ flex: 0 0 83.333333%;
+ max-width: 83.333333%;
+ }
+ .col-md-11 {
+ -ms-flex: 0 0 91.666667%;
+ flex: 0 0 91.666667%;
+ max-width: 91.666667%;
+ }
+ .col-md-12 {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .order-md-first {
+ -ms-flex-order: -1;
+ order: -1;
+ }
+ .order-md-last {
+ -ms-flex-order: 13;
+ order: 13;
+ }
+ .order-md-0 {
+ -ms-flex-order: 0;
+ order: 0;
+ }
+ .order-md-1 {
+ -ms-flex-order: 1;
+ order: 1;
+ }
+ .order-md-2 {
+ -ms-flex-order: 2;
+ order: 2;
+ }
+ .order-md-3 {
+ -ms-flex-order: 3;
+ order: 3;
+ }
+ .order-md-4 {
+ -ms-flex-order: 4;
+ order: 4;
+ }
+ .order-md-5 {
+ -ms-flex-order: 5;
+ order: 5;
+ }
+ .order-md-6 {
+ -ms-flex-order: 6;
+ order: 6;
+ }
+ .order-md-7 {
+ -ms-flex-order: 7;
+ order: 7;
+ }
+ .order-md-8 {
+ -ms-flex-order: 8;
+ order: 8;
+ }
+ .order-md-9 {
+ -ms-flex-order: 9;
+ order: 9;
+ }
+ .order-md-10 {
+ -ms-flex-order: 10;
+ order: 10;
+ }
+ .order-md-11 {
+ -ms-flex-order: 11;
+ order: 11;
+ }
+ .order-md-12 {
+ -ms-flex-order: 12;
+ order: 12;
+ }
+ .offset-md-0 {
+ margin-left: 0;
+ }
+ .offset-md-1 {
+ margin-left: 8.333333%;
+ }
+ .offset-md-2 {
+ margin-left: 16.666667%;
+ }
+ .offset-md-3 {
+ margin-left: 25%;
+ }
+ .offset-md-4 {
+ margin-left: 33.333333%;
+ }
+ .offset-md-5 {
+ margin-left: 41.666667%;
+ }
+ .offset-md-6 {
+ margin-left: 50%;
+ }
+ .offset-md-7 {
+ margin-left: 58.333333%;
+ }
+ .offset-md-8 {
+ margin-left: 66.666667%;
+ }
+ .offset-md-9 {
+ margin-left: 75%;
+ }
+ .offset-md-10 {
+ margin-left: 83.333333%;
+ }
+ .offset-md-11 {
+ margin-left: 91.666667%;
+ }
+}
+
+@media (min-width: 992px) {
+ .col-lg {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ max-width: 100%;
+ }
+ .row-cols-lg-1 > * {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .row-cols-lg-2 > * {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .row-cols-lg-3 > * {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .row-cols-lg-4 > * {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .row-cols-lg-5 > * {
+ -ms-flex: 0 0 20%;
+ flex: 0 0 20%;
+ max-width: 20%;
+ }
+ .row-cols-lg-6 > * {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-lg-auto {
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: auto;
+ max-width: 100%;
+ }
+ .col-lg-1 {
+ -ms-flex: 0 0 8.333333%;
+ flex: 0 0 8.333333%;
+ max-width: 8.333333%;
+ }
+ .col-lg-2 {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-lg-3 {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .col-lg-4 {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .col-lg-5 {
+ -ms-flex: 0 0 41.666667%;
+ flex: 0 0 41.666667%;
+ max-width: 41.666667%;
+ }
+ .col-lg-6 {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .col-lg-7 {
+ -ms-flex: 0 0 58.333333%;
+ flex: 0 0 58.333333%;
+ max-width: 58.333333%;
+ }
+ .col-lg-8 {
+ -ms-flex: 0 0 66.666667%;
+ flex: 0 0 66.666667%;
+ max-width: 66.666667%;
+ }
+ .col-lg-9 {
+ -ms-flex: 0 0 75%;
+ flex: 0 0 75%;
+ max-width: 75%;
+ }
+ .col-lg-10 {
+ -ms-flex: 0 0 83.333333%;
+ flex: 0 0 83.333333%;
+ max-width: 83.333333%;
+ }
+ .col-lg-11 {
+ -ms-flex: 0 0 91.666667%;
+ flex: 0 0 91.666667%;
+ max-width: 91.666667%;
+ }
+ .col-lg-12 {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .order-lg-first {
+ -ms-flex-order: -1;
+ order: -1;
+ }
+ .order-lg-last {
+ -ms-flex-order: 13;
+ order: 13;
+ }
+ .order-lg-0 {
+ -ms-flex-order: 0;
+ order: 0;
+ }
+ .order-lg-1 {
+ -ms-flex-order: 1;
+ order: 1;
+ }
+ .order-lg-2 {
+ -ms-flex-order: 2;
+ order: 2;
+ }
+ .order-lg-3 {
+ -ms-flex-order: 3;
+ order: 3;
+ }
+ .order-lg-4 {
+ -ms-flex-order: 4;
+ order: 4;
+ }
+ .order-lg-5 {
+ -ms-flex-order: 5;
+ order: 5;
+ }
+ .order-lg-6 {
+ -ms-flex-order: 6;
+ order: 6;
+ }
+ .order-lg-7 {
+ -ms-flex-order: 7;
+ order: 7;
+ }
+ .order-lg-8 {
+ -ms-flex-order: 8;
+ order: 8;
+ }
+ .order-lg-9 {
+ -ms-flex-order: 9;
+ order: 9;
+ }
+ .order-lg-10 {
+ -ms-flex-order: 10;
+ order: 10;
+ }
+ .order-lg-11 {
+ -ms-flex-order: 11;
+ order: 11;
+ }
+ .order-lg-12 {
+ -ms-flex-order: 12;
+ order: 12;
+ }
+ .offset-lg-0 {
+ margin-left: 0;
+ }
+ .offset-lg-1 {
+ margin-left: 8.333333%;
+ }
+ .offset-lg-2 {
+ margin-left: 16.666667%;
+ }
+ .offset-lg-3 {
+ margin-left: 25%;
+ }
+ .offset-lg-4 {
+ margin-left: 33.333333%;
+ }
+ .offset-lg-5 {
+ margin-left: 41.666667%;
+ }
+ .offset-lg-6 {
+ margin-left: 50%;
+ }
+ .offset-lg-7 {
+ margin-left: 58.333333%;
+ }
+ .offset-lg-8 {
+ margin-left: 66.666667%;
+ }
+ .offset-lg-9 {
+ margin-left: 75%;
+ }
+ .offset-lg-10 {
+ margin-left: 83.333333%;
+ }
+ .offset-lg-11 {
+ margin-left: 91.666667%;
+ }
+}
+
+@media (min-width: 1200px) {
+ .col-xl {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ max-width: 100%;
+ }
+ .row-cols-xl-1 > * {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .row-cols-xl-2 > * {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .row-cols-xl-3 > * {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .row-cols-xl-4 > * {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .row-cols-xl-5 > * {
+ -ms-flex: 0 0 20%;
+ flex: 0 0 20%;
+ max-width: 20%;
+ }
+ .row-cols-xl-6 > * {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-xl-auto {
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: auto;
+ max-width: 100%;
+ }
+ .col-xl-1 {
+ -ms-flex: 0 0 8.333333%;
+ flex: 0 0 8.333333%;
+ max-width: 8.333333%;
+ }
+ .col-xl-2 {
+ -ms-flex: 0 0 16.666667%;
+ flex: 0 0 16.666667%;
+ max-width: 16.666667%;
+ }
+ .col-xl-3 {
+ -ms-flex: 0 0 25%;
+ flex: 0 0 25%;
+ max-width: 25%;
+ }
+ .col-xl-4 {
+ -ms-flex: 0 0 33.333333%;
+ flex: 0 0 33.333333%;
+ max-width: 33.333333%;
+ }
+ .col-xl-5 {
+ -ms-flex: 0 0 41.666667%;
+ flex: 0 0 41.666667%;
+ max-width: 41.666667%;
+ }
+ .col-xl-6 {
+ -ms-flex: 0 0 50%;
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ .col-xl-7 {
+ -ms-flex: 0 0 58.333333%;
+ flex: 0 0 58.333333%;
+ max-width: 58.333333%;
+ }
+ .col-xl-8 {
+ -ms-flex: 0 0 66.666667%;
+ flex: 0 0 66.666667%;
+ max-width: 66.666667%;
+ }
+ .col-xl-9 {
+ -ms-flex: 0 0 75%;
+ flex: 0 0 75%;
+ max-width: 75%;
+ }
+ .col-xl-10 {
+ -ms-flex: 0 0 83.333333%;
+ flex: 0 0 83.333333%;
+ max-width: 83.333333%;
+ }
+ .col-xl-11 {
+ -ms-flex: 0 0 91.666667%;
+ flex: 0 0 91.666667%;
+ max-width: 91.666667%;
+ }
+ .col-xl-12 {
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+ .order-xl-first {
+ -ms-flex-order: -1;
+ order: -1;
+ }
+ .order-xl-last {
+ -ms-flex-order: 13;
+ order: 13;
+ }
+ .order-xl-0 {
+ -ms-flex-order: 0;
+ order: 0;
+ }
+ .order-xl-1 {
+ -ms-flex-order: 1;
+ order: 1;
+ }
+ .order-xl-2 {
+ -ms-flex-order: 2;
+ order: 2;
+ }
+ .order-xl-3 {
+ -ms-flex-order: 3;
+ order: 3;
+ }
+ .order-xl-4 {
+ -ms-flex-order: 4;
+ order: 4;
+ }
+ .order-xl-5 {
+ -ms-flex-order: 5;
+ order: 5;
+ }
+ .order-xl-6 {
+ -ms-flex-order: 6;
+ order: 6;
+ }
+ .order-xl-7 {
+ -ms-flex-order: 7;
+ order: 7;
+ }
+ .order-xl-8 {
+ -ms-flex-order: 8;
+ order: 8;
+ }
+ .order-xl-9 {
+ -ms-flex-order: 9;
+ order: 9;
+ }
+ .order-xl-10 {
+ -ms-flex-order: 10;
+ order: 10;
+ }
+ .order-xl-11 {
+ -ms-flex-order: 11;
+ order: 11;
+ }
+ .order-xl-12 {
+ -ms-flex-order: 12;
+ order: 12;
+ }
+ .offset-xl-0 {
+ margin-left: 0;
+ }
+ .offset-xl-1 {
+ margin-left: 8.333333%;
+ }
+ .offset-xl-2 {
+ margin-left: 16.666667%;
+ }
+ .offset-xl-3 {
+ margin-left: 25%;
+ }
+ .offset-xl-4 {
+ margin-left: 33.333333%;
+ }
+ .offset-xl-5 {
+ margin-left: 41.666667%;
+ }
+ .offset-xl-6 {
+ margin-left: 50%;
+ }
+ .offset-xl-7 {
+ margin-left: 58.333333%;
+ }
+ .offset-xl-8 {
+ margin-left: 66.666667%;
+ }
+ .offset-xl-9 {
+ margin-left: 75%;
+ }
+ .offset-xl-10 {
+ margin-left: 83.333333%;
+ }
+ .offset-xl-11 {
+ margin-left: 91.666667%;
+ }
+}
+
+.table {
+ width: 100%;
+ margin-bottom: 1rem;
+ color: #212529;
+}
+
+.table th,
+.table td {
+ padding: 0.75rem;
+ vertical-align: top;
+ border-top: 1px solid #dee2e6;
+}
+
+.table thead th {
+ vertical-align: bottom;
+ border-bottom: 2px solid #dee2e6;
+}
+
+.table tbody + tbody {
+ border-top: 2px solid #dee2e6;
+}
+
+.table-sm th,
+.table-sm td {
+ padding: 0.3rem;
+}
+
+.table-bordered {
+ border: 1px solid #dee2e6;
+}
+
+.table-bordered th,
+.table-bordered td {
+ border: 1px solid #dee2e6;
+}
+
+.table-bordered thead th,
+.table-bordered thead td {
+ border-bottom-width: 2px;
+}
+
+.table-borderless th,
+.table-borderless td,
+.table-borderless thead th,
+.table-borderless tbody + tbody {
+ border: 0;
+}
+
+.table-striped tbody tr:nth-of-type(odd) {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+
+.table-hover tbody tr:hover {
+ color: #212529;
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table-primary,
+.table-primary > th,
+.table-primary > td {
+ background-color: #b8daff;
+}
+
+.table-primary th,
+.table-primary td,
+.table-primary thead th,
+.table-primary tbody + tbody {
+ border-color: #7abaff;
+}
+
+.table-hover .table-primary:hover {
+ background-color: #9fcdff;
+}
+
+.table-hover .table-primary:hover > td,
+.table-hover .table-primary:hover > th {
+ background-color: #9fcdff;
+}
+
+.table-secondary,
+.table-secondary > th,
+.table-secondary > td {
+ background-color: #d6d8db;
+}
+
+.table-secondary th,
+.table-secondary td,
+.table-secondary thead th,
+.table-secondary tbody + tbody {
+ border-color: #b3b7bb;
+}
+
+.table-hover .table-secondary:hover {
+ background-color: #c8cbcf;
+}
+
+.table-hover .table-secondary:hover > td,
+.table-hover .table-secondary:hover > th {
+ background-color: #c8cbcf;
+}
+
+.table-success,
+.table-success > th,
+.table-success > td {
+ background-color: #c3e6cb;
+}
+
+.table-success th,
+.table-success td,
+.table-success thead th,
+.table-success tbody + tbody {
+ border-color: #8fd19e;
+}
+
+.table-hover .table-success:hover {
+ background-color: #b1dfbb;
+}
+
+.table-hover .table-success:hover > td,
+.table-hover .table-success:hover > th {
+ background-color: #b1dfbb;
+}
+
+.table-info,
+.table-info > th,
+.table-info > td {
+ background-color: #bee5eb;
+}
+
+.table-info th,
+.table-info td,
+.table-info thead th,
+.table-info tbody + tbody {
+ border-color: #86cfda;
+}
+
+.table-hover .table-info:hover {
+ background-color: #abdde5;
+}
+
+.table-hover .table-info:hover > td,
+.table-hover .table-info:hover > th {
+ background-color: #abdde5;
+}
+
+.table-warning,
+.table-warning > th,
+.table-warning > td {
+ background-color: #ffeeba;
+}
+
+.table-warning th,
+.table-warning td,
+.table-warning thead th,
+.table-warning tbody + tbody {
+ border-color: #ffdf7e;
+}
+
+.table-hover .table-warning:hover {
+ background-color: #ffe8a1;
+}
+
+.table-hover .table-warning:hover > td,
+.table-hover .table-warning:hover > th {
+ background-color: #ffe8a1;
+}
+
+.table-danger,
+.table-danger > th,
+.table-danger > td {
+ background-color: #f5c6cb;
+}
+
+.table-danger th,
+.table-danger td,
+.table-danger thead th,
+.table-danger tbody + tbody {
+ border-color: #ed969e;
+}
+
+.table-hover .table-danger:hover {
+ background-color: #f1b0b7;
+}
+
+.table-hover .table-danger:hover > td,
+.table-hover .table-danger:hover > th {
+ background-color: #f1b0b7;
+}
+
+.table-light,
+.table-light > th,
+.table-light > td {
+ background-color: #fdfdfe;
+}
+
+.table-light th,
+.table-light td,
+.table-light thead th,
+.table-light tbody + tbody {
+ border-color: #fbfcfc;
+}
+
+.table-hover .table-light:hover {
+ background-color: #ececf6;
+}
+
+.table-hover .table-light:hover > td,
+.table-hover .table-light:hover > th {
+ background-color: #ececf6;
+}
+
+.table-dark,
+.table-dark > th,
+.table-dark > td {
+ background-color: #c6c8ca;
+}
+
+.table-dark th,
+.table-dark td,
+.table-dark thead th,
+.table-dark tbody + tbody {
+ border-color: #95999c;
+}
+
+.table-hover .table-dark:hover {
+ background-color: #b9bbbe;
+}
+
+.table-hover .table-dark:hover > td,
+.table-hover .table-dark:hover > th {
+ background-color: #b9bbbe;
+}
+
+.table-active,
+.table-active > th,
+.table-active > td {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table-hover .table-active:hover {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table-hover .table-active:hover > td,
+.table-hover .table-active:hover > th {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table .thead-dark th {
+ color: #fff;
+ background-color: #343a40;
+ border-color: #454d55;
+}
+
+.table .thead-light th {
+ color: #495057;
+ background-color: #e9ecef;
+ border-color: #dee2e6;
+}
+
+.table-dark {
+ color: #fff;
+ background-color: #343a40;
+}
+
+.table-dark th,
+.table-dark td,
+.table-dark thead th {
+ border-color: #454d55;
+}
+
+.table-dark.table-bordered {
+ border: 0;
+}
+
+.table-dark.table-striped tbody tr:nth-of-type(odd) {
+ background-color: rgba(255, 255, 255, 0.05);
+}
+
+.table-dark.table-hover tbody tr:hover {
+ color: #fff;
+ background-color: rgba(255, 255, 255, 0.075);
+}
+
+@media (max-width: 575.98px) {
+ .table-responsive-sm {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+ .table-responsive-sm > .table-bordered {
+ border: 0;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .table-responsive-md {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+ .table-responsive-md > .table-bordered {
+ border: 0;
+ }
+}
+
+@media (max-width: 991.98px) {
+ .table-responsive-lg {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+ .table-responsive-lg > .table-bordered {
+ border: 0;
+ }
+}
+
+@media (max-width: 1199.98px) {
+ .table-responsive-xl {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+ .table-responsive-xl > .table-bordered {
+ border: 0;
+ }
+}
+
+.table-responsive {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.table-responsive > .table-bordered {
+ border: 0;
+}
+
+.form-control {
+ display: block;
+ width: 100%;
+ height: calc(1.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .form-control {
+ transition: none;
+ }
+}
+
+.form-control::-ms-expand {
+ background-color: transparent;
+ border: 0;
+}
+
+.form-control:-moz-focusring {
+ color: transparent;
+ text-shadow: 0 0 0 #495057;
+}
+
+.form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-color: #80bdff;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.form-control::-webkit-input-placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+
+.form-control::-moz-placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+
+.form-control:-ms-input-placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+
+.form-control::-ms-input-placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+
+.form-control::placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+
+.form-control:disabled, .form-control[readonly] {
+ background-color: #e9ecef;
+ opacity: 1;
+}
+
+select.form-control:focus::-ms-value {
+ color: #495057;
+ background-color: #fff;
+}
+
+.form-control-file,
+.form-control-range {
+ display: block;
+ width: 100%;
+}
+
+.col-form-label {
+ padding-top: calc(0.375rem + 1px);
+ padding-bottom: calc(0.375rem + 1px);
+ margin-bottom: 0;
+ font-size: inherit;
+ line-height: 1.5;
+}
+
+.col-form-label-lg {
+ padding-top: calc(0.5rem + 1px);
+ padding-bottom: calc(0.5rem + 1px);
+ font-size: 1.25rem;
+ line-height: 1.5;
+}
+
+.col-form-label-sm {
+ padding-top: calc(0.25rem + 1px);
+ padding-bottom: calc(0.25rem + 1px);
+ font-size: 0.875rem;
+ line-height: 1.5;
+}
+
+.form-control-plaintext {
+ display: block;
+ width: 100%;
+ padding: 0.375rem 0;
+ margin-bottom: 0;
+ font-size: 1rem;
+ line-height: 1.5;
+ color: #212529;
+ background-color: transparent;
+ border: solid transparent;
+ border-width: 1px 0;
+}
+
+.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.form-control-sm {
+ height: calc(1.5em + 0.5rem + 2px);
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ border-radius: 0.2rem;
+}
+
+.form-control-lg {
+ height: calc(1.5em + 1rem + 2px);
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ line-height: 1.5;
+ border-radius: 0.3rem;
+}
+
+select.form-control[size], select.form-control[multiple] {
+ height: auto;
+}
+
+textarea.form-control {
+ height: auto;
+}
+
+.form-group {
+ margin-bottom: 1rem;
+}
+
+.form-text {
+ display: block;
+ margin-top: 0.25rem;
+}
+
+.form-row {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ margin-right: -5px;
+ margin-left: -5px;
+}
+
+.form-row > .col,
+.form-row > [class*="col-"] {
+ padding-right: 5px;
+ padding-left: 5px;
+}
+
+.form-check {
+ position: relative;
+ display: block;
+ padding-left: 1.25rem;
+}
+
+.form-check-input {
+ position: absolute;
+ margin-top: 0.3rem;
+ margin-left: -1.25rem;
+}
+
+.form-check-input[disabled] ~ .form-check-label,
+.form-check-input:disabled ~ .form-check-label {
+ color: #6c757d;
+}
+
+.form-check-label {
+ margin-bottom: 0;
+}
+
+.form-check-inline {
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ -ms-flex-align: center;
+ align-items: center;
+ padding-left: 0;
+ margin-right: 0.75rem;
+}
+
+.form-check-inline .form-check-input {
+ position: static;
+ margin-top: 0;
+ margin-right: 0.3125rem;
+ margin-left: 0;
+}
+
+.valid-feedback {
+ display: none;
+ width: 100%;
+ margin-top: 0.25rem;
+ font-size: 80%;
+ color: #28a745;
+}
+
+.valid-tooltip {
+ position: absolute;
+ top: 100%;
+ z-index: 5;
+ display: none;
+ max-width: 100%;
+ padding: 0.25rem 0.5rem;
+ margin-top: .1rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ color: #fff;
+ background-color: rgba(40, 167, 69, 0.9);
+ border-radius: 0.25rem;
+}
+
+.was-validated :valid ~ .valid-feedback,
+.was-validated :valid ~ .valid-tooltip,
+.is-valid ~ .valid-feedback,
+.is-valid ~ .valid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:valid, .form-control.is-valid {
+ border-color: #28a745;
+ padding-right: calc(1.5em + 0.75rem);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right calc(0.375em + 0.1875rem) center;
+ background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+
+.was-validated .form-control:valid:focus, .form-control.is-valid:focus {
+ border-color: #28a745;
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
+}
+
+.was-validated textarea.form-control:valid, textarea.form-control.is-valid {
+ padding-right: calc(1.5em + 0.75rem);
+ background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);
+}
+
+.was-validated .custom-select:valid, .custom-select.is-valid {
+ border-color: #28a745;
+ padding-right: calc(0.75em + 2.3125rem);
+ background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+
+.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus {
+ border-color: #28a745;
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
+}
+
+.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {
+ color: #28a745;
+}
+
+.was-validated .form-check-input:valid ~ .valid-feedback,
+.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback,
+.form-check-input.is-valid ~ .valid-tooltip {
+ display: block;
+}
+
+.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label {
+ color: #28a745;
+}
+
+.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before {
+ border-color: #28a745;
+}
+
+.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before {
+ border-color: #34ce57;
+ background-color: #34ce57;
+}
+
+.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before {
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
+}
+
+.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before {
+ border-color: #28a745;
+}
+
+.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label {
+ border-color: #28a745;
+}
+
+.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label {
+ border-color: #28a745;
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
+}
+
+.invalid-feedback {
+ display: none;
+ width: 100%;
+ margin-top: 0.25rem;
+ font-size: 80%;
+ color: #dc3545;
+}
+
+.invalid-tooltip {
+ position: absolute;
+ top: 100%;
+ z-index: 5;
+ display: none;
+ max-width: 100%;
+ padding: 0.25rem 0.5rem;
+ margin-top: .1rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ color: #fff;
+ background-color: rgba(220, 53, 69, 0.9);
+ border-radius: 0.25rem;
+}
+
+.was-validated :invalid ~ .invalid-feedback,
+.was-validated :invalid ~ .invalid-tooltip,
+.is-invalid ~ .invalid-feedback,
+.is-invalid ~ .invalid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:invalid, .form-control.is-invalid {
+ border-color: #dc3545;
+ padding-right: calc(1.5em + 0.75rem);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right calc(0.375em + 0.1875rem) center;
+ background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+
+.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {
+ border-color: #dc3545;
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
+}
+
+.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {
+ padding-right: calc(1.5em + 0.75rem);
+ background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);
+}
+
+.was-validated .custom-select:invalid, .custom-select.is-invalid {
+ border-color: #dc3545;
+ padding-right: calc(0.75em + 2.3125rem);
+ background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+
+.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus {
+ border-color: #dc3545;
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
+}
+
+.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {
+ color: #dc3545;
+}
+
+.was-validated .form-check-input:invalid ~ .invalid-feedback,
+.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback,
+.form-check-input.is-invalid ~ .invalid-tooltip {
+ display: block;
+}
+
+.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label {
+ color: #dc3545;
+}
+
+.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before {
+ border-color: #dc3545;
+}
+
+.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before {
+ border-color: #e4606d;
+ background-color: #e4606d;
+}
+
+.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before {
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
+}
+
+.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before {
+ border-color: #dc3545;
+}
+
+.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label {
+ border-color: #dc3545;
+}
+
+.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label {
+ border-color: #dc3545;
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
+}
+
+.form-inline {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.form-inline .form-check {
+ width: 100%;
+}
+
+@media (min-width: 576px) {
+ .form-inline label {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ margin-bottom: 0;
+ }
+ .form-inline .form-group {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap;
+ -ms-flex-align: center;
+ align-items: center;
+ margin-bottom: 0;
+ }
+ .form-inline .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-control-plaintext {
+ display: inline-block;
+ }
+ .form-inline .input-group,
+ .form-inline .custom-select {
+ width: auto;
+ }
+ .form-inline .form-check {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ width: auto;
+ padding-left: 0;
+ }
+ .form-inline .form-check-input {
+ position: relative;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ margin-top: 0;
+ margin-right: 0.25rem;
+ margin-left: 0;
+ }
+ .form-inline .custom-control {
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ }
+ .form-inline .custom-control-label {
+ margin-bottom: 0;
+ }
+}
+
+.btn {
+ display: inline-block;
+ font-weight: 400;
+ color: #212529;
+ text-align: center;
+ vertical-align: middle;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-color: transparent;
+ border: 1px solid transparent;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ line-height: 1.5;
+ border-radius: 0.25rem;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .btn {
+ transition: none;
+ }
+}
+
+.btn:hover {
+ color: #212529;
+ text-decoration: none;
+}
+
+.btn:focus, .btn.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.btn.disabled, .btn:disabled {
+ opacity: 0.65;
+}
+
+a.btn.disabled,
+fieldset:disabled a.btn {
+ pointer-events: none;
+}
+
+.btn-primary {
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-primary:hover {
+ color: #fff;
+ background-color: #0069d9;
+ border-color: #0062cc;
+}
+
+.btn-primary:focus, .btn-primary.focus {
+ color: #fff;
+ background-color: #0069d9;
+ border-color: #0062cc;
+ box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);
+}
+
+.btn-primary.disabled, .btn-primary:disabled {
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,
+.show > .btn-primary.dropdown-toggle {
+ color: #fff;
+ background-color: #0062cc;
+ border-color: #005cbf;
+}
+
+.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,
+.show > .btn-primary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);
+}
+
+.btn-secondary {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-secondary:hover {
+ color: #fff;
+ background-color: #5a6268;
+ border-color: #545b62;
+}
+
+.btn-secondary:focus, .btn-secondary.focus {
+ color: #fff;
+ background-color: #5a6268;
+ border-color: #545b62;
+ box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);
+}
+
+.btn-secondary.disabled, .btn-secondary:disabled {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,
+.show > .btn-secondary.dropdown-toggle {
+ color: #fff;
+ background-color: #545b62;
+ border-color: #4e555b;
+}
+
+.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,
+.show > .btn-secondary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);
+}
+
+.btn-success {
+ color: #fff;
+ background-color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-success:hover {
+ color: #fff;
+ background-color: #218838;
+ border-color: #1e7e34;
+}
+
+.btn-success:focus, .btn-success.focus {
+ color: #fff;
+ background-color: #218838;
+ border-color: #1e7e34;
+ box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);
+}
+
+.btn-success.disabled, .btn-success:disabled {
+ color: #fff;
+ background-color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,
+.show > .btn-success.dropdown-toggle {
+ color: #fff;
+ background-color: #1e7e34;
+ border-color: #1c7430;
+}
+
+.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,
+.show > .btn-success.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);
+}
+
+.btn-info {
+ color: #fff;
+ background-color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-info:hover {
+ color: #fff;
+ background-color: #138496;
+ border-color: #117a8b;
+}
+
+.btn-info:focus, .btn-info.focus {
+ color: #fff;
+ background-color: #138496;
+ border-color: #117a8b;
+ box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);
+}
+
+.btn-info.disabled, .btn-info:disabled {
+ color: #fff;
+ background-color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
+.show > .btn-info.dropdown-toggle {
+ color: #fff;
+ background-color: #117a8b;
+ border-color: #10707f;
+}
+
+.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
+.show > .btn-info.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);
+}
+
+.btn-warning {
+ color: #212529;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-warning:hover {
+ color: #212529;
+ background-color: #e0a800;
+ border-color: #d39e00;
+}
+
+.btn-warning:focus, .btn-warning.focus {
+ color: #212529;
+ background-color: #e0a800;
+ border-color: #d39e00;
+ box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);
+}
+
+.btn-warning.disabled, .btn-warning:disabled {
+ color: #212529;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,
+.show > .btn-warning.dropdown-toggle {
+ color: #212529;
+ background-color: #d39e00;
+ border-color: #c69500;
+}
+
+.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,
+.show > .btn-warning.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);
+}
+
+.btn-danger {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-danger:hover {
+ color: #fff;
+ background-color: #c82333;
+ border-color: #bd2130;
+}
+
+.btn-danger:focus, .btn-danger.focus {
+ color: #fff;
+ background-color: #c82333;
+ border-color: #bd2130;
+ box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);
+}
+
+.btn-danger.disabled, .btn-danger:disabled {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,
+.show > .btn-danger.dropdown-toggle {
+ color: #fff;
+ background-color: #bd2130;
+ border-color: #b21f2d;
+}
+
+.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,
+.show > .btn-danger.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);
+}
+
+.btn-light {
+ color: #212529;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-light:hover {
+ color: #212529;
+ background-color: #e2e6ea;
+ border-color: #dae0e5;
+}
+
+.btn-light:focus, .btn-light.focus {
+ color: #212529;
+ background-color: #e2e6ea;
+ border-color: #dae0e5;
+ box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);
+}
+
+.btn-light.disabled, .btn-light:disabled {
+ color: #212529;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,
+.show > .btn-light.dropdown-toggle {
+ color: #212529;
+ background-color: #dae0e5;
+ border-color: #d3d9df;
+}
+
+.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,
+.show > .btn-light.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);
+}
+
+.btn-dark {
+ color: #fff;
+ background-color: #343a40;
+ border-color: #343a40;
+}
+
+.btn-dark:hover {
+ color: #fff;
+ background-color: #23272b;
+ border-color: #1d2124;
+}
+
+.btn-dark:focus, .btn-dark.focus {
+ color: #fff;
+ background-color: #23272b;
+ border-color: #1d2124;
+ box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);
+}
+
+.btn-dark.disabled, .btn-dark:disabled {
+ color: #fff;
+ background-color: #343a40;
+ border-color: #343a40;
+}
+
+.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,
+.show > .btn-dark.dropdown-toggle {
+ color: #fff;
+ background-color: #1d2124;
+ border-color: #171a1d;
+}
+
+.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,
+.show > .btn-dark.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);
+}
+
+.btn-outline-primary {
+ color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-outline-primary:hover {
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-outline-primary:focus, .btn-outline-primary.focus {
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
+}
+
+.btn-outline-primary.disabled, .btn-outline-primary:disabled {
+ color: #007bff;
+ background-color: transparent;
+}
+
+.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,
+.show > .btn-outline-primary.dropdown-toggle {
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-primary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
+}
+
+.btn-outline-secondary {
+ color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-outline-secondary:hover {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-outline-secondary:focus, .btn-outline-secondary.focus {
+ box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
+}
+
+.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {
+ color: #6c757d;
+ background-color: transparent;
+}
+
+.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,
+.show > .btn-outline-secondary.dropdown-toggle {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-secondary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
+}
+
+.btn-outline-success {
+ color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-outline-success:hover {
+ color: #fff;
+ background-color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-outline-success:focus, .btn-outline-success.focus {
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
+}
+
+.btn-outline-success.disabled, .btn-outline-success:disabled {
+ color: #28a745;
+ background-color: transparent;
+}
+
+.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,
+.show > .btn-outline-success.dropdown-toggle {
+ color: #fff;
+ background-color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-success.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
+}
+
+.btn-outline-info {
+ color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-outline-info:hover {
+ color: #fff;
+ background-color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-outline-info:focus, .btn-outline-info.focus {
+ box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
+}
+
+.btn-outline-info.disabled, .btn-outline-info:disabled {
+ color: #17a2b8;
+ background-color: transparent;
+}
+
+.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
+.show > .btn-outline-info.dropdown-toggle {
+ color: #fff;
+ background-color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-info.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
+}
+
+.btn-outline-warning {
+ color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-outline-warning:hover {
+ color: #212529;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-outline-warning:focus, .btn-outline-warning.focus {
+ box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
+}
+
+.btn-outline-warning.disabled, .btn-outline-warning:disabled {
+ color: #ffc107;
+ background-color: transparent;
+}
+
+.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,
+.show > .btn-outline-warning.dropdown-toggle {
+ color: #212529;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-warning.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
+}
+
+.btn-outline-danger {
+ color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-outline-danger:hover {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-outline-danger:focus, .btn-outline-danger.focus {
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
+}
+
+.btn-outline-danger.disabled, .btn-outline-danger:disabled {
+ color: #dc3545;
+ background-color: transparent;
+}
+
+.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,
+.show > .btn-outline-danger.dropdown-toggle {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-danger.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
+}
+
+.btn-outline-light {
+ color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-outline-light:hover {
+ color: #212529;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-outline-light:focus, .btn-outline-light.focus {
+ box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
+}
+
+.btn-outline-light.disabled, .btn-outline-light:disabled {
+ color: #f8f9fa;
+ background-color: transparent;
+}
+
+.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,
+.show > .btn-outline-light.dropdown-toggle {
+ color: #212529;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-light.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
+}
+
+.btn-outline-dark {
+ color: #343a40;
+ border-color: #343a40;
+}
+
+.btn-outline-dark:hover {
+ color: #fff;
+ background-color: #343a40;
+ border-color: #343a40;
+}
+
+.btn-outline-dark:focus, .btn-outline-dark.focus {
+ box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
+}
+
+.btn-outline-dark.disabled, .btn-outline-dark:disabled {
+ color: #343a40;
+ background-color: transparent;
+}
+
+.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,
+.show > .btn-outline-dark.dropdown-toggle {
+ color: #fff;
+ background-color: #343a40;
+ border-color: #343a40;
+}
+
+.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,
+.show > .btn-outline-dark.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
+}
+
+.btn-link {
+ font-weight: 400;
+ color: #007bff;
+ text-decoration: none;
+}
+
+.btn-link:hover {
+ color: #0056b3;
+ text-decoration: underline;
+}
+
+.btn-link:focus, .btn-link.focus {
+ text-decoration: underline;
+ box-shadow: none;
+}
+
+.btn-link:disabled, .btn-link.disabled {
+ color: #6c757d;
+ pointer-events: none;
+}
+
+.btn-lg, .btn-group-lg > .btn {
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ line-height: 1.5;
+ border-radius: 0.3rem;
+}
+
+.btn-sm, .btn-group-sm > .btn {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ border-radius: 0.2rem;
+}
+
+.btn-block {
+ display: block;
+ width: 100%;
+}
+
+.btn-block + .btn-block {
+ margin-top: 0.5rem;
+}
+
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+
+.fade {
+ transition: opacity 0.15s linear;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .fade {
+ transition: none;
+ }
+}
+
+.fade:not(.show) {
+ opacity: 0;
+}
+
+.collapse:not(.show) {
+ display: none;
+}
+
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ transition: height 0.35s ease;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .collapsing {
+ transition: none;
+ }
+}
+
+.dropup,
+.dropright,
+.dropdown,
+.dropleft {
+ position: relative;
+}
+
+.dropdown-toggle {
+ white-space: nowrap;
+}
+
+.dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0;
+ border-left: 0.3em solid transparent;
+}
+
+.dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 10rem;
+ padding: 0.5rem 0;
+ margin: 0.125rem 0 0;
+ font-size: 1rem;
+ color: #212529;
+ text-align: left;
+ list-style: none;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 0.25rem;
+}
+
+.dropdown-menu-left {
+ right: auto;
+ left: 0;
+}
+
+.dropdown-menu-right {
+ right: 0;
+ left: auto;
+}
+
+@media (min-width: 576px) {
+ .dropdown-menu-sm-left {
+ right: auto;
+ left: 0;
+ }
+ .dropdown-menu-sm-right {
+ right: 0;
+ left: auto;
+ }
+}
+
+@media (min-width: 768px) {
+ .dropdown-menu-md-left {
+ right: auto;
+ left: 0;
+ }
+ .dropdown-menu-md-right {
+ right: 0;
+ left: auto;
+ }
+}
+
+@media (min-width: 992px) {
+ .dropdown-menu-lg-left {
+ right: auto;
+ left: 0;
+ }
+ .dropdown-menu-lg-right {
+ right: 0;
+ left: auto;
+ }
+}
+
+@media (min-width: 1200px) {
+ .dropdown-menu-xl-left {
+ right: auto;
+ left: 0;
+ }
+ .dropdown-menu-xl-right {
+ right: 0;
+ left: auto;
+ }
+}
+
+.dropup .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-top: 0;
+ margin-bottom: 0.125rem;
+}
+
+.dropup .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0.3em solid;
+ border-left: 0.3em solid transparent;
+}
+
+.dropup .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropright .dropdown-menu {
+ top: 0;
+ right: auto;
+ left: 100%;
+ margin-top: 0;
+ margin-left: 0.125rem;
+}
+
+.dropright .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0;
+ border-bottom: 0.3em solid transparent;
+ border-left: 0.3em solid;
+}
+
+.dropright .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropright .dropdown-toggle::after {
+ vertical-align: 0;
+}
+
+.dropleft .dropdown-menu {
+ top: 0;
+ right: 100%;
+ left: auto;
+ margin-top: 0;
+ margin-right: 0.125rem;
+}
+
+.dropleft .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+}
+
+.dropleft .dropdown-toggle::after {
+ display: none;
+}
+
+.dropleft .dropdown-toggle::before {
+ display: inline-block;
+ margin-right: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0.3em solid;
+ border-bottom: 0.3em solid transparent;
+}
+
+.dropleft .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropleft .dropdown-toggle::before {
+ vertical-align: 0;
+}
+
+.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] {
+ right: auto;
+ bottom: auto;
+}
+
+.dropdown-divider {
+ height: 0;
+ margin: 0.5rem 0;
+ overflow: hidden;
+ border-top: 1px solid #e9ecef;
+}
+
+.dropdown-item {
+ display: block;
+ width: 100%;
+ padding: 0.25rem 1.5rem;
+ clear: both;
+ font-weight: 400;
+ color: #212529;
+ text-align: inherit;
+ white-space: nowrap;
+ background-color: transparent;
+ border: 0;
+}
+
+.dropdown-item:hover, .dropdown-item:focus {
+ color: #16181b;
+ text-decoration: none;
+ background-color: #f8f9fa;
+}
+
+.dropdown-item.active, .dropdown-item:active {
+ color: #fff;
+ text-decoration: none;
+ background-color: #007bff;
+}
+
+.dropdown-item.disabled, .dropdown-item:disabled {
+ color: #6c757d;
+ pointer-events: none;
+ background-color: transparent;
+}
+
+.dropdown-menu.show {
+ display: block;
+}
+
+.dropdown-header {
+ display: block;
+ padding: 0.5rem 1.5rem;
+ margin-bottom: 0;
+ font-size: 0.875rem;
+ color: #6c757d;
+ white-space: nowrap;
+}
+
+.dropdown-item-text {
+ display: block;
+ padding: 0.25rem 1.5rem;
+ color: #212529;
+}
+
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ vertical-align: middle;
+}
+
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+}
+
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover {
+ z-index: 1;
+}
+
+.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
+.btn-group-vertical > .btn:focus,
+.btn-group-vertical > .btn:active,
+.btn-group-vertical > .btn.active {
+ z-index: 1;
+}
+
+.btn-toolbar {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+}
+
+.btn-toolbar .input-group {
+ width: auto;
+}
+
+.btn-group > .btn:not(:first-child),
+.btn-group > .btn-group:not(:first-child) {
+ margin-left: -1px;
+}
+
+.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.btn-group > .btn:not(:first-child),
+.btn-group > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.dropdown-toggle-split {
+ padding-right: 0.5625rem;
+ padding-left: 0.5625rem;
+}
+
+.dropdown-toggle-split::after,
+.dropup .dropdown-toggle-split::after,
+.dropright .dropdown-toggle-split::after {
+ margin-left: 0;
+}
+
+.dropleft .dropdown-toggle-split::before {
+ margin-right: 0;
+}
+
+.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
+ padding-right: 0.375rem;
+ padding-left: 0.375rem;
+}
+
+.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
+ padding-right: 0.75rem;
+ padding-left: 0.75rem;
+}
+
+.btn-group-vertical {
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -ms-flex-align: start;
+ align-items: flex-start;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
+
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group {
+ width: 100%;
+}
+
+.btn-group-vertical > .btn:not(:first-child),
+.btn-group-vertical > .btn-group:not(:first-child) {
+ margin-top: -1px;
+}
+
+.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group-vertical > .btn-group:not(:last-child) > .btn {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.btn-group-vertical > .btn:not(:first-child),
+.btn-group-vertical > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.btn-group-toggle > .btn,
+.btn-group-toggle > .btn-group > .btn {
+ margin-bottom: 0;
+}
+
+.btn-group-toggle > .btn input[type="radio"],
+.btn-group-toggle > .btn input[type="checkbox"],
+.btn-group-toggle > .btn-group > .btn input[type="radio"],
+.btn-group-toggle > .btn-group > .btn input[type="checkbox"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+
+.input-group {
+ position: relative;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ width: 100%;
+}
+
+.input-group > .form-control,
+.input-group > .form-control-plaintext,
+.input-group > .custom-select,
+.input-group > .custom-file {
+ position: relative;
+ -ms-flex: 1 1 0%;
+ flex: 1 1 0%;
+ min-width: 0;
+ margin-bottom: 0;
+}
+
+.input-group > .form-control + .form-control,
+.input-group > .form-control + .custom-select,
+.input-group > .form-control + .custom-file,
+.input-group > .form-control-plaintext + .form-control,
+.input-group > .form-control-plaintext + .custom-select,
+.input-group > .form-control-plaintext + .custom-file,
+.input-group > .custom-select + .form-control,
+.input-group > .custom-select + .custom-select,
+.input-group > .custom-select + .custom-file,
+.input-group > .custom-file + .form-control,
+.input-group > .custom-file + .custom-select,
+.input-group > .custom-file + .custom-file {
+ margin-left: -1px;
+}
+
+.input-group > .form-control:focus,
+.input-group > .custom-select:focus,
+.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label {
+ z-index: 3;
+}
+
+.input-group > .custom-file .custom-file-input:focus {
+ z-index: 4;
+}
+
+.input-group > .form-control:not(:last-child),
+.input-group > .custom-select:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.input-group > .form-control:not(:first-child),
+.input-group > .custom-select:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.input-group > .custom-file {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.input-group > .custom-file:not(:last-child) .custom-file-label,
+.input-group > .custom-file:not(:last-child) .custom-file-label::after {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.input-group > .custom-file:not(:first-child) .custom-file-label {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.input-group-prepend,
+.input-group-append {
+ display: -ms-flexbox;
+ display: flex;
+}
+
+.input-group-prepend .btn,
+.input-group-append .btn {
+ position: relative;
+ z-index: 2;
+}
+
+.input-group-prepend .btn:focus,
+.input-group-append .btn:focus {
+ z-index: 3;
+}
+
+.input-group-prepend .btn + .btn,
+.input-group-prepend .btn + .input-group-text,
+.input-group-prepend .input-group-text + .input-group-text,
+.input-group-prepend .input-group-text + .btn,
+.input-group-append .btn + .btn,
+.input-group-append .btn + .input-group-text,
+.input-group-append .input-group-text + .input-group-text,
+.input-group-append .input-group-text + .btn {
+ margin-left: -1px;
+}
+
+.input-group-prepend {
+ margin-right: -1px;
+}
+
+.input-group-append {
+ margin-left: -1px;
+}
+
+.input-group-text {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 0.375rem 0.75rem;
+ margin-bottom: 0;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ text-align: center;
+ white-space: nowrap;
+ background-color: #e9ecef;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+}
+
+.input-group-text input[type="radio"],
+.input-group-text input[type="checkbox"] {
+ margin-top: 0;
+}
+
+.input-group-lg > .form-control:not(textarea),
+.input-group-lg > .custom-select {
+ height: calc(1.5em + 1rem + 2px);
+}
+
+.input-group-lg > .form-control,
+.input-group-lg > .custom-select,
+.input-group-lg > .input-group-prepend > .input-group-text,
+.input-group-lg > .input-group-append > .input-group-text,
+.input-group-lg > .input-group-prepend > .btn,
+.input-group-lg > .input-group-append > .btn {
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ line-height: 1.5;
+ border-radius: 0.3rem;
+}
+
+.input-group-sm > .form-control:not(textarea),
+.input-group-sm > .custom-select {
+ height: calc(1.5em + 0.5rem + 2px);
+}
+
+.input-group-sm > .form-control,
+.input-group-sm > .custom-select,
+.input-group-sm > .input-group-prepend > .input-group-text,
+.input-group-sm > .input-group-append > .input-group-text,
+.input-group-sm > .input-group-prepend > .btn,
+.input-group-sm > .input-group-append > .btn {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ border-radius: 0.2rem;
+}
+
+.input-group-lg > .custom-select,
+.input-group-sm > .custom-select {
+ padding-right: 1.75rem;
+}
+
+.input-group > .input-group-prepend > .btn,
+.input-group > .input-group-prepend > .input-group-text,
+.input-group > .input-group-append:not(:last-child) > .btn,
+.input-group > .input-group-append:not(:last-child) > .input-group-text,
+.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.input-group > .input-group-append > .btn,
+.input-group > .input-group-append > .input-group-text,
+.input-group > .input-group-prepend:not(:first-child) > .btn,
+.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
+.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
+.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.custom-control {
+ position: relative;
+ display: block;
+ min-height: 1.5rem;
+ padding-left: 1.5rem;
+}
+
+.custom-control-inline {
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ margin-right: 1rem;
+}
+
+.custom-control-input {
+ position: absolute;
+ left: 0;
+ z-index: -1;
+ width: 1rem;
+ height: 1.25rem;
+ opacity: 0;
+}
+
+.custom-control-input:checked ~ .custom-control-label::before {
+ color: #fff;
+ border-color: #007bff;
+ background-color: #007bff;
+}
+
+.custom-control-input:focus ~ .custom-control-label::before {
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {
+ border-color: #80bdff;
+}
+
+.custom-control-input:not(:disabled):active ~ .custom-control-label::before {
+ color: #fff;
+ background-color: #b3d7ff;
+ border-color: #b3d7ff;
+}
+
+.custom-control-input[disabled] ~ .custom-control-label, .custom-control-input:disabled ~ .custom-control-label {
+ color: #6c757d;
+}
+
+.custom-control-input[disabled] ~ .custom-control-label::before, .custom-control-input:disabled ~ .custom-control-label::before {
+ background-color: #e9ecef;
+}
+
+.custom-control-label {
+ position: relative;
+ margin-bottom: 0;
+ vertical-align: top;
+}
+
+.custom-control-label::before {
+ position: absolute;
+ top: 0.25rem;
+ left: -1.5rem;
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ pointer-events: none;
+ content: "";
+ background-color: #fff;
+ border: #adb5bd solid 1px;
+}
+
+.custom-control-label::after {
+ position: absolute;
+ top: 0.25rem;
+ left: -1.5rem;
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ content: "";
+ background: no-repeat 50% / 50% 50%;
+}
+
+.custom-checkbox .custom-control-label::before {
+ border-radius: 0.25rem;
+}
+
+.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e");
+}
+
+.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {
+ border-color: #007bff;
+ background-color: #007bff;
+}
+
+.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e");
+}
+
+.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before {
+ background-color: rgba(0, 123, 255, 0.5);
+}
+
+.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before {
+ background-color: rgba(0, 123, 255, 0.5);
+}
+
+.custom-radio .custom-control-label::before {
+ border-radius: 50%;
+}
+
+.custom-radio .custom-control-input:checked ~ .custom-control-label::after {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
+}
+
+.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before {
+ background-color: rgba(0, 123, 255, 0.5);
+}
+
+.custom-switch {
+ padding-left: 2.25rem;
+}
+
+.custom-switch .custom-control-label::before {
+ left: -2.25rem;
+ width: 1.75rem;
+ pointer-events: all;
+ border-radius: 0.5rem;
+}
+
+.custom-switch .custom-control-label::after {
+ top: calc(0.25rem + 2px);
+ left: calc(-2.25rem + 2px);
+ width: calc(1rem - 4px);
+ height: calc(1rem - 4px);
+ background-color: #adb5bd;
+ border-radius: 0.5rem;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;
+ transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .custom-switch .custom-control-label::after {
+ transition: none;
+ }
+}
+
+.custom-switch .custom-control-input:checked ~ .custom-control-label::after {
+ background-color: #fff;
+ -webkit-transform: translateX(0.75rem);
+ transform: translateX(0.75rem);
+}
+
+.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before {
+ background-color: rgba(0, 123, 255, 0.5);
+}
+
+.custom-select {
+ display: inline-block;
+ width: 100%;
+ height: calc(1.5em + 0.75rem + 2px);
+ padding: 0.375rem 1.75rem 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ vertical-align: middle;
+ background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+.custom-select:focus {
+ border-color: #80bdff;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-select:focus::-ms-value {
+ color: #495057;
+ background-color: #fff;
+}
+
+.custom-select[multiple], .custom-select[size]:not([size="1"]) {
+ height: auto;
+ padding-right: 0.75rem;
+ background-image: none;
+}
+
+.custom-select:disabled {
+ color: #6c757d;
+ background-color: #e9ecef;
+}
+
+.custom-select::-ms-expand {
+ display: none;
+}
+
+.custom-select:-moz-focusring {
+ color: transparent;
+ text-shadow: 0 0 0 #495057;
+}
+
+.custom-select-sm {
+ height: calc(1.5em + 0.5rem + 2px);
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 0.5rem;
+ font-size: 0.875rem;
+}
+
+.custom-select-lg {
+ height: calc(1.5em + 1rem + 2px);
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ padding-left: 1rem;
+ font-size: 1.25rem;
+}
+
+.custom-file {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ height: calc(1.5em + 0.75rem + 2px);
+ margin-bottom: 0;
+}
+
+.custom-file-input {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ height: calc(1.5em + 0.75rem + 2px);
+ margin: 0;
+ opacity: 0;
+}
+
+.custom-file-input:focus ~ .custom-file-label {
+ border-color: #80bdff;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-file-input[disabled] ~ .custom-file-label,
+.custom-file-input:disabled ~ .custom-file-label {
+ background-color: #e9ecef;
+}
+
+.custom-file-input:lang(en) ~ .custom-file-label::after {
+ content: "Browse";
+}
+
+.custom-file-input ~ .custom-file-label[data-browse]::after {
+ content: attr(data-browse);
+}
+
+.custom-file-label {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1;
+ height: calc(1.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #fff;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+}
+
+.custom-file-label::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 3;
+ display: block;
+ height: calc(1.5em + 0.75rem);
+ padding: 0.375rem 0.75rem;
+ line-height: 1.5;
+ color: #495057;
+ content: "Browse";
+ background-color: #e9ecef;
+ border-left: inherit;
+ border-radius: 0 0.25rem 0.25rem 0;
+}
+
+.custom-range {
+ width: 100%;
+ height: 1.4rem;
+ padding: 0;
+ background-color: transparent;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+.custom-range:focus {
+ outline: none;
+}
+
+.custom-range:focus::-webkit-slider-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-range:focus::-moz-range-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-range:focus::-ms-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.custom-range::-moz-focus-outer {
+ border: 0;
+}
+
+.custom-range::-webkit-slider-thumb {
+ width: 1rem;
+ height: 1rem;
+ margin-top: -0.25rem;
+ background-color: #007bff;
+ border: 0;
+ border-radius: 1rem;
+ -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .custom-range::-webkit-slider-thumb {
+ -webkit-transition: none;
+ transition: none;
+ }
+}
+
+.custom-range::-webkit-slider-thumb:active {
+ background-color: #b3d7ff;
+}
+
+.custom-range::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: #dee2e6;
+ border-color: transparent;
+ border-radius: 1rem;
+}
+
+.custom-range::-moz-range-thumb {
+ width: 1rem;
+ height: 1rem;
+ background-color: #007bff;
+ border: 0;
+ border-radius: 1rem;
+ -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .custom-range::-moz-range-thumb {
+ -moz-transition: none;
+ transition: none;
+ }
+}
+
+.custom-range::-moz-range-thumb:active {
+ background-color: #b3d7ff;
+}
+
+.custom-range::-moz-range-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: #dee2e6;
+ border-color: transparent;
+ border-radius: 1rem;
+}
+
+.custom-range::-ms-thumb {
+ width: 1rem;
+ height: 1rem;
+ margin-top: 0;
+ margin-right: 0.2rem;
+ margin-left: 0.2rem;
+ background-color: #007bff;
+ border: 0;
+ border-radius: 1rem;
+ -ms-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ appearance: none;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .custom-range::-ms-thumb {
+ -ms-transition: none;
+ transition: none;
+ }
+}
+
+.custom-range::-ms-thumb:active {
+ background-color: #b3d7ff;
+}
+
+.custom-range::-ms-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: transparent;
+ border-color: transparent;
+ border-width: 0.5rem;
+}
+
+.custom-range::-ms-fill-lower {
+ background-color: #dee2e6;
+ border-radius: 1rem;
+}
+
+.custom-range::-ms-fill-upper {
+ margin-right: 15px;
+ background-color: #dee2e6;
+ border-radius: 1rem;
+}
+
+.custom-range:disabled::-webkit-slider-thumb {
+ background-color: #adb5bd;
+}
+
+.custom-range:disabled::-webkit-slider-runnable-track {
+ cursor: default;
+}
+
+.custom-range:disabled::-moz-range-thumb {
+ background-color: #adb5bd;
+}
+
+.custom-range:disabled::-moz-range-track {
+ cursor: default;
+}
+
+.custom-range:disabled::-ms-thumb {
+ background-color: #adb5bd;
+}
+
+.custom-control-label::before,
+.custom-file-label,
+.custom-select {
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .custom-control-label::before,
+ .custom-file-label,
+ .custom-select {
+ transition: none;
+ }
+}
+
+.nav {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+
+.nav-link {
+ display: block;
+ padding: 0.5rem 1rem;
+}
+
+.nav-link:hover, .nav-link:focus {
+ text-decoration: none;
+}
+
+.nav-link.disabled {
+ color: #6c757d;
+ pointer-events: none;
+ cursor: default;
+}
+
+.nav-tabs {
+ border-bottom: 1px solid #dee2e6;
+}
+
+.nav-tabs .nav-item {
+ margin-bottom: -1px;
+}
+
+.nav-tabs .nav-link {
+ border: 1px solid transparent;
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+}
+
+.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
+ border-color: #e9ecef #e9ecef #dee2e6;
+}
+
+.nav-tabs .nav-link.disabled {
+ color: #6c757d;
+ background-color: transparent;
+ border-color: transparent;
+}
+
+.nav-tabs .nav-link.active,
+.nav-tabs .nav-item.show .nav-link {
+ color: #495057;
+ background-color: #fff;
+ border-color: #dee2e6 #dee2e6 #fff;
+}
+
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.nav-pills .nav-link {
+ border-radius: 0.25rem;
+}
+
+.nav-pills .nav-link.active,
+.nav-pills .show > .nav-link {
+ color: #fff;
+ background-color: #007bff;
+}
+
+.nav-fill .nav-item {
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ text-align: center;
+}
+
+.nav-justified .nav-item {
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ text-align: center;
+}
+
+.tab-content > .tab-pane {
+ display: none;
+}
+
+.tab-content > .active {
+ display: block;
+}
+
+.navbar {
+ position: relative;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ padding: 0.5rem 1rem;
+}
+
+.navbar .container,
+.navbar .container-fluid, .navbar .container-sm, .navbar .container-md, .navbar .container-lg, .navbar .container-xl {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+
+.navbar-brand {
+ display: inline-block;
+ padding-top: 0.3125rem;
+ padding-bottom: 0.3125rem;
+ margin-right: 1rem;
+ font-size: 1.25rem;
+ line-height: inherit;
+ white-space: nowrap;
+}
+
+.navbar-brand:hover, .navbar-brand:focus {
+ text-decoration: none;
+}
+
+.navbar-nav {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+
+.navbar-nav .nav-link {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.navbar-nav .dropdown-menu {
+ position: static;
+ float: none;
+}
+
+.navbar-text {
+ display: inline-block;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+}
+
+.navbar-collapse {
+ -ms-flex-preferred-size: 100%;
+ flex-basis: 100%;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.navbar-toggler {
+ padding: 0.25rem 0.75rem;
+ font-size: 1.25rem;
+ line-height: 1;
+ background-color: transparent;
+ border: 1px solid transparent;
+ border-radius: 0.25rem;
+}
+
+.navbar-toggler:hover, .navbar-toggler:focus {
+ text-decoration: none;
+}
+
+.navbar-toggler-icon {
+ display: inline-block;
+ width: 1.5em;
+ height: 1.5em;
+ vertical-align: middle;
+ content: "";
+ background: no-repeat center center;
+ background-size: 100% 100%;
+}
+
+@media (max-width: 575.98px) {
+ .navbar-expand-sm > .container,
+ .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+
+@media (min-width: 576px) {
+ .navbar-expand-sm {
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ }
+ .navbar-expand-sm .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .navbar-expand-sm .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-sm .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-sm > .container,
+ .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl {
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ }
+ .navbar-expand-sm .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+ .navbar-expand-sm .navbar-toggler {
+ display: none;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .navbar-expand-md > .container,
+ .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+
+@media (min-width: 768px) {
+ .navbar-expand-md {
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ }
+ .navbar-expand-md .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .navbar-expand-md .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-md .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-md > .container,
+ .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl {
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ }
+ .navbar-expand-md .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+ .navbar-expand-md .navbar-toggler {
+ display: none;
+ }
+}
+
+@media (max-width: 991.98px) {
+ .navbar-expand-lg > .container,
+ .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+
+@media (min-width: 992px) {
+ .navbar-expand-lg {
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ }
+ .navbar-expand-lg .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .navbar-expand-lg .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-lg .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-lg > .container,
+ .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl {
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ }
+ .navbar-expand-lg .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+ .navbar-expand-lg .navbar-toggler {
+ display: none;
+ }
+}
+
+@media (max-width: 1199.98px) {
+ .navbar-expand-xl > .container,
+ .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+
+@media (min-width: 1200px) {
+ .navbar-expand-xl {
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ }
+ .navbar-expand-xl .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .navbar-expand-xl .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-xl .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-xl > .container,
+ .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl {
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ }
+ .navbar-expand-xl .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+ .navbar-expand-xl .navbar-toggler {
+ display: none;
+ }
+}
+
+.navbar-expand {
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+}
+
+.navbar-expand > .container,
+.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.navbar-expand .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.navbar-expand .navbar-nav .dropdown-menu {
+ position: absolute;
+}
+
+.navbar-expand .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+}
+
+.navbar-expand > .container,
+.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl {
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+}
+
+.navbar-expand .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+}
+
+.navbar-expand .navbar-toggler {
+ display: none;
+}
+
+.navbar-light .navbar-brand {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-light .navbar-nav .nav-link {
+ color: rgba(0, 0, 0, 0.5);
+}
+
+.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
+ color: rgba(0, 0, 0, 0.7);
+}
+
+.navbar-light .navbar-nav .nav-link.disabled {
+ color: rgba(0, 0, 0, 0.3);
+}
+
+.navbar-light .navbar-nav .show > .nav-link,
+.navbar-light .navbar-nav .active > .nav-link,
+.navbar-light .navbar-nav .nav-link.show,
+.navbar-light .navbar-nav .nav-link.active {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-light .navbar-toggler {
+ color: rgba(0, 0, 0, 0.5);
+ border-color: rgba(0, 0, 0, 0.1);
+}
+
+.navbar-light .navbar-toggler-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+}
+
+.navbar-light .navbar-text {
+ color: rgba(0, 0, 0, 0.5);
+}
+
+.navbar-light .navbar-text a {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-dark .navbar-brand {
+ color: #fff;
+}
+
+.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {
+ color: #fff;
+}
+
+.navbar-dark .navbar-nav .nav-link {
+ color: rgba(255, 255, 255, 0.5);
+}
+
+.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {
+ color: rgba(255, 255, 255, 0.75);
+}
+
+.navbar-dark .navbar-nav .nav-link.disabled {
+ color: rgba(255, 255, 255, 0.25);
+}
+
+.navbar-dark .navbar-nav .show > .nav-link,
+.navbar-dark .navbar-nav .active > .nav-link,
+.navbar-dark .navbar-nav .nav-link.show,
+.navbar-dark .navbar-nav .nav-link.active {
+ color: #fff;
+}
+
+.navbar-dark .navbar-toggler {
+ color: rgba(255, 255, 255, 0.5);
+ border-color: rgba(255, 255, 255, 0.1);
+}
+
+.navbar-dark .navbar-toggler-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+}
+
+.navbar-dark .navbar-text {
+ color: rgba(255, 255, 255, 0.5);
+}
+
+.navbar-dark .navbar-text a {
+ color: #fff;
+}
+
+.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {
+ color: #fff;
+}
+
+.card {
+ position: relative;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ min-width: 0;
+ word-wrap: break-word;
+ background-color: #fff;
+ background-clip: border-box;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+ border-radius: 0.25rem;
+}
+
+.card > hr {
+ margin-right: 0;
+ margin-left: 0;
+}
+
+.card > .list-group:first-child .list-group-item:first-child {
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+}
+
+.card > .list-group:last-child .list-group-item:last-child {
+ border-bottom-right-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+
+.card-body {
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ min-height: 1px;
+ padding: 1.25rem;
+}
+
+.card-title {
+ margin-bottom: 0.75rem;
+}
+
+.card-subtitle {
+ margin-top: -0.375rem;
+ margin-bottom: 0;
+}
+
+.card-text:last-child {
+ margin-bottom: 0;
+}
+
+.card-link:hover {
+ text-decoration: none;
+}
+
+.card-link + .card-link {
+ margin-left: 1.25rem;
+}
+
+.card-header {
+ padding: 0.75rem 1.25rem;
+ margin-bottom: 0;
+ background-color: rgba(0, 0, 0, 0.03);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
+}
+
+.card-header:first-child {
+ border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;
+}
+
+.card-header + .list-group .list-group-item:first-child {
+ border-top: 0;
+}
+
+.card-footer {
+ padding: 0.75rem 1.25rem;
+ background-color: rgba(0, 0, 0, 0.03);
+ border-top: 1px solid rgba(0, 0, 0, 0.125);
+}
+
+.card-footer:last-child {
+ border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);
+}
+
+.card-header-tabs {
+ margin-right: -0.625rem;
+ margin-bottom: -0.75rem;
+ margin-left: -0.625rem;
+ border-bottom: 0;
+}
+
+.card-header-pills {
+ margin-right: -0.625rem;
+ margin-left: -0.625rem;
+}
+
+.card-img-overlay {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: 1.25rem;
+}
+
+.card-img,
+.card-img-top,
+.card-img-bottom {
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ width: 100%;
+}
+
+.card-img,
+.card-img-top {
+ border-top-left-radius: calc(0.25rem - 1px);
+ border-top-right-radius: calc(0.25rem - 1px);
+}
+
+.card-img,
+.card-img-bottom {
+ border-bottom-right-radius: calc(0.25rem - 1px);
+ border-bottom-left-radius: calc(0.25rem - 1px);
+}
+
+.card-deck .card {
+ margin-bottom: 15px;
+}
+
+@media (min-width: 576px) {
+ .card-deck {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap;
+ margin-right: -15px;
+ margin-left: -15px;
+ }
+ .card-deck .card {
+ -ms-flex: 1 0 0%;
+ flex: 1 0 0%;
+ margin-right: 15px;
+ margin-bottom: 0;
+ margin-left: 15px;
+ }
+}
+
+.card-group > .card {
+ margin-bottom: 15px;
+}
+
+@media (min-width: 576px) {
+ .card-group {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap;
+ }
+ .card-group > .card {
+ -ms-flex: 1 0 0%;
+ flex: 1 0 0%;
+ margin-bottom: 0;
+ }
+ .card-group > .card + .card {
+ margin-left: 0;
+ border-left: 0;
+ }
+ .card-group > .card:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-top,
+ .card-group > .card:not(:last-child) .card-header {
+ border-top-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-bottom,
+ .card-group > .card:not(:last-child) .card-footer {
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-top,
+ .card-group > .card:not(:first-child) .card-header {
+ border-top-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-bottom,
+ .card-group > .card:not(:first-child) .card-footer {
+ border-bottom-left-radius: 0;
+ }
+}
+
+.card-columns .card {
+ margin-bottom: 0.75rem;
+}
+
+@media (min-width: 576px) {
+ .card-columns {
+ -webkit-column-count: 3;
+ -moz-column-count: 3;
+ column-count: 3;
+ -webkit-column-gap: 1.25rem;
+ -moz-column-gap: 1.25rem;
+ column-gap: 1.25rem;
+ orphans: 1;
+ widows: 1;
+ }
+ .card-columns .card {
+ display: inline-block;
+ width: 100%;
+ }
+}
+
+.accordion > .card {
+ overflow: hidden;
+}
+
+.accordion > .card:not(:last-of-type) {
+ border-bottom: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.accordion > .card:not(:first-of-type) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.accordion > .card > .card-header {
+ border-radius: 0;
+ margin-bottom: -1px;
+}
+
+.breadcrumb {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ padding: 0.75rem 1rem;
+ margin-bottom: 1rem;
+ list-style: none;
+ background-color: #e9ecef;
+ border-radius: 0.25rem;
+}
+
+.breadcrumb-item + .breadcrumb-item {
+ padding-left: 0.5rem;
+}
+
+.breadcrumb-item + .breadcrumb-item::before {
+ display: inline-block;
+ padding-right: 0.5rem;
+ color: #6c757d;
+ content: "/";
+}
+
+.breadcrumb-item + .breadcrumb-item:hover::before {
+ text-decoration: underline;
+}
+
+.breadcrumb-item + .breadcrumb-item:hover::before {
+ text-decoration: none;
+}
+
+.breadcrumb-item.active {
+ color: #6c757d;
+}
+
+.pagination {
+ display: -ms-flexbox;
+ display: flex;
+ padding-left: 0;
+ list-style: none;
+ border-radius: 0.25rem;
+}
+
+.page-link {
+ position: relative;
+ display: block;
+ padding: 0.5rem 0.75rem;
+ margin-left: -1px;
+ line-height: 1.25;
+ color: #007bff;
+ background-color: #fff;
+ border: 1px solid #dee2e6;
+}
+
+.page-link:hover {
+ z-index: 2;
+ color: #0056b3;
+ text-decoration: none;
+ background-color: #e9ecef;
+ border-color: #dee2e6;
+}
+
+.page-link:focus {
+ z-index: 3;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.page-item:first-child .page-link {
+ margin-left: 0;
+ border-top-left-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+
+.page-item:last-child .page-link {
+ border-top-right-radius: 0.25rem;
+ border-bottom-right-radius: 0.25rem;
+}
+
+.page-item.active .page-link {
+ z-index: 3;
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.page-item.disabled .page-link {
+ color: #6c757d;
+ pointer-events: none;
+ cursor: auto;
+ background-color: #fff;
+ border-color: #dee2e6;
+}
+
+.pagination-lg .page-link {
+ padding: 0.75rem 1.5rem;
+ font-size: 1.25rem;
+ line-height: 1.5;
+}
+
+.pagination-lg .page-item:first-child .page-link {
+ border-top-left-radius: 0.3rem;
+ border-bottom-left-radius: 0.3rem;
+}
+
+.pagination-lg .page-item:last-child .page-link {
+ border-top-right-radius: 0.3rem;
+ border-bottom-right-radius: 0.3rem;
+}
+
+.pagination-sm .page-link {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ line-height: 1.5;
+}
+
+.pagination-sm .page-item:first-child .page-link {
+ border-top-left-radius: 0.2rem;
+ border-bottom-left-radius: 0.2rem;
+}
+
+.pagination-sm .page-item:last-child .page-link {
+ border-top-right-radius: 0.2rem;
+ border-bottom-right-radius: 0.2rem;
+}
+
+.badge {
+ display: inline-block;
+ padding: 0.25em 0.4em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 0.25rem;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .badge {
+ transition: none;
+ }
+}
+
+a.badge:hover, a.badge:focus {
+ text-decoration: none;
+}
+
+.badge:empty {
+ display: none;
+}
+
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+
+.badge-pill {
+ padding-right: 0.6em;
+ padding-left: 0.6em;
+ border-radius: 10rem;
+}
+
+.badge-primary {
+ color: #fff;
+ background-color: #007bff;
+}
+
+a.badge-primary:hover, a.badge-primary:focus {
+ color: #fff;
+ background-color: #0062cc;
+}
+
+a.badge-primary:focus, a.badge-primary.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
+}
+
+.badge-secondary {
+ color: #fff;
+ background-color: #6c757d;
+}
+
+a.badge-secondary:hover, a.badge-secondary:focus {
+ color: #fff;
+ background-color: #545b62;
+}
+
+a.badge-secondary:focus, a.badge-secondary.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
+}
+
+.badge-success {
+ color: #fff;
+ background-color: #28a745;
+}
+
+a.badge-success:hover, a.badge-success:focus {
+ color: #fff;
+ background-color: #1e7e34;
+}
+
+a.badge-success:focus, a.badge-success.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
+}
+
+.badge-info {
+ color: #fff;
+ background-color: #17a2b8;
+}
+
+a.badge-info:hover, a.badge-info:focus {
+ color: #fff;
+ background-color: #117a8b;
+}
+
+a.badge-info:focus, a.badge-info.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
+}
+
+.badge-warning {
+ color: #212529;
+ background-color: #ffc107;
+}
+
+a.badge-warning:hover, a.badge-warning:focus {
+ color: #212529;
+ background-color: #d39e00;
+}
+
+a.badge-warning:focus, a.badge-warning.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
+}
+
+.badge-danger {
+ color: #fff;
+ background-color: #dc3545;
+}
+
+a.badge-danger:hover, a.badge-danger:focus {
+ color: #fff;
+ background-color: #bd2130;
+}
+
+a.badge-danger:focus, a.badge-danger.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
+}
+
+.badge-light {
+ color: #212529;
+ background-color: #f8f9fa;
+}
+
+a.badge-light:hover, a.badge-light:focus {
+ color: #212529;
+ background-color: #dae0e5;
+}
+
+a.badge-light:focus, a.badge-light.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
+}
+
+.badge-dark {
+ color: #fff;
+ background-color: #343a40;
+}
+
+a.badge-dark:hover, a.badge-dark:focus {
+ color: #fff;
+ background-color: #1d2124;
+}
+
+a.badge-dark:focus, a.badge-dark.focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
+}
+
+.jumbotron {
+ padding: 2rem 1rem;
+ margin-bottom: 2rem;
+ background-color: #e9ecef;
+ border-radius: 0.3rem;
+}
+
+@media (min-width: 576px) {
+ .jumbotron {
+ padding: 4rem 2rem;
+ }
+}
+
+.jumbotron-fluid {
+ padding-right: 0;
+ padding-left: 0;
+ border-radius: 0;
+}
+
+.alert {
+ position: relative;
+ padding: 0.75rem 1.25rem;
+ margin-bottom: 1rem;
+ border: 1px solid transparent;
+ border-radius: 0.25rem;
+}
+
+.alert-heading {
+ color: inherit;
+}
+
+.alert-link {
+ font-weight: 700;
+}
+
+.alert-dismissible {
+ padding-right: 4rem;
+}
+
+.alert-dismissible .close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 0.75rem 1.25rem;
+ color: inherit;
+}
+
+.alert-primary {
+ color: #004085;
+ background-color: #cce5ff;
+ border-color: #b8daff;
+}
+
+.alert-primary hr {
+ border-top-color: #9fcdff;
+}
+
+.alert-primary .alert-link {
+ color: #002752;
+}
+
+.alert-secondary {
+ color: #383d41;
+ background-color: #e2e3e5;
+ border-color: #d6d8db;
+}
+
+.alert-secondary hr {
+ border-top-color: #c8cbcf;
+}
+
+.alert-secondary .alert-link {
+ color: #202326;
+}
+
+.alert-success {
+ color: #155724;
+ background-color: #d4edda;
+ border-color: #c3e6cb;
+}
+
+.alert-success hr {
+ border-top-color: #b1dfbb;
+}
+
+.alert-success .alert-link {
+ color: #0b2e13;
+}
+
+.alert-info {
+ color: #0c5460;
+ background-color: #d1ecf1;
+ border-color: #bee5eb;
+}
+
+.alert-info hr {
+ border-top-color: #abdde5;
+}
+
+.alert-info .alert-link {
+ color: #062c33;
+}
+
+.alert-warning {
+ color: #856404;
+ background-color: #fff3cd;
+ border-color: #ffeeba;
+}
+
+.alert-warning hr {
+ border-top-color: #ffe8a1;
+}
+
+.alert-warning .alert-link {
+ color: #533f03;
+}
+
+.alert-danger {
+ color: #721c24;
+ background-color: #f8d7da;
+ border-color: #f5c6cb;
+}
+
+.alert-danger hr {
+ border-top-color: #f1b0b7;
+}
+
+.alert-danger .alert-link {
+ color: #491217;
+}
+
+.alert-light {
+ color: #818182;
+ background-color: #fefefe;
+ border-color: #fdfdfe;
+}
+
+.alert-light hr {
+ border-top-color: #ececf6;
+}
+
+.alert-light .alert-link {
+ color: #686868;
+}
+
+.alert-dark {
+ color: #1b1e21;
+ background-color: #d6d8d9;
+ border-color: #c6c8ca;
+}
+
+.alert-dark hr {
+ border-top-color: #b9bbbe;
+}
+
+.alert-dark .alert-link {
+ color: #040505;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 1rem 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 1rem 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+.progress {
+ display: -ms-flexbox;
+ display: flex;
+ height: 1rem;
+ overflow: hidden;
+ font-size: 0.75rem;
+ background-color: #e9ecef;
+ border-radius: 0.25rem;
+}
+
+.progress-bar {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -ms-flex-pack: center;
+ justify-content: center;
+ overflow: hidden;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ background-color: #007bff;
+ transition: width 0.6s ease;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar {
+ transition: none;
+ }
+}
+
+.progress-bar-striped {
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-size: 1rem 1rem;
+}
+
+.progress-bar-animated {
+ -webkit-animation: progress-bar-stripes 1s linear infinite;
+ animation: progress-bar-stripes 1s linear infinite;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar-animated {
+ -webkit-animation: none;
+ animation: none;
+ }
+}
+
+.media {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: start;
+ align-items: flex-start;
+}
+
+.media-body {
+ -ms-flex: 1;
+ flex: 1;
+}
+
+.list-group {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ padding-left: 0;
+ margin-bottom: 0;
+}
+
+.list-group-item-action {
+ width: 100%;
+ color: #495057;
+ text-align: inherit;
+}
+
+.list-group-item-action:hover, .list-group-item-action:focus {
+ z-index: 1;
+ color: #495057;
+ text-decoration: none;
+ background-color: #f8f9fa;
+}
+
+.list-group-item-action:active {
+ color: #212529;
+ background-color: #e9ecef;
+}
+
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 0.75rem 1.25rem;
+ background-color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+}
+
+.list-group-item:first-child {
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+}
+
+.list-group-item:last-child {
+ border-bottom-right-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+
+.list-group-item.disabled, .list-group-item:disabled {
+ color: #6c757d;
+ pointer-events: none;
+ background-color: #fff;
+}
+
+.list-group-item.active {
+ z-index: 2;
+ color: #fff;
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.list-group-item + .list-group-item {
+ border-top-width: 0;
+}
+
+.list-group-item + .list-group-item.active {
+ margin-top: -1px;
+ border-top-width: 1px;
+}
+
+.list-group-horizontal {
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.list-group-horizontal .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+}
+
+.list-group-horizontal .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+}
+
+.list-group-horizontal .list-group-item.active {
+ margin-top: 0;
+}
+
+.list-group-horizontal .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+}
+
+.list-group-horizontal .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+}
+
+@media (min-width: 576px) {
+ .list-group-horizontal-sm {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .list-group-horizontal-sm .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-sm .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-sm .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-sm .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-sm .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+
+@media (min-width: 768px) {
+ .list-group-horizontal-md {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .list-group-horizontal-md .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-md .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-md .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-md .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-md .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+
+@media (min-width: 992px) {
+ .list-group-horizontal-lg {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .list-group-horizontal-lg .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-lg .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-lg .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-lg .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-lg .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .list-group-horizontal-xl {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+ .list-group-horizontal-xl .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-xl .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-xl .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-xl .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-xl .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+
+.list-group-flush .list-group-item {
+ border-right-width: 0;
+ border-left-width: 0;
+ border-radius: 0;
+}
+
+.list-group-flush .list-group-item:first-child {
+ border-top-width: 0;
+}
+
+.list-group-flush:last-child .list-group-item:last-child {
+ border-bottom-width: 0;
+}
+
+.list-group-item-primary {
+ color: #004085;
+ background-color: #b8daff;
+}
+
+.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {
+ color: #004085;
+ background-color: #9fcdff;
+}
+
+.list-group-item-primary.list-group-item-action.active {
+ color: #fff;
+ background-color: #004085;
+ border-color: #004085;
+}
+
+.list-group-item-secondary {
+ color: #383d41;
+ background-color: #d6d8db;
+}
+
+.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {
+ color: #383d41;
+ background-color: #c8cbcf;
+}
+
+.list-group-item-secondary.list-group-item-action.active {
+ color: #fff;
+ background-color: #383d41;
+ border-color: #383d41;
+}
+
+.list-group-item-success {
+ color: #155724;
+ background-color: #c3e6cb;
+}
+
+.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {
+ color: #155724;
+ background-color: #b1dfbb;
+}
+
+.list-group-item-success.list-group-item-action.active {
+ color: #fff;
+ background-color: #155724;
+ border-color: #155724;
+}
+
+.list-group-item-info {
+ color: #0c5460;
+ background-color: #bee5eb;
+}
+
+.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
+ color: #0c5460;
+ background-color: #abdde5;
+}
+
+.list-group-item-info.list-group-item-action.active {
+ color: #fff;
+ background-color: #0c5460;
+ border-color: #0c5460;
+}
+
+.list-group-item-warning {
+ color: #856404;
+ background-color: #ffeeba;
+}
+
+.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {
+ color: #856404;
+ background-color: #ffe8a1;
+}
+
+.list-group-item-warning.list-group-item-action.active {
+ color: #fff;
+ background-color: #856404;
+ border-color: #856404;
+}
+
+.list-group-item-danger {
+ color: #721c24;
+ background-color: #f5c6cb;
+}
+
+.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {
+ color: #721c24;
+ background-color: #f1b0b7;
+}
+
+.list-group-item-danger.list-group-item-action.active {
+ color: #fff;
+ background-color: #721c24;
+ border-color: #721c24;
+}
+
+.list-group-item-light {
+ color: #818182;
+ background-color: #fdfdfe;
+}
+
+.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {
+ color: #818182;
+ background-color: #ececf6;
+}
+
+.list-group-item-light.list-group-item-action.active {
+ color: #fff;
+ background-color: #818182;
+ border-color: #818182;
+}
+
+.list-group-item-dark {
+ color: #1b1e21;
+ background-color: #c6c8ca;
+}
+
+.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {
+ color: #1b1e21;
+ background-color: #b9bbbe;
+}
+
+.list-group-item-dark.list-group-item-action.active {
+ color: #fff;
+ background-color: #1b1e21;
+ border-color: #1b1e21;
+}
+
+.close {
+ float: right;
+ font-size: 1.5rem;
+ font-weight: 700;
+ line-height: 1;
+ color: #000;
+ text-shadow: 0 1px 0 #fff;
+ opacity: .5;
+}
+
+.close:hover {
+ color: #000;
+ text-decoration: none;
+}
+
+.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus {
+ opacity: .75;
+}
+
+button.close {
+ padding: 0;
+ background-color: transparent;
+ border: 0;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+a.close.disabled {
+ pointer-events: none;
+}
+
+.toast {
+ max-width: 350px;
+ overflow: hidden;
+ font-size: 0.875rem;
+ background-color: rgba(255, 255, 255, 0.85);
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
+ -webkit-backdrop-filter: blur(10px);
+ backdrop-filter: blur(10px);
+ opacity: 0;
+ border-radius: 0.25rem;
+}
+
+.toast:not(:last-child) {
+ margin-bottom: 0.75rem;
+}
+
+.toast.showing {
+ opacity: 1;
+}
+
+.toast.show {
+ display: block;
+ opacity: 1;
+}
+
+.toast.hide {
+ display: none;
+}
+
+.toast-header {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 0.25rem 0.75rem;
+ color: #6c757d;
+ background-color: rgba(255, 255, 255, 0.85);
+ background-clip: padding-box;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.toast-body {
+ padding: 0.75rem;
+}
+
+.modal-open {
+ overflow: hidden;
+}
+
+.modal-open .modal {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1050;
+ display: none;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ outline: 0;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0.5rem;
+ pointer-events: none;
+}
+
+.modal.fade .modal-dialog {
+ transition: -webkit-transform 0.3s ease-out;
+ transition: transform 0.3s ease-out;
+ transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out;
+ -webkit-transform: translate(0, -50px);
+ transform: translate(0, -50px);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .modal.fade .modal-dialog {
+ transition: none;
+ }
+}
+
+.modal.show .modal-dialog {
+ -webkit-transform: none;
+ transform: none;
+}
+
+.modal.modal-static .modal-dialog {
+ -webkit-transform: scale(1.02);
+ transform: scale(1.02);
+}
+
+.modal-dialog-scrollable {
+ display: -ms-flexbox;
+ display: flex;
+ max-height: calc(100% - 1rem);
+}
+
+.modal-dialog-scrollable .modal-content {
+ max-height: calc(100vh - 1rem);
+ overflow: hidden;
+}
+
+.modal-dialog-scrollable .modal-header,
+.modal-dialog-scrollable .modal-footer {
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.modal-dialog-scrollable .modal-body {
+ overflow-y: auto;
+}
+
+.modal-dialog-centered {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ min-height: calc(100% - 1rem);
+}
+
+.modal-dialog-centered::before {
+ display: block;
+ height: calc(100vh - 1rem);
+ content: "";
+}
+
+.modal-dialog-centered.modal-dialog-scrollable {
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -ms-flex-pack: center;
+ justify-content: center;
+ height: 100%;
+}
+
+.modal-dialog-centered.modal-dialog-scrollable .modal-content {
+ max-height: none;
+}
+
+.modal-dialog-centered.modal-dialog-scrollable::before {
+ content: none;
+}
+
+.modal-content {
+ position: relative;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ width: 100%;
+ pointer-events: auto;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 0.3rem;
+ outline: 0;
+}
+
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1040;
+ width: 100vw;
+ height: 100vh;
+ background-color: #000;
+}
+
+.modal-backdrop.fade {
+ opacity: 0;
+}
+
+.modal-backdrop.show {
+ opacity: 0.5;
+}
+
+.modal-header {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: start;
+ align-items: flex-start;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ padding: 1rem 1rem;
+ border-bottom: 1px solid #dee2e6;
+ border-top-left-radius: calc(0.3rem - 1px);
+ border-top-right-radius: calc(0.3rem - 1px);
+}
+
+.modal-header .close {
+ padding: 1rem 1rem;
+ margin: -1rem -1rem -1rem auto;
+}
+
+.modal-title {
+ margin-bottom: 0;
+ line-height: 1.5;
+}
+
+.modal-body {
+ position: relative;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ padding: 1rem;
+}
+
+.modal-footer {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ padding: 0.75rem;
+ border-top: 1px solid #dee2e6;
+ border-bottom-right-radius: calc(0.3rem - 1px);
+ border-bottom-left-radius: calc(0.3rem - 1px);
+}
+
+.modal-footer > * {
+ margin: 0.25rem;
+}
+
+.modal-scrollbar-measure {
+ position: absolute;
+ top: -9999px;
+ width: 50px;
+ height: 50px;
+ overflow: scroll;
+}
+
+@media (min-width: 576px) {
+ .modal-dialog {
+ max-width: 500px;
+ margin: 1.75rem auto;
+ }
+ .modal-dialog-scrollable {
+ max-height: calc(100% - 3.5rem);
+ }
+ .modal-dialog-scrollable .modal-content {
+ max-height: calc(100vh - 3.5rem);
+ }
+ .modal-dialog-centered {
+ min-height: calc(100% - 3.5rem);
+ }
+ .modal-dialog-centered::before {
+ height: calc(100vh - 3.5rem);
+ }
+ .modal-sm {
+ max-width: 300px;
+ }
+}
+
+@media (min-width: 992px) {
+ .modal-lg,
+ .modal-xl {
+ max-width: 800px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .modal-xl {
+ max-width: 1140px;
+ }
+}
+
+.tooltip {
+ position: absolute;
+ z-index: 1070;
+ display: block;
+ margin: 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-style: normal;
+ font-weight: 400;
+ line-height: 1.5;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ white-space: normal;
+ line-break: auto;
+ font-size: 0.875rem;
+ word-wrap: break-word;
+ opacity: 0;
+}
+
+.tooltip.show {
+ opacity: 0.9;
+}
+
+.tooltip .arrow {
+ position: absolute;
+ display: block;
+ width: 0.8rem;
+ height: 0.4rem;
+}
+
+.tooltip .arrow::before {
+ position: absolute;
+ content: "";
+ border-color: transparent;
+ border-style: solid;
+}
+
+.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] {
+ padding: 0.4rem 0;
+}
+
+.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow {
+ bottom: 0;
+}
+
+.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before {
+ top: 0;
+ border-width: 0.4rem 0.4rem 0;
+ border-top-color: #000;
+}
+
+.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] {
+ padding: 0 0.4rem;
+}
+
+.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow {
+ left: 0;
+ width: 0.4rem;
+ height: 0.8rem;
+}
+
+.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before {
+ right: 0;
+ border-width: 0.4rem 0.4rem 0.4rem 0;
+ border-right-color: #000;
+}
+
+.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] {
+ padding: 0.4rem 0;
+}
+
+.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow {
+ top: 0;
+}
+
+.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before {
+ bottom: 0;
+ border-width: 0 0.4rem 0.4rem;
+ border-bottom-color: #000;
+}
+
+.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] {
+ padding: 0 0.4rem;
+}
+
+.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow {
+ right: 0;
+ width: 0.4rem;
+ height: 0.8rem;
+}
+
+.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before {
+ left: 0;
+ border-width: 0.4rem 0 0.4rem 0.4rem;
+ border-left-color: #000;
+}
+
+.tooltip-inner {
+ max-width: 200px;
+ padding: 0.25rem 0.5rem;
+ color: #fff;
+ text-align: center;
+ background-color: #000;
+ border-radius: 0.25rem;
+}
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: block;
+ max-width: 276px;
+ 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-style: normal;
+ font-weight: 400;
+ line-height: 1.5;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ white-space: normal;
+ line-break: auto;
+ font-size: 0.875rem;
+ word-wrap: break-word;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 0.3rem;
+}
+
+.popover .arrow {
+ position: absolute;
+ display: block;
+ width: 1rem;
+ height: 0.5rem;
+ margin: 0 0.3rem;
+}
+
+.popover .arrow::before, .popover .arrow::after {
+ position: absolute;
+ display: block;
+ content: "";
+ border-color: transparent;
+ border-style: solid;
+}
+
+.bs-popover-top, .bs-popover-auto[x-placement^="top"] {
+ margin-bottom: 0.5rem;
+}
+
+.bs-popover-top > .arrow, .bs-popover-auto[x-placement^="top"] > .arrow {
+ bottom: calc(-0.5rem - 1px);
+}
+
+.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^="top"] > .arrow::before {
+ bottom: 0;
+ border-width: 0.5rem 0.5rem 0;
+ border-top-color: rgba(0, 0, 0, 0.25);
+}
+
+.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^="top"] > .arrow::after {
+ bottom: 1px;
+ border-width: 0.5rem 0.5rem 0;
+ border-top-color: #fff;
+}
+
+.bs-popover-right, .bs-popover-auto[x-placement^="right"] {
+ margin-left: 0.5rem;
+}
+
+.bs-popover-right > .arrow, .bs-popover-auto[x-placement^="right"] > .arrow {
+ left: calc(-0.5rem - 1px);
+ width: 0.5rem;
+ height: 1rem;
+ margin: 0.3rem 0;
+}
+
+.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^="right"] > .arrow::before {
+ left: 0;
+ border-width: 0.5rem 0.5rem 0.5rem 0;
+ border-right-color: rgba(0, 0, 0, 0.25);
+}
+
+.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^="right"] > .arrow::after {
+ left: 1px;
+ border-width: 0.5rem 0.5rem 0.5rem 0;
+ border-right-color: #fff;
+}
+
+.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] {
+ margin-top: 0.5rem;
+}
+
+.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^="bottom"] > .arrow {
+ top: calc(-0.5rem - 1px);
+}
+
+.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^="bottom"] > .arrow::before {
+ top: 0;
+ border-width: 0 0.5rem 0.5rem 0.5rem;
+ border-bottom-color: rgba(0, 0, 0, 0.25);
+}
+
+.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^="bottom"] > .arrow::after {
+ top: 1px;
+ border-width: 0 0.5rem 0.5rem 0.5rem;
+ border-bottom-color: #fff;
+}
+
+.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ display: block;
+ width: 1rem;
+ margin-left: -0.5rem;
+ content: "";
+ border-bottom: 1px solid #f7f7f7;
+}
+
+.bs-popover-left, .bs-popover-auto[x-placement^="left"] {
+ margin-right: 0.5rem;
+}
+
+.bs-popover-left > .arrow, .bs-popover-auto[x-placement^="left"] > .arrow {
+ right: calc(-0.5rem - 1px);
+ width: 0.5rem;
+ height: 1rem;
+ margin: 0.3rem 0;
+}
+
+.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^="left"] > .arrow::before {
+ right: 0;
+ border-width: 0.5rem 0 0.5rem 0.5rem;
+ border-left-color: rgba(0, 0, 0, 0.25);
+}
+
+.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^="left"] > .arrow::after {
+ right: 1px;
+ border-width: 0.5rem 0 0.5rem 0.5rem;
+ border-left-color: #fff;
+}
+
+.popover-header {
+ padding: 0.5rem 0.75rem;
+ margin-bottom: 0;
+ font-size: 1rem;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-top-left-radius: calc(0.3rem - 1px);
+ border-top-right-radius: calc(0.3rem - 1px);
+}
+
+.popover-header:empty {
+ display: none;
+}
+
+.popover-body {
+ padding: 0.5rem 0.75rem;
+ color: #212529;
+}
+
+.carousel {
+ position: relative;
+}
+
+.carousel.pointer-event {
+ -ms-touch-action: pan-y;
+ touch-action: pan-y;
+}
+
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+
+.carousel-inner::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.carousel-item {
+ position: relative;
+ display: none;
+ float: left;
+ width: 100%;
+ margin-right: -100%;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ transition: -webkit-transform 0.6s ease-in-out;
+ transition: transform 0.6s ease-in-out;
+ transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .carousel-item {
+ transition: none;
+ }
+}
+
+.carousel-item.active,
+.carousel-item-next,
+.carousel-item-prev {
+ display: block;
+}
+
+.carousel-item-next:not(.carousel-item-left),
+.active.carousel-item-right {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+}
+
+.carousel-item-prev:not(.carousel-item-right),
+.active.carousel-item-left {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+}
+
+.carousel-fade .carousel-item {
+ opacity: 0;
+ transition-property: opacity;
+ -webkit-transform: none;
+ transform: none;
+}
+
+.carousel-fade .carousel-item.active,
+.carousel-fade .carousel-item-next.carousel-item-left,
+.carousel-fade .carousel-item-prev.carousel-item-right {
+ z-index: 1;
+ opacity: 1;
+}
+
+.carousel-fade .active.carousel-item-left,
+.carousel-fade .active.carousel-item-right {
+ z-index: 0;
+ opacity: 0;
+ transition: opacity 0s 0.6s;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .carousel-fade .active.carousel-item-left,
+ .carousel-fade .active.carousel-item-right {
+ transition: none;
+ }
+}
+
+.carousel-control-prev,
+.carousel-control-next {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-align: center;
+ align-items: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ width: 15%;
+ color: #fff;
+ text-align: center;
+ opacity: 0.5;
+ transition: opacity 0.15s ease;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .carousel-control-prev,
+ .carousel-control-next {
+ transition: none;
+ }
+}
+
+.carousel-control-prev:hover, .carousel-control-prev:focus,
+.carousel-control-next:hover,
+.carousel-control-next:focus {
+ color: #fff;
+ text-decoration: none;
+ outline: 0;
+ opacity: 0.9;
+}
+
+.carousel-control-prev {
+ left: 0;
+}
+
+.carousel-control-next {
+ right: 0;
+}
+
+.carousel-control-prev-icon,
+.carousel-control-next-icon {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ background: no-repeat 50% / 100% 100%;
+}
+
+.carousel-control-prev-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e");
+}
+
+.carousel-control-next-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e");
+}
+
+.carousel-indicators {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 15;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: center;
+ justify-content: center;
+ padding-left: 0;
+ margin-right: 15%;
+ margin-left: 15%;
+ list-style: none;
+}
+
+.carousel-indicators li {
+ box-sizing: content-box;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto;
+ width: 30px;
+ height: 3px;
+ margin-right: 3px;
+ margin-left: 3px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #fff;
+ background-clip: padding-box;
+ border-top: 10px solid transparent;
+ border-bottom: 10px solid transparent;
+ opacity: .5;
+ transition: opacity 0.6s ease;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .carousel-indicators li {
+ transition: none;
+ }
+}
+
+.carousel-indicators .active {
+ opacity: 1;
+}
+
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 20px;
+ left: 15%;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: #fff;
+ text-align: center;
+}
+
+@-webkit-keyframes spinner-border {
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes spinner-border {
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+.spinner-border {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ vertical-align: text-bottom;
+ border: 0.25em solid currentColor;
+ border-right-color: transparent;
+ border-radius: 50%;
+ -webkit-animation: spinner-border .75s linear infinite;
+ animation: spinner-border .75s linear infinite;
+}
+
+.spinner-border-sm {
+ width: 1rem;
+ height: 1rem;
+ border-width: 0.2em;
+}
+
+@-webkit-keyframes spinner-grow {
+ 0% {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes spinner-grow {
+ 0% {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+.spinner-grow {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ vertical-align: text-bottom;
+ background-color: currentColor;
+ border-radius: 50%;
+ opacity: 0;
+ -webkit-animation: spinner-grow .75s linear infinite;
+ animation: spinner-grow .75s linear infinite;
+}
+
+.spinner-grow-sm {
+ width: 1rem;
+ height: 1rem;
+}
+
+.align-baseline {
+ vertical-align: baseline !important;
+}
+
+.align-top {
+ vertical-align: top !important;
+}
+
+.align-middle {
+ vertical-align: middle !important;
+}
+
+.align-bottom {
+ vertical-align: bottom !important;
+}
+
+.align-text-bottom {
+ vertical-align: text-bottom !important;
+}
+
+.align-text-top {
+ vertical-align: text-top !important;
+}
+
+.bg-primary {
+ background-color: #007bff !important;
+}
+
+a.bg-primary:hover, a.bg-primary:focus,
+button.bg-primary:hover,
+button.bg-primary:focus {
+ background-color: #0062cc !important;
+}
+
+.bg-secondary {
+ background-color: #6c757d !important;
+}
+
+a.bg-secondary:hover, a.bg-secondary:focus,
+button.bg-secondary:hover,
+button.bg-secondary:focus {
+ background-color: #545b62 !important;
+}
+
+.bg-success {
+ background-color: #28a745 !important;
+}
+
+a.bg-success:hover, a.bg-success:focus,
+button.bg-success:hover,
+button.bg-success:focus {
+ background-color: #1e7e34 !important;
+}
+
+.bg-info {
+ background-color: #17a2b8 !important;
+}
+
+a.bg-info:hover, a.bg-info:focus,
+button.bg-info:hover,
+button.bg-info:focus {
+ background-color: #117a8b !important;
+}
+
+.bg-warning {
+ background-color: #ffc107 !important;
+}
+
+a.bg-warning:hover, a.bg-warning:focus,
+button.bg-warning:hover,
+button.bg-warning:focus {
+ background-color: #d39e00 !important;
+}
+
+.bg-danger {
+ background-color: #dc3545 !important;
+}
+
+a.bg-danger:hover, a.bg-danger:focus,
+button.bg-danger:hover,
+button.bg-danger:focus {
+ background-color: #bd2130 !important;
+}
+
+.bg-light {
+ background-color: #f8f9fa !important;
+}
+
+a.bg-light:hover, a.bg-light:focus,
+button.bg-light:hover,
+button.bg-light:focus {
+ background-color: #dae0e5 !important;
+}
+
+.bg-dark {
+ background-color: #343a40 !important;
+}
+
+a.bg-dark:hover, a.bg-dark:focus,
+button.bg-dark:hover,
+button.bg-dark:focus {
+ background-color: #1d2124 !important;
+}
+
+.bg-white {
+ background-color: #fff !important;
+}
+
+.bg-transparent {
+ background-color: transparent !important;
+}
+
+.border {
+ border: 1px solid #dee2e6 !important;
+}
+
+.border-top {
+ border-top: 1px solid #dee2e6 !important;
+}
+
+.border-right {
+ border-right: 1px solid #dee2e6 !important;
+}
+
+.border-bottom {
+ border-bottom: 1px solid #dee2e6 !important;
+}
+
+.border-left {
+ border-left: 1px solid #dee2e6 !important;
+}
+
+.border-0 {
+ border: 0 !important;
+}
+
+.border-top-0 {
+ border-top: 0 !important;
+}
+
+.border-right-0 {
+ border-right: 0 !important;
+}
+
+.border-bottom-0 {
+ border-bottom: 0 !important;
+}
+
+.border-left-0 {
+ border-left: 0 !important;
+}
+
+.border-primary {
+ border-color: #007bff !important;
+}
+
+.border-secondary {
+ border-color: #6c757d !important;
+}
+
+.border-success {
+ border-color: #28a745 !important;
+}
+
+.border-info {
+ border-color: #17a2b8 !important;
+}
+
+.border-warning {
+ border-color: #ffc107 !important;
+}
+
+.border-danger {
+ border-color: #dc3545 !important;
+}
+
+.border-light {
+ border-color: #f8f9fa !important;
+}
+
+.border-dark {
+ border-color: #343a40 !important;
+}
+
+.border-white {
+ border-color: #fff !important;
+}
+
+.rounded-sm {
+ border-radius: 0.2rem !important;
+}
+
+.rounded {
+ border-radius: 0.25rem !important;
+}
+
+.rounded-top {
+ border-top-left-radius: 0.25rem !important;
+ border-top-right-radius: 0.25rem !important;
+}
+
+.rounded-right {
+ border-top-right-radius: 0.25rem !important;
+ border-bottom-right-radius: 0.25rem !important;
+}
+
+.rounded-bottom {
+ border-bottom-right-radius: 0.25rem !important;
+ border-bottom-left-radius: 0.25rem !important;
+}
+
+.rounded-left {
+ border-top-left-radius: 0.25rem !important;
+ border-bottom-left-radius: 0.25rem !important;
+}
+
+.rounded-lg {
+ border-radius: 0.3rem !important;
+}
+
+.rounded-circle {
+ border-radius: 50% !important;
+}
+
+.rounded-pill {
+ border-radius: 50rem !important;
+}
+
+.rounded-0 {
+ border-radius: 0 !important;
+}
+
+.clearfix::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.d-none {
+ display: none !important;
+}
+
+.d-inline {
+ display: inline !important;
+}
+
+.d-inline-block {
+ display: inline-block !important;
+}
+
+.d-block {
+ display: block !important;
+}
+
+.d-table {
+ display: table !important;
+}
+
+.d-table-row {
+ display: table-row !important;
+}
+
+.d-table-cell {
+ display: table-cell !important;
+}
+
+.d-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+}
+
+.d-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+}
+
+@media (min-width: 576px) {
+ .d-sm-none {
+ display: none !important;
+ }
+ .d-sm-inline {
+ display: inline !important;
+ }
+ .d-sm-inline-block {
+ display: inline-block !important;
+ }
+ .d-sm-block {
+ display: block !important;
+ }
+ .d-sm-table {
+ display: table !important;
+ }
+ .d-sm-table-row {
+ display: table-row !important;
+ }
+ .d-sm-table-cell {
+ display: table-cell !important;
+ }
+ .d-sm-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ }
+ .d-sm-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .d-md-none {
+ display: none !important;
+ }
+ .d-md-inline {
+ display: inline !important;
+ }
+ .d-md-inline-block {
+ display: inline-block !important;
+ }
+ .d-md-block {
+ display: block !important;
+ }
+ .d-md-table {
+ display: table !important;
+ }
+ .d-md-table-row {
+ display: table-row !important;
+ }
+ .d-md-table-cell {
+ display: table-cell !important;
+ }
+ .d-md-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ }
+ .d-md-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+ }
+}
+
+@media (min-width: 992px) {
+ .d-lg-none {
+ display: none !important;
+ }
+ .d-lg-inline {
+ display: inline !important;
+ }
+ .d-lg-inline-block {
+ display: inline-block !important;
+ }
+ .d-lg-block {
+ display: block !important;
+ }
+ .d-lg-table {
+ display: table !important;
+ }
+ .d-lg-table-row {
+ display: table-row !important;
+ }
+ .d-lg-table-cell {
+ display: table-cell !important;
+ }
+ .d-lg-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ }
+ .d-lg-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .d-xl-none {
+ display: none !important;
+ }
+ .d-xl-inline {
+ display: inline !important;
+ }
+ .d-xl-inline-block {
+ display: inline-block !important;
+ }
+ .d-xl-block {
+ display: block !important;
+ }
+ .d-xl-table {
+ display: table !important;
+ }
+ .d-xl-table-row {
+ display: table-row !important;
+ }
+ .d-xl-table-cell {
+ display: table-cell !important;
+ }
+ .d-xl-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ }
+ .d-xl-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+ }
+}
+
+@media print {
+ .d-print-none {
+ display: none !important;
+ }
+ .d-print-inline {
+ display: inline !important;
+ }
+ .d-print-inline-block {
+ display: inline-block !important;
+ }
+ .d-print-block {
+ display: block !important;
+ }
+ .d-print-table {
+ display: table !important;
+ }
+ .d-print-table-row {
+ display: table-row !important;
+ }
+ .d-print-table-cell {
+ display: table-cell !important;
+ }
+ .d-print-flex {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ }
+ .d-print-inline-flex {
+ display: -ms-inline-flexbox !important;
+ display: inline-flex !important;
+ }
+}
+
+.embed-responsive {
+ position: relative;
+ display: block;
+ width: 100%;
+ padding: 0;
+ overflow: hidden;
+}
+
+.embed-responsive::before {
+ display: block;
+ content: "";
+}
+
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 0;
+}
+
+.embed-responsive-21by9::before {
+ padding-top: 42.857143%;
+}
+
+.embed-responsive-16by9::before {
+ padding-top: 56.25%;
+}
+
+.embed-responsive-4by3::before {
+ padding-top: 75%;
+}
+
+.embed-responsive-1by1::before {
+ padding-top: 100%;
+}
+
+.flex-row {
+ -ms-flex-direction: row !important;
+ flex-direction: row !important;
+}
+
+.flex-column {
+ -ms-flex-direction: column !important;
+ flex-direction: column !important;
+}
+
+.flex-row-reverse {
+ -ms-flex-direction: row-reverse !important;
+ flex-direction: row-reverse !important;
+}
+
+.flex-column-reverse {
+ -ms-flex-direction: column-reverse !important;
+ flex-direction: column-reverse !important;
+}
+
+.flex-wrap {
+ -ms-flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
+}
+
+.flex-nowrap {
+ -ms-flex-wrap: nowrap !important;
+ flex-wrap: nowrap !important;
+}
+
+.flex-wrap-reverse {
+ -ms-flex-wrap: wrap-reverse !important;
+ flex-wrap: wrap-reverse !important;
+}
+
+.flex-fill {
+ -ms-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+}
+
+.flex-grow-0 {
+ -ms-flex-positive: 0 !important;
+ flex-grow: 0 !important;
+}
+
+.flex-grow-1 {
+ -ms-flex-positive: 1 !important;
+ flex-grow: 1 !important;
+}
+
+.flex-shrink-0 {
+ -ms-flex-negative: 0 !important;
+ flex-shrink: 0 !important;
+}
+
+.flex-shrink-1 {
+ -ms-flex-negative: 1 !important;
+ flex-shrink: 1 !important;
+}
+
+.justify-content-start {
+ -ms-flex-pack: start !important;
+ justify-content: flex-start !important;
+}
+
+.justify-content-end {
+ -ms-flex-pack: end !important;
+ justify-content: flex-end !important;
+}
+
+.justify-content-center {
+ -ms-flex-pack: center !important;
+ justify-content: center !important;
+}
+
+.justify-content-between {
+ -ms-flex-pack: justify !important;
+ justify-content: space-between !important;
+}
+
+.justify-content-around {
+ -ms-flex-pack: distribute !important;
+ justify-content: space-around !important;
+}
+
+.align-items-start {
+ -ms-flex-align: start !important;
+ align-items: flex-start !important;
+}
+
+.align-items-end {
+ -ms-flex-align: end !important;
+ align-items: flex-end !important;
+}
+
+.align-items-center {
+ -ms-flex-align: center !important;
+ align-items: center !important;
+}
+
+.align-items-baseline {
+ -ms-flex-align: baseline !important;
+ align-items: baseline !important;
+}
+
+.align-items-stretch {
+ -ms-flex-align: stretch !important;
+ align-items: stretch !important;
+}
+
+.align-content-start {
+ -ms-flex-line-pack: start !important;
+ align-content: flex-start !important;
+}
+
+.align-content-end {
+ -ms-flex-line-pack: end !important;
+ align-content: flex-end !important;
+}
+
+.align-content-center {
+ -ms-flex-line-pack: center !important;
+ align-content: center !important;
+}
+
+.align-content-between {
+ -ms-flex-line-pack: justify !important;
+ align-content: space-between !important;
+}
+
+.align-content-around {
+ -ms-flex-line-pack: distribute !important;
+ align-content: space-around !important;
+}
+
+.align-content-stretch {
+ -ms-flex-line-pack: stretch !important;
+ align-content: stretch !important;
+}
+
+.align-self-auto {
+ -ms-flex-item-align: auto !important;
+ align-self: auto !important;
+}
+
+.align-self-start {
+ -ms-flex-item-align: start !important;
+ align-self: flex-start !important;
+}
+
+.align-self-end {
+ -ms-flex-item-align: end !important;
+ align-self: flex-end !important;
+}
+
+.align-self-center {
+ -ms-flex-item-align: center !important;
+ align-self: center !important;
+}
+
+.align-self-baseline {
+ -ms-flex-item-align: baseline !important;
+ align-self: baseline !important;
+}
+
+.align-self-stretch {
+ -ms-flex-item-align: stretch !important;
+ align-self: stretch !important;
+}
+
+@media (min-width: 576px) {
+ .flex-sm-row {
+ -ms-flex-direction: row !important;
+ flex-direction: row !important;
+ }
+ .flex-sm-column {
+ -ms-flex-direction: column !important;
+ flex-direction: column !important;
+ }
+ .flex-sm-row-reverse {
+ -ms-flex-direction: row-reverse !important;
+ flex-direction: row-reverse !important;
+ }
+ .flex-sm-column-reverse {
+ -ms-flex-direction: column-reverse !important;
+ flex-direction: column-reverse !important;
+ }
+ .flex-sm-wrap {
+ -ms-flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
+ }
+ .flex-sm-nowrap {
+ -ms-flex-wrap: nowrap !important;
+ flex-wrap: nowrap !important;
+ }
+ .flex-sm-wrap-reverse {
+ -ms-flex-wrap: wrap-reverse !important;
+ flex-wrap: wrap-reverse !important;
+ }
+ .flex-sm-fill {
+ -ms-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+ }
+ .flex-sm-grow-0 {
+ -ms-flex-positive: 0 !important;
+ flex-grow: 0 !important;
+ }
+ .flex-sm-grow-1 {
+ -ms-flex-positive: 1 !important;
+ flex-grow: 1 !important;
+ }
+ .flex-sm-shrink-0 {
+ -ms-flex-negative: 0 !important;
+ flex-shrink: 0 !important;
+ }
+ .flex-sm-shrink-1 {
+ -ms-flex-negative: 1 !important;
+ flex-shrink: 1 !important;
+ }
+ .justify-content-sm-start {
+ -ms-flex-pack: start !important;
+ justify-content: flex-start !important;
+ }
+ .justify-content-sm-end {
+ -ms-flex-pack: end !important;
+ justify-content: flex-end !important;
+ }
+ .justify-content-sm-center {
+ -ms-flex-pack: center !important;
+ justify-content: center !important;
+ }
+ .justify-content-sm-between {
+ -ms-flex-pack: justify !important;
+ justify-content: space-between !important;
+ }
+ .justify-content-sm-around {
+ -ms-flex-pack: distribute !important;
+ justify-content: space-around !important;
+ }
+ .align-items-sm-start {
+ -ms-flex-align: start !important;
+ align-items: flex-start !important;
+ }
+ .align-items-sm-end {
+ -ms-flex-align: end !important;
+ align-items: flex-end !important;
+ }
+ .align-items-sm-center {
+ -ms-flex-align: center !important;
+ align-items: center !important;
+ }
+ .align-items-sm-baseline {
+ -ms-flex-align: baseline !important;
+ align-items: baseline !important;
+ }
+ .align-items-sm-stretch {
+ -ms-flex-align: stretch !important;
+ align-items: stretch !important;
+ }
+ .align-content-sm-start {
+ -ms-flex-line-pack: start !important;
+ align-content: flex-start !important;
+ }
+ .align-content-sm-end {
+ -ms-flex-line-pack: end !important;
+ align-content: flex-end !important;
+ }
+ .align-content-sm-center {
+ -ms-flex-line-pack: center !important;
+ align-content: center !important;
+ }
+ .align-content-sm-between {
+ -ms-flex-line-pack: justify !important;
+ align-content: space-between !important;
+ }
+ .align-content-sm-around {
+ -ms-flex-line-pack: distribute !important;
+ align-content: space-around !important;
+ }
+ .align-content-sm-stretch {
+ -ms-flex-line-pack: stretch !important;
+ align-content: stretch !important;
+ }
+ .align-self-sm-auto {
+ -ms-flex-item-align: auto !important;
+ align-self: auto !important;
+ }
+ .align-self-sm-start {
+ -ms-flex-item-align: start !important;
+ align-self: flex-start !important;
+ }
+ .align-self-sm-end {
+ -ms-flex-item-align: end !important;
+ align-self: flex-end !important;
+ }
+ .align-self-sm-center {
+ -ms-flex-item-align: center !important;
+ align-self: center !important;
+ }
+ .align-self-sm-baseline {
+ -ms-flex-item-align: baseline !important;
+ align-self: baseline !important;
+ }
+ .align-self-sm-stretch {
+ -ms-flex-item-align: stretch !important;
+ align-self: stretch !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .flex-md-row {
+ -ms-flex-direction: row !important;
+ flex-direction: row !important;
+ }
+ .flex-md-column {
+ -ms-flex-direction: column !important;
+ flex-direction: column !important;
+ }
+ .flex-md-row-reverse {
+ -ms-flex-direction: row-reverse !important;
+ flex-direction: row-reverse !important;
+ }
+ .flex-md-column-reverse {
+ -ms-flex-direction: column-reverse !important;
+ flex-direction: column-reverse !important;
+ }
+ .flex-md-wrap {
+ -ms-flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
+ }
+ .flex-md-nowrap {
+ -ms-flex-wrap: nowrap !important;
+ flex-wrap: nowrap !important;
+ }
+ .flex-md-wrap-reverse {
+ -ms-flex-wrap: wrap-reverse !important;
+ flex-wrap: wrap-reverse !important;
+ }
+ .flex-md-fill {
+ -ms-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+ }
+ .flex-md-grow-0 {
+ -ms-flex-positive: 0 !important;
+ flex-grow: 0 !important;
+ }
+ .flex-md-grow-1 {
+ -ms-flex-positive: 1 !important;
+ flex-grow: 1 !important;
+ }
+ .flex-md-shrink-0 {
+ -ms-flex-negative: 0 !important;
+ flex-shrink: 0 !important;
+ }
+ .flex-md-shrink-1 {
+ -ms-flex-negative: 1 !important;
+ flex-shrink: 1 !important;
+ }
+ .justify-content-md-start {
+ -ms-flex-pack: start !important;
+ justify-content: flex-start !important;
+ }
+ .justify-content-md-end {
+ -ms-flex-pack: end !important;
+ justify-content: flex-end !important;
+ }
+ .justify-content-md-center {
+ -ms-flex-pack: center !important;
+ justify-content: center !important;
+ }
+ .justify-content-md-between {
+ -ms-flex-pack: justify !important;
+ justify-content: space-between !important;
+ }
+ .justify-content-md-around {
+ -ms-flex-pack: distribute !important;
+ justify-content: space-around !important;
+ }
+ .align-items-md-start {
+ -ms-flex-align: start !important;
+ align-items: flex-start !important;
+ }
+ .align-items-md-end {
+ -ms-flex-align: end !important;
+ align-items: flex-end !important;
+ }
+ .align-items-md-center {
+ -ms-flex-align: center !important;
+ align-items: center !important;
+ }
+ .align-items-md-baseline {
+ -ms-flex-align: baseline !important;
+ align-items: baseline !important;
+ }
+ .align-items-md-stretch {
+ -ms-flex-align: stretch !important;
+ align-items: stretch !important;
+ }
+ .align-content-md-start {
+ -ms-flex-line-pack: start !important;
+ align-content: flex-start !important;
+ }
+ .align-content-md-end {
+ -ms-flex-line-pack: end !important;
+ align-content: flex-end !important;
+ }
+ .align-content-md-center {
+ -ms-flex-line-pack: center !important;
+ align-content: center !important;
+ }
+ .align-content-md-between {
+ -ms-flex-line-pack: justify !important;
+ align-content: space-between !important;
+ }
+ .align-content-md-around {
+ -ms-flex-line-pack: distribute !important;
+ align-content: space-around !important;
+ }
+ .align-content-md-stretch {
+ -ms-flex-line-pack: stretch !important;
+ align-content: stretch !important;
+ }
+ .align-self-md-auto {
+ -ms-flex-item-align: auto !important;
+ align-self: auto !important;
+ }
+ .align-self-md-start {
+ -ms-flex-item-align: start !important;
+ align-self: flex-start !important;
+ }
+ .align-self-md-end {
+ -ms-flex-item-align: end !important;
+ align-self: flex-end !important;
+ }
+ .align-self-md-center {
+ -ms-flex-item-align: center !important;
+ align-self: center !important;
+ }
+ .align-self-md-baseline {
+ -ms-flex-item-align: baseline !important;
+ align-self: baseline !important;
+ }
+ .align-self-md-stretch {
+ -ms-flex-item-align: stretch !important;
+ align-self: stretch !important;
+ }
+}
+
+@media (min-width: 992px) {
+ .flex-lg-row {
+ -ms-flex-direction: row !important;
+ flex-direction: row !important;
+ }
+ .flex-lg-column {
+ -ms-flex-direction: column !important;
+ flex-direction: column !important;
+ }
+ .flex-lg-row-reverse {
+ -ms-flex-direction: row-reverse !important;
+ flex-direction: row-reverse !important;
+ }
+ .flex-lg-column-reverse {
+ -ms-flex-direction: column-reverse !important;
+ flex-direction: column-reverse !important;
+ }
+ .flex-lg-wrap {
+ -ms-flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
+ }
+ .flex-lg-nowrap {
+ -ms-flex-wrap: nowrap !important;
+ flex-wrap: nowrap !important;
+ }
+ .flex-lg-wrap-reverse {
+ -ms-flex-wrap: wrap-reverse !important;
+ flex-wrap: wrap-reverse !important;
+ }
+ .flex-lg-fill {
+ -ms-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+ }
+ .flex-lg-grow-0 {
+ -ms-flex-positive: 0 !important;
+ flex-grow: 0 !important;
+ }
+ .flex-lg-grow-1 {
+ -ms-flex-positive: 1 !important;
+ flex-grow: 1 !important;
+ }
+ .flex-lg-shrink-0 {
+ -ms-flex-negative: 0 !important;
+ flex-shrink: 0 !important;
+ }
+ .flex-lg-shrink-1 {
+ -ms-flex-negative: 1 !important;
+ flex-shrink: 1 !important;
+ }
+ .justify-content-lg-start {
+ -ms-flex-pack: start !important;
+ justify-content: flex-start !important;
+ }
+ .justify-content-lg-end {
+ -ms-flex-pack: end !important;
+ justify-content: flex-end !important;
+ }
+ .justify-content-lg-center {
+ -ms-flex-pack: center !important;
+ justify-content: center !important;
+ }
+ .justify-content-lg-between {
+ -ms-flex-pack: justify !important;
+ justify-content: space-between !important;
+ }
+ .justify-content-lg-around {
+ -ms-flex-pack: distribute !important;
+ justify-content: space-around !important;
+ }
+ .align-items-lg-start {
+ -ms-flex-align: start !important;
+ align-items: flex-start !important;
+ }
+ .align-items-lg-end {
+ -ms-flex-align: end !important;
+ align-items: flex-end !important;
+ }
+ .align-items-lg-center {
+ -ms-flex-align: center !important;
+ align-items: center !important;
+ }
+ .align-items-lg-baseline {
+ -ms-flex-align: baseline !important;
+ align-items: baseline !important;
+ }
+ .align-items-lg-stretch {
+ -ms-flex-align: stretch !important;
+ align-items: stretch !important;
+ }
+ .align-content-lg-start {
+ -ms-flex-line-pack: start !important;
+ align-content: flex-start !important;
+ }
+ .align-content-lg-end {
+ -ms-flex-line-pack: end !important;
+ align-content: flex-end !important;
+ }
+ .align-content-lg-center {
+ -ms-flex-line-pack: center !important;
+ align-content: center !important;
+ }
+ .align-content-lg-between {
+ -ms-flex-line-pack: justify !important;
+ align-content: space-between !important;
+ }
+ .align-content-lg-around {
+ -ms-flex-line-pack: distribute !important;
+ align-content: space-around !important;
+ }
+ .align-content-lg-stretch {
+ -ms-flex-line-pack: stretch !important;
+ align-content: stretch !important;
+ }
+ .align-self-lg-auto {
+ -ms-flex-item-align: auto !important;
+ align-self: auto !important;
+ }
+ .align-self-lg-start {
+ -ms-flex-item-align: start !important;
+ align-self: flex-start !important;
+ }
+ .align-self-lg-end {
+ -ms-flex-item-align: end !important;
+ align-self: flex-end !important;
+ }
+ .align-self-lg-center {
+ -ms-flex-item-align: center !important;
+ align-self: center !important;
+ }
+ .align-self-lg-baseline {
+ -ms-flex-item-align: baseline !important;
+ align-self: baseline !important;
+ }
+ .align-self-lg-stretch {
+ -ms-flex-item-align: stretch !important;
+ align-self: stretch !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .flex-xl-row {
+ -ms-flex-direction: row !important;
+ flex-direction: row !important;
+ }
+ .flex-xl-column {
+ -ms-flex-direction: column !important;
+ flex-direction: column !important;
+ }
+ .flex-xl-row-reverse {
+ -ms-flex-direction: row-reverse !important;
+ flex-direction: row-reverse !important;
+ }
+ .flex-xl-column-reverse {
+ -ms-flex-direction: column-reverse !important;
+ flex-direction: column-reverse !important;
+ }
+ .flex-xl-wrap {
+ -ms-flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
+ }
+ .flex-xl-nowrap {
+ -ms-flex-wrap: nowrap !important;
+ flex-wrap: nowrap !important;
+ }
+ .flex-xl-wrap-reverse {
+ -ms-flex-wrap: wrap-reverse !important;
+ flex-wrap: wrap-reverse !important;
+ }
+ .flex-xl-fill {
+ -ms-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+ }
+ .flex-xl-grow-0 {
+ -ms-flex-positive: 0 !important;
+ flex-grow: 0 !important;
+ }
+ .flex-xl-grow-1 {
+ -ms-flex-positive: 1 !important;
+ flex-grow: 1 !important;
+ }
+ .flex-xl-shrink-0 {
+ -ms-flex-negative: 0 !important;
+ flex-shrink: 0 !important;
+ }
+ .flex-xl-shrink-1 {
+ -ms-flex-negative: 1 !important;
+ flex-shrink: 1 !important;
+ }
+ .justify-content-xl-start {
+ -ms-flex-pack: start !important;
+ justify-content: flex-start !important;
+ }
+ .justify-content-xl-end {
+ -ms-flex-pack: end !important;
+ justify-content: flex-end !important;
+ }
+ .justify-content-xl-center {
+ -ms-flex-pack: center !important;
+ justify-content: center !important;
+ }
+ .justify-content-xl-between {
+ -ms-flex-pack: justify !important;
+ justify-content: space-between !important;
+ }
+ .justify-content-xl-around {
+ -ms-flex-pack: distribute !important;
+ justify-content: space-around !important;
+ }
+ .align-items-xl-start {
+ -ms-flex-align: start !important;
+ align-items: flex-start !important;
+ }
+ .align-items-xl-end {
+ -ms-flex-align: end !important;
+ align-items: flex-end !important;
+ }
+ .align-items-xl-center {
+ -ms-flex-align: center !important;
+ align-items: center !important;
+ }
+ .align-items-xl-baseline {
+ -ms-flex-align: baseline !important;
+ align-items: baseline !important;
+ }
+ .align-items-xl-stretch {
+ -ms-flex-align: stretch !important;
+ align-items: stretch !important;
+ }
+ .align-content-xl-start {
+ -ms-flex-line-pack: start !important;
+ align-content: flex-start !important;
+ }
+ .align-content-xl-end {
+ -ms-flex-line-pack: end !important;
+ align-content: flex-end !important;
+ }
+ .align-content-xl-center {
+ -ms-flex-line-pack: center !important;
+ align-content: center !important;
+ }
+ .align-content-xl-between {
+ -ms-flex-line-pack: justify !important;
+ align-content: space-between !important;
+ }
+ .align-content-xl-around {
+ -ms-flex-line-pack: distribute !important;
+ align-content: space-around !important;
+ }
+ .align-content-xl-stretch {
+ -ms-flex-line-pack: stretch !important;
+ align-content: stretch !important;
+ }
+ .align-self-xl-auto {
+ -ms-flex-item-align: auto !important;
+ align-self: auto !important;
+ }
+ .align-self-xl-start {
+ -ms-flex-item-align: start !important;
+ align-self: flex-start !important;
+ }
+ .align-self-xl-end {
+ -ms-flex-item-align: end !important;
+ align-self: flex-end !important;
+ }
+ .align-self-xl-center {
+ -ms-flex-item-align: center !important;
+ align-self: center !important;
+ }
+ .align-self-xl-baseline {
+ -ms-flex-item-align: baseline !important;
+ align-self: baseline !important;
+ }
+ .align-self-xl-stretch {
+ -ms-flex-item-align: stretch !important;
+ align-self: stretch !important;
+ }
+}
+
+.float-left {
+ float: left !important;
+}
+
+.float-right {
+ float: right !important;
+}
+
+.float-none {
+ float: none !important;
+}
+
+@media (min-width: 576px) {
+ .float-sm-left {
+ float: left !important;
+ }
+ .float-sm-right {
+ float: right !important;
+ }
+ .float-sm-none {
+ float: none !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .float-md-left {
+ float: left !important;
+ }
+ .float-md-right {
+ float: right !important;
+ }
+ .float-md-none {
+ float: none !important;
+ }
+}
+
+@media (min-width: 992px) {
+ .float-lg-left {
+ float: left !important;
+ }
+ .float-lg-right {
+ float: right !important;
+ }
+ .float-lg-none {
+ float: none !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .float-xl-left {
+ float: left !important;
+ }
+ .float-xl-right {
+ float: right !important;
+ }
+ .float-xl-none {
+ float: none !important;
+ }
+}
+
+.overflow-auto {
+ overflow: auto !important;
+}
+
+.overflow-hidden {
+ overflow: hidden !important;
+}
+
+.position-static {
+ position: static !important;
+}
+
+.position-relative {
+ position: relative !important;
+}
+
+.position-absolute {
+ position: absolute !important;
+}
+
+.position-fixed {
+ position: fixed !important;
+}
+
+.position-sticky {
+ position: -webkit-sticky !important;
+ position: sticky !important;
+}
+
+.fixed-top {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+
+.fixed-bottom {
+ position: fixed;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1030;
+}
+
+@supports ((position: -webkit-sticky) or (position: sticky)) {
+ .sticky-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+.sr-only-focusable:active, .sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ overflow: visible;
+ clip: auto;
+ white-space: normal;
+}
+
+.shadow-sm {
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;
+}
+
+.shadow {
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
+}
+
+.shadow-lg {
+ box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;
+}
+
+.shadow-none {
+ box-shadow: none !important;
+}
+
+.w-25 {
+ width: 25% !important;
+}
+
+.w-50 {
+ width: 50% !important;
+}
+
+.w-75 {
+ width: 75% !important;
+}
+
+.w-100 {
+ width: 100% !important;
+}
+
+.w-auto {
+ width: auto !important;
+}
+
+.h-25 {
+ height: 25% !important;
+}
+
+.h-50 {
+ height: 50% !important;
+}
+
+.h-75 {
+ height: 75% !important;
+}
+
+.h-100 {
+ height: 100% !important;
+}
+
+.h-auto {
+ height: auto !important;
+}
+
+.mw-100 {
+ max-width: 100% !important;
+}
+
+.mh-100 {
+ max-height: 100% !important;
+}
+
+.min-vw-100 {
+ min-width: 100vw !important;
+}
+
+.min-vh-100 {
+ min-height: 100vh !important;
+}
+
+.vw-100 {
+ width: 100vw !important;
+}
+
+.vh-100 {
+ height: 100vh !important;
+}
+
+.stretched-link::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1;
+ pointer-events: auto;
+ content: "";
+ background-color: rgba(0, 0, 0, 0);
+}
+
+.m-0 {
+ margin: 0 !important;
+}
+
+.mt-0,
+.my-0 {
+ margin-top: 0 !important;
+}
+
+.mr-0,
+.mx-0 {
+ margin-right: 0 !important;
+}
+
+.mb-0,
+.my-0 {
+ margin-bottom: 0 !important;
+}
+
+.ml-0,
+.mx-0 {
+ margin-left: 0 !important;
+}
+
+.m-1 {
+ margin: 0.25rem !important;
+}
+
+.mt-1,
+.my-1 {
+ margin-top: 0.25rem !important;
+}
+
+.mr-1,
+.mx-1 {
+ margin-right: 0.25rem !important;
+}
+
+.mb-1,
+.my-1 {
+ margin-bottom: 0.25rem !important;
+}
+
+.ml-1,
+.mx-1 {
+ margin-left: 0.25rem !important;
+}
+
+.m-2 {
+ margin: 0.5rem !important;
+}
+
+.mt-2,
+.my-2 {
+ margin-top: 0.5rem !important;
+}
+
+.mr-2,
+.mx-2 {
+ margin-right: 0.5rem !important;
+}
+
+.mb-2,
+.my-2 {
+ margin-bottom: 0.5rem !important;
+}
+
+.ml-2,
+.mx-2 {
+ margin-left: 0.5rem !important;
+}
+
+.m-3 {
+ margin: 1rem !important;
+}
+
+.mt-3,
+.my-3 {
+ margin-top: 1rem !important;
+}
+
+.mr-3,
+.mx-3 {
+ margin-right: 1rem !important;
+}
+
+.mb-3,
+.my-3 {
+ margin-bottom: 1rem !important;
+}
+
+.ml-3,
+.mx-3 {
+ margin-left: 1rem !important;
+}
+
+.m-4 {
+ margin: 1.5rem !important;
+}
+
+.mt-4,
+.my-4 {
+ margin-top: 1.5rem !important;
+}
+
+.mr-4,
+.mx-4 {
+ margin-right: 1.5rem !important;
+}
+
+.mb-4,
+.my-4 {
+ margin-bottom: 1.5rem !important;
+}
+
+.ml-4,
+.mx-4 {
+ margin-left: 1.5rem !important;
+}
+
+.m-5 {
+ margin: 3rem !important;
+}
+
+.mt-5,
+.my-5 {
+ margin-top: 3rem !important;
+}
+
+.mr-5,
+.mx-5 {
+ margin-right: 3rem !important;
+}
+
+.mb-5,
+.my-5 {
+ margin-bottom: 3rem !important;
+}
+
+.ml-5,
+.mx-5 {
+ margin-left: 3rem !important;
+}
+
+.p-0 {
+ padding: 0 !important;
+}
+
+.pt-0,
+.py-0 {
+ padding-top: 0 !important;
+}
+
+.pr-0,
+.px-0 {
+ padding-right: 0 !important;
+}
+
+.pb-0,
+.py-0 {
+ padding-bottom: 0 !important;
+}
+
+.pl-0,
+.px-0 {
+ padding-left: 0 !important;
+}
+
+.p-1 {
+ padding: 0.25rem !important;
+}
+
+.pt-1,
+.py-1 {
+ padding-top: 0.25rem !important;
+}
+
+.pr-1,
+.px-1 {
+ padding-right: 0.25rem !important;
+}
+
+.pb-1,
+.py-1 {
+ padding-bottom: 0.25rem !important;
+}
+
+.pl-1,
+.px-1 {
+ padding-left: 0.25rem !important;
+}
+
+.p-2 {
+ padding: 0.5rem !important;
+}
+
+.pt-2,
+.py-2 {
+ padding-top: 0.5rem !important;
+}
+
+.pr-2,
+.px-2 {
+ padding-right: 0.5rem !important;
+}
+
+.pb-2,
+.py-2 {
+ padding-bottom: 0.5rem !important;
+}
+
+.pl-2,
+.px-2 {
+ padding-left: 0.5rem !important;
+}
+
+.p-3 {
+ padding: 1rem !important;
+}
+
+.pt-3,
+.py-3 {
+ padding-top: 1rem !important;
+}
+
+.pr-3,
+.px-3 {
+ padding-right: 1rem !important;
+}
+
+.pb-3,
+.py-3 {
+ padding-bottom: 1rem !important;
+}
+
+.pl-3,
+.px-3 {
+ padding-left: 1rem !important;
+}
+
+.p-4 {
+ padding: 1.5rem !important;
+}
+
+.pt-4,
+.py-4 {
+ padding-top: 1.5rem !important;
+}
+
+.pr-4,
+.px-4 {
+ padding-right: 1.5rem !important;
+}
+
+.pb-4,
+.py-4 {
+ padding-bottom: 1.5rem !important;
+}
+
+.pl-4,
+.px-4 {
+ padding-left: 1.5rem !important;
+}
+
+.p-5 {
+ padding: 3rem !important;
+}
+
+.pt-5,
+.py-5 {
+ padding-top: 3rem !important;
+}
+
+.pr-5,
+.px-5 {
+ padding-right: 3rem !important;
+}
+
+.pb-5,
+.py-5 {
+ padding-bottom: 3rem !important;
+}
+
+.pl-5,
+.px-5 {
+ padding-left: 3rem !important;
+}
+
+.m-n1 {
+ margin: -0.25rem !important;
+}
+
+.mt-n1,
+.my-n1 {
+ margin-top: -0.25rem !important;
+}
+
+.mr-n1,
+.mx-n1 {
+ margin-right: -0.25rem !important;
+}
+
+.mb-n1,
+.my-n1 {
+ margin-bottom: -0.25rem !important;
+}
+
+.ml-n1,
+.mx-n1 {
+ margin-left: -0.25rem !important;
+}
+
+.m-n2 {
+ margin: -0.5rem !important;
+}
+
+.mt-n2,
+.my-n2 {
+ margin-top: -0.5rem !important;
+}
+
+.mr-n2,
+.mx-n2 {
+ margin-right: -0.5rem !important;
+}
+
+.mb-n2,
+.my-n2 {
+ margin-bottom: -0.5rem !important;
+}
+
+.ml-n2,
+.mx-n2 {
+ margin-left: -0.5rem !important;
+}
+
+.m-n3 {
+ margin: -1rem !important;
+}
+
+.mt-n3,
+.my-n3 {
+ margin-top: -1rem !important;
+}
+
+.mr-n3,
+.mx-n3 {
+ margin-right: -1rem !important;
+}
+
+.mb-n3,
+.my-n3 {
+ margin-bottom: -1rem !important;
+}
+
+.ml-n3,
+.mx-n3 {
+ margin-left: -1rem !important;
+}
+
+.m-n4 {
+ margin: -1.5rem !important;
+}
+
+.mt-n4,
+.my-n4 {
+ margin-top: -1.5rem !important;
+}
+
+.mr-n4,
+.mx-n4 {
+ margin-right: -1.5rem !important;
+}
+
+.mb-n4,
+.my-n4 {
+ margin-bottom: -1.5rem !important;
+}
+
+.ml-n4,
+.mx-n4 {
+ margin-left: -1.5rem !important;
+}
+
+.m-n5 {
+ margin: -3rem !important;
+}
+
+.mt-n5,
+.my-n5 {
+ margin-top: -3rem !important;
+}
+
+.mr-n5,
+.mx-n5 {
+ margin-right: -3rem !important;
+}
+
+.mb-n5,
+.my-n5 {
+ margin-bottom: -3rem !important;
+}
+
+.ml-n5,
+.mx-n5 {
+ margin-left: -3rem !important;
+}
+
+.m-auto {
+ margin: auto !important;
+}
+
+.mt-auto,
+.my-auto {
+ margin-top: auto !important;
+}
+
+.mr-auto,
+.mx-auto {
+ margin-right: auto !important;
+}
+
+.mb-auto,
+.my-auto {
+ margin-bottom: auto !important;
+}
+
+.ml-auto,
+.mx-auto {
+ margin-left: auto !important;
+}
+
+@media (min-width: 576px) {
+ .m-sm-0 {
+ margin: 0 !important;
+ }
+ .mt-sm-0,
+ .my-sm-0 {
+ margin-top: 0 !important;
+ }
+ .mr-sm-0,
+ .mx-sm-0 {
+ margin-right: 0 !important;
+ }
+ .mb-sm-0,
+ .my-sm-0 {
+ margin-bottom: 0 !important;
+ }
+ .ml-sm-0,
+ .mx-sm-0 {
+ margin-left: 0 !important;
+ }
+ .m-sm-1 {
+ margin: 0.25rem !important;
+ }
+ .mt-sm-1,
+ .my-sm-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mr-sm-1,
+ .mx-sm-1 {
+ margin-right: 0.25rem !important;
+ }
+ .mb-sm-1,
+ .my-sm-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .ml-sm-1,
+ .mx-sm-1 {
+ margin-left: 0.25rem !important;
+ }
+ .m-sm-2 {
+ margin: 0.5rem !important;
+ }
+ .mt-sm-2,
+ .my-sm-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mr-sm-2,
+ .mx-sm-2 {
+ margin-right: 0.5rem !important;
+ }
+ .mb-sm-2,
+ .my-sm-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .ml-sm-2,
+ .mx-sm-2 {
+ margin-left: 0.5rem !important;
+ }
+ .m-sm-3 {
+ margin: 1rem !important;
+ }
+ .mt-sm-3,
+ .my-sm-3 {
+ margin-top: 1rem !important;
+ }
+ .mr-sm-3,
+ .mx-sm-3 {
+ margin-right: 1rem !important;
+ }
+ .mb-sm-3,
+ .my-sm-3 {
+ margin-bottom: 1rem !important;
+ }
+ .ml-sm-3,
+ .mx-sm-3 {
+ margin-left: 1rem !important;
+ }
+ .m-sm-4 {
+ margin: 1.5rem !important;
+ }
+ .mt-sm-4,
+ .my-sm-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mr-sm-4,
+ .mx-sm-4 {
+ margin-right: 1.5rem !important;
+ }
+ .mb-sm-4,
+ .my-sm-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .ml-sm-4,
+ .mx-sm-4 {
+ margin-left: 1.5rem !important;
+ }
+ .m-sm-5 {
+ margin: 3rem !important;
+ }
+ .mt-sm-5,
+ .my-sm-5 {
+ margin-top: 3rem !important;
+ }
+ .mr-sm-5,
+ .mx-sm-5 {
+ margin-right: 3rem !important;
+ }
+ .mb-sm-5,
+ .my-sm-5 {
+ margin-bottom: 3rem !important;
+ }
+ .ml-sm-5,
+ .mx-sm-5 {
+ margin-left: 3rem !important;
+ }
+ .p-sm-0 {
+ padding: 0 !important;
+ }
+ .pt-sm-0,
+ .py-sm-0 {
+ padding-top: 0 !important;
+ }
+ .pr-sm-0,
+ .px-sm-0 {
+ padding-right: 0 !important;
+ }
+ .pb-sm-0,
+ .py-sm-0 {
+ padding-bottom: 0 !important;
+ }
+ .pl-sm-0,
+ .px-sm-0 {
+ padding-left: 0 !important;
+ }
+ .p-sm-1 {
+ padding: 0.25rem !important;
+ }
+ .pt-sm-1,
+ .py-sm-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pr-sm-1,
+ .px-sm-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pb-sm-1,
+ .py-sm-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pl-sm-1,
+ .px-sm-1 {
+ padding-left: 0.25rem !important;
+ }
+ .p-sm-2 {
+ padding: 0.5rem !important;
+ }
+ .pt-sm-2,
+ .py-sm-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pr-sm-2,
+ .px-sm-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pb-sm-2,
+ .py-sm-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pl-sm-2,
+ .px-sm-2 {
+ padding-left: 0.5rem !important;
+ }
+ .p-sm-3 {
+ padding: 1rem !important;
+ }
+ .pt-sm-3,
+ .py-sm-3 {
+ padding-top: 1rem !important;
+ }
+ .pr-sm-3,
+ .px-sm-3 {
+ padding-right: 1rem !important;
+ }
+ .pb-sm-3,
+ .py-sm-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pl-sm-3,
+ .px-sm-3 {
+ padding-left: 1rem !important;
+ }
+ .p-sm-4 {
+ padding: 1.5rem !important;
+ }
+ .pt-sm-4,
+ .py-sm-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pr-sm-4,
+ .px-sm-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pb-sm-4,
+ .py-sm-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pl-sm-4,
+ .px-sm-4 {
+ padding-left: 1.5rem !important;
+ }
+ .p-sm-5 {
+ padding: 3rem !important;
+ }
+ .pt-sm-5,
+ .py-sm-5 {
+ padding-top: 3rem !important;
+ }
+ .pr-sm-5,
+ .px-sm-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-sm-5,
+ .py-sm-5 {
+ padding-bottom: 3rem !important;
+ }
+ .pl-sm-5,
+ .px-sm-5 {
+ padding-left: 3rem !important;
+ }
+ .m-sm-n1 {
+ margin: -0.25rem !important;
+ }
+ .mt-sm-n1,
+ .my-sm-n1 {
+ margin-top: -0.25rem !important;
+ }
+ .mr-sm-n1,
+ .mx-sm-n1 {
+ margin-right: -0.25rem !important;
+ }
+ .mb-sm-n1,
+ .my-sm-n1 {
+ margin-bottom: -0.25rem !important;
+ }
+ .ml-sm-n1,
+ .mx-sm-n1 {
+ margin-left: -0.25rem !important;
+ }
+ .m-sm-n2 {
+ margin: -0.5rem !important;
+ }
+ .mt-sm-n2,
+ .my-sm-n2 {
+ margin-top: -0.5rem !important;
+ }
+ .mr-sm-n2,
+ .mx-sm-n2 {
+ margin-right: -0.5rem !important;
+ }
+ .mb-sm-n2,
+ .my-sm-n2 {
+ margin-bottom: -0.5rem !important;
+ }
+ .ml-sm-n2,
+ .mx-sm-n2 {
+ margin-left: -0.5rem !important;
+ }
+ .m-sm-n3 {
+ margin: -1rem !important;
+ }
+ .mt-sm-n3,
+ .my-sm-n3 {
+ margin-top: -1rem !important;
+ }
+ .mr-sm-n3,
+ .mx-sm-n3 {
+ margin-right: -1rem !important;
+ }
+ .mb-sm-n3,
+ .my-sm-n3 {
+ margin-bottom: -1rem !important;
+ }
+ .ml-sm-n3,
+ .mx-sm-n3 {
+ margin-left: -1rem !important;
+ }
+ .m-sm-n4 {
+ margin: -1.5rem !important;
+ }
+ .mt-sm-n4,
+ .my-sm-n4 {
+ margin-top: -1.5rem !important;
+ }
+ .mr-sm-n4,
+ .mx-sm-n4 {
+ margin-right: -1.5rem !important;
+ }
+ .mb-sm-n4,
+ .my-sm-n4 {
+ margin-bottom: -1.5rem !important;
+ }
+ .ml-sm-n4,
+ .mx-sm-n4 {
+ margin-left: -1.5rem !important;
+ }
+ .m-sm-n5 {
+ margin: -3rem !important;
+ }
+ .mt-sm-n5,
+ .my-sm-n5 {
+ margin-top: -3rem !important;
+ }
+ .mr-sm-n5,
+ .mx-sm-n5 {
+ margin-right: -3rem !important;
+ }
+ .mb-sm-n5,
+ .my-sm-n5 {
+ margin-bottom: -3rem !important;
+ }
+ .ml-sm-n5,
+ .mx-sm-n5 {
+ margin-left: -3rem !important;
+ }
+ .m-sm-auto {
+ margin: auto !important;
+ }
+ .mt-sm-auto,
+ .my-sm-auto {
+ margin-top: auto !important;
+ }
+ .mr-sm-auto,
+ .mx-sm-auto {
+ margin-right: auto !important;
+ }
+ .mb-sm-auto,
+ .my-sm-auto {
+ margin-bottom: auto !important;
+ }
+ .ml-sm-auto,
+ .mx-sm-auto {
+ margin-left: auto !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .m-md-0 {
+ margin: 0 !important;
+ }
+ .mt-md-0,
+ .my-md-0 {
+ margin-top: 0 !important;
+ }
+ .mr-md-0,
+ .mx-md-0 {
+ margin-right: 0 !important;
+ }
+ .mb-md-0,
+ .my-md-0 {
+ margin-bottom: 0 !important;
+ }
+ .ml-md-0,
+ .mx-md-0 {
+ margin-left: 0 !important;
+ }
+ .m-md-1 {
+ margin: 0.25rem !important;
+ }
+ .mt-md-1,
+ .my-md-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mr-md-1,
+ .mx-md-1 {
+ margin-right: 0.25rem !important;
+ }
+ .mb-md-1,
+ .my-md-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .ml-md-1,
+ .mx-md-1 {
+ margin-left: 0.25rem !important;
+ }
+ .m-md-2 {
+ margin: 0.5rem !important;
+ }
+ .mt-md-2,
+ .my-md-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mr-md-2,
+ .mx-md-2 {
+ margin-right: 0.5rem !important;
+ }
+ .mb-md-2,
+ .my-md-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .ml-md-2,
+ .mx-md-2 {
+ margin-left: 0.5rem !important;
+ }
+ .m-md-3 {
+ margin: 1rem !important;
+ }
+ .mt-md-3,
+ .my-md-3 {
+ margin-top: 1rem !important;
+ }
+ .mr-md-3,
+ .mx-md-3 {
+ margin-right: 1rem !important;
+ }
+ .mb-md-3,
+ .my-md-3 {
+ margin-bottom: 1rem !important;
+ }
+ .ml-md-3,
+ .mx-md-3 {
+ margin-left: 1rem !important;
+ }
+ .m-md-4 {
+ margin: 1.5rem !important;
+ }
+ .mt-md-4,
+ .my-md-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mr-md-4,
+ .mx-md-4 {
+ margin-right: 1.5rem !important;
+ }
+ .mb-md-4,
+ .my-md-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .ml-md-4,
+ .mx-md-4 {
+ margin-left: 1.5rem !important;
+ }
+ .m-md-5 {
+ margin: 3rem !important;
+ }
+ .mt-md-5,
+ .my-md-5 {
+ margin-top: 3rem !important;
+ }
+ .mr-md-5,
+ .mx-md-5 {
+ margin-right: 3rem !important;
+ }
+ .mb-md-5,
+ .my-md-5 {
+ margin-bottom: 3rem !important;
+ }
+ .ml-md-5,
+ .mx-md-5 {
+ margin-left: 3rem !important;
+ }
+ .p-md-0 {
+ padding: 0 !important;
+ }
+ .pt-md-0,
+ .py-md-0 {
+ padding-top: 0 !important;
+ }
+ .pr-md-0,
+ .px-md-0 {
+ padding-right: 0 !important;
+ }
+ .pb-md-0,
+ .py-md-0 {
+ padding-bottom: 0 !important;
+ }
+ .pl-md-0,
+ .px-md-0 {
+ padding-left: 0 !important;
+ }
+ .p-md-1 {
+ padding: 0.25rem !important;
+ }
+ .pt-md-1,
+ .py-md-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pr-md-1,
+ .px-md-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pb-md-1,
+ .py-md-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pl-md-1,
+ .px-md-1 {
+ padding-left: 0.25rem !important;
+ }
+ .p-md-2 {
+ padding: 0.5rem !important;
+ }
+ .pt-md-2,
+ .py-md-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pr-md-2,
+ .px-md-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pb-md-2,
+ .py-md-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pl-md-2,
+ .px-md-2 {
+ padding-left: 0.5rem !important;
+ }
+ .p-md-3 {
+ padding: 1rem !important;
+ }
+ .pt-md-3,
+ .py-md-3 {
+ padding-top: 1rem !important;
+ }
+ .pr-md-3,
+ .px-md-3 {
+ padding-right: 1rem !important;
+ }
+ .pb-md-3,
+ .py-md-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pl-md-3,
+ .px-md-3 {
+ padding-left: 1rem !important;
+ }
+ .p-md-4 {
+ padding: 1.5rem !important;
+ }
+ .pt-md-4,
+ .py-md-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pr-md-4,
+ .px-md-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pb-md-4,
+ .py-md-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pl-md-4,
+ .px-md-4 {
+ padding-left: 1.5rem !important;
+ }
+ .p-md-5 {
+ padding: 3rem !important;
+ }
+ .pt-md-5,
+ .py-md-5 {
+ padding-top: 3rem !important;
+ }
+ .pr-md-5,
+ .px-md-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-md-5,
+ .py-md-5 {
+ padding-bottom: 3rem !important;
+ }
+ .pl-md-5,
+ .px-md-5 {
+ padding-left: 3rem !important;
+ }
+ .m-md-n1 {
+ margin: -0.25rem !important;
+ }
+ .mt-md-n1,
+ .my-md-n1 {
+ margin-top: -0.25rem !important;
+ }
+ .mr-md-n1,
+ .mx-md-n1 {
+ margin-right: -0.25rem !important;
+ }
+ .mb-md-n1,
+ .my-md-n1 {
+ margin-bottom: -0.25rem !important;
+ }
+ .ml-md-n1,
+ .mx-md-n1 {
+ margin-left: -0.25rem !important;
+ }
+ .m-md-n2 {
+ margin: -0.5rem !important;
+ }
+ .mt-md-n2,
+ .my-md-n2 {
+ margin-top: -0.5rem !important;
+ }
+ .mr-md-n2,
+ .mx-md-n2 {
+ margin-right: -0.5rem !important;
+ }
+ .mb-md-n2,
+ .my-md-n2 {
+ margin-bottom: -0.5rem !important;
+ }
+ .ml-md-n2,
+ .mx-md-n2 {
+ margin-left: -0.5rem !important;
+ }
+ .m-md-n3 {
+ margin: -1rem !important;
+ }
+ .mt-md-n3,
+ .my-md-n3 {
+ margin-top: -1rem !important;
+ }
+ .mr-md-n3,
+ .mx-md-n3 {
+ margin-right: -1rem !important;
+ }
+ .mb-md-n3,
+ .my-md-n3 {
+ margin-bottom: -1rem !important;
+ }
+ .ml-md-n3,
+ .mx-md-n3 {
+ margin-left: -1rem !important;
+ }
+ .m-md-n4 {
+ margin: -1.5rem !important;
+ }
+ .mt-md-n4,
+ .my-md-n4 {
+ margin-top: -1.5rem !important;
+ }
+ .mr-md-n4,
+ .mx-md-n4 {
+ margin-right: -1.5rem !important;
+ }
+ .mb-md-n4,
+ .my-md-n4 {
+ margin-bottom: -1.5rem !important;
+ }
+ .ml-md-n4,
+ .mx-md-n4 {
+ margin-left: -1.5rem !important;
+ }
+ .m-md-n5 {
+ margin: -3rem !important;
+ }
+ .mt-md-n5,
+ .my-md-n5 {
+ margin-top: -3rem !important;
+ }
+ .mr-md-n5,
+ .mx-md-n5 {
+ margin-right: -3rem !important;
+ }
+ .mb-md-n5,
+ .my-md-n5 {
+ margin-bottom: -3rem !important;
+ }
+ .ml-md-n5,
+ .mx-md-n5 {
+ margin-left: -3rem !important;
+ }
+ .m-md-auto {
+ margin: auto !important;
+ }
+ .mt-md-auto,
+ .my-md-auto {
+ margin-top: auto !important;
+ }
+ .mr-md-auto,
+ .mx-md-auto {
+ margin-right: auto !important;
+ }
+ .mb-md-auto,
+ .my-md-auto {
+ margin-bottom: auto !important;
+ }
+ .ml-md-auto,
+ .mx-md-auto {
+ margin-left: auto !important;
+ }
+}
+
+@media (min-width: 992px) {
+ .m-lg-0 {
+ margin: 0 !important;
+ }
+ .mt-lg-0,
+ .my-lg-0 {
+ margin-top: 0 !important;
+ }
+ .mr-lg-0,
+ .mx-lg-0 {
+ margin-right: 0 !important;
+ }
+ .mb-lg-0,
+ .my-lg-0 {
+ margin-bottom: 0 !important;
+ }
+ .ml-lg-0,
+ .mx-lg-0 {
+ margin-left: 0 !important;
+ }
+ .m-lg-1 {
+ margin: 0.25rem !important;
+ }
+ .mt-lg-1,
+ .my-lg-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mr-lg-1,
+ .mx-lg-1 {
+ margin-right: 0.25rem !important;
+ }
+ .mb-lg-1,
+ .my-lg-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .ml-lg-1,
+ .mx-lg-1 {
+ margin-left: 0.25rem !important;
+ }
+ .m-lg-2 {
+ margin: 0.5rem !important;
+ }
+ .mt-lg-2,
+ .my-lg-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mr-lg-2,
+ .mx-lg-2 {
+ margin-right: 0.5rem !important;
+ }
+ .mb-lg-2,
+ .my-lg-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .ml-lg-2,
+ .mx-lg-2 {
+ margin-left: 0.5rem !important;
+ }
+ .m-lg-3 {
+ margin: 1rem !important;
+ }
+ .mt-lg-3,
+ .my-lg-3 {
+ margin-top: 1rem !important;
+ }
+ .mr-lg-3,
+ .mx-lg-3 {
+ margin-right: 1rem !important;
+ }
+ .mb-lg-3,
+ .my-lg-3 {
+ margin-bottom: 1rem !important;
+ }
+ .ml-lg-3,
+ .mx-lg-3 {
+ margin-left: 1rem !important;
+ }
+ .m-lg-4 {
+ margin: 1.5rem !important;
+ }
+ .mt-lg-4,
+ .my-lg-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mr-lg-4,
+ .mx-lg-4 {
+ margin-right: 1.5rem !important;
+ }
+ .mb-lg-4,
+ .my-lg-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .ml-lg-4,
+ .mx-lg-4 {
+ margin-left: 1.5rem !important;
+ }
+ .m-lg-5 {
+ margin: 3rem !important;
+ }
+ .mt-lg-5,
+ .my-lg-5 {
+ margin-top: 3rem !important;
+ }
+ .mr-lg-5,
+ .mx-lg-5 {
+ margin-right: 3rem !important;
+ }
+ .mb-lg-5,
+ .my-lg-5 {
+ margin-bottom: 3rem !important;
+ }
+ .ml-lg-5,
+ .mx-lg-5 {
+ margin-left: 3rem !important;
+ }
+ .p-lg-0 {
+ padding: 0 !important;
+ }
+ .pt-lg-0,
+ .py-lg-0 {
+ padding-top: 0 !important;
+ }
+ .pr-lg-0,
+ .px-lg-0 {
+ padding-right: 0 !important;
+ }
+ .pb-lg-0,
+ .py-lg-0 {
+ padding-bottom: 0 !important;
+ }
+ .pl-lg-0,
+ .px-lg-0 {
+ padding-left: 0 !important;
+ }
+ .p-lg-1 {
+ padding: 0.25rem !important;
+ }
+ .pt-lg-1,
+ .py-lg-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pr-lg-1,
+ .px-lg-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pb-lg-1,
+ .py-lg-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pl-lg-1,
+ .px-lg-1 {
+ padding-left: 0.25rem !important;
+ }
+ .p-lg-2 {
+ padding: 0.5rem !important;
+ }
+ .pt-lg-2,
+ .py-lg-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pr-lg-2,
+ .px-lg-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pb-lg-2,
+ .py-lg-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pl-lg-2,
+ .px-lg-2 {
+ padding-left: 0.5rem !important;
+ }
+ .p-lg-3 {
+ padding: 1rem !important;
+ }
+ .pt-lg-3,
+ .py-lg-3 {
+ padding-top: 1rem !important;
+ }
+ .pr-lg-3,
+ .px-lg-3 {
+ padding-right: 1rem !important;
+ }
+ .pb-lg-3,
+ .py-lg-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pl-lg-3,
+ .px-lg-3 {
+ padding-left: 1rem !important;
+ }
+ .p-lg-4 {
+ padding: 1.5rem !important;
+ }
+ .pt-lg-4,
+ .py-lg-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pr-lg-4,
+ .px-lg-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pb-lg-4,
+ .py-lg-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pl-lg-4,
+ .px-lg-4 {
+ padding-left: 1.5rem !important;
+ }
+ .p-lg-5 {
+ padding: 3rem !important;
+ }
+ .pt-lg-5,
+ .py-lg-5 {
+ padding-top: 3rem !important;
+ }
+ .pr-lg-5,
+ .px-lg-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-lg-5,
+ .py-lg-5 {
+ padding-bottom: 3rem !important;
+ }
+ .pl-lg-5,
+ .px-lg-5 {
+ padding-left: 3rem !important;
+ }
+ .m-lg-n1 {
+ margin: -0.25rem !important;
+ }
+ .mt-lg-n1,
+ .my-lg-n1 {
+ margin-top: -0.25rem !important;
+ }
+ .mr-lg-n1,
+ .mx-lg-n1 {
+ margin-right: -0.25rem !important;
+ }
+ .mb-lg-n1,
+ .my-lg-n1 {
+ margin-bottom: -0.25rem !important;
+ }
+ .ml-lg-n1,
+ .mx-lg-n1 {
+ margin-left: -0.25rem !important;
+ }
+ .m-lg-n2 {
+ margin: -0.5rem !important;
+ }
+ .mt-lg-n2,
+ .my-lg-n2 {
+ margin-top: -0.5rem !important;
+ }
+ .mr-lg-n2,
+ .mx-lg-n2 {
+ margin-right: -0.5rem !important;
+ }
+ .mb-lg-n2,
+ .my-lg-n2 {
+ margin-bottom: -0.5rem !important;
+ }
+ .ml-lg-n2,
+ .mx-lg-n2 {
+ margin-left: -0.5rem !important;
+ }
+ .m-lg-n3 {
+ margin: -1rem !important;
+ }
+ .mt-lg-n3,
+ .my-lg-n3 {
+ margin-top: -1rem !important;
+ }
+ .mr-lg-n3,
+ .mx-lg-n3 {
+ margin-right: -1rem !important;
+ }
+ .mb-lg-n3,
+ .my-lg-n3 {
+ margin-bottom: -1rem !important;
+ }
+ .ml-lg-n3,
+ .mx-lg-n3 {
+ margin-left: -1rem !important;
+ }
+ .m-lg-n4 {
+ margin: -1.5rem !important;
+ }
+ .mt-lg-n4,
+ .my-lg-n4 {
+ margin-top: -1.5rem !important;
+ }
+ .mr-lg-n4,
+ .mx-lg-n4 {
+ margin-right: -1.5rem !important;
+ }
+ .mb-lg-n4,
+ .my-lg-n4 {
+ margin-bottom: -1.5rem !important;
+ }
+ .ml-lg-n4,
+ .mx-lg-n4 {
+ margin-left: -1.5rem !important;
+ }
+ .m-lg-n5 {
+ margin: -3rem !important;
+ }
+ .mt-lg-n5,
+ .my-lg-n5 {
+ margin-top: -3rem !important;
+ }
+ .mr-lg-n5,
+ .mx-lg-n5 {
+ margin-right: -3rem !important;
+ }
+ .mb-lg-n5,
+ .my-lg-n5 {
+ margin-bottom: -3rem !important;
+ }
+ .ml-lg-n5,
+ .mx-lg-n5 {
+ margin-left: -3rem !important;
+ }
+ .m-lg-auto {
+ margin: auto !important;
+ }
+ .mt-lg-auto,
+ .my-lg-auto {
+ margin-top: auto !important;
+ }
+ .mr-lg-auto,
+ .mx-lg-auto {
+ margin-right: auto !important;
+ }
+ .mb-lg-auto,
+ .my-lg-auto {
+ margin-bottom: auto !important;
+ }
+ .ml-lg-auto,
+ .mx-lg-auto {
+ margin-left: auto !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .m-xl-0 {
+ margin: 0 !important;
+ }
+ .mt-xl-0,
+ .my-xl-0 {
+ margin-top: 0 !important;
+ }
+ .mr-xl-0,
+ .mx-xl-0 {
+ margin-right: 0 !important;
+ }
+ .mb-xl-0,
+ .my-xl-0 {
+ margin-bottom: 0 !important;
+ }
+ .ml-xl-0,
+ .mx-xl-0 {
+ margin-left: 0 !important;
+ }
+ .m-xl-1 {
+ margin: 0.25rem !important;
+ }
+ .mt-xl-1,
+ .my-xl-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mr-xl-1,
+ .mx-xl-1 {
+ margin-right: 0.25rem !important;
+ }
+ .mb-xl-1,
+ .my-xl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .ml-xl-1,
+ .mx-xl-1 {
+ margin-left: 0.25rem !important;
+ }
+ .m-xl-2 {
+ margin: 0.5rem !important;
+ }
+ .mt-xl-2,
+ .my-xl-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mr-xl-2,
+ .mx-xl-2 {
+ margin-right: 0.5rem !important;
+ }
+ .mb-xl-2,
+ .my-xl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .ml-xl-2,
+ .mx-xl-2 {
+ margin-left: 0.5rem !important;
+ }
+ .m-xl-3 {
+ margin: 1rem !important;
+ }
+ .mt-xl-3,
+ .my-xl-3 {
+ margin-top: 1rem !important;
+ }
+ .mr-xl-3,
+ .mx-xl-3 {
+ margin-right: 1rem !important;
+ }
+ .mb-xl-3,
+ .my-xl-3 {
+ margin-bottom: 1rem !important;
+ }
+ .ml-xl-3,
+ .mx-xl-3 {
+ margin-left: 1rem !important;
+ }
+ .m-xl-4 {
+ margin: 1.5rem !important;
+ }
+ .mt-xl-4,
+ .my-xl-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mr-xl-4,
+ .mx-xl-4 {
+ margin-right: 1.5rem !important;
+ }
+ .mb-xl-4,
+ .my-xl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .ml-xl-4,
+ .mx-xl-4 {
+ margin-left: 1.5rem !important;
+ }
+ .m-xl-5 {
+ margin: 3rem !important;
+ }
+ .mt-xl-5,
+ .my-xl-5 {
+ margin-top: 3rem !important;
+ }
+ .mr-xl-5,
+ .mx-xl-5 {
+ margin-right: 3rem !important;
+ }
+ .mb-xl-5,
+ .my-xl-5 {
+ margin-bottom: 3rem !important;
+ }
+ .ml-xl-5,
+ .mx-xl-5 {
+ margin-left: 3rem !important;
+ }
+ .p-xl-0 {
+ padding: 0 !important;
+ }
+ .pt-xl-0,
+ .py-xl-0 {
+ padding-top: 0 !important;
+ }
+ .pr-xl-0,
+ .px-xl-0 {
+ padding-right: 0 !important;
+ }
+ .pb-xl-0,
+ .py-xl-0 {
+ padding-bottom: 0 !important;
+ }
+ .pl-xl-0,
+ .px-xl-0 {
+ padding-left: 0 !important;
+ }
+ .p-xl-1 {
+ padding: 0.25rem !important;
+ }
+ .pt-xl-1,
+ .py-xl-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pr-xl-1,
+ .px-xl-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pb-xl-1,
+ .py-xl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pl-xl-1,
+ .px-xl-1 {
+ padding-left: 0.25rem !important;
+ }
+ .p-xl-2 {
+ padding: 0.5rem !important;
+ }
+ .pt-xl-2,
+ .py-xl-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pr-xl-2,
+ .px-xl-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pb-xl-2,
+ .py-xl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pl-xl-2,
+ .px-xl-2 {
+ padding-left: 0.5rem !important;
+ }
+ .p-xl-3 {
+ padding: 1rem !important;
+ }
+ .pt-xl-3,
+ .py-xl-3 {
+ padding-top: 1rem !important;
+ }
+ .pr-xl-3,
+ .px-xl-3 {
+ padding-right: 1rem !important;
+ }
+ .pb-xl-3,
+ .py-xl-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pl-xl-3,
+ .px-xl-3 {
+ padding-left: 1rem !important;
+ }
+ .p-xl-4 {
+ padding: 1.5rem !important;
+ }
+ .pt-xl-4,
+ .py-xl-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pr-xl-4,
+ .px-xl-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pb-xl-4,
+ .py-xl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pl-xl-4,
+ .px-xl-4 {
+ padding-left: 1.5rem !important;
+ }
+ .p-xl-5 {
+ padding: 3rem !important;
+ }
+ .pt-xl-5,
+ .py-xl-5 {
+ padding-top: 3rem !important;
+ }
+ .pr-xl-5,
+ .px-xl-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-xl-5,
+ .py-xl-5 {
+ padding-bottom: 3rem !important;
+ }
+ .pl-xl-5,
+ .px-xl-5 {
+ padding-left: 3rem !important;
+ }
+ .m-xl-n1 {
+ margin: -0.25rem !important;
+ }
+ .mt-xl-n1,
+ .my-xl-n1 {
+ margin-top: -0.25rem !important;
+ }
+ .mr-xl-n1,
+ .mx-xl-n1 {
+ margin-right: -0.25rem !important;
+ }
+ .mb-xl-n1,
+ .my-xl-n1 {
+ margin-bottom: -0.25rem !important;
+ }
+ .ml-xl-n1,
+ .mx-xl-n1 {
+ margin-left: -0.25rem !important;
+ }
+ .m-xl-n2 {
+ margin: -0.5rem !important;
+ }
+ .mt-xl-n2,
+ .my-xl-n2 {
+ margin-top: -0.5rem !important;
+ }
+ .mr-xl-n2,
+ .mx-xl-n2 {
+ margin-right: -0.5rem !important;
+ }
+ .mb-xl-n2,
+ .my-xl-n2 {
+ margin-bottom: -0.5rem !important;
+ }
+ .ml-xl-n2,
+ .mx-xl-n2 {
+ margin-left: -0.5rem !important;
+ }
+ .m-xl-n3 {
+ margin: -1rem !important;
+ }
+ .mt-xl-n3,
+ .my-xl-n3 {
+ margin-top: -1rem !important;
+ }
+ .mr-xl-n3,
+ .mx-xl-n3 {
+ margin-right: -1rem !important;
+ }
+ .mb-xl-n3,
+ .my-xl-n3 {
+ margin-bottom: -1rem !important;
+ }
+ .ml-xl-n3,
+ .mx-xl-n3 {
+ margin-left: -1rem !important;
+ }
+ .m-xl-n4 {
+ margin: -1.5rem !important;
+ }
+ .mt-xl-n4,
+ .my-xl-n4 {
+ margin-top: -1.5rem !important;
+ }
+ .mr-xl-n4,
+ .mx-xl-n4 {
+ margin-right: -1.5rem !important;
+ }
+ .mb-xl-n4,
+ .my-xl-n4 {
+ margin-bottom: -1.5rem !important;
+ }
+ .ml-xl-n4,
+ .mx-xl-n4 {
+ margin-left: -1.5rem !important;
+ }
+ .m-xl-n5 {
+ margin: -3rem !important;
+ }
+ .mt-xl-n5,
+ .my-xl-n5 {
+ margin-top: -3rem !important;
+ }
+ .mr-xl-n5,
+ .mx-xl-n5 {
+ margin-right: -3rem !important;
+ }
+ .mb-xl-n5,
+ .my-xl-n5 {
+ margin-bottom: -3rem !important;
+ }
+ .ml-xl-n5,
+ .mx-xl-n5 {
+ margin-left: -3rem !important;
+ }
+ .m-xl-auto {
+ margin: auto !important;
+ }
+ .mt-xl-auto,
+ .my-xl-auto {
+ margin-top: auto !important;
+ }
+ .mr-xl-auto,
+ .mx-xl-auto {
+ margin-right: auto !important;
+ }
+ .mb-xl-auto,
+ .my-xl-auto {
+ margin-bottom: auto !important;
+ }
+ .ml-xl-auto,
+ .mx-xl-auto {
+ margin-left: auto !important;
+ }
+}
+
+.text-monospace {
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;
+}
+
+.text-justify {
+ text-align: justify !important;
+}
+
+.text-wrap {
+ white-space: normal !important;
+}
+
+.text-nowrap {
+ white-space: nowrap !important;
+}
+
+.text-truncate {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.text-left {
+ text-align: left !important;
+}
+
+.text-right {
+ text-align: right !important;
+}
+
+.text-center {
+ text-align: center !important;
+}
+
+@media (min-width: 576px) {
+ .text-sm-left {
+ text-align: left !important;
+ }
+ .text-sm-right {
+ text-align: right !important;
+ }
+ .text-sm-center {
+ text-align: center !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .text-md-left {
+ text-align: left !important;
+ }
+ .text-md-right {
+ text-align: right !important;
+ }
+ .text-md-center {
+ text-align: center !important;
+ }
+}
+
+@media (min-width: 992px) {
+ .text-lg-left {
+ text-align: left !important;
+ }
+ .text-lg-right {
+ text-align: right !important;
+ }
+ .text-lg-center {
+ text-align: center !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .text-xl-left {
+ text-align: left !important;
+ }
+ .text-xl-right {
+ text-align: right !important;
+ }
+ .text-xl-center {
+ text-align: center !important;
+ }
+}
+
+.text-lowercase {
+ text-transform: lowercase !important;
+}
+
+.text-uppercase {
+ text-transform: uppercase !important;
+}
+
+.text-capitalize {
+ text-transform: capitalize !important;
+}
+
+.font-weight-light {
+ font-weight: 300 !important;
+}
+
+.font-weight-lighter {
+ font-weight: lighter !important;
+}
+
+.font-weight-normal {
+ font-weight: 400 !important;
+}
+
+.font-weight-bold {
+ font-weight: 700 !important;
+}
+
+.font-weight-bolder {
+ font-weight: bolder !important;
+}
+
+.font-italic {
+ font-style: italic !important;
+}
+
+.text-white {
+ color: #fff !important;
+}
+
+.text-primary {
+ color: #007bff !important;
+}
+
+a.text-primary:hover, a.text-primary:focus {
+ color: #0056b3 !important;
+}
+
+.text-secondary {
+ color: #6c757d !important;
+}
+
+a.text-secondary:hover, a.text-secondary:focus {
+ color: #494f54 !important;
+}
+
+.text-success {
+ color: #28a745 !important;
+}
+
+a.text-success:hover, a.text-success:focus {
+ color: #19692c !important;
+}
+
+.text-info {
+ color: #17a2b8 !important;
+}
+
+a.text-info:hover, a.text-info:focus {
+ color: #0f6674 !important;
+}
+
+.text-warning {
+ color: #ffc107 !important;
+}
+
+a.text-warning:hover, a.text-warning:focus {
+ color: #ba8b00 !important;
+}
+
+.text-danger {
+ color: #dc3545 !important;
+}
+
+a.text-danger:hover, a.text-danger:focus {
+ color: #a71d2a !important;
+}
+
+.text-light {
+ color: #f8f9fa !important;
+}
+
+a.text-light:hover, a.text-light:focus {
+ color: #cbd3da !important;
+}
+
+.text-dark {
+ color: #343a40 !important;
+}
+
+a.text-dark:hover, a.text-dark:focus {
+ color: #121416 !important;
+}
+
+.text-body {
+ color: #212529 !important;
+}
+
+.text-muted {
+ color: #6c757d !important;
+}
+
+.text-black-50 {
+ color: rgba(0, 0, 0, 0.5) !important;
+}
+
+.text-white-50 {
+ color: rgba(255, 255, 255, 0.5) !important;
+}
+
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+
+.text-decoration-none {
+ text-decoration: none !important;
+}
+
+.text-break {
+ word-break: break-word !important;
+ overflow-wrap: break-word !important;
+}
+
+.text-reset {
+ color: inherit !important;
+}
+
+.visible {
+ visibility: visible !important;
+}
+
+.invisible {
+ visibility: hidden !important;
+}
+
+@media print {
+ *,
+ *::before,
+ *::after {
+ text-shadow: none !important;
+ box-shadow: none !important;
+ }
+ a:not(.btn) {
+ text-decoration: underline;
+ }
+ abbr[title]::after {
+ content: " (" attr(title) ")";
+ }
+ pre {
+ white-space: pre-wrap !important;
+ }
+ pre,
+ blockquote {
+ border: 1px solid #adb5bd;
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+ @page {
+ size: a3;
+ }
+ body {
+ min-width: 992px !important;
+ }
+ .container {
+ min-width: 992px !important;
+ }
+ .navbar {
+ display: none;
+ }
+ .badge {
+ border: 1px solid #000;
+ }
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
+ .table-bordered th,
+ .table-bordered td {
+ border: 1px solid #dee2e6 !important;
+ }
+ .table-dark {
+ color: inherit;
+ }
+ .table-dark th,
+ .table-dark td,
+ .table-dark thead th,
+ .table-dark tbody + tbody {
+ border-color: #dee2e6;
+ }
+ .table .thead-dark th {
+ color: inherit;
+ border-color: #dee2e6;
+ }
+}
+/*# sourceMappingURL=bootstrap.css.map */
\ No newline at end of file
diff --git a/app/webroot/css/cake.css b/app/webroot/css/cake.css
new file mode 100644
index 0000000..959b811
--- /dev/null
+++ b/app/webroot/css/cake.css
@@ -0,0 +1,177 @@
+/* Miligram overrides */
+a {
+ font-family: "Raleway", sans-serif;
+ color: #404041;
+}
+
+/* Utility */
+.table-responsive {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+/* Main */
+body {
+ background: #f5f7fa;
+}
+.content {
+ padding: 2rem;
+ background: #ffffff;
+ border-radius: 0.4rem;
+ /* Thanks Stripe */
+ box-shadow: 0 7px 14px 0 rgba(60, 66, 87, 0.1),
+ 0 3px 6px 0 rgba(0, 0, 0, 0.07);
+}
+.actions a {
+ font-weight: bold;
+ padding: 0 0.4rem;
+}
+th {
+ white-space: nowrap;
+}
+
+/* Nav bar */
+.top-nav {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ max-width: 112rem;
+ padding: 2rem;
+ margin: 0 auto 2rem;
+}
+.top-nav-title a {
+ font-size: 2.4rem;
+ color: #d33c43;
+}
+.top-nav-title span {
+ color: #404041;
+}
+.top-nav-links a {
+ margin: 0 0.5rem;
+}
+.top-nav-title a,
+.top-nav-links a {
+ font-weight: bold;
+}
+
+.side-nav-item {
+ display: block;
+ padding: 0.5rem 0;
+}
+
+/* View action */
+.view.content .text {
+ margin-top: 1.2rem;
+}
+.related {
+ margin-top: 2rem;
+}
+
+/* Flash messages */
+.message {
+ padding: 1rem;
+
+ background: #eff8ff;
+ color: #2779bd;
+
+ border-color: #6cb2eb;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 4px;
+ margin-bottom: 2rem;
+}
+.message.hidden {
+ display: none;
+}
+.message.success {
+ background: #e3fcec;
+ color: #1f9d55;
+ border-color: #51d88a;
+}
+.message.error {
+ background: #fcebea;
+ color: #cc1f1a;
+ border-color: #ef5753;
+}
+
+/* Forms */
+.input.radio,
+.input.checkbox {
+ margin-bottom: 2.0rem;
+}
+.input.radio input,
+.input.checkbox input {
+ margin: 0;
+}
+.input.radio label,
+.input.checkbox label {
+ margin: 0;
+ display: flex;
+ align-items: center;
+}
+.input.radio label > input,
+.input.checkbox label > input {
+ margin-right: 1.0rem;
+}
+.input.radio label:first-of-type {
+ margin-bottom: 2.0rem;
+}
+
+/* Paginator */
+.paginator {
+ text-align: right;
+}
+.pagination {
+ display: flex;
+ justify-content: center;
+ list-style: none;
+ padding: 0;
+ margin: 0 0 1rem;
+}
+.pagination li {
+ margin: 0 0.5rem;
+}
+.prev.disabled a,
+.next.disabled a {
+ cursor: not-allowed;
+ color: #606c76;
+}
+.asc:after {
+ content: " \2193";
+}
+.desc:after {
+ content: " \2191";
+}
+
+/* Error */
+.error-container {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ justify-content: center;
+}
+
+@media screen and (max-width: 640px) {
+ .top-nav {
+ margin: 0 auto;
+ }
+ .side-nav {
+ margin-bottom: 1rem;
+ }
+ .heading {
+ margin-bottom: 1rem;
+ }
+ .side-nav-item {
+ display: inline;
+ margin: 0 1.5rem 0 0;
+ }
+ .asc:after {
+ content: " \2192";
+ }
+ .desc:after {
+ content: " \2190";
+ }
+}
diff --git a/app/webroot/css/font-awesome.css b/app/webroot/css/font-awesome.css
new file mode 100644
index 0000000..391a837
--- /dev/null
+++ b/app/webroot/css/font-awesome.css
@@ -0,0 +1,4336 @@
+/*!
+ * Font Awesome Free 5.8.2 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ */
+.fa,
+.fas,
+.far,
+.fal,
+.fab {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ display: inline-block;
+ font-style: normal;
+ font-variant: normal;
+ text-rendering: auto;
+ line-height: 1; }
+
+.fa-lg {
+ font-size: 1.33333em;
+ line-height: 0.75em;
+ vertical-align: -.0667em; }
+
+.fa-xs {
+ font-size: .75em; }
+
+.fa-sm {
+ font-size: .875em; }
+
+.fa-1x {
+ font-size: 1em; }
+
+.fa-2x {
+ font-size: 2em; }
+
+.fa-3x {
+ font-size: 3em; }
+
+.fa-4x {
+ font-size: 4em; }
+
+.fa-5x {
+ font-size: 5em; }
+
+.fa-6x {
+ font-size: 6em; }
+
+.fa-7x {
+ font-size: 7em; }
+
+.fa-8x {
+ font-size: 8em; }
+
+.fa-9x {
+ font-size: 9em; }
+
+.fa-10x {
+ font-size: 10em; }
+
+.fa-fw {
+ text-align: center;
+ width: 1.25em; }
+
+.fa-ul {
+ list-style-type: none;
+ margin-left: 2.5em;
+ padding-left: 0; }
+ .fa-ul > li {
+ position: relative; }
+
+.fa-li {
+ left: -2em;
+ position: absolute;
+ text-align: center;
+ width: 2em;
+ line-height: inherit; }
+
+.fa-border {
+ border: solid 0.08em #eee;
+ border-radius: .1em;
+ padding: .2em .25em .15em; }
+
+.fa-pull-left {
+ float: left; }
+
+.fa-pull-right {
+ float: right; }
+
+.fa.fa-pull-left,
+.fas.fa-pull-left,
+.far.fa-pull-left,
+.fal.fa-pull-left,
+.fab.fa-pull-left {
+ margin-right: .3em; }
+
+.fa.fa-pull-right,
+.fas.fa-pull-right,
+.far.fa-pull-right,
+.fal.fa-pull-right,
+.fab.fa-pull-right {
+ margin-left: .3em; }
+
+.fa-spin {
+ -webkit-animation: fa-spin 2s infinite linear;
+ animation: fa-spin 2s infinite linear; }
+
+.fa-pulse {
+ -webkit-animation: fa-spin 1s infinite steps(8);
+ animation: fa-spin 1s infinite steps(8); }
+
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+.fa-rotate-90 {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg); }
+
+.fa-rotate-180 {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg); }
+
+.fa-rotate-270 {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg); }
+
+.fa-flip-horizontal {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
+ -webkit-transform: scale(-1, 1);
+ transform: scale(-1, 1); }
+
+.fa-flip-vertical {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
+ -webkit-transform: scale(1, -1);
+ transform: scale(1, -1); }
+
+.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
+ -webkit-transform: scale(-1, -1);
+ transform: scale(-1, -1); }
+
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical,
+:root .fa-flip-both {
+ -webkit-filter: none;
+ filter: none; }
+
+.fa-stack {
+ display: inline-block;
+ height: 2em;
+ line-height: 2em;
+ position: relative;
+ vertical-align: middle;
+ width: 2.5em; }
+
+.fa-stack-1x,
+.fa-stack-2x {
+ left: 0;
+ position: absolute;
+ text-align: center;
+ width: 100%; }
+
+.fa-stack-1x {
+ line-height: inherit; }
+
+.fa-stack-2x {
+ font-size: 2em; }
+
+.fa-inverse {
+ color: #fff; }
+
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+readers do not read off random characters that represent icons */
+.fa-500px:before {
+ content: "\f26e"; }
+
+.fa-accessible-icon:before {
+ content: "\f368"; }
+
+.fa-accusoft:before {
+ content: "\f369"; }
+
+.fa-acquisitions-incorporated:before {
+ content: "\f6af"; }
+
+.fa-ad:before {
+ content: "\f641"; }
+
+.fa-address-book:before {
+ content: "\f2b9"; }
+
+.fa-address-card:before {
+ content: "\f2bb"; }
+
+.fa-adjust:before {
+ content: "\f042"; }
+
+.fa-adn:before {
+ content: "\f170"; }
+
+.fa-adobe:before {
+ content: "\f778"; }
+
+.fa-adversal:before {
+ content: "\f36a"; }
+
+.fa-affiliatetheme:before {
+ content: "\f36b"; }
+
+.fa-air-freshener:before {
+ content: "\f5d0"; }
+
+.fa-airbnb:before {
+ content: "\f834"; }
+
+.fa-algolia:before {
+ content: "\f36c"; }
+
+.fa-align-center:before {
+ content: "\f037"; }
+
+.fa-align-justify:before {
+ content: "\f039"; }
+
+.fa-align-left:before {
+ content: "\f036"; }
+
+.fa-align-right:before {
+ content: "\f038"; }
+
+.fa-alipay:before {
+ content: "\f642"; }
+
+.fa-allergies:before {
+ content: "\f461"; }
+
+.fa-amazon:before {
+ content: "\f270"; }
+
+.fa-amazon-pay:before {
+ content: "\f42c"; }
+
+.fa-ambulance:before {
+ content: "\f0f9"; }
+
+.fa-american-sign-language-interpreting:before {
+ content: "\f2a3"; }
+
+.fa-amilia:before {
+ content: "\f36d"; }
+
+.fa-anchor:before {
+ content: "\f13d"; }
+
+.fa-android:before {
+ content: "\f17b"; }
+
+.fa-angellist:before {
+ content: "\f209"; }
+
+.fa-angle-double-down:before {
+ content: "\f103"; }
+
+.fa-angle-double-left:before {
+ content: "\f100"; }
+
+.fa-angle-double-right:before {
+ content: "\f101"; }
+
+.fa-angle-double-up:before {
+ content: "\f102"; }
+
+.fa-angle-down:before {
+ content: "\f107"; }
+
+.fa-angle-left:before {
+ content: "\f104"; }
+
+.fa-angle-right:before {
+ content: "\f105"; }
+
+.fa-angle-up:before {
+ content: "\f106"; }
+
+.fa-angry:before {
+ content: "\f556"; }
+
+.fa-angrycreative:before {
+ content: "\f36e"; }
+
+.fa-angular:before {
+ content: "\f420"; }
+
+.fa-ankh:before {
+ content: "\f644"; }
+
+.fa-app-store:before {
+ content: "\f36f"; }
+
+.fa-app-store-ios:before {
+ content: "\f370"; }
+
+.fa-apper:before {
+ content: "\f371"; }
+
+.fa-apple:before {
+ content: "\f179"; }
+
+.fa-apple-alt:before {
+ content: "\f5d1"; }
+
+.fa-apple-pay:before {
+ content: "\f415"; }
+
+.fa-archive:before {
+ content: "\f187"; }
+
+.fa-archway:before {
+ content: "\f557"; }
+
+.fa-arrow-alt-circle-down:before {
+ content: "\f358"; }
+
+.fa-arrow-alt-circle-left:before {
+ content: "\f359"; }
+
+.fa-arrow-alt-circle-right:before {
+ content: "\f35a"; }
+
+.fa-arrow-alt-circle-up:before {
+ content: "\f35b"; }
+
+.fa-arrow-circle-down:before {
+ content: "\f0ab"; }
+
+.fa-arrow-circle-left:before {
+ content: "\f0a8"; }
+
+.fa-arrow-circle-right:before {
+ content: "\f0a9"; }
+
+.fa-arrow-circle-up:before {
+ content: "\f0aa"; }
+
+.fa-arrow-down:before {
+ content: "\f063"; }
+
+.fa-arrow-left:before {
+ content: "\f060"; }
+
+.fa-arrow-right:before {
+ content: "\f061"; }
+
+.fa-arrow-up:before {
+ content: "\f062"; }
+
+.fa-arrows-alt:before {
+ content: "\f0b2"; }
+
+.fa-arrows-alt-h:before {
+ content: "\f337"; }
+
+.fa-arrows-alt-v:before {
+ content: "\f338"; }
+
+.fa-artstation:before {
+ content: "\f77a"; }
+
+.fa-assistive-listening-systems:before {
+ content: "\f2a2"; }
+
+.fa-asterisk:before {
+ content: "\f069"; }
+
+.fa-asymmetrik:before {
+ content: "\f372"; }
+
+.fa-at:before {
+ content: "\f1fa"; }
+
+.fa-atlas:before {
+ content: "\f558"; }
+
+.fa-atlassian:before {
+ content: "\f77b"; }
+
+.fa-atom:before {
+ content: "\f5d2"; }
+
+.fa-audible:before {
+ content: "\f373"; }
+
+.fa-audio-description:before {
+ content: "\f29e"; }
+
+.fa-autoprefixer:before {
+ content: "\f41c"; }
+
+.fa-avianex:before {
+ content: "\f374"; }
+
+.fa-aviato:before {
+ content: "\f421"; }
+
+.fa-award:before {
+ content: "\f559"; }
+
+.fa-aws:before {
+ content: "\f375"; }
+
+.fa-baby:before {
+ content: "\f77c"; }
+
+.fa-baby-carriage:before {
+ content: "\f77d"; }
+
+.fa-backspace:before {
+ content: "\f55a"; }
+
+.fa-backward:before {
+ content: "\f04a"; }
+
+.fa-bacon:before {
+ content: "\f7e5"; }
+
+.fa-balance-scale:before {
+ content: "\f24e"; }
+
+.fa-ban:before {
+ content: "\f05e"; }
+
+.fa-band-aid:before {
+ content: "\f462"; }
+
+.fa-bandcamp:before {
+ content: "\f2d5"; }
+
+.fa-barcode:before {
+ content: "\f02a"; }
+
+.fa-bars:before {
+ content: "\f0c9"; }
+
+.fa-baseball-ball:before {
+ content: "\f433"; }
+
+.fa-basketball-ball:before {
+ content: "\f434"; }
+
+.fa-bath:before {
+ content: "\f2cd"; }
+
+.fa-battery-empty:before {
+ content: "\f244"; }
+
+.fa-battery-full:before {
+ content: "\f240"; }
+
+.fa-battery-half:before {
+ content: "\f242"; }
+
+.fa-battery-quarter:before {
+ content: "\f243"; }
+
+.fa-battery-three-quarters:before {
+ content: "\f241"; }
+
+.fa-battle-net:before {
+ content: "\f835"; }
+
+.fa-bed:before {
+ content: "\f236"; }
+
+.fa-beer:before {
+ content: "\f0fc"; }
+
+.fa-behance:before {
+ content: "\f1b4"; }
+
+.fa-behance-square:before {
+ content: "\f1b5"; }
+
+.fa-bell:before {
+ content: "\f0f3"; }
+
+.fa-bell-slash:before {
+ content: "\f1f6"; }
+
+.fa-bezier-curve:before {
+ content: "\f55b"; }
+
+.fa-bible:before {
+ content: "\f647"; }
+
+.fa-bicycle:before {
+ content: "\f206"; }
+
+.fa-bimobject:before {
+ content: "\f378"; }
+
+.fa-binoculars:before {
+ content: "\f1e5"; }
+
+.fa-biohazard:before {
+ content: "\f780"; }
+
+.fa-birthday-cake:before {
+ content: "\f1fd"; }
+
+.fa-bitbucket:before {
+ content: "\f171"; }
+
+.fa-bitcoin:before {
+ content: "\f379"; }
+
+.fa-bity:before {
+ content: "\f37a"; }
+
+.fa-black-tie:before {
+ content: "\f27e"; }
+
+.fa-blackberry:before {
+ content: "\f37b"; }
+
+.fa-blender:before {
+ content: "\f517"; }
+
+.fa-blender-phone:before {
+ content: "\f6b6"; }
+
+.fa-blind:before {
+ content: "\f29d"; }
+
+.fa-blog:before {
+ content: "\f781"; }
+
+.fa-blogger:before {
+ content: "\f37c"; }
+
+.fa-blogger-b:before {
+ content: "\f37d"; }
+
+.fa-bluetooth:before {
+ content: "\f293"; }
+
+.fa-bluetooth-b:before {
+ content: "\f294"; }
+
+.fa-bold:before {
+ content: "\f032"; }
+
+.fa-bolt:before {
+ content: "\f0e7"; }
+
+.fa-bomb:before {
+ content: "\f1e2"; }
+
+.fa-bone:before {
+ content: "\f5d7"; }
+
+.fa-bong:before {
+ content: "\f55c"; }
+
+.fa-book:before {
+ content: "\f02d"; }
+
+.fa-book-dead:before {
+ content: "\f6b7"; }
+
+.fa-book-medical:before {
+ content: "\f7e6"; }
+
+.fa-book-open:before {
+ content: "\f518"; }
+
+.fa-book-reader:before {
+ content: "\f5da"; }
+
+.fa-bookmark:before {
+ content: "\f02e"; }
+
+.fa-bootstrap:before {
+ content: "\f836"; }
+
+.fa-bowling-ball:before {
+ content: "\f436"; }
+
+.fa-box:before {
+ content: "\f466"; }
+
+.fa-box-open:before {
+ content: "\f49e"; }
+
+.fa-boxes:before {
+ content: "\f468"; }
+
+.fa-braille:before {
+ content: "\f2a1"; }
+
+.fa-brain:before {
+ content: "\f5dc"; }
+
+.fa-bread-slice:before {
+ content: "\f7ec"; }
+
+.fa-briefcase:before {
+ content: "\f0b1"; }
+
+.fa-briefcase-medical:before {
+ content: "\f469"; }
+
+.fa-broadcast-tower:before {
+ content: "\f519"; }
+
+.fa-broom:before {
+ content: "\f51a"; }
+
+.fa-brush:before {
+ content: "\f55d"; }
+
+.fa-btc:before {
+ content: "\f15a"; }
+
+.fa-buffer:before {
+ content: "\f837"; }
+
+.fa-bug:before {
+ content: "\f188"; }
+
+.fa-building:before {
+ content: "\f1ad"; }
+
+.fa-bullhorn:before {
+ content: "\f0a1"; }
+
+.fa-bullseye:before {
+ content: "\f140"; }
+
+.fa-burn:before {
+ content: "\f46a"; }
+
+.fa-buromobelexperte:before {
+ content: "\f37f"; }
+
+.fa-bus:before {
+ content: "\f207"; }
+
+.fa-bus-alt:before {
+ content: "\f55e"; }
+
+.fa-business-time:before {
+ content: "\f64a"; }
+
+.fa-buysellads:before {
+ content: "\f20d"; }
+
+.fa-calculator:before {
+ content: "\f1ec"; }
+
+.fa-calendar:before {
+ content: "\f133"; }
+
+.fa-calendar-alt:before {
+ content: "\f073"; }
+
+.fa-calendar-check:before {
+ content: "\f274"; }
+
+.fa-calendar-day:before {
+ content: "\f783"; }
+
+.fa-calendar-minus:before {
+ content: "\f272"; }
+
+.fa-calendar-plus:before {
+ content: "\f271"; }
+
+.fa-calendar-times:before {
+ content: "\f273"; }
+
+.fa-calendar-week:before {
+ content: "\f784"; }
+
+.fa-camera:before {
+ content: "\f030"; }
+
+.fa-camera-retro:before {
+ content: "\f083"; }
+
+.fa-campground:before {
+ content: "\f6bb"; }
+
+.fa-canadian-maple-leaf:before {
+ content: "\f785"; }
+
+.fa-candy-cane:before {
+ content: "\f786"; }
+
+.fa-cannabis:before {
+ content: "\f55f"; }
+
+.fa-capsules:before {
+ content: "\f46b"; }
+
+.fa-car:before {
+ content: "\f1b9"; }
+
+.fa-car-alt:before {
+ content: "\f5de"; }
+
+.fa-car-battery:before {
+ content: "\f5df"; }
+
+.fa-car-crash:before {
+ content: "\f5e1"; }
+
+.fa-car-side:before {
+ content: "\f5e4"; }
+
+.fa-caret-down:before {
+ content: "\f0d7"; }
+
+.fa-caret-left:before {
+ content: "\f0d9"; }
+
+.fa-caret-right:before {
+ content: "\f0da"; }
+
+.fa-caret-square-down:before {
+ content: "\f150"; }
+
+.fa-caret-square-left:before {
+ content: "\f191"; }
+
+.fa-caret-square-right:before {
+ content: "\f152"; }
+
+.fa-caret-square-up:before {
+ content: "\f151"; }
+
+.fa-caret-up:before {
+ content: "\f0d8"; }
+
+.fa-carrot:before {
+ content: "\f787"; }
+
+.fa-cart-arrow-down:before {
+ content: "\f218"; }
+
+.fa-cart-plus:before {
+ content: "\f217"; }
+
+.fa-cash-register:before {
+ content: "\f788"; }
+
+.fa-cat:before {
+ content: "\f6be"; }
+
+.fa-cc-amazon-pay:before {
+ content: "\f42d"; }
+
+.fa-cc-amex:before {
+ content: "\f1f3"; }
+
+.fa-cc-apple-pay:before {
+ content: "\f416"; }
+
+.fa-cc-diners-club:before {
+ content: "\f24c"; }
+
+.fa-cc-discover:before {
+ content: "\f1f2"; }
+
+.fa-cc-jcb:before {
+ content: "\f24b"; }
+
+.fa-cc-mastercard:before {
+ content: "\f1f1"; }
+
+.fa-cc-paypal:before {
+ content: "\f1f4"; }
+
+.fa-cc-stripe:before {
+ content: "\f1f5"; }
+
+.fa-cc-visa:before {
+ content: "\f1f0"; }
+
+.fa-centercode:before {
+ content: "\f380"; }
+
+.fa-centos:before {
+ content: "\f789"; }
+
+.fa-certificate:before {
+ content: "\f0a3"; }
+
+.fa-chair:before {
+ content: "\f6c0"; }
+
+.fa-chalkboard:before {
+ content: "\f51b"; }
+
+.fa-chalkboard-teacher:before {
+ content: "\f51c"; }
+
+.fa-charging-station:before {
+ content: "\f5e7"; }
+
+.fa-chart-area:before {
+ content: "\f1fe"; }
+
+.fa-chart-bar:before {
+ content: "\f080"; }
+
+.fa-chart-line:before {
+ content: "\f201"; }
+
+.fa-chart-pie:before {
+ content: "\f200"; }
+
+.fa-check:before {
+ content: "\f00c"; }
+
+.fa-check-circle:before {
+ content: "\f058"; }
+
+.fa-check-double:before {
+ content: "\f560"; }
+
+.fa-check-square:before {
+ content: "\f14a"; }
+
+.fa-cheese:before {
+ content: "\f7ef"; }
+
+.fa-chess:before {
+ content: "\f439"; }
+
+.fa-chess-bishop:before {
+ content: "\f43a"; }
+
+.fa-chess-board:before {
+ content: "\f43c"; }
+
+.fa-chess-king:before {
+ content: "\f43f"; }
+
+.fa-chess-knight:before {
+ content: "\f441"; }
+
+.fa-chess-pawn:before {
+ content: "\f443"; }
+
+.fa-chess-queen:before {
+ content: "\f445"; }
+
+.fa-chess-rook:before {
+ content: "\f447"; }
+
+.fa-chevron-circle-down:before {
+ content: "\f13a"; }
+
+.fa-chevron-circle-left:before {
+ content: "\f137"; }
+
+.fa-chevron-circle-right:before {
+ content: "\f138"; }
+
+.fa-chevron-circle-up:before {
+ content: "\f139"; }
+
+.fa-chevron-down:before {
+ content: "\f078"; }
+
+.fa-chevron-left:before {
+ content: "\f053"; }
+
+.fa-chevron-right:before {
+ content: "\f054"; }
+
+.fa-chevron-up:before {
+ content: "\f077"; }
+
+.fa-child:before {
+ content: "\f1ae"; }
+
+.fa-chrome:before {
+ content: "\f268"; }
+
+.fa-chromecast:before {
+ content: "\f838"; }
+
+.fa-church:before {
+ content: "\f51d"; }
+
+.fa-circle:before {
+ content: "\f111"; }
+
+.fa-circle-notch:before {
+ content: "\f1ce"; }
+
+.fa-city:before {
+ content: "\f64f"; }
+
+.fa-clinic-medical:before {
+ content: "\f7f2"; }
+
+.fa-clipboard:before {
+ content: "\f328"; }
+
+.fa-clipboard-check:before {
+ content: "\f46c"; }
+
+.fa-clipboard-list:before {
+ content: "\f46d"; }
+
+.fa-clock:before {
+ content: "\f017"; }
+
+.fa-clone:before {
+ content: "\f24d"; }
+
+.fa-closed-captioning:before {
+ content: "\f20a"; }
+
+.fa-cloud:before {
+ content: "\f0c2"; }
+
+.fa-cloud-download-alt:before {
+ content: "\f381"; }
+
+.fa-cloud-meatball:before {
+ content: "\f73b"; }
+
+.fa-cloud-moon:before {
+ content: "\f6c3"; }
+
+.fa-cloud-moon-rain:before {
+ content: "\f73c"; }
+
+.fa-cloud-rain:before {
+ content: "\f73d"; }
+
+.fa-cloud-showers-heavy:before {
+ content: "\f740"; }
+
+.fa-cloud-sun:before {
+ content: "\f6c4"; }
+
+.fa-cloud-sun-rain:before {
+ content: "\f743"; }
+
+.fa-cloud-upload-alt:before {
+ content: "\f382"; }
+
+.fa-cloudscale:before {
+ content: "\f383"; }
+
+.fa-cloudsmith:before {
+ content: "\f384"; }
+
+.fa-cloudversify:before {
+ content: "\f385"; }
+
+.fa-cocktail:before {
+ content: "\f561"; }
+
+.fa-code:before {
+ content: "\f121"; }
+
+.fa-code-branch:before {
+ content: "\f126"; }
+
+.fa-codepen:before {
+ content: "\f1cb"; }
+
+.fa-codiepie:before {
+ content: "\f284"; }
+
+.fa-coffee:before {
+ content: "\f0f4"; }
+
+.fa-cog:before {
+ content: "\f013"; }
+
+.fa-cogs:before {
+ content: "\f085"; }
+
+.fa-coins:before {
+ content: "\f51e"; }
+
+.fa-columns:before {
+ content: "\f0db"; }
+
+.fa-comment:before {
+ content: "\f075"; }
+
+.fa-comment-alt:before {
+ content: "\f27a"; }
+
+.fa-comment-dollar:before {
+ content: "\f651"; }
+
+.fa-comment-dots:before {
+ content: "\f4ad"; }
+
+.fa-comment-medical:before {
+ content: "\f7f5"; }
+
+.fa-comment-slash:before {
+ content: "\f4b3"; }
+
+.fa-comments:before {
+ content: "\f086"; }
+
+.fa-comments-dollar:before {
+ content: "\f653"; }
+
+.fa-compact-disc:before {
+ content: "\f51f"; }
+
+.fa-compass:before {
+ content: "\f14e"; }
+
+.fa-compress:before {
+ content: "\f066"; }
+
+.fa-compress-arrows-alt:before {
+ content: "\f78c"; }
+
+.fa-concierge-bell:before {
+ content: "\f562"; }
+
+.fa-confluence:before {
+ content: "\f78d"; }
+
+.fa-connectdevelop:before {
+ content: "\f20e"; }
+
+.fa-contao:before {
+ content: "\f26d"; }
+
+.fa-cookie:before {
+ content: "\f563"; }
+
+.fa-cookie-bite:before {
+ content: "\f564"; }
+
+.fa-copy:before {
+ content: "\f0c5"; }
+
+.fa-copyright:before {
+ content: "\f1f9"; }
+
+.fa-couch:before {
+ content: "\f4b8"; }
+
+.fa-cpanel:before {
+ content: "\f388"; }
+
+.fa-creative-commons:before {
+ content: "\f25e"; }
+
+.fa-creative-commons-by:before {
+ content: "\f4e7"; }
+
+.fa-creative-commons-nc:before {
+ content: "\f4e8"; }
+
+.fa-creative-commons-nc-eu:before {
+ content: "\f4e9"; }
+
+.fa-creative-commons-nc-jp:before {
+ content: "\f4ea"; }
+
+.fa-creative-commons-nd:before {
+ content: "\f4eb"; }
+
+.fa-creative-commons-pd:before {
+ content: "\f4ec"; }
+
+.fa-creative-commons-pd-alt:before {
+ content: "\f4ed"; }
+
+.fa-creative-commons-remix:before {
+ content: "\f4ee"; }
+
+.fa-creative-commons-sa:before {
+ content: "\f4ef"; }
+
+.fa-creative-commons-sampling:before {
+ content: "\f4f0"; }
+
+.fa-creative-commons-sampling-plus:before {
+ content: "\f4f1"; }
+
+.fa-creative-commons-share:before {
+ content: "\f4f2"; }
+
+.fa-creative-commons-zero:before {
+ content: "\f4f3"; }
+
+.fa-credit-card:before {
+ content: "\f09d"; }
+
+.fa-critical-role:before {
+ content: "\f6c9"; }
+
+.fa-crop:before {
+ content: "\f125"; }
+
+.fa-crop-alt:before {
+ content: "\f565"; }
+
+.fa-cross:before {
+ content: "\f654"; }
+
+.fa-crosshairs:before {
+ content: "\f05b"; }
+
+.fa-crow:before {
+ content: "\f520"; }
+
+.fa-crown:before {
+ content: "\f521"; }
+
+.fa-crutch:before {
+ content: "\f7f7"; }
+
+.fa-css3:before {
+ content: "\f13c"; }
+
+.fa-css3-alt:before {
+ content: "\f38b"; }
+
+.fa-cube:before {
+ content: "\f1b2"; }
+
+.fa-cubes:before {
+ content: "\f1b3"; }
+
+.fa-cut:before {
+ content: "\f0c4"; }
+
+.fa-cuttlefish:before {
+ content: "\f38c"; }
+
+.fa-d-and-d:before {
+ content: "\f38d"; }
+
+.fa-d-and-d-beyond:before {
+ content: "\f6ca"; }
+
+.fa-dashcube:before {
+ content: "\f210"; }
+
+.fa-database:before {
+ content: "\f1c0"; }
+
+.fa-deaf:before {
+ content: "\f2a4"; }
+
+.fa-delicious:before {
+ content: "\f1a5"; }
+
+.fa-democrat:before {
+ content: "\f747"; }
+
+.fa-deploydog:before {
+ content: "\f38e"; }
+
+.fa-deskpro:before {
+ content: "\f38f"; }
+
+.fa-desktop:before {
+ content: "\f108"; }
+
+.fa-dev:before {
+ content: "\f6cc"; }
+
+.fa-deviantart:before {
+ content: "\f1bd"; }
+
+.fa-dharmachakra:before {
+ content: "\f655"; }
+
+.fa-dhl:before {
+ content: "\f790"; }
+
+.fa-diagnoses:before {
+ content: "\f470"; }
+
+.fa-diaspora:before {
+ content: "\f791"; }
+
+.fa-dice:before {
+ content: "\f522"; }
+
+.fa-dice-d20:before {
+ content: "\f6cf"; }
+
+.fa-dice-d6:before {
+ content: "\f6d1"; }
+
+.fa-dice-five:before {
+ content: "\f523"; }
+
+.fa-dice-four:before {
+ content: "\f524"; }
+
+.fa-dice-one:before {
+ content: "\f525"; }
+
+.fa-dice-six:before {
+ content: "\f526"; }
+
+.fa-dice-three:before {
+ content: "\f527"; }
+
+.fa-dice-two:before {
+ content: "\f528"; }
+
+.fa-digg:before {
+ content: "\f1a6"; }
+
+.fa-digital-ocean:before {
+ content: "\f391"; }
+
+.fa-digital-tachograph:before {
+ content: "\f566"; }
+
+.fa-directions:before {
+ content: "\f5eb"; }
+
+.fa-discord:before {
+ content: "\f392"; }
+
+.fa-discourse:before {
+ content: "\f393"; }
+
+.fa-divide:before {
+ content: "\f529"; }
+
+.fa-dizzy:before {
+ content: "\f567"; }
+
+.fa-dna:before {
+ content: "\f471"; }
+
+.fa-dochub:before {
+ content: "\f394"; }
+
+.fa-docker:before {
+ content: "\f395"; }
+
+.fa-dog:before {
+ content: "\f6d3"; }
+
+.fa-dollar-sign:before {
+ content: "\f155"; }
+
+.fa-dolly:before {
+ content: "\f472"; }
+
+.fa-dolly-flatbed:before {
+ content: "\f474"; }
+
+.fa-donate:before {
+ content: "\f4b9"; }
+
+.fa-door-closed:before {
+ content: "\f52a"; }
+
+.fa-door-open:before {
+ content: "\f52b"; }
+
+.fa-dot-circle:before {
+ content: "\f192"; }
+
+.fa-dove:before {
+ content: "\f4ba"; }
+
+.fa-download:before {
+ content: "\f019"; }
+
+.fa-draft2digital:before {
+ content: "\f396"; }
+
+.fa-drafting-compass:before {
+ content: "\f568"; }
+
+.fa-dragon:before {
+ content: "\f6d5"; }
+
+.fa-draw-polygon:before {
+ content: "\f5ee"; }
+
+.fa-dribbble:before {
+ content: "\f17d"; }
+
+.fa-dribbble-square:before {
+ content: "\f397"; }
+
+.fa-dropbox:before {
+ content: "\f16b"; }
+
+.fa-drum:before {
+ content: "\f569"; }
+
+.fa-drum-steelpan:before {
+ content: "\f56a"; }
+
+.fa-drumstick-bite:before {
+ content: "\f6d7"; }
+
+.fa-drupal:before {
+ content: "\f1a9"; }
+
+.fa-dumbbell:before {
+ content: "\f44b"; }
+
+.fa-dumpster:before {
+ content: "\f793"; }
+
+.fa-dumpster-fire:before {
+ content: "\f794"; }
+
+.fa-dungeon:before {
+ content: "\f6d9"; }
+
+.fa-dyalog:before {
+ content: "\f399"; }
+
+.fa-earlybirds:before {
+ content: "\f39a"; }
+
+.fa-ebay:before {
+ content: "\f4f4"; }
+
+.fa-edge:before {
+ content: "\f282"; }
+
+.fa-edit:before {
+ content: "\f044"; }
+
+.fa-egg:before {
+ content: "\f7fb"; }
+
+.fa-eject:before {
+ content: "\f052"; }
+
+.fa-elementor:before {
+ content: "\f430"; }
+
+.fa-ellipsis-h:before {
+ content: "\f141"; }
+
+.fa-ellipsis-v:before {
+ content: "\f142"; }
+
+.fa-ello:before {
+ content: "\f5f1"; }
+
+.fa-ember:before {
+ content: "\f423"; }
+
+.fa-empire:before {
+ content: "\f1d1"; }
+
+.fa-envelope:before {
+ content: "\f0e0"; }
+
+.fa-envelope-open:before {
+ content: "\f2b6"; }
+
+.fa-envelope-open-text:before {
+ content: "\f658"; }
+
+.fa-envelope-square:before {
+ content: "\f199"; }
+
+.fa-envira:before {
+ content: "\f299"; }
+
+.fa-equals:before {
+ content: "\f52c"; }
+
+.fa-eraser:before {
+ content: "\f12d"; }
+
+.fa-erlang:before {
+ content: "\f39d"; }
+
+.fa-ethereum:before {
+ content: "\f42e"; }
+
+.fa-ethernet:before {
+ content: "\f796"; }
+
+.fa-etsy:before {
+ content: "\f2d7"; }
+
+.fa-euro-sign:before {
+ content: "\f153"; }
+
+.fa-evernote:before {
+ content: "\f839"; }
+
+.fa-exchange-alt:before {
+ content: "\f362"; }
+
+.fa-exclamation:before {
+ content: "\f12a"; }
+
+.fa-exclamation-circle:before {
+ content: "\f06a"; }
+
+.fa-exclamation-triangle:before {
+ content: "\f071"; }
+
+.fa-expand:before {
+ content: "\f065"; }
+
+.fa-expand-arrows-alt:before {
+ content: "\f31e"; }
+
+.fa-expeditedssl:before {
+ content: "\f23e"; }
+
+.fa-external-link-alt:before {
+ content: "\f35d"; }
+
+.fa-external-link-square-alt:before {
+ content: "\f360"; }
+
+.fa-eye:before {
+ content: "\f06e"; }
+
+.fa-eye-dropper:before {
+ content: "\f1fb"; }
+
+.fa-eye-slash:before {
+ content: "\f070"; }
+
+.fa-facebook:before {
+ content: "\f09a"; }
+
+.fa-facebook-f:before {
+ content: "\f39e"; }
+
+.fa-facebook-messenger:before {
+ content: "\f39f"; }
+
+.fa-facebook-square:before {
+ content: "\f082"; }
+
+.fa-fantasy-flight-games:before {
+ content: "\f6dc"; }
+
+.fa-fast-backward:before {
+ content: "\f049"; }
+
+.fa-fast-forward:before {
+ content: "\f050"; }
+
+.fa-fax:before {
+ content: "\f1ac"; }
+
+.fa-feather:before {
+ content: "\f52d"; }
+
+.fa-feather-alt:before {
+ content: "\f56b"; }
+
+.fa-fedex:before {
+ content: "\f797"; }
+
+.fa-fedora:before {
+ content: "\f798"; }
+
+.fa-female:before {
+ content: "\f182"; }
+
+.fa-fighter-jet:before {
+ content: "\f0fb"; }
+
+.fa-figma:before {
+ content: "\f799"; }
+
+.fa-file:before {
+ content: "\f15b"; }
+
+.fa-file-alt:before {
+ content: "\f15c"; }
+
+.fa-file-archive:before {
+ content: "\f1c6"; }
+
+.fa-file-audio:before {
+ content: "\f1c7"; }
+
+.fa-file-code:before {
+ content: "\f1c9"; }
+
+.fa-file-contract:before {
+ content: "\f56c"; }
+
+.fa-file-csv:before {
+ content: "\f6dd"; }
+
+.fa-file-download:before {
+ content: "\f56d"; }
+
+.fa-file-excel:before {
+ content: "\f1c3"; }
+
+.fa-file-export:before {
+ content: "\f56e"; }
+
+.fa-file-image:before {
+ content: "\f1c5"; }
+
+.fa-file-import:before {
+ content: "\f56f"; }
+
+.fa-file-invoice:before {
+ content: "\f570"; }
+
+.fa-file-invoice-dollar:before {
+ content: "\f571"; }
+
+.fa-file-medical:before {
+ content: "\f477"; }
+
+.fa-file-medical-alt:before {
+ content: "\f478"; }
+
+.fa-file-pdf:before {
+ content: "\f1c1"; }
+
+.fa-file-powerpoint:before {
+ content: "\f1c4"; }
+
+.fa-file-prescription:before {
+ content: "\f572"; }
+
+.fa-file-signature:before {
+ content: "\f573"; }
+
+.fa-file-upload:before {
+ content: "\f574"; }
+
+.fa-file-video:before {
+ content: "\f1c8"; }
+
+.fa-file-word:before {
+ content: "\f1c2"; }
+
+.fa-fill:before {
+ content: "\f575"; }
+
+.fa-fill-drip:before {
+ content: "\f576"; }
+
+.fa-film:before {
+ content: "\f008"; }
+
+.fa-filter:before {
+ content: "\f0b0"; }
+
+.fa-fingerprint:before {
+ content: "\f577"; }
+
+.fa-fire:before {
+ content: "\f06d"; }
+
+.fa-fire-alt:before {
+ content: "\f7e4"; }
+
+.fa-fire-extinguisher:before {
+ content: "\f134"; }
+
+.fa-firefox:before {
+ content: "\f269"; }
+
+.fa-first-aid:before {
+ content: "\f479"; }
+
+.fa-first-order:before {
+ content: "\f2b0"; }
+
+.fa-first-order-alt:before {
+ content: "\f50a"; }
+
+.fa-firstdraft:before {
+ content: "\f3a1"; }
+
+.fa-fish:before {
+ content: "\f578"; }
+
+.fa-fist-raised:before {
+ content: "\f6de"; }
+
+.fa-flag:before {
+ content: "\f024"; }
+
+.fa-flag-checkered:before {
+ content: "\f11e"; }
+
+.fa-flag-usa:before {
+ content: "\f74d"; }
+
+.fa-flask:before {
+ content: "\f0c3"; }
+
+.fa-flickr:before {
+ content: "\f16e"; }
+
+.fa-flipboard:before {
+ content: "\f44d"; }
+
+.fa-flushed:before {
+ content: "\f579"; }
+
+.fa-fly:before {
+ content: "\f417"; }
+
+.fa-folder:before {
+ content: "\f07b"; }
+
+.fa-folder-minus:before {
+ content: "\f65d"; }
+
+.fa-folder-open:before {
+ content: "\f07c"; }
+
+.fa-folder-plus:before {
+ content: "\f65e"; }
+
+.fa-font:before {
+ content: "\f031"; }
+
+.fa-font-awesome:before {
+ content: "\f2b4"; }
+
+.fa-font-awesome-alt:before {
+ content: "\f35c"; }
+
+.fa-font-awesome-flag:before {
+ content: "\f425"; }
+
+.fa-font-awesome-logo-full:before {
+ content: "\f4e6"; }
+
+.fa-fonticons:before {
+ content: "\f280"; }
+
+.fa-fonticons-fi:before {
+ content: "\f3a2"; }
+
+.fa-football-ball:before {
+ content: "\f44e"; }
+
+.fa-fort-awesome:before {
+ content: "\f286"; }
+
+.fa-fort-awesome-alt:before {
+ content: "\f3a3"; }
+
+.fa-forumbee:before {
+ content: "\f211"; }
+
+.fa-forward:before {
+ content: "\f04e"; }
+
+.fa-foursquare:before {
+ content: "\f180"; }
+
+.fa-free-code-camp:before {
+ content: "\f2c5"; }
+
+.fa-freebsd:before {
+ content: "\f3a4"; }
+
+.fa-frog:before {
+ content: "\f52e"; }
+
+.fa-frown:before {
+ content: "\f119"; }
+
+.fa-frown-open:before {
+ content: "\f57a"; }
+
+.fa-fulcrum:before {
+ content: "\f50b"; }
+
+.fa-funnel-dollar:before {
+ content: "\f662"; }
+
+.fa-futbol:before {
+ content: "\f1e3"; }
+
+.fa-galactic-republic:before {
+ content: "\f50c"; }
+
+.fa-galactic-senate:before {
+ content: "\f50d"; }
+
+.fa-gamepad:before {
+ content: "\f11b"; }
+
+.fa-gas-pump:before {
+ content: "\f52f"; }
+
+.fa-gavel:before {
+ content: "\f0e3"; }
+
+.fa-gem:before {
+ content: "\f3a5"; }
+
+.fa-genderless:before {
+ content: "\f22d"; }
+
+.fa-get-pocket:before {
+ content: "\f265"; }
+
+.fa-gg:before {
+ content: "\f260"; }
+
+.fa-gg-circle:before {
+ content: "\f261"; }
+
+.fa-ghost:before {
+ content: "\f6e2"; }
+
+.fa-gift:before {
+ content: "\f06b"; }
+
+.fa-gifts:before {
+ content: "\f79c"; }
+
+.fa-git:before {
+ content: "\f1d3"; }
+
+.fa-git-alt:before {
+ content: "\f841"; }
+
+.fa-git-square:before {
+ content: "\f1d2"; }
+
+.fa-github:before {
+ content: "\f09b"; }
+
+.fa-github-alt:before {
+ content: "\f113"; }
+
+.fa-github-square:before {
+ content: "\f092"; }
+
+.fa-gitkraken:before {
+ content: "\f3a6"; }
+
+.fa-gitlab:before {
+ content: "\f296"; }
+
+.fa-gitter:before {
+ content: "\f426"; }
+
+.fa-glass-cheers:before {
+ content: "\f79f"; }
+
+.fa-glass-martini:before {
+ content: "\f000"; }
+
+.fa-glass-martini-alt:before {
+ content: "\f57b"; }
+
+.fa-glass-whiskey:before {
+ content: "\f7a0"; }
+
+.fa-glasses:before {
+ content: "\f530"; }
+
+.fa-glide:before {
+ content: "\f2a5"; }
+
+.fa-glide-g:before {
+ content: "\f2a6"; }
+
+.fa-globe:before {
+ content: "\f0ac"; }
+
+.fa-globe-africa:before {
+ content: "\f57c"; }
+
+.fa-globe-americas:before {
+ content: "\f57d"; }
+
+.fa-globe-asia:before {
+ content: "\f57e"; }
+
+.fa-globe-europe:before {
+ content: "\f7a2"; }
+
+.fa-gofore:before {
+ content: "\f3a7"; }
+
+.fa-golf-ball:before {
+ content: "\f450"; }
+
+.fa-goodreads:before {
+ content: "\f3a8"; }
+
+.fa-goodreads-g:before {
+ content: "\f3a9"; }
+
+.fa-google:before {
+ content: "\f1a0"; }
+
+.fa-google-drive:before {
+ content: "\f3aa"; }
+
+.fa-google-play:before {
+ content: "\f3ab"; }
+
+.fa-google-plus:before {
+ content: "\f2b3"; }
+
+.fa-google-plus-g:before {
+ content: "\f0d5"; }
+
+.fa-google-plus-square:before {
+ content: "\f0d4"; }
+
+.fa-google-wallet:before {
+ content: "\f1ee"; }
+
+.fa-gopuram:before {
+ content: "\f664"; }
+
+.fa-graduation-cap:before {
+ content: "\f19d"; }
+
+.fa-gratipay:before {
+ content: "\f184"; }
+
+.fa-grav:before {
+ content: "\f2d6"; }
+
+.fa-greater-than:before {
+ content: "\f531"; }
+
+.fa-greater-than-equal:before {
+ content: "\f532"; }
+
+.fa-grimace:before {
+ content: "\f57f"; }
+
+.fa-grin:before {
+ content: "\f580"; }
+
+.fa-grin-alt:before {
+ content: "\f581"; }
+
+.fa-grin-beam:before {
+ content: "\f582"; }
+
+.fa-grin-beam-sweat:before {
+ content: "\f583"; }
+
+.fa-grin-hearts:before {
+ content: "\f584"; }
+
+.fa-grin-squint:before {
+ content: "\f585"; }
+
+.fa-grin-squint-tears:before {
+ content: "\f586"; }
+
+.fa-grin-stars:before {
+ content: "\f587"; }
+
+.fa-grin-tears:before {
+ content: "\f588"; }
+
+.fa-grin-tongue:before {
+ content: "\f589"; }
+
+.fa-grin-tongue-squint:before {
+ content: "\f58a"; }
+
+.fa-grin-tongue-wink:before {
+ content: "\f58b"; }
+
+.fa-grin-wink:before {
+ content: "\f58c"; }
+
+.fa-grip-horizontal:before {
+ content: "\f58d"; }
+
+.fa-grip-lines:before {
+ content: "\f7a4"; }
+
+.fa-grip-lines-vertical:before {
+ content: "\f7a5"; }
+
+.fa-grip-vertical:before {
+ content: "\f58e"; }
+
+.fa-gripfire:before {
+ content: "\f3ac"; }
+
+.fa-grunt:before {
+ content: "\f3ad"; }
+
+.fa-guitar:before {
+ content: "\f7a6"; }
+
+.fa-gulp:before {
+ content: "\f3ae"; }
+
+.fa-h-square:before {
+ content: "\f0fd"; }
+
+.fa-hacker-news:before {
+ content: "\f1d4"; }
+
+.fa-hacker-news-square:before {
+ content: "\f3af"; }
+
+.fa-hackerrank:before {
+ content: "\f5f7"; }
+
+.fa-hamburger:before {
+ content: "\f805"; }
+
+.fa-hammer:before {
+ content: "\f6e3"; }
+
+.fa-hamsa:before {
+ content: "\f665"; }
+
+.fa-hand-holding:before {
+ content: "\f4bd"; }
+
+.fa-hand-holding-heart:before {
+ content: "\f4be"; }
+
+.fa-hand-holding-usd:before {
+ content: "\f4c0"; }
+
+.fa-hand-lizard:before {
+ content: "\f258"; }
+
+.fa-hand-middle-finger:before {
+ content: "\f806"; }
+
+.fa-hand-paper:before {
+ content: "\f256"; }
+
+.fa-hand-peace:before {
+ content: "\f25b"; }
+
+.fa-hand-point-down:before {
+ content: "\f0a7"; }
+
+.fa-hand-point-left:before {
+ content: "\f0a5"; }
+
+.fa-hand-point-right:before {
+ content: "\f0a4"; }
+
+.fa-hand-point-up:before {
+ content: "\f0a6"; }
+
+.fa-hand-pointer:before {
+ content: "\f25a"; }
+
+.fa-hand-rock:before {
+ content: "\f255"; }
+
+.fa-hand-scissors:before {
+ content: "\f257"; }
+
+.fa-hand-spock:before {
+ content: "\f259"; }
+
+.fa-hands:before {
+ content: "\f4c2"; }
+
+.fa-hands-helping:before {
+ content: "\f4c4"; }
+
+.fa-handshake:before {
+ content: "\f2b5"; }
+
+.fa-hanukiah:before {
+ content: "\f6e6"; }
+
+.fa-hard-hat:before {
+ content: "\f807"; }
+
+.fa-hashtag:before {
+ content: "\f292"; }
+
+.fa-hat-wizard:before {
+ content: "\f6e8"; }
+
+.fa-haykal:before {
+ content: "\f666"; }
+
+.fa-hdd:before {
+ content: "\f0a0"; }
+
+.fa-heading:before {
+ content: "\f1dc"; }
+
+.fa-headphones:before {
+ content: "\f025"; }
+
+.fa-headphones-alt:before {
+ content: "\f58f"; }
+
+.fa-headset:before {
+ content: "\f590"; }
+
+.fa-heart:before {
+ content: "\f004"; }
+
+.fa-heart-broken:before {
+ content: "\f7a9"; }
+
+.fa-heartbeat:before {
+ content: "\f21e"; }
+
+.fa-helicopter:before {
+ content: "\f533"; }
+
+.fa-highlighter:before {
+ content: "\f591"; }
+
+.fa-hiking:before {
+ content: "\f6ec"; }
+
+.fa-hippo:before {
+ content: "\f6ed"; }
+
+.fa-hips:before {
+ content: "\f452"; }
+
+.fa-hire-a-helper:before {
+ content: "\f3b0"; }
+
+.fa-history:before {
+ content: "\f1da"; }
+
+.fa-hockey-puck:before {
+ content: "\f453"; }
+
+.fa-holly-berry:before {
+ content: "\f7aa"; }
+
+.fa-home:before {
+ content: "\f015"; }
+
+.fa-hooli:before {
+ content: "\f427"; }
+
+.fa-hornbill:before {
+ content: "\f592"; }
+
+.fa-horse:before {
+ content: "\f6f0"; }
+
+.fa-horse-head:before {
+ content: "\f7ab"; }
+
+.fa-hospital:before {
+ content: "\f0f8"; }
+
+.fa-hospital-alt:before {
+ content: "\f47d"; }
+
+.fa-hospital-symbol:before {
+ content: "\f47e"; }
+
+.fa-hot-tub:before {
+ content: "\f593"; }
+
+.fa-hotdog:before {
+ content: "\f80f"; }
+
+.fa-hotel:before {
+ content: "\f594"; }
+
+.fa-hotjar:before {
+ content: "\f3b1"; }
+
+.fa-hourglass:before {
+ content: "\f254"; }
+
+.fa-hourglass-end:before {
+ content: "\f253"; }
+
+.fa-hourglass-half:before {
+ content: "\f252"; }
+
+.fa-hourglass-start:before {
+ content: "\f251"; }
+
+.fa-house-damage:before {
+ content: "\f6f1"; }
+
+.fa-houzz:before {
+ content: "\f27c"; }
+
+.fa-hryvnia:before {
+ content: "\f6f2"; }
+
+.fa-html5:before {
+ content: "\f13b"; }
+
+.fa-hubspot:before {
+ content: "\f3b2"; }
+
+.fa-i-cursor:before {
+ content: "\f246"; }
+
+.fa-ice-cream:before {
+ content: "\f810"; }
+
+.fa-icicles:before {
+ content: "\f7ad"; }
+
+.fa-id-badge:before {
+ content: "\f2c1"; }
+
+.fa-id-card:before {
+ content: "\f2c2"; }
+
+.fa-id-card-alt:before {
+ content: "\f47f"; }
+
+.fa-igloo:before {
+ content: "\f7ae"; }
+
+.fa-image:before {
+ content: "\f03e"; }
+
+.fa-images:before {
+ content: "\f302"; }
+
+.fa-imdb:before {
+ content: "\f2d8"; }
+
+.fa-inbox:before {
+ content: "\f01c"; }
+
+.fa-indent:before {
+ content: "\f03c"; }
+
+.fa-industry:before {
+ content: "\f275"; }
+
+.fa-infinity:before {
+ content: "\f534"; }
+
+.fa-info:before {
+ content: "\f129"; }
+
+.fa-info-circle:before {
+ content: "\f05a"; }
+
+.fa-instagram:before {
+ content: "\f16d"; }
+
+.fa-intercom:before {
+ content: "\f7af"; }
+
+.fa-internet-explorer:before {
+ content: "\f26b"; }
+
+.fa-invision:before {
+ content: "\f7b0"; }
+
+.fa-ioxhost:before {
+ content: "\f208"; }
+
+.fa-italic:before {
+ content: "\f033"; }
+
+.fa-itch-io:before {
+ content: "\f83a"; }
+
+.fa-itunes:before {
+ content: "\f3b4"; }
+
+.fa-itunes-note:before {
+ content: "\f3b5"; }
+
+.fa-java:before {
+ content: "\f4e4"; }
+
+.fa-jedi:before {
+ content: "\f669"; }
+
+.fa-jedi-order:before {
+ content: "\f50e"; }
+
+.fa-jenkins:before {
+ content: "\f3b6"; }
+
+.fa-jira:before {
+ content: "\f7b1"; }
+
+.fa-joget:before {
+ content: "\f3b7"; }
+
+.fa-joint:before {
+ content: "\f595"; }
+
+.fa-joomla:before {
+ content: "\f1aa"; }
+
+.fa-journal-whills:before {
+ content: "\f66a"; }
+
+.fa-js:before {
+ content: "\f3b8"; }
+
+.fa-js-square:before {
+ content: "\f3b9"; }
+
+.fa-jsfiddle:before {
+ content: "\f1cc"; }
+
+.fa-kaaba:before {
+ content: "\f66b"; }
+
+.fa-kaggle:before {
+ content: "\f5fa"; }
+
+.fa-key:before {
+ content: "\f084"; }
+
+.fa-keybase:before {
+ content: "\f4f5"; }
+
+.fa-keyboard:before {
+ content: "\f11c"; }
+
+.fa-keycdn:before {
+ content: "\f3ba"; }
+
+.fa-khanda:before {
+ content: "\f66d"; }
+
+.fa-kickstarter:before {
+ content: "\f3bb"; }
+
+.fa-kickstarter-k:before {
+ content: "\f3bc"; }
+
+.fa-kiss:before {
+ content: "\f596"; }
+
+.fa-kiss-beam:before {
+ content: "\f597"; }
+
+.fa-kiss-wink-heart:before {
+ content: "\f598"; }
+
+.fa-kiwi-bird:before {
+ content: "\f535"; }
+
+.fa-korvue:before {
+ content: "\f42f"; }
+
+.fa-landmark:before {
+ content: "\f66f"; }
+
+.fa-language:before {
+ content: "\f1ab"; }
+
+.fa-laptop:before {
+ content: "\f109"; }
+
+.fa-laptop-code:before {
+ content: "\f5fc"; }
+
+.fa-laptop-medical:before {
+ content: "\f812"; }
+
+.fa-laravel:before {
+ content: "\f3bd"; }
+
+.fa-lastfm:before {
+ content: "\f202"; }
+
+.fa-lastfm-square:before {
+ content: "\f203"; }
+
+.fa-laugh:before {
+ content: "\f599"; }
+
+.fa-laugh-beam:before {
+ content: "\f59a"; }
+
+.fa-laugh-squint:before {
+ content: "\f59b"; }
+
+.fa-laugh-wink:before {
+ content: "\f59c"; }
+
+.fa-layer-group:before {
+ content: "\f5fd"; }
+
+.fa-leaf:before {
+ content: "\f06c"; }
+
+.fa-leanpub:before {
+ content: "\f212"; }
+
+.fa-lemon:before {
+ content: "\f094"; }
+
+.fa-less:before {
+ content: "\f41d"; }
+
+.fa-less-than:before {
+ content: "\f536"; }
+
+.fa-less-than-equal:before {
+ content: "\f537"; }
+
+.fa-level-down-alt:before {
+ content: "\f3be"; }
+
+.fa-level-up-alt:before {
+ content: "\f3bf"; }
+
+.fa-life-ring:before {
+ content: "\f1cd"; }
+
+.fa-lightbulb:before {
+ content: "\f0eb"; }
+
+.fa-line:before {
+ content: "\f3c0"; }
+
+.fa-link:before {
+ content: "\f0c1"; }
+
+.fa-linkedin:before {
+ content: "\f08c"; }
+
+.fa-linkedin-in:before {
+ content: "\f0e1"; }
+
+.fa-linode:before {
+ content: "\f2b8"; }
+
+.fa-linux:before {
+ content: "\f17c"; }
+
+.fa-lira-sign:before {
+ content: "\f195"; }
+
+.fa-list:before {
+ content: "\f03a"; }
+
+.fa-list-alt:before {
+ content: "\f022"; }
+
+.fa-list-ol:before {
+ content: "\f0cb"; }
+
+.fa-list-ul:before {
+ content: "\f0ca"; }
+
+.fa-location-arrow:before {
+ content: "\f124"; }
+
+.fa-lock:before {
+ content: "\f023"; }
+
+.fa-lock-open:before {
+ content: "\f3c1"; }
+
+.fa-long-arrow-alt-down:before {
+ content: "\f309"; }
+
+.fa-long-arrow-alt-left:before {
+ content: "\f30a"; }
+
+.fa-long-arrow-alt-right:before {
+ content: "\f30b"; }
+
+.fa-long-arrow-alt-up:before {
+ content: "\f30c"; }
+
+.fa-low-vision:before {
+ content: "\f2a8"; }
+
+.fa-luggage-cart:before {
+ content: "\f59d"; }
+
+.fa-lyft:before {
+ content: "\f3c3"; }
+
+.fa-magento:before {
+ content: "\f3c4"; }
+
+.fa-magic:before {
+ content: "\f0d0"; }
+
+.fa-magnet:before {
+ content: "\f076"; }
+
+.fa-mail-bulk:before {
+ content: "\f674"; }
+
+.fa-mailchimp:before {
+ content: "\f59e"; }
+
+.fa-male:before {
+ content: "\f183"; }
+
+.fa-mandalorian:before {
+ content: "\f50f"; }
+
+.fa-map:before {
+ content: "\f279"; }
+
+.fa-map-marked:before {
+ content: "\f59f"; }
+
+.fa-map-marked-alt:before {
+ content: "\f5a0"; }
+
+.fa-map-marker:before {
+ content: "\f041"; }
+
+.fa-map-marker-alt:before {
+ content: "\f3c5"; }
+
+.fa-map-pin:before {
+ content: "\f276"; }
+
+.fa-map-signs:before {
+ content: "\f277"; }
+
+.fa-markdown:before {
+ content: "\f60f"; }
+
+.fa-marker:before {
+ content: "\f5a1"; }
+
+.fa-mars:before {
+ content: "\f222"; }
+
+.fa-mars-double:before {
+ content: "\f227"; }
+
+.fa-mars-stroke:before {
+ content: "\f229"; }
+
+.fa-mars-stroke-h:before {
+ content: "\f22b"; }
+
+.fa-mars-stroke-v:before {
+ content: "\f22a"; }
+
+.fa-mask:before {
+ content: "\f6fa"; }
+
+.fa-mastodon:before {
+ content: "\f4f6"; }
+
+.fa-maxcdn:before {
+ content: "\f136"; }
+
+.fa-medal:before {
+ content: "\f5a2"; }
+
+.fa-medapps:before {
+ content: "\f3c6"; }
+
+.fa-medium:before {
+ content: "\f23a"; }
+
+.fa-medium-m:before {
+ content: "\f3c7"; }
+
+.fa-medkit:before {
+ content: "\f0fa"; }
+
+.fa-medrt:before {
+ content: "\f3c8"; }
+
+.fa-meetup:before {
+ content: "\f2e0"; }
+
+.fa-megaport:before {
+ content: "\f5a3"; }
+
+.fa-meh:before {
+ content: "\f11a"; }
+
+.fa-meh-blank:before {
+ content: "\f5a4"; }
+
+.fa-meh-rolling-eyes:before {
+ content: "\f5a5"; }
+
+.fa-memory:before {
+ content: "\f538"; }
+
+.fa-mendeley:before {
+ content: "\f7b3"; }
+
+.fa-menorah:before {
+ content: "\f676"; }
+
+.fa-mercury:before {
+ content: "\f223"; }
+
+.fa-meteor:before {
+ content: "\f753"; }
+
+.fa-microchip:before {
+ content: "\f2db"; }
+
+.fa-microphone:before {
+ content: "\f130"; }
+
+.fa-microphone-alt:before {
+ content: "\f3c9"; }
+
+.fa-microphone-alt-slash:before {
+ content: "\f539"; }
+
+.fa-microphone-slash:before {
+ content: "\f131"; }
+
+.fa-microscope:before {
+ content: "\f610"; }
+
+.fa-microsoft:before {
+ content: "\f3ca"; }
+
+.fa-minus:before {
+ content: "\f068"; }
+
+.fa-minus-circle:before {
+ content: "\f056"; }
+
+.fa-minus-square:before {
+ content: "\f146"; }
+
+.fa-mitten:before {
+ content: "\f7b5"; }
+
+.fa-mix:before {
+ content: "\f3cb"; }
+
+.fa-mixcloud:before {
+ content: "\f289"; }
+
+.fa-mizuni:before {
+ content: "\f3cc"; }
+
+.fa-mobile:before {
+ content: "\f10b"; }
+
+.fa-mobile-alt:before {
+ content: "\f3cd"; }
+
+.fa-modx:before {
+ content: "\f285"; }
+
+.fa-monero:before {
+ content: "\f3d0"; }
+
+.fa-money-bill:before {
+ content: "\f0d6"; }
+
+.fa-money-bill-alt:before {
+ content: "\f3d1"; }
+
+.fa-money-bill-wave:before {
+ content: "\f53a"; }
+
+.fa-money-bill-wave-alt:before {
+ content: "\f53b"; }
+
+.fa-money-check:before {
+ content: "\f53c"; }
+
+.fa-money-check-alt:before {
+ content: "\f53d"; }
+
+.fa-monument:before {
+ content: "\f5a6"; }
+
+.fa-moon:before {
+ content: "\f186"; }
+
+.fa-mortar-pestle:before {
+ content: "\f5a7"; }
+
+.fa-mosque:before {
+ content: "\f678"; }
+
+.fa-motorcycle:before {
+ content: "\f21c"; }
+
+.fa-mountain:before {
+ content: "\f6fc"; }
+
+.fa-mouse-pointer:before {
+ content: "\f245"; }
+
+.fa-mug-hot:before {
+ content: "\f7b6"; }
+
+.fa-music:before {
+ content: "\f001"; }
+
+.fa-napster:before {
+ content: "\f3d2"; }
+
+.fa-neos:before {
+ content: "\f612"; }
+
+.fa-network-wired:before {
+ content: "\f6ff"; }
+
+.fa-neuter:before {
+ content: "\f22c"; }
+
+.fa-newspaper:before {
+ content: "\f1ea"; }
+
+.fa-nimblr:before {
+ content: "\f5a8"; }
+
+.fa-nintendo-switch:before {
+ content: "\f418"; }
+
+.fa-node:before {
+ content: "\f419"; }
+
+.fa-node-js:before {
+ content: "\f3d3"; }
+
+.fa-not-equal:before {
+ content: "\f53e"; }
+
+.fa-notes-medical:before {
+ content: "\f481"; }
+
+.fa-npm:before {
+ content: "\f3d4"; }
+
+.fa-ns8:before {
+ content: "\f3d5"; }
+
+.fa-nutritionix:before {
+ content: "\f3d6"; }
+
+.fa-object-group:before {
+ content: "\f247"; }
+
+.fa-object-ungroup:before {
+ content: "\f248"; }
+
+.fa-odnoklassniki:before {
+ content: "\f263"; }
+
+.fa-odnoklassniki-square:before {
+ content: "\f264"; }
+
+.fa-oil-can:before {
+ content: "\f613"; }
+
+.fa-old-republic:before {
+ content: "\f510"; }
+
+.fa-om:before {
+ content: "\f679"; }
+
+.fa-opencart:before {
+ content: "\f23d"; }
+
+.fa-openid:before {
+ content: "\f19b"; }
+
+.fa-opera:before {
+ content: "\f26a"; }
+
+.fa-optin-monster:before {
+ content: "\f23c"; }
+
+.fa-osi:before {
+ content: "\f41a"; }
+
+.fa-otter:before {
+ content: "\f700"; }
+
+.fa-outdent:before {
+ content: "\f03b"; }
+
+.fa-page4:before {
+ content: "\f3d7"; }
+
+.fa-pagelines:before {
+ content: "\f18c"; }
+
+.fa-pager:before {
+ content: "\f815"; }
+
+.fa-paint-brush:before {
+ content: "\f1fc"; }
+
+.fa-paint-roller:before {
+ content: "\f5aa"; }
+
+.fa-palette:before {
+ content: "\f53f"; }
+
+.fa-palfed:before {
+ content: "\f3d8"; }
+
+.fa-pallet:before {
+ content: "\f482"; }
+
+.fa-paper-plane:before {
+ content: "\f1d8"; }
+
+.fa-paperclip:before {
+ content: "\f0c6"; }
+
+.fa-parachute-box:before {
+ content: "\f4cd"; }
+
+.fa-paragraph:before {
+ content: "\f1dd"; }
+
+.fa-parking:before {
+ content: "\f540"; }
+
+.fa-passport:before {
+ content: "\f5ab"; }
+
+.fa-pastafarianism:before {
+ content: "\f67b"; }
+
+.fa-paste:before {
+ content: "\f0ea"; }
+
+.fa-patreon:before {
+ content: "\f3d9"; }
+
+.fa-pause:before {
+ content: "\f04c"; }
+
+.fa-pause-circle:before {
+ content: "\f28b"; }
+
+.fa-paw:before {
+ content: "\f1b0"; }
+
+.fa-paypal:before {
+ content: "\f1ed"; }
+
+.fa-peace:before {
+ content: "\f67c"; }
+
+.fa-pen:before {
+ content: "\f304"; }
+
+.fa-pen-alt:before {
+ content: "\f305"; }
+
+.fa-pen-fancy:before {
+ content: "\f5ac"; }
+
+.fa-pen-nib:before {
+ content: "\f5ad"; }
+
+.fa-pen-square:before {
+ content: "\f14b"; }
+
+.fa-pencil-alt:before {
+ content: "\f303"; }
+
+.fa-pencil-ruler:before {
+ content: "\f5ae"; }
+
+.fa-penny-arcade:before {
+ content: "\f704"; }
+
+.fa-people-carry:before {
+ content: "\f4ce"; }
+
+.fa-pepper-hot:before {
+ content: "\f816"; }
+
+.fa-percent:before {
+ content: "\f295"; }
+
+.fa-percentage:before {
+ content: "\f541"; }
+
+.fa-periscope:before {
+ content: "\f3da"; }
+
+.fa-person-booth:before {
+ content: "\f756"; }
+
+.fa-phabricator:before {
+ content: "\f3db"; }
+
+.fa-phoenix-framework:before {
+ content: "\f3dc"; }
+
+.fa-phoenix-squadron:before {
+ content: "\f511"; }
+
+.fa-phone:before {
+ content: "\f095"; }
+
+.fa-phone-slash:before {
+ content: "\f3dd"; }
+
+.fa-phone-square:before {
+ content: "\f098"; }
+
+.fa-phone-volume:before {
+ content: "\f2a0"; }
+
+.fa-php:before {
+ content: "\f457"; }
+
+.fa-pied-piper:before {
+ content: "\f2ae"; }
+
+.fa-pied-piper-alt:before {
+ content: "\f1a8"; }
+
+.fa-pied-piper-hat:before {
+ content: "\f4e5"; }
+
+.fa-pied-piper-pp:before {
+ content: "\f1a7"; }
+
+.fa-piggy-bank:before {
+ content: "\f4d3"; }
+
+.fa-pills:before {
+ content: "\f484"; }
+
+.fa-pinterest:before {
+ content: "\f0d2"; }
+
+.fa-pinterest-p:before {
+ content: "\f231"; }
+
+.fa-pinterest-square:before {
+ content: "\f0d3"; }
+
+.fa-pizza-slice:before {
+ content: "\f818"; }
+
+.fa-place-of-worship:before {
+ content: "\f67f"; }
+
+.fa-plane:before {
+ content: "\f072"; }
+
+.fa-plane-arrival:before {
+ content: "\f5af"; }
+
+.fa-plane-departure:before {
+ content: "\f5b0"; }
+
+.fa-play:before {
+ content: "\f04b"; }
+
+.fa-play-circle:before {
+ content: "\f144"; }
+
+.fa-playstation:before {
+ content: "\f3df"; }
+
+.fa-plug:before {
+ content: "\f1e6"; }
+
+.fa-plus:before {
+ content: "\f067"; }
+
+.fa-plus-circle:before {
+ content: "\f055"; }
+
+.fa-plus-square:before {
+ content: "\f0fe"; }
+
+.fa-podcast:before {
+ content: "\f2ce"; }
+
+.fa-poll:before {
+ content: "\f681"; }
+
+.fa-poll-h:before {
+ content: "\f682"; }
+
+.fa-poo:before {
+ content: "\f2fe"; }
+
+.fa-poo-storm:before {
+ content: "\f75a"; }
+
+.fa-poop:before {
+ content: "\f619"; }
+
+.fa-portrait:before {
+ content: "\f3e0"; }
+
+.fa-pound-sign:before {
+ content: "\f154"; }
+
+.fa-power-off:before {
+ content: "\f011"; }
+
+.fa-pray:before {
+ content: "\f683"; }
+
+.fa-praying-hands:before {
+ content: "\f684"; }
+
+.fa-prescription:before {
+ content: "\f5b1"; }
+
+.fa-prescription-bottle:before {
+ content: "\f485"; }
+
+.fa-prescription-bottle-alt:before {
+ content: "\f486"; }
+
+.fa-print:before {
+ content: "\f02f"; }
+
+.fa-procedures:before {
+ content: "\f487"; }
+
+.fa-product-hunt:before {
+ content: "\f288"; }
+
+.fa-project-diagram:before {
+ content: "\f542"; }
+
+.fa-pushed:before {
+ content: "\f3e1"; }
+
+.fa-puzzle-piece:before {
+ content: "\f12e"; }
+
+.fa-python:before {
+ content: "\f3e2"; }
+
+.fa-qq:before {
+ content: "\f1d6"; }
+
+.fa-qrcode:before {
+ content: "\f029"; }
+
+.fa-question:before {
+ content: "\f128"; }
+
+.fa-question-circle:before {
+ content: "\f059"; }
+
+.fa-quidditch:before {
+ content: "\f458"; }
+
+.fa-quinscape:before {
+ content: "\f459"; }
+
+.fa-quora:before {
+ content: "\f2c4"; }
+
+.fa-quote-left:before {
+ content: "\f10d"; }
+
+.fa-quote-right:before {
+ content: "\f10e"; }
+
+.fa-quran:before {
+ content: "\f687"; }
+
+.fa-r-project:before {
+ content: "\f4f7"; }
+
+.fa-radiation:before {
+ content: "\f7b9"; }
+
+.fa-radiation-alt:before {
+ content: "\f7ba"; }
+
+.fa-rainbow:before {
+ content: "\f75b"; }
+
+.fa-random:before {
+ content: "\f074"; }
+
+.fa-raspberry-pi:before {
+ content: "\f7bb"; }
+
+.fa-ravelry:before {
+ content: "\f2d9"; }
+
+.fa-react:before {
+ content: "\f41b"; }
+
+.fa-reacteurope:before {
+ content: "\f75d"; }
+
+.fa-readme:before {
+ content: "\f4d5"; }
+
+.fa-rebel:before {
+ content: "\f1d0"; }
+
+.fa-receipt:before {
+ content: "\f543"; }
+
+.fa-recycle:before {
+ content: "\f1b8"; }
+
+.fa-red-river:before {
+ content: "\f3e3"; }
+
+.fa-reddit:before {
+ content: "\f1a1"; }
+
+.fa-reddit-alien:before {
+ content: "\f281"; }
+
+.fa-reddit-square:before {
+ content: "\f1a2"; }
+
+.fa-redhat:before {
+ content: "\f7bc"; }
+
+.fa-redo:before {
+ content: "\f01e"; }
+
+.fa-redo-alt:before {
+ content: "\f2f9"; }
+
+.fa-registered:before {
+ content: "\f25d"; }
+
+.fa-renren:before {
+ content: "\f18b"; }
+
+.fa-reply:before {
+ content: "\f3e5"; }
+
+.fa-reply-all:before {
+ content: "\f122"; }
+
+.fa-replyd:before {
+ content: "\f3e6"; }
+
+.fa-republican:before {
+ content: "\f75e"; }
+
+.fa-researchgate:before {
+ content: "\f4f8"; }
+
+.fa-resolving:before {
+ content: "\f3e7"; }
+
+.fa-restroom:before {
+ content: "\f7bd"; }
+
+.fa-retweet:before {
+ content: "\f079"; }
+
+.fa-rev:before {
+ content: "\f5b2"; }
+
+.fa-ribbon:before {
+ content: "\f4d6"; }
+
+.fa-ring:before {
+ content: "\f70b"; }
+
+.fa-road:before {
+ content: "\f018"; }
+
+.fa-robot:before {
+ content: "\f544"; }
+
+.fa-rocket:before {
+ content: "\f135"; }
+
+.fa-rocketchat:before {
+ content: "\f3e8"; }
+
+.fa-rockrms:before {
+ content: "\f3e9"; }
+
+.fa-route:before {
+ content: "\f4d7"; }
+
+.fa-rss:before {
+ content: "\f09e"; }
+
+.fa-rss-square:before {
+ content: "\f143"; }
+
+.fa-ruble-sign:before {
+ content: "\f158"; }
+
+.fa-ruler:before {
+ content: "\f545"; }
+
+.fa-ruler-combined:before {
+ content: "\f546"; }
+
+.fa-ruler-horizontal:before {
+ content: "\f547"; }
+
+.fa-ruler-vertical:before {
+ content: "\f548"; }
+
+.fa-running:before {
+ content: "\f70c"; }
+
+.fa-rupee-sign:before {
+ content: "\f156"; }
+
+.fa-sad-cry:before {
+ content: "\f5b3"; }
+
+.fa-sad-tear:before {
+ content: "\f5b4"; }
+
+.fa-safari:before {
+ content: "\f267"; }
+
+.fa-salesforce:before {
+ content: "\f83b"; }
+
+.fa-sass:before {
+ content: "\f41e"; }
+
+.fa-satellite:before {
+ content: "\f7bf"; }
+
+.fa-satellite-dish:before {
+ content: "\f7c0"; }
+
+.fa-save:before {
+ content: "\f0c7"; }
+
+.fa-schlix:before {
+ content: "\f3ea"; }
+
+.fa-school:before {
+ content: "\f549"; }
+
+.fa-screwdriver:before {
+ content: "\f54a"; }
+
+.fa-scribd:before {
+ content: "\f28a"; }
+
+.fa-scroll:before {
+ content: "\f70e"; }
+
+.fa-sd-card:before {
+ content: "\f7c2"; }
+
+.fa-search:before {
+ content: "\f002"; }
+
+.fa-search-dollar:before {
+ content: "\f688"; }
+
+.fa-search-location:before {
+ content: "\f689"; }
+
+.fa-search-minus:before {
+ content: "\f010"; }
+
+.fa-search-plus:before {
+ content: "\f00e"; }
+
+.fa-searchengin:before {
+ content: "\f3eb"; }
+
+.fa-seedling:before {
+ content: "\f4d8"; }
+
+.fa-sellcast:before {
+ content: "\f2da"; }
+
+.fa-sellsy:before {
+ content: "\f213"; }
+
+.fa-server:before {
+ content: "\f233"; }
+
+.fa-servicestack:before {
+ content: "\f3ec"; }
+
+.fa-shapes:before {
+ content: "\f61f"; }
+
+.fa-share:before {
+ content: "\f064"; }
+
+.fa-share-alt:before {
+ content: "\f1e0"; }
+
+.fa-share-alt-square:before {
+ content: "\f1e1"; }
+
+.fa-share-square:before {
+ content: "\f14d"; }
+
+.fa-shekel-sign:before {
+ content: "\f20b"; }
+
+.fa-shield-alt:before {
+ content: "\f3ed"; }
+
+.fa-ship:before {
+ content: "\f21a"; }
+
+.fa-shipping-fast:before {
+ content: "\f48b"; }
+
+.fa-shirtsinbulk:before {
+ content: "\f214"; }
+
+.fa-shoe-prints:before {
+ content: "\f54b"; }
+
+.fa-shopping-bag:before {
+ content: "\f290"; }
+
+.fa-shopping-basket:before {
+ content: "\f291"; }
+
+.fa-shopping-cart:before {
+ content: "\f07a"; }
+
+.fa-shopware:before {
+ content: "\f5b5"; }
+
+.fa-shower:before {
+ content: "\f2cc"; }
+
+.fa-shuttle-van:before {
+ content: "\f5b6"; }
+
+.fa-sign:before {
+ content: "\f4d9"; }
+
+.fa-sign-in-alt:before {
+ content: "\f2f6"; }
+
+.fa-sign-language:before {
+ content: "\f2a7"; }
+
+.fa-sign-out-alt:before {
+ content: "\f2f5"; }
+
+.fa-signal:before {
+ content: "\f012"; }
+
+.fa-signature:before {
+ content: "\f5b7"; }
+
+.fa-sim-card:before {
+ content: "\f7c4"; }
+
+.fa-simplybuilt:before {
+ content: "\f215"; }
+
+.fa-sistrix:before {
+ content: "\f3ee"; }
+
+.fa-sitemap:before {
+ content: "\f0e8"; }
+
+.fa-sith:before {
+ content: "\f512"; }
+
+.fa-skating:before {
+ content: "\f7c5"; }
+
+.fa-sketch:before {
+ content: "\f7c6"; }
+
+.fa-skiing:before {
+ content: "\f7c9"; }
+
+.fa-skiing-nordic:before {
+ content: "\f7ca"; }
+
+.fa-skull:before {
+ content: "\f54c"; }
+
+.fa-skull-crossbones:before {
+ content: "\f714"; }
+
+.fa-skyatlas:before {
+ content: "\f216"; }
+
+.fa-skype:before {
+ content: "\f17e"; }
+
+.fa-slack:before {
+ content: "\f198"; }
+
+.fa-slack-hash:before {
+ content: "\f3ef"; }
+
+.fa-slash:before {
+ content: "\f715"; }
+
+.fa-sleigh:before {
+ content: "\f7cc"; }
+
+.fa-sliders-h:before {
+ content: "\f1de"; }
+
+.fa-slideshare:before {
+ content: "\f1e7"; }
+
+.fa-smile:before {
+ content: "\f118"; }
+
+.fa-smile-beam:before {
+ content: "\f5b8"; }
+
+.fa-smile-wink:before {
+ content: "\f4da"; }
+
+.fa-smog:before {
+ content: "\f75f"; }
+
+.fa-smoking:before {
+ content: "\f48d"; }
+
+.fa-smoking-ban:before {
+ content: "\f54d"; }
+
+.fa-sms:before {
+ content: "\f7cd"; }
+
+.fa-snapchat:before {
+ content: "\f2ab"; }
+
+.fa-snapchat-ghost:before {
+ content: "\f2ac"; }
+
+.fa-snapchat-square:before {
+ content: "\f2ad"; }
+
+.fa-snowboarding:before {
+ content: "\f7ce"; }
+
+.fa-snowflake:before {
+ content: "\f2dc"; }
+
+.fa-snowman:before {
+ content: "\f7d0"; }
+
+.fa-snowplow:before {
+ content: "\f7d2"; }
+
+.fa-socks:before {
+ content: "\f696"; }
+
+.fa-solar-panel:before {
+ content: "\f5ba"; }
+
+.fa-sort:before {
+ content: "\f0dc"; }
+
+.fa-sort-alpha-down:before {
+ content: "\f15d"; }
+
+.fa-sort-alpha-up:before {
+ content: "\f15e"; }
+
+.fa-sort-amount-down:before {
+ content: "\f160"; }
+
+.fa-sort-amount-up:before {
+ content: "\f161"; }
+
+.fa-sort-down:before {
+ content: "\f0dd"; }
+
+.fa-sort-numeric-down:before {
+ content: "\f162"; }
+
+.fa-sort-numeric-up:before {
+ content: "\f163"; }
+
+.fa-sort-up:before {
+ content: "\f0de"; }
+
+.fa-soundcloud:before {
+ content: "\f1be"; }
+
+.fa-sourcetree:before {
+ content: "\f7d3"; }
+
+.fa-spa:before {
+ content: "\f5bb"; }
+
+.fa-space-shuttle:before {
+ content: "\f197"; }
+
+.fa-speakap:before {
+ content: "\f3f3"; }
+
+.fa-speaker-deck:before {
+ content: "\f83c"; }
+
+.fa-spider:before {
+ content: "\f717"; }
+
+.fa-spinner:before {
+ content: "\f110"; }
+
+.fa-splotch:before {
+ content: "\f5bc"; }
+
+.fa-spotify:before {
+ content: "\f1bc"; }
+
+.fa-spray-can:before {
+ content: "\f5bd"; }
+
+.fa-square:before {
+ content: "\f0c8"; }
+
+.fa-square-full:before {
+ content: "\f45c"; }
+
+.fa-square-root-alt:before {
+ content: "\f698"; }
+
+.fa-squarespace:before {
+ content: "\f5be"; }
+
+.fa-stack-exchange:before {
+ content: "\f18d"; }
+
+.fa-stack-overflow:before {
+ content: "\f16c"; }
+
+.fa-stackpath:before {
+ content: "\f842"; }
+
+.fa-stamp:before {
+ content: "\f5bf"; }
+
+.fa-star:before {
+ content: "\f005"; }
+
+.fa-star-and-crescent:before {
+ content: "\f699"; }
+
+.fa-star-half:before {
+ content: "\f089"; }
+
+.fa-star-half-alt:before {
+ content: "\f5c0"; }
+
+.fa-star-of-david:before {
+ content: "\f69a"; }
+
+.fa-star-of-life:before {
+ content: "\f621"; }
+
+.fa-staylinked:before {
+ content: "\f3f5"; }
+
+.fa-steam:before {
+ content: "\f1b6"; }
+
+.fa-steam-square:before {
+ content: "\f1b7"; }
+
+.fa-steam-symbol:before {
+ content: "\f3f6"; }
+
+.fa-step-backward:before {
+ content: "\f048"; }
+
+.fa-step-forward:before {
+ content: "\f051"; }
+
+.fa-stethoscope:before {
+ content: "\f0f1"; }
+
+.fa-sticker-mule:before {
+ content: "\f3f7"; }
+
+.fa-sticky-note:before {
+ content: "\f249"; }
+
+.fa-stop:before {
+ content: "\f04d"; }
+
+.fa-stop-circle:before {
+ content: "\f28d"; }
+
+.fa-stopwatch:before {
+ content: "\f2f2"; }
+
+.fa-store:before {
+ content: "\f54e"; }
+
+.fa-store-alt:before {
+ content: "\f54f"; }
+
+.fa-strava:before {
+ content: "\f428"; }
+
+.fa-stream:before {
+ content: "\f550"; }
+
+.fa-street-view:before {
+ content: "\f21d"; }
+
+.fa-strikethrough:before {
+ content: "\f0cc"; }
+
+.fa-stripe:before {
+ content: "\f429"; }
+
+.fa-stripe-s:before {
+ content: "\f42a"; }
+
+.fa-stroopwafel:before {
+ content: "\f551"; }
+
+.fa-studiovinari:before {
+ content: "\f3f8"; }
+
+.fa-stumbleupon:before {
+ content: "\f1a4"; }
+
+.fa-stumbleupon-circle:before {
+ content: "\f1a3"; }
+
+.fa-subscript:before {
+ content: "\f12c"; }
+
+.fa-subway:before {
+ content: "\f239"; }
+
+.fa-suitcase:before {
+ content: "\f0f2"; }
+
+.fa-suitcase-rolling:before {
+ content: "\f5c1"; }
+
+.fa-sun:before {
+ content: "\f185"; }
+
+.fa-superpowers:before {
+ content: "\f2dd"; }
+
+.fa-superscript:before {
+ content: "\f12b"; }
+
+.fa-supple:before {
+ content: "\f3f9"; }
+
+.fa-surprise:before {
+ content: "\f5c2"; }
+
+.fa-suse:before {
+ content: "\f7d6"; }
+
+.fa-swatchbook:before {
+ content: "\f5c3"; }
+
+.fa-swimmer:before {
+ content: "\f5c4"; }
+
+.fa-swimming-pool:before {
+ content: "\f5c5"; }
+
+.fa-symfony:before {
+ content: "\f83d"; }
+
+.fa-synagogue:before {
+ content: "\f69b"; }
+
+.fa-sync:before {
+ content: "\f021"; }
+
+.fa-sync-alt:before {
+ content: "\f2f1"; }
+
+.fa-syringe:before {
+ content: "\f48e"; }
+
+.fa-table:before {
+ content: "\f0ce"; }
+
+.fa-table-tennis:before {
+ content: "\f45d"; }
+
+.fa-tablet:before {
+ content: "\f10a"; }
+
+.fa-tablet-alt:before {
+ content: "\f3fa"; }
+
+.fa-tablets:before {
+ content: "\f490"; }
+
+.fa-tachometer-alt:before {
+ content: "\f3fd"; }
+
+.fa-tag:before {
+ content: "\f02b"; }
+
+.fa-tags:before {
+ content: "\f02c"; }
+
+.fa-tape:before {
+ content: "\f4db"; }
+
+.fa-tasks:before {
+ content: "\f0ae"; }
+
+.fa-taxi:before {
+ content: "\f1ba"; }
+
+.fa-teamspeak:before {
+ content: "\f4f9"; }
+
+.fa-teeth:before {
+ content: "\f62e"; }
+
+.fa-teeth-open:before {
+ content: "\f62f"; }
+
+.fa-telegram:before {
+ content: "\f2c6"; }
+
+.fa-telegram-plane:before {
+ content: "\f3fe"; }
+
+.fa-temperature-high:before {
+ content: "\f769"; }
+
+.fa-temperature-low:before {
+ content: "\f76b"; }
+
+.fa-tencent-weibo:before {
+ content: "\f1d5"; }
+
+.fa-tenge:before {
+ content: "\f7d7"; }
+
+.fa-terminal:before {
+ content: "\f120"; }
+
+.fa-text-height:before {
+ content: "\f034"; }
+
+.fa-text-width:before {
+ content: "\f035"; }
+
+.fa-th:before {
+ content: "\f00a"; }
+
+.fa-th-large:before {
+ content: "\f009"; }
+
+.fa-th-list:before {
+ content: "\f00b"; }
+
+.fa-the-red-yeti:before {
+ content: "\f69d"; }
+
+.fa-theater-masks:before {
+ content: "\f630"; }
+
+.fa-themeco:before {
+ content: "\f5c6"; }
+
+.fa-themeisle:before {
+ content: "\f2b2"; }
+
+.fa-thermometer:before {
+ content: "\f491"; }
+
+.fa-thermometer-empty:before {
+ content: "\f2cb"; }
+
+.fa-thermometer-full:before {
+ content: "\f2c7"; }
+
+.fa-thermometer-half:before {
+ content: "\f2c9"; }
+
+.fa-thermometer-quarter:before {
+ content: "\f2ca"; }
+
+.fa-thermometer-three-quarters:before {
+ content: "\f2c8"; }
+
+.fa-think-peaks:before {
+ content: "\f731"; }
+
+.fa-thumbs-down:before {
+ content: "\f165"; }
+
+.fa-thumbs-up:before {
+ content: "\f164"; }
+
+.fa-thumbtack:before {
+ content: "\f08d"; }
+
+.fa-ticket-alt:before {
+ content: "\f3ff"; }
+
+.fa-times:before {
+ content: "\f00d"; }
+
+.fa-times-circle:before {
+ content: "\f057"; }
+
+.fa-tint:before {
+ content: "\f043"; }
+
+.fa-tint-slash:before {
+ content: "\f5c7"; }
+
+.fa-tired:before {
+ content: "\f5c8"; }
+
+.fa-toggle-off:before {
+ content: "\f204"; }
+
+.fa-toggle-on:before {
+ content: "\f205"; }
+
+.fa-toilet:before {
+ content: "\f7d8"; }
+
+.fa-toilet-paper:before {
+ content: "\f71e"; }
+
+.fa-toolbox:before {
+ content: "\f552"; }
+
+.fa-tools:before {
+ content: "\f7d9"; }
+
+.fa-tooth:before {
+ content: "\f5c9"; }
+
+.fa-torah:before {
+ content: "\f6a0"; }
+
+.fa-torii-gate:before {
+ content: "\f6a1"; }
+
+.fa-tractor:before {
+ content: "\f722"; }
+
+.fa-trade-federation:before {
+ content: "\f513"; }
+
+.fa-trademark:before {
+ content: "\f25c"; }
+
+.fa-traffic-light:before {
+ content: "\f637"; }
+
+.fa-train:before {
+ content: "\f238"; }
+
+.fa-tram:before {
+ content: "\f7da"; }
+
+.fa-transgender:before {
+ content: "\f224"; }
+
+.fa-transgender-alt:before {
+ content: "\f225"; }
+
+.fa-trash:before {
+ content: "\f1f8"; }
+
+.fa-trash-alt:before {
+ content: "\f2ed"; }
+
+.fa-trash-restore:before {
+ content: "\f829"; }
+
+.fa-trash-restore-alt:before {
+ content: "\f82a"; }
+
+.fa-tree:before {
+ content: "\f1bb"; }
+
+.fa-trello:before {
+ content: "\f181"; }
+
+.fa-tripadvisor:before {
+ content: "\f262"; }
+
+.fa-trophy:before {
+ content: "\f091"; }
+
+.fa-truck:before {
+ content: "\f0d1"; }
+
+.fa-truck-loading:before {
+ content: "\f4de"; }
+
+.fa-truck-monster:before {
+ content: "\f63b"; }
+
+.fa-truck-moving:before {
+ content: "\f4df"; }
+
+.fa-truck-pickup:before {
+ content: "\f63c"; }
+
+.fa-tshirt:before {
+ content: "\f553"; }
+
+.fa-tty:before {
+ content: "\f1e4"; }
+
+.fa-tumblr:before {
+ content: "\f173"; }
+
+.fa-tumblr-square:before {
+ content: "\f174"; }
+
+.fa-tv:before {
+ content: "\f26c"; }
+
+.fa-twitch:before {
+ content: "\f1e8"; }
+
+.fa-twitter:before {
+ content: "\f099"; }
+
+.fa-twitter-square:before {
+ content: "\f081"; }
+
+.fa-typo3:before {
+ content: "\f42b"; }
+
+.fa-uber:before {
+ content: "\f402"; }
+
+.fa-ubuntu:before {
+ content: "\f7df"; }
+
+.fa-uikit:before {
+ content: "\f403"; }
+
+.fa-umbrella:before {
+ content: "\f0e9"; }
+
+.fa-umbrella-beach:before {
+ content: "\f5ca"; }
+
+.fa-underline:before {
+ content: "\f0cd"; }
+
+.fa-undo:before {
+ content: "\f0e2"; }
+
+.fa-undo-alt:before {
+ content: "\f2ea"; }
+
+.fa-uniregistry:before {
+ content: "\f404"; }
+
+.fa-universal-access:before {
+ content: "\f29a"; }
+
+.fa-university:before {
+ content: "\f19c"; }
+
+.fa-unlink:before {
+ content: "\f127"; }
+
+.fa-unlock:before {
+ content: "\f09c"; }
+
+.fa-unlock-alt:before {
+ content: "\f13e"; }
+
+.fa-untappd:before {
+ content: "\f405"; }
+
+.fa-upload:before {
+ content: "\f093"; }
+
+.fa-ups:before {
+ content: "\f7e0"; }
+
+.fa-usb:before {
+ content: "\f287"; }
+
+.fa-user:before {
+ content: "\f007"; }
+
+.fa-user-alt:before {
+ content: "\f406"; }
+
+.fa-user-alt-slash:before {
+ content: "\f4fa"; }
+
+.fa-user-astronaut:before {
+ content: "\f4fb"; }
+
+.fa-user-check:before {
+ content: "\f4fc"; }
+
+.fa-user-circle:before {
+ content: "\f2bd"; }
+
+.fa-user-clock:before {
+ content: "\f4fd"; }
+
+.fa-user-cog:before {
+ content: "\f4fe"; }
+
+.fa-user-edit:before {
+ content: "\f4ff"; }
+
+.fa-user-friends:before {
+ content: "\f500"; }
+
+.fa-user-graduate:before {
+ content: "\f501"; }
+
+.fa-user-injured:before {
+ content: "\f728"; }
+
+.fa-user-lock:before {
+ content: "\f502"; }
+
+.fa-user-md:before {
+ content: "\f0f0"; }
+
+.fa-user-minus:before {
+ content: "\f503"; }
+
+.fa-user-ninja:before {
+ content: "\f504"; }
+
+.fa-user-nurse:before {
+ content: "\f82f"; }
+
+.fa-user-plus:before {
+ content: "\f234"; }
+
+.fa-user-secret:before {
+ content: "\f21b"; }
+
+.fa-user-shield:before {
+ content: "\f505"; }
+
+.fa-user-slash:before {
+ content: "\f506"; }
+
+.fa-user-tag:before {
+ content: "\f507"; }
+
+.fa-user-tie:before {
+ content: "\f508"; }
+
+.fa-user-times:before {
+ content: "\f235"; }
+
+.fa-users:before {
+ content: "\f0c0"; }
+
+.fa-users-cog:before {
+ content: "\f509"; }
+
+.fa-usps:before {
+ content: "\f7e1"; }
+
+.fa-ussunnah:before {
+ content: "\f407"; }
+
+.fa-utensil-spoon:before {
+ content: "\f2e5"; }
+
+.fa-utensils:before {
+ content: "\f2e7"; }
+
+.fa-vaadin:before {
+ content: "\f408"; }
+
+.fa-vector-square:before {
+ content: "\f5cb"; }
+
+.fa-venus:before {
+ content: "\f221"; }
+
+.fa-venus-double:before {
+ content: "\f226"; }
+
+.fa-venus-mars:before {
+ content: "\f228"; }
+
+.fa-viacoin:before {
+ content: "\f237"; }
+
+.fa-viadeo:before {
+ content: "\f2a9"; }
+
+.fa-viadeo-square:before {
+ content: "\f2aa"; }
+
+.fa-vial:before {
+ content: "\f492"; }
+
+.fa-vials:before {
+ content: "\f493"; }
+
+.fa-viber:before {
+ content: "\f409"; }
+
+.fa-video:before {
+ content: "\f03d"; }
+
+.fa-video-slash:before {
+ content: "\f4e2"; }
+
+.fa-vihara:before {
+ content: "\f6a7"; }
+
+.fa-vimeo:before {
+ content: "\f40a"; }
+
+.fa-vimeo-square:before {
+ content: "\f194"; }
+
+.fa-vimeo-v:before {
+ content: "\f27d"; }
+
+.fa-vine:before {
+ content: "\f1ca"; }
+
+.fa-vk:before {
+ content: "\f189"; }
+
+.fa-vnv:before {
+ content: "\f40b"; }
+
+.fa-volleyball-ball:before {
+ content: "\f45f"; }
+
+.fa-volume-down:before {
+ content: "\f027"; }
+
+.fa-volume-mute:before {
+ content: "\f6a9"; }
+
+.fa-volume-off:before {
+ content: "\f026"; }
+
+.fa-volume-up:before {
+ content: "\f028"; }
+
+.fa-vote-yea:before {
+ content: "\f772"; }
+
+.fa-vr-cardboard:before {
+ content: "\f729"; }
+
+.fa-vuejs:before {
+ content: "\f41f"; }
+
+.fa-walking:before {
+ content: "\f554"; }
+
+.fa-wallet:before {
+ content: "\f555"; }
+
+.fa-warehouse:before {
+ content: "\f494"; }
+
+.fa-water:before {
+ content: "\f773"; }
+
+.fa-wave-square:before {
+ content: "\f83e"; }
+
+.fa-waze:before {
+ content: "\f83f"; }
+
+.fa-weebly:before {
+ content: "\f5cc"; }
+
+.fa-weibo:before {
+ content: "\f18a"; }
+
+.fa-weight:before {
+ content: "\f496"; }
+
+.fa-weight-hanging:before {
+ content: "\f5cd"; }
+
+.fa-weixin:before {
+ content: "\f1d7"; }
+
+.fa-whatsapp:before {
+ content: "\f232"; }
+
+.fa-whatsapp-square:before {
+ content: "\f40c"; }
+
+.fa-wheelchair:before {
+ content: "\f193"; }
+
+.fa-whmcs:before {
+ content: "\f40d"; }
+
+.fa-wifi:before {
+ content: "\f1eb"; }
+
+.fa-wikipedia-w:before {
+ content: "\f266"; }
+
+.fa-wind:before {
+ content: "\f72e"; }
+
+.fa-window-close:before {
+ content: "\f410"; }
+
+.fa-window-maximize:before {
+ content: "\f2d0"; }
+
+.fa-window-minimize:before {
+ content: "\f2d1"; }
+
+.fa-window-restore:before {
+ content: "\f2d2"; }
+
+.fa-windows:before {
+ content: "\f17a"; }
+
+.fa-wine-bottle:before {
+ content: "\f72f"; }
+
+.fa-wine-glass:before {
+ content: "\f4e3"; }
+
+.fa-wine-glass-alt:before {
+ content: "\f5ce"; }
+
+.fa-wix:before {
+ content: "\f5cf"; }
+
+.fa-wizards-of-the-coast:before {
+ content: "\f730"; }
+
+.fa-wolf-pack-battalion:before {
+ content: "\f514"; }
+
+.fa-won-sign:before {
+ content: "\f159"; }
+
+.fa-wordpress:before {
+ content: "\f19a"; }
+
+.fa-wordpress-simple:before {
+ content: "\f411"; }
+
+.fa-wpbeginner:before {
+ content: "\f297"; }
+
+.fa-wpexplorer:before {
+ content: "\f2de"; }
+
+.fa-wpforms:before {
+ content: "\f298"; }
+
+.fa-wpressr:before {
+ content: "\f3e4"; }
+
+.fa-wrench:before {
+ content: "\f0ad"; }
+
+.fa-x-ray:before {
+ content: "\f497"; }
+
+.fa-xbox:before {
+ content: "\f412"; }
+
+.fa-xing:before {
+ content: "\f168"; }
+
+.fa-xing-square:before {
+ content: "\f169"; }
+
+.fa-y-combinator:before {
+ content: "\f23b"; }
+
+.fa-yahoo:before {
+ content: "\f19e"; }
+
+.fa-yammer:before {
+ content: "\f840"; }
+
+.fa-yandex:before {
+ content: "\f413"; }
+
+.fa-yandex-international:before {
+ content: "\f414"; }
+
+.fa-yarn:before {
+ content: "\f7e3"; }
+
+.fa-yelp:before {
+ content: "\f1e9"; }
+
+.fa-yen-sign:before {
+ content: "\f157"; }
+
+.fa-yin-yang:before {
+ content: "\f6ad"; }
+
+.fa-yoast:before {
+ content: "\f2b1"; }
+
+.fa-youtube:before {
+ content: "\f167"; }
+
+.fa-youtube-square:before {
+ content: "\f431"; }
+
+.fa-zhihu:before {
+ content: "\f63f"; }
+
+.sr-only {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px; }
+
+.sr-only-focusable:active, .sr-only-focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ width: auto; }
+
+ @font-face {
+ font-family: 'Font Awesome 5 Brands';
+ font-style: normal;
+ font-weight: normal;
+ font-display: auto;
+ src: url("../webfonts/fa-brands-400.eot");
+ src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); }
+
+.fab {
+ font-family: 'Font Awesome 5 Brands'; }
+@font-face {
+ font-family: 'Font Awesome 5 Free';
+ font-style: normal;
+ font-weight: 400;
+ font-display: auto;
+ src: url("../webfonts/fa-regular-400.eot");
+ src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); }
+
+.far {
+ font-family: 'Font Awesome 5 Free';
+ font-weight: 400; }
+@font-face {
+ font-family: 'Font Awesome 5 Free';
+ font-style: normal;
+ font-weight: 900;
+ font-display: auto;
+ src: url("../webfonts/fa-solid-900.eot");
+ src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
+
+.fa,
+.fas {
+ font-family: 'Font Awesome 5 Free';
+ font-weight: 900; }
diff --git a/app/webroot/css/home.css b/app/webroot/css/home.css
new file mode 100644
index 0000000..7d8cd59
--- /dev/null
+++ b/app/webroot/css/home.css
@@ -0,0 +1,72 @@
+/* Home page styles */
+@font-face {
+ font-family: 'cakefont';
+ src: url('../font/cakedingbats-webfont.eot');
+ src: url('../font/cakedingbats-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../font/cakedingbats-webfont.woff2') format('woff2'),
+ url('../font/cakedingbats-webfont.woff') format('woff'),
+ url('../font/cakedingbats-webfont.ttf') format('truetype'),
+ url('../font/cakedingbats-webfont.svg#cake_dingbatsregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+body {
+ padding: 60px 0;
+}
+header {
+ margin-bottom: 60px;
+}
+img {
+ margin-bottom: 30px;
+}
+h1 {
+ font-weight: bold;
+}
+ul {
+ list-style-type: none;
+ margin: 0 0 30px 0;
+ padding-left: 25px;
+}
+a {
+ color: #0071BC;
+ text-decoration: underline;
+}
+hr {
+ border-bottom: 1px solid #e7e7e7;
+ border-top: 0;
+ margin-bottom: 35px;
+}
+
+.text-center {
+ text-align: center;
+}
+.links a {
+ margin-right: 10px;
+}
+.release-name {
+ color: #D33C43;
+ font-weight: 400;
+ font-style: italic;
+}
+.bullet:before {
+ font-family: 'cakefont', sans-serif;
+ font-size: 18px;
+ display: inline-block;
+ margin-left: -1.3em;
+ width: 1.2em;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ vertical-align: -1px;
+}
+.success:before {
+ color: #88c671;
+ content: "\0056";
+}
+.problem:before {
+ color: #d33d44;
+ content: "\0057";
+}
+.cake-error {
+ padding: 10px;
+ margin: 10px 0;
+}
diff --git a/app/webroot/css/main.css b/app/webroot/css/main.css
new file mode 100644
index 0000000..623c1e2
--- /dev/null
+++ b/app/webroot/css/main.css
@@ -0,0 +1,111 @@
+.footer {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ /* Set the fixed height of the footer here */
+ height: 60px;
+ line-height: 60px; /* Vertically center the text there */
+ background-color: #f5f5f5;
+}
+
+.black {
+ color:black;
+}
+
+.sidebar {}
+
+.side-bar-ul {
+ top: 70px;
+ left:0;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.side-bar-ul li {
+ line-height: 40px;
+}
+
+.side-bar-ul .sidebar-header {
+ padding-left: 10px;
+ color: black;
+}
+
+.side-bar-ul .sidebar-element {
+ padding-left: 20px;
+}
+
+.side-bar-ul li a {
+ display: block;
+ text-decoration: none;
+}
+
+.sidebar-header a {
+ color: black;
+}
+
+.sidebar-element a {
+ color: #999999;
+}
+
+.side-bar-ul li a:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+.side-bar-ul li:hover {
+ background: #007bff;
+}
+
+.side-bar-ul .active {
+ background: #007bff;
+}
+
+.side-bar-ul .active a {
+ color: white !important;
+}
+
+.side-bar-ul li a:active, .side-bar-ul li a:focus {
+ text-decoration: none;
+}
+
+.side-bar-ul>.sidebar-brand {
+ height: 65px;
+ font-size: 18px;
+ line-height: 60px;
+}
+
+.side-bar-ul>.sidebar-brand a {
+ color: #999999;
+}
+
+.side-bar-ul>.sidebar-brand a:hover {
+ color: #fff;
+ background: none;
+}
+
+@media(min-width:768px) {
+ #wrapper {
+ padding-left: 0;
+ }
+ #wrapper.toggled {
+ padding-left: 250px;
+ }
+ #sidebar-wrapper {
+ width: 0;
+ }
+ #wrapper.toggled #sidebar-wrapper {
+ width: 250px;
+ }
+ #page-content-wrapper {
+ padding: 20px;
+ position: relative;
+ }
+ #wrapper.toggled #page-content-wrapper {
+ position: relative;
+ margin-right: 0;
+ }
+}
+
+.text-black {color:black;}
+.text-white {color:white;}
diff --git a/app/webroot/css/milligram.min.css b/app/webroot/css/milligram.min.css
new file mode 100644
index 0000000..c266074
--- /dev/null
+++ b/app/webroot/css/milligram.min.css
@@ -0,0 +1,11 @@
+/*!
+ * Milligram v1.3.0
+ * https://milligram.io
+ *
+ * Copyright (c) 2019 CJ Patoilo
+ * Licensed under the MIT license
+ */
+
+*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#d33c43;border:0.1rem solid #d33c43;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#d33c43;border-color:#d33c43}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#d33c43}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#d33c43}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#d33c43}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#d33c43}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #d33c43;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='email'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='color'],input[type='date'],input[type='month'],input[type='week'],input[type='datetime'],input[type='datetime-local'],input:not([type]),textarea,select{background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem;width:100%}input[type='email']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='color']:focus,input[type='date']:focus,input[type='month']:focus,input[type='week']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#606c76;outline:0}select{padding-right:3.0rem}textarea{min-height:6.5rem}label,legend{display:block;font-size:2.0rem;font-weight:700;margin-bottom:2.0rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{-ms-grid-row-align:center;align-self:center}.row .column-responsive{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}@media (min-width: 640px){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}.row .column-responsive{margin-bottom:inherit;padding:0 1.0rem}.row .column-responsive.column-10{flex:0 0 10%;max-width:10%}.row .column-responsive.column-20{flex:0 0 20%;max-width:20%}.row .column-responsive.column-25{flex:0 0 25%;max-width:25%}.row .column-responsive.column-33,.row .column-responsive.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column-responsive.column-40{flex:0 0 40%;max-width:40%}.row .column-responsive.column-50{flex:0 0 50%;max-width:50%}.row .column-responsive.column-60{flex:0 0 60%;max-width:60%}.row .column-responsive.column-66,.row .column-responsive.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column-responsive.column-75{flex:0 0 75%;max-width:75%}.row .column-responsive.column-80{flex:0 0 80%;max-width:80%}.row .column-responsive.column-90{flex:0 0 90%;max-width:90%}}a{color:#d33c43;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:0}table{border-spacing:0;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media screen and (max-width: 640px){table{border-spacing:0;display:flex;width:100%}table thead{border-right:solid 0.1rem #e1e1e1}table thead td,table thead th{padding-left:0}table thead td:first-child,table thead th:first-child{padding-left:0}table thead td:last-child,table thead th:last-child{padding-right:1.2rem}table tbody{display:flex;overflow-x:auto;white-space:nowrap}table tbody tr{border-right:solid 0.1rem #e1e1e1}table tbody tr:last-child{border-right:none}table td,table th{display:block}table td:first-child,table th:first-child{padding-left:1.2rem}table td:last-child,table th:last-child{padding-right:1.2rem}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right}
+
+/*# sourceMappingURL=milligram.min.css.map */
\ No newline at end of file
diff --git a/app/webroot/debug_kit b/app/webroot/debug_kit
new file mode 120000
index 0000000..d60b5fd
--- /dev/null
+++ b/app/webroot/debug_kit
@@ -0,0 +1 @@
+../vendor/cakephp/debug_kit/webroot
\ No newline at end of file
diff --git a/app/webroot/favicon.ico b/app/webroot/favicon.ico
new file mode 100644
index 0000000..b38a3a0
Binary files /dev/null and b/app/webroot/favicon.ico differ
diff --git a/app/webroot/font/cakedingbats-webfont.eot b/app/webroot/font/cakedingbats-webfont.eot
new file mode 100644
index 0000000..e8605d9
Binary files /dev/null and b/app/webroot/font/cakedingbats-webfont.eot differ
diff --git a/app/webroot/font/cakedingbats-webfont.svg b/app/webroot/font/cakedingbats-webfont.svg
new file mode 100644
index 0000000..d1e0c98
--- /dev/null
+++ b/app/webroot/font/cakedingbats-webfont.svg
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/webroot/font/cakedingbats-webfont.ttf b/app/webroot/font/cakedingbats-webfont.ttf
new file mode 100644
index 0000000..13d5445
Binary files /dev/null and b/app/webroot/font/cakedingbats-webfont.ttf differ
diff --git a/app/webroot/font/cakedingbats-webfont.woff b/app/webroot/font/cakedingbats-webfont.woff
new file mode 100644
index 0000000..073baab
Binary files /dev/null and b/app/webroot/font/cakedingbats-webfont.woff differ
diff --git a/app/webroot/font/cakedingbats-webfont.woff2 b/app/webroot/font/cakedingbats-webfont.woff2
new file mode 100644
index 0000000..6e71eaf
Binary files /dev/null and b/app/webroot/font/cakedingbats-webfont.woff2 differ
diff --git a/app/webroot/img/cake-logo.png b/app/webroot/img/cake-logo.png
new file mode 100644
index 0000000..41939ef
Binary files /dev/null and b/app/webroot/img/cake-logo.png differ
diff --git a/app/webroot/img/cake.icon.png b/app/webroot/img/cake.icon.png
new file mode 100644
index 0000000..394fa42
Binary files /dev/null and b/app/webroot/img/cake.icon.png differ
diff --git a/app/webroot/img/cake.logo.svg b/app/webroot/img/cake.logo.svg
new file mode 100644
index 0000000..e73abb5
--- /dev/null
+++ b/app/webroot/img/cake.logo.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/webroot/img/cake.power.gif b/app/webroot/img/cake.power.gif
new file mode 100644
index 0000000..8f8d570
Binary files /dev/null and b/app/webroot/img/cake.power.gif differ
diff --git a/app/webroot/img/favicon.ico b/app/webroot/img/favicon.ico
new file mode 100644
index 0000000..b38a3a0
Binary files /dev/null and b/app/webroot/img/favicon.ico differ
diff --git a/app/webroot/img/zicon.png b/app/webroot/img/zicon.png
new file mode 100644
index 0000000..9f551b8
Binary files /dev/null and b/app/webroot/img/zicon.png differ
diff --git a/app/webroot/index.php b/app/webroot/index.php
new file mode 100644
index 0000000..6bc06dc
--- /dev/null
+++ b/app/webroot/index.php
@@ -0,0 +1,40 @@
+emit($server->run());
diff --git a/app/webroot/js/.gitkeep b/app/webroot/js/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/webroot/js/bootstrap.bundle.js b/app/webroot/js/bootstrap.bundle.js
new file mode 100644
index 0000000..5344522
--- /dev/null
+++ b/app/webroot/js/bootstrap.bundle.js
@@ -0,0 +1,7134 @@
+/*!
+ * Bootstrap v4.4.1 (https://getbootstrap.com/)
+ * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) :
+ typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) :
+ (global = global || self, factory(global.bootstrap = {}, global.jQuery));
+}(this, (function (exports, $) { 'use strict';
+
+ $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+
+ function _defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ function _createClass(Constructor, protoProps, staticProps) {
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) _defineProperties(Constructor, staticProps);
+ return Constructor;
+ }
+
+ function _defineProperty(obj, key, value) {
+ if (key in obj) {
+ Object.defineProperty(obj, key, {
+ value: value,
+ enumerable: true,
+ configurable: true,
+ writable: true
+ });
+ } else {
+ obj[key] = value;
+ }
+
+ return obj;
+ }
+
+ function ownKeys(object, enumerableOnly) {
+ var keys = Object.keys(object);
+
+ if (Object.getOwnPropertySymbols) {
+ var symbols = Object.getOwnPropertySymbols(object);
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+ });
+ keys.push.apply(keys, symbols);
+ }
+
+ return keys;
+ }
+
+ function _objectSpread2(target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i] != null ? arguments[i] : {};
+
+ if (i % 2) {
+ ownKeys(Object(source), true).forEach(function (key) {
+ _defineProperty(target, key, source[key]);
+ });
+ } else if (Object.getOwnPropertyDescriptors) {
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+ } else {
+ ownKeys(Object(source)).forEach(function (key) {
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+ });
+ }
+ }
+
+ return target;
+ }
+
+ function _inheritsLoose(subClass, superClass) {
+ subClass.prototype = Object.create(superClass.prototype);
+ subClass.prototype.constructor = subClass;
+ subClass.__proto__ = superClass;
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.4.1): util.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+ /**
+ * ------------------------------------------------------------------------
+ * Private TransitionEnd Helpers
+ * ------------------------------------------------------------------------
+ */
+
+ var TRANSITION_END = 'transitionend';
+ var MAX_UID = 1000000;
+ var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
+
+ function toType(obj) {
+ return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
+ }
+
+ function getSpecialTransitionEndEvent() {
+ return {
+ bindType: TRANSITION_END,
+ delegateType: TRANSITION_END,
+ handle: function handle(event) {
+ if ($(event.target).is(this)) {
+ return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
+ }
+
+ return undefined; // eslint-disable-line no-undefined
+ }
+ };
+ }
+
+ function transitionEndEmulator(duration) {
+ var _this = this;
+
+ var called = false;
+ $(this).one(Util.TRANSITION_END, function () {
+ called = true;
+ });
+ setTimeout(function () {
+ if (!called) {
+ Util.triggerTransitionEnd(_this);
+ }
+ }, duration);
+ return this;
+ }
+
+ function setTransitionEndSupport() {
+ $.fn.emulateTransitionEnd = transitionEndEmulator;
+ $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
+ }
+ /**
+ * --------------------------------------------------------------------------
+ * Public Util Api
+ * --------------------------------------------------------------------------
+ */
+
+
+ var Util = {
+ TRANSITION_END: 'bsTransitionEnd',
+ getUID: function getUID(prefix) {
+ do {
+ // eslint-disable-next-line no-bitwise
+ prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
+ } while (document.getElementById(prefix));
+
+ return prefix;
+ },
+ getSelectorFromElement: function getSelectorFromElement(element) {
+ var selector = element.getAttribute('data-target');
+
+ if (!selector || selector === '#') {
+ var hrefAttr = element.getAttribute('href');
+ selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';
+ }
+
+ try {
+ return document.querySelector(selector) ? selector : null;
+ } catch (err) {
+ return null;
+ }
+ },
+ getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {
+ if (!element) {
+ return 0;
+ } // Get transition-duration of the element
+
+
+ var transitionDuration = $(element).css('transition-duration');
+ var transitionDelay = $(element).css('transition-delay');
+ var floatTransitionDuration = parseFloat(transitionDuration);
+ var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
+
+ if (!floatTransitionDuration && !floatTransitionDelay) {
+ return 0;
+ } // If multiple durations are defined, take the first
+
+
+ transitionDuration = transitionDuration.split(',')[0];
+ transitionDelay = transitionDelay.split(',')[0];
+ return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
+ },
+ reflow: function reflow(element) {
+ return element.offsetHeight;
+ },
+ triggerTransitionEnd: function triggerTransitionEnd(element) {
+ $(element).trigger(TRANSITION_END);
+ },
+ // TODO: Remove in v5
+ supportsTransitionEnd: function supportsTransitionEnd() {
+ return Boolean(TRANSITION_END);
+ },
+ isElement: function isElement(obj) {
+ return (obj[0] || obj).nodeType;
+ },
+ typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
+ for (var property in configTypes) {
+ if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
+ var expectedTypes = configTypes[property];
+ var value = config[property];
+ var valueType = value && Util.isElement(value) ? 'element' : toType(value);
+
+ if (!new RegExp(expectedTypes).test(valueType)) {
+ throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
+ }
+ }
+ }
+ },
+ findShadowRoot: function findShadowRoot(element) {
+ if (!document.documentElement.attachShadow) {
+ return null;
+ } // Can find the shadow root otherwise it'll return the document
+
+
+ if (typeof element.getRootNode === 'function') {
+ var root = element.getRootNode();
+ return root instanceof ShadowRoot ? root : null;
+ }
+
+ if (element instanceof ShadowRoot) {
+ return element;
+ } // when we don't find a shadow root
+
+
+ if (!element.parentNode) {
+ return null;
+ }
+
+ return Util.findShadowRoot(element.parentNode);
+ },
+ jQueryDetection: function jQueryDetection() {
+ if (typeof $ === 'undefined') {
+ throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.');
+ }
+
+ var version = $.fn.jquery.split(' ')[0].split('.');
+ var minMajor = 1;
+ var ltMajor = 2;
+ var minMinor = 9;
+ var minPatch = 1;
+ var maxMajor = 4;
+
+ if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
+ throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');
+ }
+ }
+ };
+ Util.jQueryDetection();
+ setTransitionEndSupport();
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME = 'alert';
+ var VERSION = '4.4.1';
+ var DATA_KEY = 'bs.alert';
+ var EVENT_KEY = "." + DATA_KEY;
+ var DATA_API_KEY = '.data-api';
+ var JQUERY_NO_CONFLICT = $.fn[NAME];
+ var Selector = {
+ DISMISS: '[data-dismiss="alert"]'
+ };
+ var Event = {
+ CLOSE: "close" + EVENT_KEY,
+ CLOSED: "closed" + EVENT_KEY,
+ CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
+ };
+ var ClassName = {
+ ALERT: 'alert',
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Alert =
+ /*#__PURE__*/
+ function () {
+ function Alert(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Alert.prototype;
+
+ // Public
+ _proto.close = function close(element) {
+ var rootElement = this._element;
+
+ if (element) {
+ rootElement = this._getRootElement(element);
+ }
+
+ var customEvent = this._triggerCloseEvent(rootElement);
+
+ if (customEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._removeElement(rootElement);
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY);
+ this._element = null;
+ } // Private
+ ;
+
+ _proto._getRootElement = function _getRootElement(element) {
+ var selector = Util.getSelectorFromElement(element);
+ var parent = false;
+
+ if (selector) {
+ parent = document.querySelector(selector);
+ }
+
+ if (!parent) {
+ parent = $(element).closest("." + ClassName.ALERT)[0];
+ }
+
+ return parent;
+ };
+
+ _proto._triggerCloseEvent = function _triggerCloseEvent(element) {
+ var closeEvent = $.Event(Event.CLOSE);
+ $(element).trigger(closeEvent);
+ return closeEvent;
+ };
+
+ _proto._removeElement = function _removeElement(element) {
+ var _this = this;
+
+ $(element).removeClass(ClassName.SHOW);
+
+ if (!$(element).hasClass(ClassName.FADE)) {
+ this._destroyElement(element);
+
+ return;
+ }
+
+ var transitionDuration = Util.getTransitionDurationFromElement(element);
+ $(element).one(Util.TRANSITION_END, function (event) {
+ return _this._destroyElement(element, event);
+ }).emulateTransitionEnd(transitionDuration);
+ };
+
+ _proto._destroyElement = function _destroyElement(element) {
+ $(element).detach().trigger(Event.CLOSED).remove();
+ } // Static
+ ;
+
+ Alert._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $element = $(this);
+ var data = $element.data(DATA_KEY);
+
+ if (!data) {
+ data = new Alert(this);
+ $element.data(DATA_KEY, data);
+ }
+
+ if (config === 'close') {
+ data[config](this);
+ }
+ });
+ };
+
+ Alert._handleDismiss = function _handleDismiss(alertInstance) {
+ return function (event) {
+ if (event) {
+ event.preventDefault();
+ }
+
+ alertInstance.close(this);
+ };
+ };
+
+ _createClass(Alert, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION;
+ }
+ }]);
+
+ return Alert;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME] = Alert._jQueryInterface;
+ $.fn[NAME].Constructor = Alert;
+
+ $.fn[NAME].noConflict = function () {
+ $.fn[NAME] = JQUERY_NO_CONFLICT;
+ return Alert._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$1 = 'button';
+ var VERSION$1 = '4.4.1';
+ var DATA_KEY$1 = 'bs.button';
+ var EVENT_KEY$1 = "." + DATA_KEY$1;
+ var DATA_API_KEY$1 = '.data-api';
+ var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];
+ var ClassName$1 = {
+ ACTIVE: 'active',
+ BUTTON: 'btn',
+ FOCUS: 'focus'
+ };
+ var Selector$1 = {
+ DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
+ DATA_TOGGLES: '[data-toggle="buttons"]',
+ DATA_TOGGLE: '[data-toggle="button"]',
+ DATA_TOGGLES_BUTTONS: '[data-toggle="buttons"] .btn',
+ INPUT: 'input:not([type="hidden"])',
+ ACTIVE: '.active',
+ BUTTON: '.btn'
+ };
+ var Event$1 = {
+ CLICK_DATA_API: "click" + EVENT_KEY$1 + DATA_API_KEY$1,
+ FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY$1 + DATA_API_KEY$1 + " " + ("blur" + EVENT_KEY$1 + DATA_API_KEY$1),
+ LOAD_DATA_API: "load" + EVENT_KEY$1 + DATA_API_KEY$1
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Button =
+ /*#__PURE__*/
+ function () {
+ function Button(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Button.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ var triggerChangeEvent = true;
+ var addAriaPressed = true;
+ var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLES)[0];
+
+ if (rootElement) {
+ var input = this._element.querySelector(Selector$1.INPUT);
+
+ if (input) {
+ if (input.type === 'radio') {
+ if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) {
+ triggerChangeEvent = false;
+ } else {
+ var activeElement = rootElement.querySelector(Selector$1.ACTIVE);
+
+ if (activeElement) {
+ $(activeElement).removeClass(ClassName$1.ACTIVE);
+ }
+ }
+ } else if (input.type === 'checkbox') {
+ if (this._element.tagName === 'LABEL' && input.checked === this._element.classList.contains(ClassName$1.ACTIVE)) {
+ triggerChangeEvent = false;
+ }
+ } else {
+ // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input
+ triggerChangeEvent = false;
+ }
+
+ if (triggerChangeEvent) {
+ input.checked = !this._element.classList.contains(ClassName$1.ACTIVE);
+ $(input).trigger('change');
+ }
+
+ input.focus();
+ addAriaPressed = false;
+ }
+ }
+
+ if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {
+ if (addAriaPressed) {
+ this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE));
+ }
+
+ if (triggerChangeEvent) {
+ $(this._element).toggleClass(ClassName$1.ACTIVE);
+ }
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$1);
+ this._element = null;
+ } // Static
+ ;
+
+ Button._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$1);
+
+ if (!data) {
+ data = new Button(this);
+ $(this).data(DATA_KEY$1, data);
+ }
+
+ if (config === 'toggle') {
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Button, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$1;
+ }
+ }]);
+
+ return Button;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
+ var button = event.target;
+
+ if (!$(button).hasClass(ClassName$1.BUTTON)) {
+ button = $(button).closest(Selector$1.BUTTON)[0];
+ }
+
+ if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {
+ event.preventDefault(); // work around Firefox bug #1540995
+ } else {
+ var inputBtn = button.querySelector(Selector$1.INPUT);
+
+ if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {
+ event.preventDefault(); // work around Firefox bug #1540995
+
+ return;
+ }
+
+ Button._jQueryInterface.call($(button), 'toggle');
+ }
+ }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
+ var button = $(event.target).closest(Selector$1.BUTTON)[0];
+ $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type));
+ });
+ $(window).on(Event$1.LOAD_DATA_API, function () {
+ // ensure correct active class is set to match the controls' actual values/states
+ // find all checkboxes/readio buttons inside data-toggle groups
+ var buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLES_BUTTONS));
+
+ for (var i = 0, len = buttons.length; i < len; i++) {
+ var button = buttons[i];
+ var input = button.querySelector(Selector$1.INPUT);
+
+ if (input.checked || input.hasAttribute('checked')) {
+ button.classList.add(ClassName$1.ACTIVE);
+ } else {
+ button.classList.remove(ClassName$1.ACTIVE);
+ }
+ } // find all button toggles
+
+
+ buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLE));
+
+ for (var _i = 0, _len = buttons.length; _i < _len; _i++) {
+ var _button = buttons[_i];
+
+ if (_button.getAttribute('aria-pressed') === 'true') {
+ _button.classList.add(ClassName$1.ACTIVE);
+ } else {
+ _button.classList.remove(ClassName$1.ACTIVE);
+ }
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$1] = Button._jQueryInterface;
+ $.fn[NAME$1].Constructor = Button;
+
+ $.fn[NAME$1].noConflict = function () {
+ $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;
+ return Button._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$2 = 'carousel';
+ var VERSION$2 = '4.4.1';
+ var DATA_KEY$2 = 'bs.carousel';
+ var EVENT_KEY$2 = "." + DATA_KEY$2;
+ var DATA_API_KEY$2 = '.data-api';
+ var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];
+ var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
+
+ var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
+
+ var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
+
+ var SWIPE_THRESHOLD = 40;
+ var Default = {
+ interval: 5000,
+ keyboard: true,
+ slide: false,
+ pause: 'hover',
+ wrap: true,
+ touch: true
+ };
+ var DefaultType = {
+ interval: '(number|boolean)',
+ keyboard: 'boolean',
+ slide: '(boolean|string)',
+ pause: '(string|boolean)',
+ wrap: 'boolean',
+ touch: 'boolean'
+ };
+ var Direction = {
+ NEXT: 'next',
+ PREV: 'prev',
+ LEFT: 'left',
+ RIGHT: 'right'
+ };
+ var Event$2 = {
+ SLIDE: "slide" + EVENT_KEY$2,
+ SLID: "slid" + EVENT_KEY$2,
+ KEYDOWN: "keydown" + EVENT_KEY$2,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$2,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$2,
+ TOUCHSTART: "touchstart" + EVENT_KEY$2,
+ TOUCHMOVE: "touchmove" + EVENT_KEY$2,
+ TOUCHEND: "touchend" + EVENT_KEY$2,
+ POINTERDOWN: "pointerdown" + EVENT_KEY$2,
+ POINTERUP: "pointerup" + EVENT_KEY$2,
+ DRAG_START: "dragstart" + EVENT_KEY$2,
+ LOAD_DATA_API: "load" + EVENT_KEY$2 + DATA_API_KEY$2,
+ CLICK_DATA_API: "click" + EVENT_KEY$2 + DATA_API_KEY$2
+ };
+ var ClassName$2 = {
+ CAROUSEL: 'carousel',
+ ACTIVE: 'active',
+ SLIDE: 'slide',
+ RIGHT: 'carousel-item-right',
+ LEFT: 'carousel-item-left',
+ NEXT: 'carousel-item-next',
+ PREV: 'carousel-item-prev',
+ ITEM: 'carousel-item',
+ POINTER_EVENT: 'pointer-event'
+ };
+ var Selector$2 = {
+ ACTIVE: '.active',
+ ACTIVE_ITEM: '.active.carousel-item',
+ ITEM: '.carousel-item',
+ ITEM_IMG: '.carousel-item img',
+ NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
+ INDICATORS: '.carousel-indicators',
+ DATA_SLIDE: '[data-slide], [data-slide-to]',
+ DATA_RIDE: '[data-ride="carousel"]'
+ };
+ var PointerType = {
+ TOUCH: 'touch',
+ PEN: 'pen'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Carousel =
+ /*#__PURE__*/
+ function () {
+ function Carousel(element, config) {
+ this._items = null;
+ this._interval = null;
+ this._activeElement = null;
+ this._isPaused = false;
+ this._isSliding = false;
+ this.touchTimeout = null;
+ this.touchStartX = 0;
+ this.touchDeltaX = 0;
+ this._config = this._getConfig(config);
+ this._element = element;
+ this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS);
+ this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
+ this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);
+
+ this._addEventListeners();
+ } // Getters
+
+
+ var _proto = Carousel.prototype;
+
+ // Public
+ _proto.next = function next() {
+ if (!this._isSliding) {
+ this._slide(Direction.NEXT);
+ }
+ };
+
+ _proto.nextWhenVisible = function nextWhenVisible() {
+ // Don't call next when the page isn't visible
+ // or the carousel or its parent isn't visible
+ if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {
+ this.next();
+ }
+ };
+
+ _proto.prev = function prev() {
+ if (!this._isSliding) {
+ this._slide(Direction.PREV);
+ }
+ };
+
+ _proto.pause = function pause(event) {
+ if (!event) {
+ this._isPaused = true;
+ }
+
+ if (this._element.querySelector(Selector$2.NEXT_PREV)) {
+ Util.triggerTransitionEnd(this._element);
+ this.cycle(true);
+ }
+
+ clearInterval(this._interval);
+ this._interval = null;
+ };
+
+ _proto.cycle = function cycle(event) {
+ if (!event) {
+ this._isPaused = false;
+ }
+
+ if (this._interval) {
+ clearInterval(this._interval);
+ this._interval = null;
+ }
+
+ if (this._config.interval && !this._isPaused) {
+ this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
+ }
+ };
+
+ _proto.to = function to(index) {
+ var _this = this;
+
+ this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
+
+ var activeIndex = this._getItemIndex(this._activeElement);
+
+ if (index > this._items.length - 1 || index < 0) {
+ return;
+ }
+
+ if (this._isSliding) {
+ $(this._element).one(Event$2.SLID, function () {
+ return _this.to(index);
+ });
+ return;
+ }
+
+ if (activeIndex === index) {
+ this.pause();
+ this.cycle();
+ return;
+ }
+
+ var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
+
+ this._slide(direction, this._items[index]);
+ };
+
+ _proto.dispose = function dispose() {
+ $(this._element).off(EVENT_KEY$2);
+ $.removeData(this._element, DATA_KEY$2);
+ this._items = null;
+ this._config = null;
+ this._element = null;
+ this._interval = null;
+ this._isPaused = null;
+ this._isSliding = null;
+ this._activeElement = null;
+ this._indicatorsElement = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default, {}, config);
+ Util.typeCheckConfig(NAME$2, config, DefaultType);
+ return config;
+ };
+
+ _proto._handleSwipe = function _handleSwipe() {
+ var absDeltax = Math.abs(this.touchDeltaX);
+
+ if (absDeltax <= SWIPE_THRESHOLD) {
+ return;
+ }
+
+ var direction = absDeltax / this.touchDeltaX;
+ this.touchDeltaX = 0; // swipe left
+
+ if (direction > 0) {
+ this.prev();
+ } // swipe right
+
+
+ if (direction < 0) {
+ this.next();
+ }
+ };
+
+ _proto._addEventListeners = function _addEventListeners() {
+ var _this2 = this;
+
+ if (this._config.keyboard) {
+ $(this._element).on(Event$2.KEYDOWN, function (event) {
+ return _this2._keydown(event);
+ });
+ }
+
+ if (this._config.pause === 'hover') {
+ $(this._element).on(Event$2.MOUSEENTER, function (event) {
+ return _this2.pause(event);
+ }).on(Event$2.MOUSELEAVE, function (event) {
+ return _this2.cycle(event);
+ });
+ }
+
+ if (this._config.touch) {
+ this._addTouchEventListeners();
+ }
+ };
+
+ _proto._addTouchEventListeners = function _addTouchEventListeners() {
+ var _this3 = this;
+
+ if (!this._touchSupported) {
+ return;
+ }
+
+ var start = function start(event) {
+ if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
+ _this3.touchStartX = event.originalEvent.clientX;
+ } else if (!_this3._pointerEvent) {
+ _this3.touchStartX = event.originalEvent.touches[0].clientX;
+ }
+ };
+
+ var move = function move(event) {
+ // ensure swiping with one touch and not pinching
+ if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {
+ _this3.touchDeltaX = 0;
+ } else {
+ _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;
+ }
+ };
+
+ var end = function end(event) {
+ if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
+ _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;
+ }
+
+ _this3._handleSwipe();
+
+ if (_this3._config.pause === 'hover') {
+ // If it's a touch-enabled device, mouseenter/leave are fired as
+ // part of the mouse compatibility events on first tap - the carousel
+ // would stop cycling until user tapped out of it;
+ // here, we listen for touchend, explicitly pause the carousel
+ // (as if it's the second time we tap on it, mouseenter compat event
+ // is NOT fired) and after a timeout (to allow for mouse compatibility
+ // events to fire) we explicitly restart cycling
+ _this3.pause();
+
+ if (_this3.touchTimeout) {
+ clearTimeout(_this3.touchTimeout);
+ }
+
+ _this3.touchTimeout = setTimeout(function (event) {
+ return _this3.cycle(event);
+ }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);
+ }
+ };
+
+ $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) {
+ return e.preventDefault();
+ });
+
+ if (this._pointerEvent) {
+ $(this._element).on(Event$2.POINTERDOWN, function (event) {
+ return start(event);
+ });
+ $(this._element).on(Event$2.POINTERUP, function (event) {
+ return end(event);
+ });
+
+ this._element.classList.add(ClassName$2.POINTER_EVENT);
+ } else {
+ $(this._element).on(Event$2.TOUCHSTART, function (event) {
+ return start(event);
+ });
+ $(this._element).on(Event$2.TOUCHMOVE, function (event) {
+ return move(event);
+ });
+ $(this._element).on(Event$2.TOUCHEND, function (event) {
+ return end(event);
+ });
+ }
+ };
+
+ _proto._keydown = function _keydown(event) {
+ if (/input|textarea/i.test(event.target.tagName)) {
+ return;
+ }
+
+ switch (event.which) {
+ case ARROW_LEFT_KEYCODE:
+ event.preventDefault();
+ this.prev();
+ break;
+
+ case ARROW_RIGHT_KEYCODE:
+ event.preventDefault();
+ this.next();
+ break;
+ }
+ };
+
+ _proto._getItemIndex = function _getItemIndex(element) {
+ this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : [];
+ return this._items.indexOf(element);
+ };
+
+ _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {
+ var isNextDirection = direction === Direction.NEXT;
+ var isPrevDirection = direction === Direction.PREV;
+
+ var activeIndex = this._getItemIndex(activeElement);
+
+ var lastItemIndex = this._items.length - 1;
+ var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
+
+ if (isGoingToWrap && !this._config.wrap) {
+ return activeElement;
+ }
+
+ var delta = direction === Direction.PREV ? -1 : 1;
+ var itemIndex = (activeIndex + delta) % this._items.length;
+ return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
+ };
+
+ _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
+ var targetIndex = this._getItemIndex(relatedTarget);
+
+ var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM));
+
+ var slideEvent = $.Event(Event$2.SLIDE, {
+ relatedTarget: relatedTarget,
+ direction: eventDirectionName,
+ from: fromIndex,
+ to: targetIndex
+ });
+ $(this._element).trigger(slideEvent);
+ return slideEvent;
+ };
+
+ _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
+ if (this._indicatorsElement) {
+ var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE));
+ $(indicators).removeClass(ClassName$2.ACTIVE);
+
+ var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
+
+ if (nextIndicator) {
+ $(nextIndicator).addClass(ClassName$2.ACTIVE);
+ }
+ }
+ };
+
+ _proto._slide = function _slide(direction, element) {
+ var _this4 = this;
+
+ var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
+
+ var activeElementIndex = this._getItemIndex(activeElement);
+
+ var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
+
+ var nextElementIndex = this._getItemIndex(nextElement);
+
+ var isCycling = Boolean(this._interval);
+ var directionalClassName;
+ var orderClassName;
+ var eventDirectionName;
+
+ if (direction === Direction.NEXT) {
+ directionalClassName = ClassName$2.LEFT;
+ orderClassName = ClassName$2.NEXT;
+ eventDirectionName = Direction.LEFT;
+ } else {
+ directionalClassName = ClassName$2.RIGHT;
+ orderClassName = ClassName$2.PREV;
+ eventDirectionName = Direction.RIGHT;
+ }
+
+ if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) {
+ this._isSliding = false;
+ return;
+ }
+
+ var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
+
+ if (slideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (!activeElement || !nextElement) {
+ // Some weirdness is happening, so we bail
+ return;
+ }
+
+ this._isSliding = true;
+
+ if (isCycling) {
+ this.pause();
+ }
+
+ this._setActiveIndicatorElement(nextElement);
+
+ var slidEvent = $.Event(Event$2.SLID, {
+ relatedTarget: nextElement,
+ direction: eventDirectionName,
+ from: activeElementIndex,
+ to: nextElementIndex
+ });
+
+ if ($(this._element).hasClass(ClassName$2.SLIDE)) {
+ $(nextElement).addClass(orderClassName);
+ Util.reflow(nextElement);
+ $(activeElement).addClass(directionalClassName);
+ $(nextElement).addClass(directionalClassName);
+ var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);
+
+ if (nextElementInterval) {
+ this._config.defaultInterval = this._config.defaultInterval || this._config.interval;
+ this._config.interval = nextElementInterval;
+ } else {
+ this._config.interval = this._config.defaultInterval || this._config.interval;
+ }
+
+ var transitionDuration = Util.getTransitionDurationFromElement(activeElement);
+ $(activeElement).one(Util.TRANSITION_END, function () {
+ $(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName$2.ACTIVE);
+ $(activeElement).removeClass(ClassName$2.ACTIVE + " " + orderClassName + " " + directionalClassName);
+ _this4._isSliding = false;
+ setTimeout(function () {
+ return $(_this4._element).trigger(slidEvent);
+ }, 0);
+ }).emulateTransitionEnd(transitionDuration);
+ } else {
+ $(activeElement).removeClass(ClassName$2.ACTIVE);
+ $(nextElement).addClass(ClassName$2.ACTIVE);
+ this._isSliding = false;
+ $(this._element).trigger(slidEvent);
+ }
+
+ if (isCycling) {
+ this.cycle();
+ }
+ } // Static
+ ;
+
+ Carousel._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$2);
+
+ var _config = _objectSpread2({}, Default, {}, $(this).data());
+
+ if (typeof config === 'object') {
+ _config = _objectSpread2({}, _config, {}, config);
+ }
+
+ var action = typeof config === 'string' ? config : _config.slide;
+
+ if (!data) {
+ data = new Carousel(this, _config);
+ $(this).data(DATA_KEY$2, data);
+ }
+
+ if (typeof config === 'number') {
+ data.to(config);
+ } else if (typeof action === 'string') {
+ if (typeof data[action] === 'undefined') {
+ throw new TypeError("No method named \"" + action + "\"");
+ }
+
+ data[action]();
+ } else if (_config.interval && _config.ride) {
+ data.pause();
+ data.cycle();
+ }
+ });
+ };
+
+ Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
+ var selector = Util.getSelectorFromElement(this);
+
+ if (!selector) {
+ return;
+ }
+
+ var target = $(selector)[0];
+
+ if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) {
+ return;
+ }
+
+ var config = _objectSpread2({}, $(target).data(), {}, $(this).data());
+
+ var slideIndex = this.getAttribute('data-slide-to');
+
+ if (slideIndex) {
+ config.interval = false;
+ }
+
+ Carousel._jQueryInterface.call($(target), config);
+
+ if (slideIndex) {
+ $(target).data(DATA_KEY$2).to(slideIndex);
+ }
+
+ event.preventDefault();
+ };
+
+ _createClass(Carousel, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$2;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default;
+ }
+ }]);
+
+ return Carousel;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler);
+ $(window).on(Event$2.LOAD_DATA_API, function () {
+ var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));
+
+ for (var i = 0, len = carousels.length; i < len; i++) {
+ var $carousel = $(carousels[i]);
+
+ Carousel._jQueryInterface.call($carousel, $carousel.data());
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$2] = Carousel._jQueryInterface;
+ $.fn[NAME$2].Constructor = Carousel;
+
+ $.fn[NAME$2].noConflict = function () {
+ $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;
+ return Carousel._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$3 = 'collapse';
+ var VERSION$3 = '4.4.1';
+ var DATA_KEY$3 = 'bs.collapse';
+ var EVENT_KEY$3 = "." + DATA_KEY$3;
+ var DATA_API_KEY$3 = '.data-api';
+ var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];
+ var Default$1 = {
+ toggle: true,
+ parent: ''
+ };
+ var DefaultType$1 = {
+ toggle: 'boolean',
+ parent: '(string|element)'
+ };
+ var Event$3 = {
+ SHOW: "show" + EVENT_KEY$3,
+ SHOWN: "shown" + EVENT_KEY$3,
+ HIDE: "hide" + EVENT_KEY$3,
+ HIDDEN: "hidden" + EVENT_KEY$3,
+ CLICK_DATA_API: "click" + EVENT_KEY$3 + DATA_API_KEY$3
+ };
+ var ClassName$3 = {
+ SHOW: 'show',
+ COLLAPSE: 'collapse',
+ COLLAPSING: 'collapsing',
+ COLLAPSED: 'collapsed'
+ };
+ var Dimension = {
+ WIDTH: 'width',
+ HEIGHT: 'height'
+ };
+ var Selector$3 = {
+ ACTIVES: '.show, .collapsing',
+ DATA_TOGGLE: '[data-toggle="collapse"]'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Collapse =
+ /*#__PURE__*/
+ function () {
+ function Collapse(element, config) {
+ this._isTransitioning = false;
+ this._element = element;
+ this._config = this._getConfig(config);
+ this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
+ var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE));
+
+ for (var i = 0, len = toggleList.length; i < len; i++) {
+ var elem = toggleList[i];
+ var selector = Util.getSelectorFromElement(elem);
+ var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {
+ return foundElem === element;
+ });
+
+ if (selector !== null && filterElement.length > 0) {
+ this._selector = selector;
+
+ this._triggerArray.push(elem);
+ }
+ }
+
+ this._parent = this._config.parent ? this._getParent() : null;
+
+ if (!this._config.parent) {
+ this._addAriaAndCollapsedClass(this._element, this._triggerArray);
+ }
+
+ if (this._config.toggle) {
+ this.toggle();
+ }
+ } // Getters
+
+
+ var _proto = Collapse.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ if ($(this._element).hasClass(ClassName$3.SHOW)) {
+ this.hide();
+ } else {
+ this.show();
+ }
+ };
+
+ _proto.show = function show() {
+ var _this = this;
+
+ if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) {
+ return;
+ }
+
+ var actives;
+ var activesData;
+
+ if (this._parent) {
+ actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) {
+ if (typeof _this._config.parent === 'string') {
+ return elem.getAttribute('data-parent') === _this._config.parent;
+ }
+
+ return elem.classList.contains(ClassName$3.COLLAPSE);
+ });
+
+ if (actives.length === 0) {
+ actives = null;
+ }
+ }
+
+ if (actives) {
+ activesData = $(actives).not(this._selector).data(DATA_KEY$3);
+
+ if (activesData && activesData._isTransitioning) {
+ return;
+ }
+ }
+
+ var startEvent = $.Event(Event$3.SHOW);
+ $(this._element).trigger(startEvent);
+
+ if (startEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (actives) {
+ Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');
+
+ if (!activesData) {
+ $(actives).data(DATA_KEY$3, null);
+ }
+ }
+
+ var dimension = this._getDimension();
+
+ $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING);
+ this._element.style[dimension] = 0;
+
+ if (this._triggerArray.length) {
+ $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true);
+ }
+
+ this.setTransitioning(true);
+
+ var complete = function complete() {
+ $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW);
+ _this._element.style[dimension] = '';
+
+ _this.setTransitioning(false);
+
+ $(_this._element).trigger(Event$3.SHOWN);
+ };
+
+ var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
+ var scrollSize = "scroll" + capitalizedDimension;
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ this._element.style[dimension] = this._element[scrollSize] + "px";
+ };
+
+ _proto.hide = function hide() {
+ var _this2 = this;
+
+ if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) {
+ return;
+ }
+
+ var startEvent = $.Event(Event$3.HIDE);
+ $(this._element).trigger(startEvent);
+
+ if (startEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ var dimension = this._getDimension();
+
+ this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
+ Util.reflow(this._element);
+ $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW);
+ var triggerArrayLength = this._triggerArray.length;
+
+ if (triggerArrayLength > 0) {
+ for (var i = 0; i < triggerArrayLength; i++) {
+ var trigger = this._triggerArray[i];
+ var selector = Util.getSelectorFromElement(trigger);
+
+ if (selector !== null) {
+ var $elem = $([].slice.call(document.querySelectorAll(selector)));
+
+ if (!$elem.hasClass(ClassName$3.SHOW)) {
+ $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false);
+ }
+ }
+ }
+ }
+
+ this.setTransitioning(true);
+
+ var complete = function complete() {
+ _this2.setTransitioning(false);
+
+ $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN);
+ };
+
+ this._element.style[dimension] = '';
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ };
+
+ _proto.setTransitioning = function setTransitioning(isTransitioning) {
+ this._isTransitioning = isTransitioning;
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$3);
+ this._config = null;
+ this._parent = null;
+ this._element = null;
+ this._triggerArray = null;
+ this._isTransitioning = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$1, {}, config);
+ config.toggle = Boolean(config.toggle); // Coerce string values
+
+ Util.typeCheckConfig(NAME$3, config, DefaultType$1);
+ return config;
+ };
+
+ _proto._getDimension = function _getDimension() {
+ var hasWidth = $(this._element).hasClass(Dimension.WIDTH);
+ return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
+ };
+
+ _proto._getParent = function _getParent() {
+ var _this3 = this;
+
+ var parent;
+
+ if (Util.isElement(this._config.parent)) {
+ parent = this._config.parent; // It's a jQuery object
+
+ if (typeof this._config.parent.jquery !== 'undefined') {
+ parent = this._config.parent[0];
+ }
+ } else {
+ parent = document.querySelector(this._config.parent);
+ }
+
+ var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
+ var children = [].slice.call(parent.querySelectorAll(selector));
+ $(children).each(function (i, element) {
+ _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
+ });
+ return parent;
+ };
+
+ _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
+ var isOpen = $(element).hasClass(ClassName$3.SHOW);
+
+ if (triggerArray.length) {
+ $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
+ }
+ } // Static
+ ;
+
+ Collapse._getTargetFromElement = function _getTargetFromElement(element) {
+ var selector = Util.getSelectorFromElement(element);
+ return selector ? document.querySelector(selector) : null;
+ };
+
+ Collapse._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $this = $(this);
+ var data = $this.data(DATA_KEY$3);
+
+ var _config = _objectSpread2({}, Default$1, {}, $this.data(), {}, typeof config === 'object' && config ? config : {});
+
+ if (!data && _config.toggle && /show|hide/.test(config)) {
+ _config.toggle = false;
+ }
+
+ if (!data) {
+ data = new Collapse(this, _config);
+ $this.data(DATA_KEY$3, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Collapse, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$3;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$1;
+ }
+ }]);
+
+ return Collapse;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) {
+ // preventDefault only for elements (which change the URL) not inside the collapsible element
+ if (event.currentTarget.tagName === 'A') {
+ event.preventDefault();
+ }
+
+ var $trigger = $(this);
+ var selector = Util.getSelectorFromElement(this);
+ var selectors = [].slice.call(document.querySelectorAll(selector));
+ $(selectors).each(function () {
+ var $target = $(this);
+ var data = $target.data(DATA_KEY$3);
+ var config = data ? 'toggle' : $trigger.data();
+
+ Collapse._jQueryInterface.call($target, config);
+ });
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$3] = Collapse._jQueryInterface;
+ $.fn[NAME$3].Constructor = Collapse;
+
+ $.fn[NAME$3].noConflict = function () {
+ $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;
+ return Collapse._jQueryInterface;
+ };
+
+ /**!
+ * @fileOverview Kickass library to create and place poppers near their reference elements.
+ * @version 1.16.0
+ * @license
+ * Copyright (c) 2016 Federico Zivolo and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+ var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';
+
+ var timeoutDuration = function () {
+ var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
+ for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
+ if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
+ return 1;
+ }
+ }
+ return 0;
+ }();
+
+ function microtaskDebounce(fn) {
+ var called = false;
+ return function () {
+ if (called) {
+ return;
+ }
+ called = true;
+ window.Promise.resolve().then(function () {
+ called = false;
+ fn();
+ });
+ };
+ }
+
+ function taskDebounce(fn) {
+ var scheduled = false;
+ return function () {
+ if (!scheduled) {
+ scheduled = true;
+ setTimeout(function () {
+ scheduled = false;
+ fn();
+ }, timeoutDuration);
+ }
+ };
+ }
+
+ var supportsMicroTasks = isBrowser && window.Promise;
+
+ /**
+ * Create a debounced version of a method, that's asynchronously deferred
+ * but called in the minimum time possible.
+ *
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Function} fn
+ * @returns {Function}
+ */
+ var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
+
+ /**
+ * Check if the given variable is a function
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Any} functionToCheck - variable to check
+ * @returns {Boolean} answer to: is a function?
+ */
+ function isFunction(functionToCheck) {
+ var getType = {};
+ return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
+ }
+
+ /**
+ * Get CSS computed property of the given element
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Eement} element
+ * @argument {String} property
+ */
+ function getStyleComputedProperty(element, property) {
+ if (element.nodeType !== 1) {
+ return [];
+ }
+ // NOTE: 1 DOM access here
+ var window = element.ownerDocument.defaultView;
+ var css = window.getComputedStyle(element, null);
+ return property ? css[property] : css;
+ }
+
+ /**
+ * Returns the parentNode or the host of the element
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @returns {Element} parent
+ */
+ function getParentNode(element) {
+ if (element.nodeName === 'HTML') {
+ return element;
+ }
+ return element.parentNode || element.host;
+ }
+
+ /**
+ * Returns the scrolling parent of the given element
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @returns {Element} scroll parent
+ */
+ function getScrollParent(element) {
+ // Return body, `getScroll` will take care to get the correct `scrollTop` from it
+ if (!element) {
+ return document.body;
+ }
+
+ switch (element.nodeName) {
+ case 'HTML':
+ case 'BODY':
+ return element.ownerDocument.body;
+ case '#document':
+ return element.body;
+ }
+
+ // Firefox want us to check `-x` and `-y` variations as well
+
+ var _getStyleComputedProp = getStyleComputedProperty(element),
+ overflow = _getStyleComputedProp.overflow,
+ overflowX = _getStyleComputedProp.overflowX,
+ overflowY = _getStyleComputedProp.overflowY;
+
+ if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
+ return element;
+ }
+
+ return getScrollParent(getParentNode(element));
+ }
+
+ /**
+ * Returns the reference node of the reference object, or the reference object itself.
+ * @method
+ * @memberof Popper.Utils
+ * @param {Element|Object} reference - the reference element (the popper will be relative to this)
+ * @returns {Element} parent
+ */
+ function getReferenceNode(reference) {
+ return reference && reference.referenceNode ? reference.referenceNode : reference;
+ }
+
+ var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
+ var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);
+
+ /**
+ * Determines if the browser is Internet Explorer
+ * @method
+ * @memberof Popper.Utils
+ * @param {Number} version to check
+ * @returns {Boolean} isIE
+ */
+ function isIE(version) {
+ if (version === 11) {
+ return isIE11;
+ }
+ if (version === 10) {
+ return isIE10;
+ }
+ return isIE11 || isIE10;
+ }
+
+ /**
+ * Returns the offset parent of the given element
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @returns {Element} offset parent
+ */
+ function getOffsetParent(element) {
+ if (!element) {
+ return document.documentElement;
+ }
+
+ var noOffsetParent = isIE(10) ? document.body : null;
+
+ // NOTE: 1 DOM access here
+ var offsetParent = element.offsetParent || null;
+ // Skip hidden elements which don't have an offsetParent
+ while (offsetParent === noOffsetParent && element.nextElementSibling) {
+ offsetParent = (element = element.nextElementSibling).offsetParent;
+ }
+
+ var nodeName = offsetParent && offsetParent.nodeName;
+
+ if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
+ return element ? element.ownerDocument.documentElement : document.documentElement;
+ }
+
+ // .offsetParent will return the closest TH, TD or TABLE in case
+ // no offsetParent is present, I hate this job...
+ if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
+ return getOffsetParent(offsetParent);
+ }
+
+ return offsetParent;
+ }
+
+ function isOffsetContainer(element) {
+ var nodeName = element.nodeName;
+
+ if (nodeName === 'BODY') {
+ return false;
+ }
+ return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
+ }
+
+ /**
+ * Finds the root node (document, shadowDOM root) of the given element
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} node
+ * @returns {Element} root node
+ */
+ function getRoot(node) {
+ if (node.parentNode !== null) {
+ return getRoot(node.parentNode);
+ }
+
+ return node;
+ }
+
+ /**
+ * Finds the offset parent common to the two provided nodes
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element1
+ * @argument {Element} element2
+ * @returns {Element} common offset parent
+ */
+ function findCommonOffsetParent(element1, element2) {
+ // This check is needed to avoid errors in case one of the elements isn't defined for any reason
+ if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
+ return document.documentElement;
+ }
+
+ // Here we make sure to give as "start" the element that comes first in the DOM
+ var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
+ var start = order ? element1 : element2;
+ var end = order ? element2 : element1;
+
+ // Get common ancestor container
+ var range = document.createRange();
+ range.setStart(start, 0);
+ range.setEnd(end, 0);
+ var commonAncestorContainer = range.commonAncestorContainer;
+
+ // Both nodes are inside #document
+
+ if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
+ if (isOffsetContainer(commonAncestorContainer)) {
+ return commonAncestorContainer;
+ }
+
+ return getOffsetParent(commonAncestorContainer);
+ }
+
+ // one of the nodes is inside shadowDOM, find which one
+ var element1root = getRoot(element1);
+ if (element1root.host) {
+ return findCommonOffsetParent(element1root.host, element2);
+ } else {
+ return findCommonOffsetParent(element1, getRoot(element2).host);
+ }
+ }
+
+ /**
+ * Gets the scroll value of the given element in the given side (top and left)
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @argument {String} side `top` or `left`
+ * @returns {number} amount of scrolled pixels
+ */
+ function getScroll(element) {
+ var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
+
+ var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
+ var nodeName = element.nodeName;
+
+ if (nodeName === 'BODY' || nodeName === 'HTML') {
+ var html = element.ownerDocument.documentElement;
+ var scrollingElement = element.ownerDocument.scrollingElement || html;
+ return scrollingElement[upperSide];
+ }
+
+ return element[upperSide];
+ }
+
+ /*
+ * Sum or subtract the element scroll values (left and top) from a given rect object
+ * @method
+ * @memberof Popper.Utils
+ * @param {Object} rect - Rect object you want to change
+ * @param {HTMLElement} element - The element from the function reads the scroll values
+ * @param {Boolean} subtract - set to true if you want to subtract the scroll values
+ * @return {Object} rect - The modifier rect object
+ */
+ function includeScroll(rect, element) {
+ var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+ var scrollTop = getScroll(element, 'top');
+ var scrollLeft = getScroll(element, 'left');
+ var modifier = subtract ? -1 : 1;
+ rect.top += scrollTop * modifier;
+ rect.bottom += scrollTop * modifier;
+ rect.left += scrollLeft * modifier;
+ rect.right += scrollLeft * modifier;
+ return rect;
+ }
+
+ /*
+ * Helper to detect borders of a given element
+ * @method
+ * @memberof Popper.Utils
+ * @param {CSSStyleDeclaration} styles
+ * Result of `getStyleComputedProperty` on the given element
+ * @param {String} axis - `x` or `y`
+ * @return {number} borders - The borders size of the given axis
+ */
+
+ function getBordersSize(styles, axis) {
+ var sideA = axis === 'x' ? 'Left' : 'Top';
+ var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
+
+ return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
+ }
+
+ function getSize(axis, body, html, computedStyle) {
+ return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);
+ }
+
+ function getWindowSizes(document) {
+ var body = document.body;
+ var html = document.documentElement;
+ var computedStyle = isIE(10) && getComputedStyle(html);
+
+ return {
+ height: getSize('Height', body, html, computedStyle),
+ width: getSize('Width', body, html, computedStyle)
+ };
+ }
+
+ var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ };
+
+ var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+
+
+
+
+ var defineProperty = function (obj, key, value) {
+ if (key in obj) {
+ Object.defineProperty(obj, key, {
+ value: value,
+ enumerable: true,
+ configurable: true,
+ writable: true
+ });
+ } else {
+ obj[key] = value;
+ }
+
+ return obj;
+ };
+
+ var _extends = Object.assign || function (target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+
+ for (var key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+
+ return target;
+ };
+
+ /**
+ * Given element offsets, generate an output similar to getBoundingClientRect
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Object} offsets
+ * @returns {Object} ClientRect like output
+ */
+ function getClientRect(offsets) {
+ return _extends({}, offsets, {
+ right: offsets.left + offsets.width,
+ bottom: offsets.top + offsets.height
+ });
+ }
+
+ /**
+ * Get bounding client rect of given element
+ * @method
+ * @memberof Popper.Utils
+ * @param {HTMLElement} element
+ * @return {Object} client rect
+ */
+ function getBoundingClientRect(element) {
+ var rect = {};
+
+ // IE10 10 FIX: Please, don't ask, the element isn't
+ // considered in DOM in some circumstances...
+ // This isn't reproducible in IE10 compatibility mode of IE11
+ try {
+ if (isIE(10)) {
+ rect = element.getBoundingClientRect();
+ var scrollTop = getScroll(element, 'top');
+ var scrollLeft = getScroll(element, 'left');
+ rect.top += scrollTop;
+ rect.left += scrollLeft;
+ rect.bottom += scrollTop;
+ rect.right += scrollLeft;
+ } else {
+ rect = element.getBoundingClientRect();
+ }
+ } catch (e) {}
+
+ var result = {
+ left: rect.left,
+ top: rect.top,
+ width: rect.right - rect.left,
+ height: rect.bottom - rect.top
+ };
+
+ // subtract scrollbar size from sizes
+ var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};
+ var width = sizes.width || element.clientWidth || result.width;
+ var height = sizes.height || element.clientHeight || result.height;
+
+ var horizScrollbar = element.offsetWidth - width;
+ var vertScrollbar = element.offsetHeight - height;
+
+ // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
+ // we make this check conditional for performance reasons
+ if (horizScrollbar || vertScrollbar) {
+ var styles = getStyleComputedProperty(element);
+ horizScrollbar -= getBordersSize(styles, 'x');
+ vertScrollbar -= getBordersSize(styles, 'y');
+
+ result.width -= horizScrollbar;
+ result.height -= vertScrollbar;
+ }
+
+ return getClientRect(result);
+ }
+
+ function getOffsetRectRelativeToArbitraryNode(children, parent) {
+ var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+ var isIE10 = isIE(10);
+ var isHTML = parent.nodeName === 'HTML';
+ var childrenRect = getBoundingClientRect(children);
+ var parentRect = getBoundingClientRect(parent);
+ var scrollParent = getScrollParent(children);
+
+ var styles = getStyleComputedProperty(parent);
+ var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
+ var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
+
+ // In cases where the parent is fixed, we must ignore negative scroll in offset calc
+ if (fixedPosition && isHTML) {
+ parentRect.top = Math.max(parentRect.top, 0);
+ parentRect.left = Math.max(parentRect.left, 0);
+ }
+ var offsets = getClientRect({
+ top: childrenRect.top - parentRect.top - borderTopWidth,
+ left: childrenRect.left - parentRect.left - borderLeftWidth,
+ width: childrenRect.width,
+ height: childrenRect.height
+ });
+ offsets.marginTop = 0;
+ offsets.marginLeft = 0;
+
+ // Subtract margins of documentElement in case it's being used as parent
+ // we do this only on HTML because it's the only element that behaves
+ // differently when margins are applied to it. The margins are included in
+ // the box of the documentElement, in the other cases not.
+ if (!isIE10 && isHTML) {
+ var marginTop = parseFloat(styles.marginTop, 10);
+ var marginLeft = parseFloat(styles.marginLeft, 10);
+
+ offsets.top -= borderTopWidth - marginTop;
+ offsets.bottom -= borderTopWidth - marginTop;
+ offsets.left -= borderLeftWidth - marginLeft;
+ offsets.right -= borderLeftWidth - marginLeft;
+
+ // Attach marginTop and marginLeft because in some circumstances we may need them
+ offsets.marginTop = marginTop;
+ offsets.marginLeft = marginLeft;
+ }
+
+ if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
+ offsets = includeScroll(offsets, parent);
+ }
+
+ return offsets;
+ }
+
+ function getViewportOffsetRectRelativeToArtbitraryNode(element) {
+ var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+ var html = element.ownerDocument.documentElement;
+ var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
+ var width = Math.max(html.clientWidth, window.innerWidth || 0);
+ var height = Math.max(html.clientHeight, window.innerHeight || 0);
+
+ var scrollTop = !excludeScroll ? getScroll(html) : 0;
+ var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;
+
+ var offset = {
+ top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
+ left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
+ width: width,
+ height: height
+ };
+
+ return getClientRect(offset);
+ }
+
+ /**
+ * Check if the given element is fixed or is inside a fixed parent
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @argument {Element} customContainer
+ * @returns {Boolean} answer to "isFixed?"
+ */
+ function isFixed(element) {
+ var nodeName = element.nodeName;
+ if (nodeName === 'BODY' || nodeName === 'HTML') {
+ return false;
+ }
+ if (getStyleComputedProperty(element, 'position') === 'fixed') {
+ return true;
+ }
+ var parentNode = getParentNode(element);
+ if (!parentNode) {
+ return false;
+ }
+ return isFixed(parentNode);
+ }
+
+ /**
+ * Finds the first parent of an element that has a transformed property defined
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @returns {Element} first transformed parent or documentElement
+ */
+
+ function getFixedPositionOffsetParent(element) {
+ // This check is needed to avoid errors in case one of the elements isn't defined for any reason
+ if (!element || !element.parentElement || isIE()) {
+ return document.documentElement;
+ }
+ var el = element.parentElement;
+ while (el && getStyleComputedProperty(el, 'transform') === 'none') {
+ el = el.parentElement;
+ }
+ return el || document.documentElement;
+ }
+
+ /**
+ * Computed the boundaries limits and return them
+ * @method
+ * @memberof Popper.Utils
+ * @param {HTMLElement} popper
+ * @param {HTMLElement} reference
+ * @param {number} padding
+ * @param {HTMLElement} boundariesElement - Element used to define the boundaries
+ * @param {Boolean} fixedPosition - Is in fixed position mode
+ * @returns {Object} Coordinates of the boundaries
+ */
+ function getBoundaries(popper, reference, padding, boundariesElement) {
+ var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+
+ // NOTE: 1 DOM access here
+
+ var boundaries = { top: 0, left: 0 };
+ var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));
+
+ // Handle viewport case
+ if (boundariesElement === 'viewport') {
+ boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
+ } else {
+ // Handle other cases based on DOM element used as boundaries
+ var boundariesNode = void 0;
+ if (boundariesElement === 'scrollParent') {
+ boundariesNode = getScrollParent(getParentNode(reference));
+ if (boundariesNode.nodeName === 'BODY') {
+ boundariesNode = popper.ownerDocument.documentElement;
+ }
+ } else if (boundariesElement === 'window') {
+ boundariesNode = popper.ownerDocument.documentElement;
+ } else {
+ boundariesNode = boundariesElement;
+ }
+
+ var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);
+
+ // In case of HTML, we need a different computation
+ if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
+ var _getWindowSizes = getWindowSizes(popper.ownerDocument),
+ height = _getWindowSizes.height,
+ width = _getWindowSizes.width;
+
+ boundaries.top += offsets.top - offsets.marginTop;
+ boundaries.bottom = height + offsets.top;
+ boundaries.left += offsets.left - offsets.marginLeft;
+ boundaries.right = width + offsets.left;
+ } else {
+ // for all the other DOM elements, this one is good
+ boundaries = offsets;
+ }
+ }
+
+ // Add paddings
+ padding = padding || 0;
+ var isPaddingNumber = typeof padding === 'number';
+ boundaries.left += isPaddingNumber ? padding : padding.left || 0;
+ boundaries.top += isPaddingNumber ? padding : padding.top || 0;
+ boundaries.right -= isPaddingNumber ? padding : padding.right || 0;
+ boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;
+
+ return boundaries;
+ }
+
+ function getArea(_ref) {
+ var width = _ref.width,
+ height = _ref.height;
+
+ return width * height;
+ }
+
+ /**
+ * Utility used to transform the `auto` placement to the placement with more
+ * available space.
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
+ var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
+
+ if (placement.indexOf('auto') === -1) {
+ return placement;
+ }
+
+ var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
+
+ var rects = {
+ top: {
+ width: boundaries.width,
+ height: refRect.top - boundaries.top
+ },
+ right: {
+ width: boundaries.right - refRect.right,
+ height: boundaries.height
+ },
+ bottom: {
+ width: boundaries.width,
+ height: boundaries.bottom - refRect.bottom
+ },
+ left: {
+ width: refRect.left - boundaries.left,
+ height: boundaries.height
+ }
+ };
+
+ var sortedAreas = Object.keys(rects).map(function (key) {
+ return _extends({
+ key: key
+ }, rects[key], {
+ area: getArea(rects[key])
+ });
+ }).sort(function (a, b) {
+ return b.area - a.area;
+ });
+
+ var filteredAreas = sortedAreas.filter(function (_ref2) {
+ var width = _ref2.width,
+ height = _ref2.height;
+ return width >= popper.clientWidth && height >= popper.clientHeight;
+ });
+
+ var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
+
+ var variation = placement.split('-')[1];
+
+ return computedPlacement + (variation ? '-' + variation : '');
+ }
+
+ /**
+ * Get offsets to the reference element
+ * @method
+ * @memberof Popper.Utils
+ * @param {Object} state
+ * @param {Element} popper - the popper element
+ * @param {Element} reference - the reference element (the popper will be relative to this)
+ * @param {Element} fixedPosition - is in fixed position mode
+ * @returns {Object} An object containing the offsets which will be applied to the popper
+ */
+ function getReferenceOffsets(state, popper, reference) {
+ var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
+
+ var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));
+ return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
+ }
+
+ /**
+ * Get the outer sizes of the given element (offset size + margins)
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element
+ * @returns {Object} object containing width and height properties
+ */
+ function getOuterSizes(element) {
+ var window = element.ownerDocument.defaultView;
+ var styles = window.getComputedStyle(element);
+ var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);
+ var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);
+ var result = {
+ width: element.offsetWidth + y,
+ height: element.offsetHeight + x
+ };
+ return result;
+ }
+
+ /**
+ * Get the opposite placement of the given one
+ * @method
+ * @memberof Popper.Utils
+ * @argument {String} placement
+ * @returns {String} flipped placement
+ */
+ function getOppositePlacement(placement) {
+ var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
+ return placement.replace(/left|right|bottom|top/g, function (matched) {
+ return hash[matched];
+ });
+ }
+
+ /**
+ * Get offsets to the popper
+ * @method
+ * @memberof Popper.Utils
+ * @param {Object} position - CSS position the Popper will get applied
+ * @param {HTMLElement} popper - the popper element
+ * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
+ * @param {String} placement - one of the valid placement options
+ * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
+ */
+ function getPopperOffsets(popper, referenceOffsets, placement) {
+ placement = placement.split('-')[0];
+
+ // Get popper node sizes
+ var popperRect = getOuterSizes(popper);
+
+ // Add position, width and height to our offsets object
+ var popperOffsets = {
+ width: popperRect.width,
+ height: popperRect.height
+ };
+
+ // depending by the popper placement we have to compute its offsets slightly differently
+ var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
+ var mainSide = isHoriz ? 'top' : 'left';
+ var secondarySide = isHoriz ? 'left' : 'top';
+ var measurement = isHoriz ? 'height' : 'width';
+ var secondaryMeasurement = !isHoriz ? 'height' : 'width';
+
+ popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
+ if (placement === secondarySide) {
+ popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
+ } else {
+ popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
+ }
+
+ return popperOffsets;
+ }
+
+ /**
+ * Mimics the `find` method of Array
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Array} arr
+ * @argument prop
+ * @argument value
+ * @returns index or -1
+ */
+ function find(arr, check) {
+ // use native find if supported
+ if (Array.prototype.find) {
+ return arr.find(check);
+ }
+
+ // use `filter` to obtain the same behavior of `find`
+ return arr.filter(check)[0];
+ }
+
+ /**
+ * Return the index of the matching object
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Array} arr
+ * @argument prop
+ * @argument value
+ * @returns index or -1
+ */
+ function findIndex(arr, prop, value) {
+ // use native findIndex if supported
+ if (Array.prototype.findIndex) {
+ return arr.findIndex(function (cur) {
+ return cur[prop] === value;
+ });
+ }
+
+ // use `find` + `indexOf` if `findIndex` isn't supported
+ var match = find(arr, function (obj) {
+ return obj[prop] === value;
+ });
+ return arr.indexOf(match);
+ }
+
+ /**
+ * Loop trough the list of modifiers and run them in order,
+ * each of them will then edit the data object.
+ * @method
+ * @memberof Popper.Utils
+ * @param {dataObject} data
+ * @param {Array} modifiers
+ * @param {String} ends - Optional modifier name used as stopper
+ * @returns {dataObject}
+ */
+ function runModifiers(modifiers, data, ends) {
+ var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
+
+ modifiersToRun.forEach(function (modifier) {
+ if (modifier['function']) {
+ // eslint-disable-line dot-notation
+ console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
+ }
+ var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
+ if (modifier.enabled && isFunction(fn)) {
+ // Add properties to offsets to make them a complete clientRect object
+ // we do this before each modifier to make sure the previous one doesn't
+ // mess with these values
+ data.offsets.popper = getClientRect(data.offsets.popper);
+ data.offsets.reference = getClientRect(data.offsets.reference);
+
+ data = fn(data, modifier);
+ }
+ });
+
+ return data;
+ }
+
+ /**
+ * Updates the position of the popper, computing the new offsets and applying
+ * the new style.
+ * Prefer `scheduleUpdate` over `update` because of performance reasons.
+ * @method
+ * @memberof Popper
+ */
+ function update() {
+ // if popper is destroyed, don't perform any further update
+ if (this.state.isDestroyed) {
+ return;
+ }
+
+ var data = {
+ instance: this,
+ styles: {},
+ arrowStyles: {},
+ attributes: {},
+ flipped: false,
+ offsets: {}
+ };
+
+ // compute reference element offsets
+ data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);
+
+ // compute auto placement, store placement inside the data object,
+ // modifiers will be able to edit `placement` if needed
+ // and refer to originalPlacement to know the original value
+ data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);
+
+ // store the computed placement inside `originalPlacement`
+ data.originalPlacement = data.placement;
+
+ data.positionFixed = this.options.positionFixed;
+
+ // compute the popper offsets
+ data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
+
+ data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';
+
+ // run the modifiers
+ data = runModifiers(this.modifiers, data);
+
+ // the first `update` will call `onCreate` callback
+ // the other ones will call `onUpdate` callback
+ if (!this.state.isCreated) {
+ this.state.isCreated = true;
+ this.options.onCreate(data);
+ } else {
+ this.options.onUpdate(data);
+ }
+ }
+
+ /**
+ * Helper used to know if the given modifier is enabled.
+ * @method
+ * @memberof Popper.Utils
+ * @returns {Boolean}
+ */
+ function isModifierEnabled(modifiers, modifierName) {
+ return modifiers.some(function (_ref) {
+ var name = _ref.name,
+ enabled = _ref.enabled;
+ return enabled && name === modifierName;
+ });
+ }
+
+ /**
+ * Get the prefixed supported property name
+ * @method
+ * @memberof Popper.Utils
+ * @argument {String} property (camelCase)
+ * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
+ */
+ function getSupportedPropertyName(property) {
+ var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
+ var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
+
+ for (var i = 0; i < prefixes.length; i++) {
+ var prefix = prefixes[i];
+ var toCheck = prefix ? '' + prefix + upperProp : property;
+ if (typeof document.body.style[toCheck] !== 'undefined') {
+ return toCheck;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Destroys the popper.
+ * @method
+ * @memberof Popper
+ */
+ function destroy() {
+ this.state.isDestroyed = true;
+
+ // touch DOM only if `applyStyle` modifier is enabled
+ if (isModifierEnabled(this.modifiers, 'applyStyle')) {
+ this.popper.removeAttribute('x-placement');
+ this.popper.style.position = '';
+ this.popper.style.top = '';
+ this.popper.style.left = '';
+ this.popper.style.right = '';
+ this.popper.style.bottom = '';
+ this.popper.style.willChange = '';
+ this.popper.style[getSupportedPropertyName('transform')] = '';
+ }
+
+ this.disableEventListeners();
+
+ // remove the popper if user explicitly asked for the deletion on destroy
+ // do not use `remove` because IE11 doesn't support it
+ if (this.options.removeOnDestroy) {
+ this.popper.parentNode.removeChild(this.popper);
+ }
+ return this;
+ }
+
+ /**
+ * Get the window associated with the element
+ * @argument {Element} element
+ * @returns {Window}
+ */
+ function getWindow(element) {
+ var ownerDocument = element.ownerDocument;
+ return ownerDocument ? ownerDocument.defaultView : window;
+ }
+
+ function attachToScrollParents(scrollParent, event, callback, scrollParents) {
+ var isBody = scrollParent.nodeName === 'BODY';
+ var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
+ target.addEventListener(event, callback, { passive: true });
+
+ if (!isBody) {
+ attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
+ }
+ scrollParents.push(target);
+ }
+
+ /**
+ * Setup needed event listeners used to update the popper position
+ * @method
+ * @memberof Popper.Utils
+ * @private
+ */
+ function setupEventListeners(reference, options, state, updateBound) {
+ // Resize event listener on window
+ state.updateBound = updateBound;
+ getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
+
+ // Scroll event listener on scroll parents
+ var scrollElement = getScrollParent(reference);
+ attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
+ state.scrollElement = scrollElement;
+ state.eventsEnabled = true;
+
+ return state;
+ }
+
+ /**
+ * It will add resize/scroll events and start recalculating
+ * position of the popper element when they are triggered.
+ * @method
+ * @memberof Popper
+ */
+ function enableEventListeners() {
+ if (!this.state.eventsEnabled) {
+ this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
+ }
+ }
+
+ /**
+ * Remove event listeners used to update the popper position
+ * @method
+ * @memberof Popper.Utils
+ * @private
+ */
+ function removeEventListeners(reference, state) {
+ // Remove resize event listener on window
+ getWindow(reference).removeEventListener('resize', state.updateBound);
+
+ // Remove scroll event listener on scroll parents
+ state.scrollParents.forEach(function (target) {
+ target.removeEventListener('scroll', state.updateBound);
+ });
+
+ // Reset state
+ state.updateBound = null;
+ state.scrollParents = [];
+ state.scrollElement = null;
+ state.eventsEnabled = false;
+ return state;
+ }
+
+ /**
+ * It will remove resize/scroll events and won't recalculate popper position
+ * when they are triggered. It also won't trigger `onUpdate` callback anymore,
+ * unless you call `update` method manually.
+ * @method
+ * @memberof Popper
+ */
+ function disableEventListeners() {
+ if (this.state.eventsEnabled) {
+ cancelAnimationFrame(this.scheduleUpdate);
+ this.state = removeEventListeners(this.reference, this.state);
+ }
+ }
+
+ /**
+ * Tells if a given input is a number
+ * @method
+ * @memberof Popper.Utils
+ * @param {*} input to check
+ * @return {Boolean}
+ */
+ function isNumeric(n) {
+ return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
+ }
+
+ /**
+ * Set the style to the given popper
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element - Element to apply the style to
+ * @argument {Object} styles
+ * Object with a list of properties and values which will be applied to the element
+ */
+ function setStyles(element, styles) {
+ Object.keys(styles).forEach(function (prop) {
+ var unit = '';
+ // add unit if the value is numeric and is one of the following
+ if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
+ unit = 'px';
+ }
+ element.style[prop] = styles[prop] + unit;
+ });
+ }
+
+ /**
+ * Set the attributes to the given popper
+ * @method
+ * @memberof Popper.Utils
+ * @argument {Element} element - Element to apply the attributes to
+ * @argument {Object} styles
+ * Object with a list of properties and values which will be applied to the element
+ */
+ function setAttributes(element, attributes) {
+ Object.keys(attributes).forEach(function (prop) {
+ var value = attributes[prop];
+ if (value !== false) {
+ element.setAttribute(prop, attributes[prop]);
+ } else {
+ element.removeAttribute(prop);
+ }
+ });
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Object} data.styles - List of style properties - values to apply to popper element
+ * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The same data object
+ */
+ function applyStyle(data) {
+ // any property present in `data.styles` will be applied to the popper,
+ // in this way we can make the 3rd party modifiers add custom styles to it
+ // Be aware, modifiers could override the properties defined in the previous
+ // lines of this modifier!
+ setStyles(data.instance.popper, data.styles);
+
+ // any property present in `data.attributes` will be applied to the popper,
+ // they will be set as HTML attributes of the element
+ setAttributes(data.instance.popper, data.attributes);
+
+ // if arrowElement is defined and arrowStyles has some properties
+ if (data.arrowElement && Object.keys(data.arrowStyles).length) {
+ setStyles(data.arrowElement, data.arrowStyles);
+ }
+
+ return data;
+ }
+
+ /**
+ * Set the x-placement attribute before everything else because it could be used
+ * to add margins to the popper margins needs to be calculated to get the
+ * correct popper offsets.
+ * @method
+ * @memberof Popper.modifiers
+ * @param {HTMLElement} reference - The reference element used to position the popper
+ * @param {HTMLElement} popper - The HTML element used as popper
+ * @param {Object} options - Popper.js options
+ */
+ function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
+ // compute reference element offsets
+ var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);
+
+ // compute auto placement, store placement inside the data object,
+ // modifiers will be able to edit `placement` if needed
+ // and refer to originalPlacement to know the original value
+ var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);
+
+ popper.setAttribute('x-placement', placement);
+
+ // Apply `position` to popper before anything else because
+ // without the position applied we can't guarantee correct computations
+ setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });
+
+ return options;
+ }
+
+ /**
+ * @function
+ * @memberof Popper.Utils
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Boolean} shouldRound - If the offsets should be rounded at all
+ * @returns {Object} The popper's position offsets rounded
+ *
+ * The tale of pixel-perfect positioning. It's still not 100% perfect, but as
+ * good as it can be within reason.
+ * Discussion here: https://github.com/FezVrasta/popper.js/pull/715
+ *
+ * Low DPI screens cause a popper to be blurry if not using full pixels (Safari
+ * as well on High DPI screens).
+ *
+ * Firefox prefers no rounding for positioning and does not have blurriness on
+ * high DPI screens.
+ *
+ * Only horizontal placement and left/right values need to be considered.
+ */
+ function getRoundedOffsets(data, shouldRound) {
+ var _data$offsets = data.offsets,
+ popper = _data$offsets.popper,
+ reference = _data$offsets.reference;
+ var round = Math.round,
+ floor = Math.floor;
+
+ var noRound = function noRound(v) {
+ return v;
+ };
+
+ var referenceWidth = round(reference.width);
+ var popperWidth = round(popper.width);
+
+ var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;
+ var isVariation = data.placement.indexOf('-') !== -1;
+ var sameWidthParity = referenceWidth % 2 === popperWidth % 2;
+ var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;
+
+ var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;
+ var verticalToInteger = !shouldRound ? noRound : round;
+
+ return {
+ left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),
+ top: verticalToInteger(popper.top),
+ bottom: verticalToInteger(popper.bottom),
+ right: horizontalToInteger(popper.right)
+ };
+ }
+
+ var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function computeStyle(data, options) {
+ var x = options.x,
+ y = options.y;
+ var popper = data.offsets.popper;
+
+ // Remove this legacy support in Popper.js v2
+
+ var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
+ return modifier.name === 'applyStyle';
+ }).gpuAcceleration;
+ if (legacyGpuAccelerationOption !== undefined) {
+ console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
+ }
+ var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;
+
+ var offsetParent = getOffsetParent(data.instance.popper);
+ var offsetParentRect = getBoundingClientRect(offsetParent);
+
+ // Styles
+ var styles = {
+ position: popper.position
+ };
+
+ var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);
+
+ var sideA = x === 'bottom' ? 'top' : 'bottom';
+ var sideB = y === 'right' ? 'left' : 'right';
+
+ // if gpuAcceleration is set to `true` and transform is supported,
+ // we use `translate3d` to apply the position to the popper we
+ // automatically use the supported prefixed version if needed
+ var prefixedProperty = getSupportedPropertyName('transform');
+
+ // now, let's make a step back and look at this code closely (wtf?)
+ // If the content of the popper grows once it's been positioned, it
+ // may happen that the popper gets misplaced because of the new content
+ // overflowing its reference element
+ // To avoid this problem, we provide two options (x and y), which allow
+ // the consumer to define the offset origin.
+ // If we position a popper on top of a reference element, we can set
+ // `x` to `top` to make the popper grow towards its top instead of
+ // its bottom.
+ var left = void 0,
+ top = void 0;
+ if (sideA === 'bottom') {
+ // when offsetParent is the positioning is relative to the bottom of the screen (excluding the scrollbar)
+ // and not the bottom of the html element
+ if (offsetParent.nodeName === 'HTML') {
+ top = -offsetParent.clientHeight + offsets.bottom;
+ } else {
+ top = -offsetParentRect.height + offsets.bottom;
+ }
+ } else {
+ top = offsets.top;
+ }
+ if (sideB === 'right') {
+ if (offsetParent.nodeName === 'HTML') {
+ left = -offsetParent.clientWidth + offsets.right;
+ } else {
+ left = -offsetParentRect.width + offsets.right;
+ }
+ } else {
+ left = offsets.left;
+ }
+ if (gpuAcceleration && prefixedProperty) {
+ styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
+ styles[sideA] = 0;
+ styles[sideB] = 0;
+ styles.willChange = 'transform';
+ } else {
+ // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
+ var invertTop = sideA === 'bottom' ? -1 : 1;
+ var invertLeft = sideB === 'right' ? -1 : 1;
+ styles[sideA] = top * invertTop;
+ styles[sideB] = left * invertLeft;
+ styles.willChange = sideA + ', ' + sideB;
+ }
+
+ // Attributes
+ var attributes = {
+ 'x-placement': data.placement
+ };
+
+ // Update `data` attributes, styles and arrowStyles
+ data.attributes = _extends({}, attributes, data.attributes);
+ data.styles = _extends({}, styles, data.styles);
+ data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);
+
+ return data;
+ }
+
+ /**
+ * Helper used to know if the given modifier depends from another one.
+ * It checks if the needed modifier is listed and enabled.
+ * @method
+ * @memberof Popper.Utils
+ * @param {Array} modifiers - list of modifiers
+ * @param {String} requestingName - name of requesting modifier
+ * @param {String} requestedName - name of requested modifier
+ * @returns {Boolean}
+ */
+ function isModifierRequired(modifiers, requestingName, requestedName) {
+ var requesting = find(modifiers, function (_ref) {
+ var name = _ref.name;
+ return name === requestingName;
+ });
+
+ var isRequired = !!requesting && modifiers.some(function (modifier) {
+ return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
+ });
+
+ if (!isRequired) {
+ var _requesting = '`' + requestingName + '`';
+ var requested = '`' + requestedName + '`';
+ console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
+ }
+ return isRequired;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function arrow(data, options) {
+ var _data$offsets$arrow;
+
+ // arrow depends on keepTogether in order to work
+ if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
+ return data;
+ }
+
+ var arrowElement = options.element;
+
+ // if arrowElement is a string, suppose it's a CSS selector
+ if (typeof arrowElement === 'string') {
+ arrowElement = data.instance.popper.querySelector(arrowElement);
+
+ // if arrowElement is not found, don't run the modifier
+ if (!arrowElement) {
+ return data;
+ }
+ } else {
+ // if the arrowElement isn't a query selector we must check that the
+ // provided DOM node is child of its popper node
+ if (!data.instance.popper.contains(arrowElement)) {
+ console.warn('WARNING: `arrow.element` must be child of its popper element!');
+ return data;
+ }
+ }
+
+ var placement = data.placement.split('-')[0];
+ var _data$offsets = data.offsets,
+ popper = _data$offsets.popper,
+ reference = _data$offsets.reference;
+
+ var isVertical = ['left', 'right'].indexOf(placement) !== -1;
+
+ var len = isVertical ? 'height' : 'width';
+ var sideCapitalized = isVertical ? 'Top' : 'Left';
+ var side = sideCapitalized.toLowerCase();
+ var altSide = isVertical ? 'left' : 'top';
+ var opSide = isVertical ? 'bottom' : 'right';
+ var arrowElementSize = getOuterSizes(arrowElement)[len];
+
+ //
+ // extends keepTogether behavior making sure the popper and its
+ // reference have enough pixels in conjunction
+ //
+
+ // top/left side
+ if (reference[opSide] - arrowElementSize < popper[side]) {
+ data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
+ }
+ // bottom/right side
+ if (reference[side] + arrowElementSize > popper[opSide]) {
+ data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
+ }
+ data.offsets.popper = getClientRect(data.offsets.popper);
+
+ // compute center of the popper
+ var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
+
+ // Compute the sideValue using the updated popper offsets
+ // take popper margin in account because we don't have this info available
+ var css = getStyleComputedProperty(data.instance.popper);
+ var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
+ var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
+ var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
+
+ // prevent arrowElement from being placed not contiguously to its popper
+ sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
+
+ data.arrowElement = arrowElement;
+ data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
+
+ return data;
+ }
+
+ /**
+ * Get the opposite placement variation of the given one
+ * @method
+ * @memberof Popper.Utils
+ * @argument {String} placement variation
+ * @returns {String} flipped placement variation
+ */
+ function getOppositeVariation(variation) {
+ if (variation === 'end') {
+ return 'start';
+ } else if (variation === 'start') {
+ return 'end';
+ }
+ return variation;
+ }
+
+ /**
+ * List of accepted placements to use as values of the `placement` option.
+ * Valid placements are:
+ * - `auto`
+ * - `top`
+ * - `right`
+ * - `bottom`
+ * - `left`
+ *
+ * Each placement can have a variation from this list:
+ * - `-start`
+ * - `-end`
+ *
+ * Variations are interpreted easily if you think of them as the left to right
+ * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
+ * is right.
+ * Vertically (`left` and `right`), `start` is top and `end` is bottom.
+ *
+ * Some valid examples are:
+ * - `top-end` (on top of reference, right aligned)
+ * - `right-start` (on right of reference, top aligned)
+ * - `bottom` (on bottom, centered)
+ * - `auto-end` (on the side with more space available, alignment depends by placement)
+ *
+ * @static
+ * @type {Array}
+ * @enum {String}
+ * @readonly
+ * @method placements
+ * @memberof Popper
+ */
+ var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
+
+ // Get rid of `auto` `auto-start` and `auto-end`
+ var validPlacements = placements.slice(3);
+
+ /**
+ * Given an initial placement, returns all the subsequent placements
+ * clockwise (or counter-clockwise).
+ *
+ * @method
+ * @memberof Popper.Utils
+ * @argument {String} placement - A valid placement (it accepts variations)
+ * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
+ * @returns {Array} placements including their variations
+ */
+ function clockwise(placement) {
+ var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+ var index = validPlacements.indexOf(placement);
+ var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
+ return counter ? arr.reverse() : arr;
+ }
+
+ var BEHAVIORS = {
+ FLIP: 'flip',
+ CLOCKWISE: 'clockwise',
+ COUNTERCLOCKWISE: 'counterclockwise'
+ };
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function flip(data, options) {
+ // if `inner` modifier is enabled, we can't use the `flip` modifier
+ if (isModifierEnabled(data.instance.modifiers, 'inner')) {
+ return data;
+ }
+
+ if (data.flipped && data.placement === data.originalPlacement) {
+ // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
+ return data;
+ }
+
+ var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);
+
+ var placement = data.placement.split('-')[0];
+ var placementOpposite = getOppositePlacement(placement);
+ var variation = data.placement.split('-')[1] || '';
+
+ var flipOrder = [];
+
+ switch (options.behavior) {
+ case BEHAVIORS.FLIP:
+ flipOrder = [placement, placementOpposite];
+ break;
+ case BEHAVIORS.CLOCKWISE:
+ flipOrder = clockwise(placement);
+ break;
+ case BEHAVIORS.COUNTERCLOCKWISE:
+ flipOrder = clockwise(placement, true);
+ break;
+ default:
+ flipOrder = options.behavior;
+ }
+
+ flipOrder.forEach(function (step, index) {
+ if (placement !== step || flipOrder.length === index + 1) {
+ return data;
+ }
+
+ placement = data.placement.split('-')[0];
+ placementOpposite = getOppositePlacement(placement);
+
+ var popperOffsets = data.offsets.popper;
+ var refOffsets = data.offsets.reference;
+
+ // using floor because the reference offsets may contain decimals we are not going to consider here
+ var floor = Math.floor;
+ var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
+
+ var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
+ var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
+ var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
+ var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
+
+ var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
+
+ // flip the variation if required
+ var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
+
+ // flips variation if reference element overflows boundaries
+ var flippedVariationByRef = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
+
+ // flips variation if popper content overflows boundaries
+ var flippedVariationByContent = !!options.flipVariationsByContent && (isVertical && variation === 'start' && overflowsRight || isVertical && variation === 'end' && overflowsLeft || !isVertical && variation === 'start' && overflowsBottom || !isVertical && variation === 'end' && overflowsTop);
+
+ var flippedVariation = flippedVariationByRef || flippedVariationByContent;
+
+ if (overlapsRef || overflowsBoundaries || flippedVariation) {
+ // this boolean to detect any flip loop
+ data.flipped = true;
+
+ if (overlapsRef || overflowsBoundaries) {
+ placement = flipOrder[index + 1];
+ }
+
+ if (flippedVariation) {
+ variation = getOppositeVariation(variation);
+ }
+
+ data.placement = placement + (variation ? '-' + variation : '');
+
+ // this object contains `position`, we want to preserve it along with
+ // any additional property we may add in the future
+ data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
+
+ data = runModifiers(data.instance.modifiers, data, 'flip');
+ }
+ });
+ return data;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function keepTogether(data) {
+ var _data$offsets = data.offsets,
+ popper = _data$offsets.popper,
+ reference = _data$offsets.reference;
+
+ var placement = data.placement.split('-')[0];
+ var floor = Math.floor;
+ var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
+ var side = isVertical ? 'right' : 'bottom';
+ var opSide = isVertical ? 'left' : 'top';
+ var measurement = isVertical ? 'width' : 'height';
+
+ if (popper[side] < floor(reference[opSide])) {
+ data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
+ }
+ if (popper[opSide] > floor(reference[side])) {
+ data.offsets.popper[opSide] = floor(reference[side]);
+ }
+
+ return data;
+ }
+
+ /**
+ * Converts a string containing value + unit into a px value number
+ * @function
+ * @memberof {modifiers~offset}
+ * @private
+ * @argument {String} str - Value + unit string
+ * @argument {String} measurement - `height` or `width`
+ * @argument {Object} popperOffsets
+ * @argument {Object} referenceOffsets
+ * @returns {Number|String}
+ * Value in pixels, or original string if no values were extracted
+ */
+ function toValue(str, measurement, popperOffsets, referenceOffsets) {
+ // separate value from unit
+ var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
+ var value = +split[1];
+ var unit = split[2];
+
+ // If it's not a number it's an operator, I guess
+ if (!value) {
+ return str;
+ }
+
+ if (unit.indexOf('%') === 0) {
+ var element = void 0;
+ switch (unit) {
+ case '%p':
+ element = popperOffsets;
+ break;
+ case '%':
+ case '%r':
+ default:
+ element = referenceOffsets;
+ }
+
+ var rect = getClientRect(element);
+ return rect[measurement] / 100 * value;
+ } else if (unit === 'vh' || unit === 'vw') {
+ // if is a vh or vw, we calculate the size based on the viewport
+ var size = void 0;
+ if (unit === 'vh') {
+ size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+ } else {
+ size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
+ }
+ return size / 100 * value;
+ } else {
+ // if is an explicit pixel unit, we get rid of the unit and keep the value
+ // if is an implicit unit, it's px, and we return just the value
+ return value;
+ }
+ }
+
+ /**
+ * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
+ * @function
+ * @memberof {modifiers~offset}
+ * @private
+ * @argument {String} offset
+ * @argument {Object} popperOffsets
+ * @argument {Object} referenceOffsets
+ * @argument {String} basePlacement
+ * @returns {Array} a two cells array with x and y offsets in numbers
+ */
+ function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
+ var offsets = [0, 0];
+
+ // Use height if placement is left or right and index is 0 otherwise use width
+ // in this way the first offset will use an axis and the second one
+ // will use the other one
+ var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;
+
+ // Split the offset string to obtain a list of values and operands
+ // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
+ var fragments = offset.split(/(\+|\-)/).map(function (frag) {
+ return frag.trim();
+ });
+
+ // Detect if the offset string contains a pair of values or a single one
+ // they could be separated by comma or space
+ var divider = fragments.indexOf(find(fragments, function (frag) {
+ return frag.search(/,|\s/) !== -1;
+ }));
+
+ if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
+ console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
+ }
+
+ // If divider is found, we divide the list of values and operands to divide
+ // them by ofset X and Y.
+ var splitRegex = /\s*,\s*|\s+/;
+ var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];
+
+ // Convert the values with units to absolute pixels to allow our computations
+ ops = ops.map(function (op, index) {
+ // Most of the units rely on the orientation of the popper
+ var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
+ var mergeWithPrevious = false;
+ return op
+ // This aggregates any `+` or `-` sign that aren't considered operators
+ // e.g.: 10 + +5 => [10, +, +5]
+ .reduce(function (a, b) {
+ if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
+ a[a.length - 1] = b;
+ mergeWithPrevious = true;
+ return a;
+ } else if (mergeWithPrevious) {
+ a[a.length - 1] += b;
+ mergeWithPrevious = false;
+ return a;
+ } else {
+ return a.concat(b);
+ }
+ }, [])
+ // Here we convert the string values into number values (in px)
+ .map(function (str) {
+ return toValue(str, measurement, popperOffsets, referenceOffsets);
+ });
+ });
+
+ // Loop trough the offsets arrays and execute the operations
+ ops.forEach(function (op, index) {
+ op.forEach(function (frag, index2) {
+ if (isNumeric(frag)) {
+ offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
+ }
+ });
+ });
+ return offsets;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @argument {Number|String} options.offset=0
+ * The offset value as described in the modifier description
+ * @returns {Object} The data object, properly modified
+ */
+ function offset(data, _ref) {
+ var offset = _ref.offset;
+ var placement = data.placement,
+ _data$offsets = data.offsets,
+ popper = _data$offsets.popper,
+ reference = _data$offsets.reference;
+
+ var basePlacement = placement.split('-')[0];
+
+ var offsets = void 0;
+ if (isNumeric(+offset)) {
+ offsets = [+offset, 0];
+ } else {
+ offsets = parseOffset(offset, popper, reference, basePlacement);
+ }
+
+ if (basePlacement === 'left') {
+ popper.top += offsets[0];
+ popper.left -= offsets[1];
+ } else if (basePlacement === 'right') {
+ popper.top += offsets[0];
+ popper.left += offsets[1];
+ } else if (basePlacement === 'top') {
+ popper.left += offsets[0];
+ popper.top -= offsets[1];
+ } else if (basePlacement === 'bottom') {
+ popper.left += offsets[0];
+ popper.top += offsets[1];
+ }
+
+ data.popper = popper;
+ return data;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function preventOverflow(data, options) {
+ var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
+
+ // If offsetParent is the reference element, we really want to
+ // go one step up and use the next offsetParent as reference to
+ // avoid to make this modifier completely useless and look like broken
+ if (data.instance.reference === boundariesElement) {
+ boundariesElement = getOffsetParent(boundariesElement);
+ }
+
+ // NOTE: DOM access here
+ // resets the popper's position so that the document size can be calculated excluding
+ // the size of the popper element itself
+ var transformProp = getSupportedPropertyName('transform');
+ var popperStyles = data.instance.popper.style; // assignment to help minification
+ var top = popperStyles.top,
+ left = popperStyles.left,
+ transform = popperStyles[transformProp];
+
+ popperStyles.top = '';
+ popperStyles.left = '';
+ popperStyles[transformProp] = '';
+
+ var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);
+
+ // NOTE: DOM access here
+ // restores the original style properties after the offsets have been computed
+ popperStyles.top = top;
+ popperStyles.left = left;
+ popperStyles[transformProp] = transform;
+
+ options.boundaries = boundaries;
+
+ var order = options.priority;
+ var popper = data.offsets.popper;
+
+ var check = {
+ primary: function primary(placement) {
+ var value = popper[placement];
+ if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
+ value = Math.max(popper[placement], boundaries[placement]);
+ }
+ return defineProperty({}, placement, value);
+ },
+ secondary: function secondary(placement) {
+ var mainSide = placement === 'right' ? 'left' : 'top';
+ var value = popper[mainSide];
+ if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
+ value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
+ }
+ return defineProperty({}, mainSide, value);
+ }
+ };
+
+ order.forEach(function (placement) {
+ var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
+ popper = _extends({}, popper, check[side](placement));
+ });
+
+ data.offsets.popper = popper;
+
+ return data;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function shift(data) {
+ var placement = data.placement;
+ var basePlacement = placement.split('-')[0];
+ var shiftvariation = placement.split('-')[1];
+
+ // if shift shiftvariation is specified, run the modifier
+ if (shiftvariation) {
+ var _data$offsets = data.offsets,
+ reference = _data$offsets.reference,
+ popper = _data$offsets.popper;
+
+ var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
+ var side = isVertical ? 'left' : 'top';
+ var measurement = isVertical ? 'width' : 'height';
+
+ var shiftOffsets = {
+ start: defineProperty({}, side, reference[side]),
+ end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
+ };
+
+ data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
+ }
+
+ return data;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by update method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function hide(data) {
+ if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
+ return data;
+ }
+
+ var refRect = data.offsets.reference;
+ var bound = find(data.instance.modifiers, function (modifier) {
+ return modifier.name === 'preventOverflow';
+ }).boundaries;
+
+ if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
+ // Avoid unnecessary DOM access if visibility hasn't changed
+ if (data.hide === true) {
+ return data;
+ }
+
+ data.hide = true;
+ data.attributes['x-out-of-boundaries'] = '';
+ } else {
+ // Avoid unnecessary DOM access if visibility hasn't changed
+ if (data.hide === false) {
+ return data;
+ }
+
+ data.hide = false;
+ data.attributes['x-out-of-boundaries'] = false;
+ }
+
+ return data;
+ }
+
+ /**
+ * @function
+ * @memberof Modifiers
+ * @argument {Object} data - The data object generated by `update` method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {Object} The data object, properly modified
+ */
+ function inner(data) {
+ var placement = data.placement;
+ var basePlacement = placement.split('-')[0];
+ var _data$offsets = data.offsets,
+ popper = _data$offsets.popper,
+ reference = _data$offsets.reference;
+
+ var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
+
+ var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
+
+ popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
+
+ data.placement = getOppositePlacement(placement);
+ data.offsets.popper = getClientRect(popper);
+
+ return data;
+ }
+
+ /**
+ * Modifier function, each modifier can have a function of this type assigned
+ * to its `fn` property.
+ * These functions will be called on each update, this means that you must
+ * make sure they are performant enough to avoid performance bottlenecks.
+ *
+ * @function ModifierFn
+ * @argument {dataObject} data - The data object generated by `update` method
+ * @argument {Object} options - Modifiers configuration and options
+ * @returns {dataObject} The data object, properly modified
+ */
+
+ /**
+ * Modifiers are plugins used to alter the behavior of your poppers.
+ * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
+ * needed by the library.
+ *
+ * Usually you don't want to override the `order`, `fn` and `onLoad` props.
+ * All the other properties are configurations that could be tweaked.
+ * @namespace modifiers
+ */
+ var modifiers = {
+ /**
+ * Modifier used to shift the popper on the start or end of its reference
+ * element.
+ * It will read the variation of the `placement` property.
+ * It can be one either `-end` or `-start`.
+ * @memberof modifiers
+ * @inner
+ */
+ shift: {
+ /** @prop {number} order=100 - Index used to define the order of execution */
+ order: 100,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: shift
+ },
+
+ /**
+ * The `offset` modifier can shift your popper on both its axis.
+ *
+ * It accepts the following units:
+ * - `px` or unit-less, interpreted as pixels
+ * - `%` or `%r`, percentage relative to the length of the reference element
+ * - `%p`, percentage relative to the length of the popper element
+ * - `vw`, CSS viewport width unit
+ * - `vh`, CSS viewport height unit
+ *
+ * For length is intended the main axis relative to the placement of the popper.
+ * This means that if the placement is `top` or `bottom`, the length will be the
+ * `width`. In case of `left` or `right`, it will be the `height`.
+ *
+ * You can provide a single value (as `Number` or `String`), or a pair of values
+ * as `String` divided by a comma or one (or more) white spaces.
+ * The latter is a deprecated method because it leads to confusion and will be
+ * removed in v2.
+ * Additionally, it accepts additions and subtractions between different units.
+ * Note that multiplications and divisions aren't supported.
+ *
+ * Valid examples are:
+ * ```
+ * 10
+ * '10%'
+ * '10, 10'
+ * '10%, 10'
+ * '10 + 10%'
+ * '10 - 5vh + 3%'
+ * '-10px + 5vh, 5px - 6%'
+ * ```
+ * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
+ * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
+ * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).
+ *
+ * @memberof modifiers
+ * @inner
+ */
+ offset: {
+ /** @prop {number} order=200 - Index used to define the order of execution */
+ order: 200,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: offset,
+ /** @prop {Number|String} offset=0
+ * The offset value as described in the modifier description
+ */
+ offset: 0
+ },
+
+ /**
+ * Modifier used to prevent the popper from being positioned outside the boundary.
+ *
+ * A scenario exists where the reference itself is not within the boundaries.
+ * We can say it has "escaped the boundaries" — or just "escaped".
+ * In this case we need to decide whether the popper should either:
+ *
+ * - detach from the reference and remain "trapped" in the boundaries, or
+ * - if it should ignore the boundary and "escape with its reference"
+ *
+ * When `escapeWithReference` is set to`true` and reference is completely
+ * outside its boundaries, the popper will overflow (or completely leave)
+ * the boundaries in order to remain attached to the edge of the reference.
+ *
+ * @memberof modifiers
+ * @inner
+ */
+ preventOverflow: {
+ /** @prop {number} order=300 - Index used to define the order of execution */
+ order: 300,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: preventOverflow,
+ /**
+ * @prop {Array} [priority=['left','right','top','bottom']]
+ * Popper will try to prevent overflow following these priorities by default,
+ * then, it could overflow on the left and on top of the `boundariesElement`
+ */
+ priority: ['left', 'right', 'top', 'bottom'],
+ /**
+ * @prop {number} padding=5
+ * Amount of pixel used to define a minimum distance between the boundaries
+ * and the popper. This makes sure the popper always has a little padding
+ * between the edges of its container
+ */
+ padding: 5,
+ /**
+ * @prop {String|HTMLElement} boundariesElement='scrollParent'
+ * Boundaries used by the modifier. Can be `scrollParent`, `window`,
+ * `viewport` or any DOM element.
+ */
+ boundariesElement: 'scrollParent'
+ },
+
+ /**
+ * Modifier used to make sure the reference and its popper stay near each other
+ * without leaving any gap between the two. Especially useful when the arrow is
+ * enabled and you want to ensure that it points to its reference element.
+ * It cares only about the first axis. You can still have poppers with margin
+ * between the popper and its reference element.
+ * @memberof modifiers
+ * @inner
+ */
+ keepTogether: {
+ /** @prop {number} order=400 - Index used to define the order of execution */
+ order: 400,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: keepTogether
+ },
+
+ /**
+ * This modifier is used to move the `arrowElement` of the popper to make
+ * sure it is positioned between the reference element and its popper element.
+ * It will read the outer size of the `arrowElement` node to detect how many
+ * pixels of conjunction are needed.
+ *
+ * It has no effect if no `arrowElement` is provided.
+ * @memberof modifiers
+ * @inner
+ */
+ arrow: {
+ /** @prop {number} order=500 - Index used to define the order of execution */
+ order: 500,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: arrow,
+ /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
+ element: '[x-arrow]'
+ },
+
+ /**
+ * Modifier used to flip the popper's placement when it starts to overlap its
+ * reference element.
+ *
+ * Requires the `preventOverflow` modifier before it in order to work.
+ *
+ * **NOTE:** this modifier will interrupt the current update cycle and will
+ * restart it if it detects the need to flip the placement.
+ * @memberof modifiers
+ * @inner
+ */
+ flip: {
+ /** @prop {number} order=600 - Index used to define the order of execution */
+ order: 600,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: flip,
+ /**
+ * @prop {String|Array} behavior='flip'
+ * The behavior used to change the popper's placement. It can be one of
+ * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
+ * placements (with optional variations)
+ */
+ behavior: 'flip',
+ /**
+ * @prop {number} padding=5
+ * The popper will flip if it hits the edges of the `boundariesElement`
+ */
+ padding: 5,
+ /**
+ * @prop {String|HTMLElement} boundariesElement='viewport'
+ * The element which will define the boundaries of the popper position.
+ * The popper will never be placed outside of the defined boundaries
+ * (except if `keepTogether` is enabled)
+ */
+ boundariesElement: 'viewport',
+ /**
+ * @prop {Boolean} flipVariations=false
+ * The popper will switch placement variation between `-start` and `-end` when
+ * the reference element overlaps its boundaries.
+ *
+ * The original placement should have a set variation.
+ */
+ flipVariations: false,
+ /**
+ * @prop {Boolean} flipVariationsByContent=false
+ * The popper will switch placement variation between `-start` and `-end` when
+ * the popper element overlaps its reference boundaries.
+ *
+ * The original placement should have a set variation.
+ */
+ flipVariationsByContent: false
+ },
+
+ /**
+ * Modifier used to make the popper flow toward the inner of the reference element.
+ * By default, when this modifier is disabled, the popper will be placed outside
+ * the reference element.
+ * @memberof modifiers
+ * @inner
+ */
+ inner: {
+ /** @prop {number} order=700 - Index used to define the order of execution */
+ order: 700,
+ /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
+ enabled: false,
+ /** @prop {ModifierFn} */
+ fn: inner
+ },
+
+ /**
+ * Modifier used to hide the popper when its reference element is outside of the
+ * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
+ * be used to hide with a CSS selector the popper when its reference is
+ * out of boundaries.
+ *
+ * Requires the `preventOverflow` modifier before it in order to work.
+ * @memberof modifiers
+ * @inner
+ */
+ hide: {
+ /** @prop {number} order=800 - Index used to define the order of execution */
+ order: 800,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: hide
+ },
+
+ /**
+ * Computes the style that will be applied to the popper element to gets
+ * properly positioned.
+ *
+ * Note that this modifier will not touch the DOM, it just prepares the styles
+ * so that `applyStyle` modifier can apply it. This separation is useful
+ * in case you need to replace `applyStyle` with a custom implementation.
+ *
+ * This modifier has `850` as `order` value to maintain backward compatibility
+ * with previous versions of Popper.js. Expect the modifiers ordering method
+ * to change in future major versions of the library.
+ *
+ * @memberof modifiers
+ * @inner
+ */
+ computeStyle: {
+ /** @prop {number} order=850 - Index used to define the order of execution */
+ order: 850,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: computeStyle,
+ /**
+ * @prop {Boolean} gpuAcceleration=true
+ * If true, it uses the CSS 3D transformation to position the popper.
+ * Otherwise, it will use the `top` and `left` properties
+ */
+ gpuAcceleration: true,
+ /**
+ * @prop {string} [x='bottom']
+ * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
+ * Change this if your popper should grow in a direction different from `bottom`
+ */
+ x: 'bottom',
+ /**
+ * @prop {string} [x='left']
+ * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
+ * Change this if your popper should grow in a direction different from `right`
+ */
+ y: 'right'
+ },
+
+ /**
+ * Applies the computed styles to the popper element.
+ *
+ * All the DOM manipulations are limited to this modifier. This is useful in case
+ * you want to integrate Popper.js inside a framework or view library and you
+ * want to delegate all the DOM manipulations to it.
+ *
+ * Note that if you disable this modifier, you must make sure the popper element
+ * has its position set to `absolute` before Popper.js can do its work!
+ *
+ * Just disable this modifier and define your own to achieve the desired effect.
+ *
+ * @memberof modifiers
+ * @inner
+ */
+ applyStyle: {
+ /** @prop {number} order=900 - Index used to define the order of execution */
+ order: 900,
+ /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
+ enabled: true,
+ /** @prop {ModifierFn} */
+ fn: applyStyle,
+ /** @prop {Function} */
+ onLoad: applyStyleOnLoad,
+ /**
+ * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
+ * @prop {Boolean} gpuAcceleration=true
+ * If true, it uses the CSS 3D transformation to position the popper.
+ * Otherwise, it will use the `top` and `left` properties
+ */
+ gpuAcceleration: undefined
+ }
+ };
+
+ /**
+ * The `dataObject` is an object containing all the information used by Popper.js.
+ * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
+ * @name dataObject
+ * @property {Object} data.instance The Popper.js instance
+ * @property {String} data.placement Placement applied to popper
+ * @property {String} data.originalPlacement Placement originally defined on init
+ * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
+ * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper
+ * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
+ * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)
+ * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)
+ * @property {Object} data.boundaries Offsets of the popper boundaries
+ * @property {Object} data.offsets The measurements of popper, reference and arrow elements
+ * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
+ * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
+ * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
+ */
+
+ /**
+ * Default options provided to Popper.js constructor.
+ * These can be overridden using the `options` argument of Popper.js.
+ * To override an option, simply pass an object with the same
+ * structure of the `options` object, as the 3rd argument. For example:
+ * ```
+ * new Popper(ref, pop, {
+ * modifiers: {
+ * preventOverflow: { enabled: false }
+ * }
+ * })
+ * ```
+ * @type {Object}
+ * @static
+ * @memberof Popper
+ */
+ var Defaults = {
+ /**
+ * Popper's placement.
+ * @prop {Popper.placements} placement='bottom'
+ */
+ placement: 'bottom',
+
+ /**
+ * Set this to true if you want popper to position it self in 'fixed' mode
+ * @prop {Boolean} positionFixed=false
+ */
+ positionFixed: false,
+
+ /**
+ * Whether events (resize, scroll) are initially enabled.
+ * @prop {Boolean} eventsEnabled=true
+ */
+ eventsEnabled: true,
+
+ /**
+ * Set to true if you want to automatically remove the popper when
+ * you call the `destroy` method.
+ * @prop {Boolean} removeOnDestroy=false
+ */
+ removeOnDestroy: false,
+
+ /**
+ * Callback called when the popper is created.
+ * By default, it is set to no-op.
+ * Access Popper.js instance with `data.instance`.
+ * @prop {onCreate}
+ */
+ onCreate: function onCreate() {},
+
+ /**
+ * Callback called when the popper is updated. This callback is not called
+ * on the initialization/creation of the popper, but only on subsequent
+ * updates.
+ * By default, it is set to no-op.
+ * Access Popper.js instance with `data.instance`.
+ * @prop {onUpdate}
+ */
+ onUpdate: function onUpdate() {},
+
+ /**
+ * List of modifiers used to modify the offsets before they are applied to the popper.
+ * They provide most of the functionalities of Popper.js.
+ * @prop {modifiers}
+ */
+ modifiers: modifiers
+ };
+
+ /**
+ * @callback onCreate
+ * @param {dataObject} data
+ */
+
+ /**
+ * @callback onUpdate
+ * @param {dataObject} data
+ */
+
+ // Utils
+ // Methods
+ var Popper = function () {
+ /**
+ * Creates a new Popper.js instance.
+ * @class Popper
+ * @param {Element|referenceObject} reference - The reference element used to position the popper
+ * @param {Element} popper - The HTML / XML element used as the popper
+ * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
+ * @return {Object} instance - The generated Popper.js instance
+ */
+ function Popper(reference, popper) {
+ var _this = this;
+
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+ classCallCheck(this, Popper);
+
+ this.scheduleUpdate = function () {
+ return requestAnimationFrame(_this.update);
+ };
+
+ // make update() debounced, so that it only runs at most once-per-tick
+ this.update = debounce(this.update.bind(this));
+
+ // with {} we create a new object with the options inside it
+ this.options = _extends({}, Popper.Defaults, options);
+
+ // init state
+ this.state = {
+ isDestroyed: false,
+ isCreated: false,
+ scrollParents: []
+ };
+
+ // get reference and popper elements (allow jQuery wrappers)
+ this.reference = reference && reference.jquery ? reference[0] : reference;
+ this.popper = popper && popper.jquery ? popper[0] : popper;
+
+ // Deep merge modifiers options
+ this.options.modifiers = {};
+ Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
+ _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
+ });
+
+ // Refactoring modifiers' list (Object => Array)
+ this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
+ return _extends({
+ name: name
+ }, _this.options.modifiers[name]);
+ })
+ // sort the modifiers by order
+ .sort(function (a, b) {
+ return a.order - b.order;
+ });
+
+ // modifiers have the ability to execute arbitrary code when Popper.js get inited
+ // such code is executed in the same order of its modifier
+ // they could add new properties to their options configuration
+ // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
+ this.modifiers.forEach(function (modifierOptions) {
+ if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
+ modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
+ }
+ });
+
+ // fire the first update to position the popper in the right place
+ this.update();
+
+ var eventsEnabled = this.options.eventsEnabled;
+ if (eventsEnabled) {
+ // setup event listeners, they will take care of update the position in specific situations
+ this.enableEventListeners();
+ }
+
+ this.state.eventsEnabled = eventsEnabled;
+ }
+
+ // We can't use class properties because they don't get listed in the
+ // class prototype and break stuff like Sinon stubs
+
+
+ createClass(Popper, [{
+ key: 'update',
+ value: function update$$1() {
+ return update.call(this);
+ }
+ }, {
+ key: 'destroy',
+ value: function destroy$$1() {
+ return destroy.call(this);
+ }
+ }, {
+ key: 'enableEventListeners',
+ value: function enableEventListeners$$1() {
+ return enableEventListeners.call(this);
+ }
+ }, {
+ key: 'disableEventListeners',
+ value: function disableEventListeners$$1() {
+ return disableEventListeners.call(this);
+ }
+
+ /**
+ * Schedules an update. It will run on the next UI update available.
+ * @method scheduleUpdate
+ * @memberof Popper
+ */
+
+
+ /**
+ * Collection of utilities useful when writing custom modifiers.
+ * Starting from version 1.7, this method is available only if you
+ * include `popper-utils.js` before `popper.js`.
+ *
+ * **DEPRECATION**: This way to access PopperUtils is deprecated
+ * and will be removed in v2! Use the PopperUtils module directly instead.
+ * Due to the high instability of the methods contained in Utils, we can't
+ * guarantee them to follow semver. Use them at your own risk!
+ * @static
+ * @private
+ * @type {Object}
+ * @deprecated since version 1.8
+ * @member Utils
+ * @memberof Popper
+ */
+
+ }]);
+ return Popper;
+ }();
+
+ /**
+ * The `referenceObject` is an object that provides an interface compatible with Popper.js
+ * and lets you use it as replacement of a real DOM node.
+ * You can use this method to position a popper relatively to a set of coordinates
+ * in case you don't have a DOM node to use as reference.
+ *
+ * ```
+ * new Popper(referenceObject, popperNode);
+ * ```
+ *
+ * NB: This feature isn't supported in Internet Explorer 10.
+ * @name referenceObject
+ * @property {Function} data.getBoundingClientRect
+ * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
+ * @property {number} data.clientWidth
+ * An ES6 getter that will return the width of the virtual reference element.
+ * @property {number} data.clientHeight
+ * An ES6 getter that will return the height of the virtual reference element.
+ */
+
+
+ Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
+ Popper.placements = placements;
+ Popper.Defaults = Defaults;
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$4 = 'dropdown';
+ var VERSION$4 = '4.4.1';
+ var DATA_KEY$4 = 'bs.dropdown';
+ var EVENT_KEY$4 = "." + DATA_KEY$4;
+ var DATA_API_KEY$4 = '.data-api';
+ var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];
+ var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
+
+ var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
+
+ var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
+
+ var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
+
+ var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
+
+ var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
+
+ var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
+ var Event$4 = {
+ HIDE: "hide" + EVENT_KEY$4,
+ HIDDEN: "hidden" + EVENT_KEY$4,
+ SHOW: "show" + EVENT_KEY$4,
+ SHOWN: "shown" + EVENT_KEY$4,
+ CLICK: "click" + EVENT_KEY$4,
+ CLICK_DATA_API: "click" + EVENT_KEY$4 + DATA_API_KEY$4,
+ KEYDOWN_DATA_API: "keydown" + EVENT_KEY$4 + DATA_API_KEY$4,
+ KEYUP_DATA_API: "keyup" + EVENT_KEY$4 + DATA_API_KEY$4
+ };
+ var ClassName$4 = {
+ DISABLED: 'disabled',
+ SHOW: 'show',
+ DROPUP: 'dropup',
+ DROPRIGHT: 'dropright',
+ DROPLEFT: 'dropleft',
+ MENURIGHT: 'dropdown-menu-right',
+ MENULEFT: 'dropdown-menu-left',
+ POSITION_STATIC: 'position-static'
+ };
+ var Selector$4 = {
+ DATA_TOGGLE: '[data-toggle="dropdown"]',
+ FORM_CHILD: '.dropdown form',
+ MENU: '.dropdown-menu',
+ NAVBAR_NAV: '.navbar-nav',
+ VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
+ };
+ var AttachmentMap = {
+ TOP: 'top-start',
+ TOPEND: 'top-end',
+ BOTTOM: 'bottom-start',
+ BOTTOMEND: 'bottom-end',
+ RIGHT: 'right-start',
+ RIGHTEND: 'right-end',
+ LEFT: 'left-start',
+ LEFTEND: 'left-end'
+ };
+ var Default$2 = {
+ offset: 0,
+ flip: true,
+ boundary: 'scrollParent',
+ reference: 'toggle',
+ display: 'dynamic',
+ popperConfig: null
+ };
+ var DefaultType$2 = {
+ offset: '(number|string|function)',
+ flip: 'boolean',
+ boundary: '(string|element)',
+ reference: '(string|element)',
+ display: 'string',
+ popperConfig: '(null|object)'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Dropdown =
+ /*#__PURE__*/
+ function () {
+ function Dropdown(element, config) {
+ this._element = element;
+ this._popper = null;
+ this._config = this._getConfig(config);
+ this._menu = this._getMenuElement();
+ this._inNavbar = this._detectNavbar();
+
+ this._addEventListeners();
+ } // Getters
+
+
+ var _proto = Dropdown.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) {
+ return;
+ }
+
+ var isActive = $(this._menu).hasClass(ClassName$4.SHOW);
+
+ Dropdown._clearMenus();
+
+ if (isActive) {
+ return;
+ }
+
+ this.show(true);
+ };
+
+ _proto.show = function show(usePopper) {
+ if (usePopper === void 0) {
+ usePopper = false;
+ }
+
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) {
+ return;
+ }
+
+ var relatedTarget = {
+ relatedTarget: this._element
+ };
+ var showEvent = $.Event(Event$4.SHOW, relatedTarget);
+
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ $(parent).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented()) {
+ return;
+ } // Disable totally Popper.js for Dropdown in Navbar
+
+
+ if (!this._inNavbar && usePopper) {
+ /**
+ * Check for Popper dependency
+ * Popper - https://popper.js.org
+ */
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)');
+ }
+
+ var referenceElement = this._element;
+
+ if (this._config.reference === 'parent') {
+ referenceElement = parent;
+ } else if (Util.isElement(this._config.reference)) {
+ referenceElement = this._config.reference; // Check if it's jQuery element
+
+ if (typeof this._config.reference.jquery !== 'undefined') {
+ referenceElement = this._config.reference[0];
+ }
+ } // If boundary is not `scrollParent`, then set position to `static`
+ // to allow the menu to "escape" the scroll parent's boundaries
+ // https://github.com/twbs/bootstrap/issues/24251
+
+
+ if (this._config.boundary !== 'scrollParent') {
+ $(parent).addClass(ClassName$4.POSITION_STATIC);
+ }
+
+ this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());
+ } // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+
+
+ if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) {
+ $(document.body).children().on('mouseover', null, $.noop);
+ }
+
+ this._element.focus();
+
+ this._element.setAttribute('aria-expanded', true);
+
+ $(this._menu).toggleClass(ClassName$4.SHOW);
+ $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));
+ };
+
+ _proto.hide = function hide() {
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) {
+ return;
+ }
+
+ var relatedTarget = {
+ relatedTarget: this._element
+ };
+ var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
+
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ $(parent).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (this._popper) {
+ this._popper.destroy();
+ }
+
+ $(this._menu).toggleClass(ClassName$4.SHOW);
+ $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$4);
+ $(this._element).off(EVENT_KEY$4);
+ this._element = null;
+ this._menu = null;
+
+ if (this._popper !== null) {
+ this._popper.destroy();
+
+ this._popper = null;
+ }
+ };
+
+ _proto.update = function update() {
+ this._inNavbar = this._detectNavbar();
+
+ if (this._popper !== null) {
+ this._popper.scheduleUpdate();
+ }
+ } // Private
+ ;
+
+ _proto._addEventListeners = function _addEventListeners() {
+ var _this = this;
+
+ $(this._element).on(Event$4.CLICK, function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ _this.toggle();
+ });
+ };
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, this.constructor.Default, {}, $(this._element).data(), {}, config);
+ Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);
+ return config;
+ };
+
+ _proto._getMenuElement = function _getMenuElement() {
+ if (!this._menu) {
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ if (parent) {
+ this._menu = parent.querySelector(Selector$4.MENU);
+ }
+ }
+
+ return this._menu;
+ };
+
+ _proto._getPlacement = function _getPlacement() {
+ var $parentDropdown = $(this._element.parentNode);
+ var placement = AttachmentMap.BOTTOM; // Handle dropup
+
+ if ($parentDropdown.hasClass(ClassName$4.DROPUP)) {
+ placement = AttachmentMap.TOP;
+
+ if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
+ placement = AttachmentMap.TOPEND;
+ }
+ } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) {
+ placement = AttachmentMap.RIGHT;
+ } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) {
+ placement = AttachmentMap.LEFT;
+ } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
+ placement = AttachmentMap.BOTTOMEND;
+ }
+
+ return placement;
+ };
+
+ _proto._detectNavbar = function _detectNavbar() {
+ return $(this._element).closest('.navbar').length > 0;
+ };
+
+ _proto._getOffset = function _getOffset() {
+ var _this2 = this;
+
+ var offset = {};
+
+ if (typeof this._config.offset === 'function') {
+ offset.fn = function (data) {
+ data.offsets = _objectSpread2({}, data.offsets, {}, _this2._config.offset(data.offsets, _this2._element) || {});
+ return data;
+ };
+ } else {
+ offset.offset = this._config.offset;
+ }
+
+ return offset;
+ };
+
+ _proto._getPopperConfig = function _getPopperConfig() {
+ var popperConfig = {
+ placement: this._getPlacement(),
+ modifiers: {
+ offset: this._getOffset(),
+ flip: {
+ enabled: this._config.flip
+ },
+ preventOverflow: {
+ boundariesElement: this._config.boundary
+ }
+ }
+ }; // Disable Popper.js if we have a static display
+
+ if (this._config.display === 'static') {
+ popperConfig.modifiers.applyStyle = {
+ enabled: false
+ };
+ }
+
+ return _objectSpread2({}, popperConfig, {}, this._config.popperConfig);
+ } // Static
+ ;
+
+ Dropdown._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$4);
+
+ var _config = typeof config === 'object' ? config : null;
+
+ if (!data) {
+ data = new Dropdown(this, _config);
+ $(this).data(DATA_KEY$4, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ Dropdown._clearMenus = function _clearMenus(event) {
+ if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
+ return;
+ }
+
+ var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE));
+
+ for (var i = 0, len = toggles.length; i < len; i++) {
+ var parent = Dropdown._getParentFromElement(toggles[i]);
+
+ var context = $(toggles[i]).data(DATA_KEY$4);
+ var relatedTarget = {
+ relatedTarget: toggles[i]
+ };
+
+ if (event && event.type === 'click') {
+ relatedTarget.clickEvent = event;
+ }
+
+ if (!context) {
+ continue;
+ }
+
+ var dropdownMenu = context._menu;
+
+ if (!$(parent).hasClass(ClassName$4.SHOW)) {
+ continue;
+ }
+
+ if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {
+ continue;
+ }
+
+ var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
+ $(parent).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ continue;
+ } // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().off('mouseover', null, $.noop);
+ }
+
+ toggles[i].setAttribute('aria-expanded', 'false');
+
+ if (context._popper) {
+ context._popper.destroy();
+ }
+
+ $(dropdownMenu).removeClass(ClassName$4.SHOW);
+ $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
+ }
+ };
+
+ Dropdown._getParentFromElement = function _getParentFromElement(element) {
+ var parent;
+ var selector = Util.getSelectorFromElement(element);
+
+ if (selector) {
+ parent = document.querySelector(selector);
+ }
+
+ return parent || element.parentNode;
+ } // eslint-disable-next-line complexity
+ ;
+
+ Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
+ // If not input/textarea:
+ // - And not a key in REGEXP_KEYDOWN => not a dropdown command
+ // If input/textarea:
+ // - If space key => not a dropdown command
+ // - If key is other than escape
+ // - If key is not up or down => not a dropdown command
+ // - If trigger inside the menu => not a dropdown command
+ if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) {
+ return;
+ }
+
+ var parent = Dropdown._getParentFromElement(this);
+
+ var isActive = $(parent).hasClass(ClassName$4.SHOW);
+
+ if (!isActive && event.which === ESCAPE_KEYCODE) {
+ return;
+ }
+
+ if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
+ if (event.which === ESCAPE_KEYCODE) {
+ var toggle = parent.querySelector(Selector$4.DATA_TOGGLE);
+ $(toggle).trigger('focus');
+ }
+
+ $(this).trigger('click');
+ return;
+ }
+
+ var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS)).filter(function (item) {
+ return $(item).is(':visible');
+ });
+
+ if (items.length === 0) {
+ return;
+ }
+
+ var index = items.indexOf(event.target);
+
+ if (event.which === ARROW_UP_KEYCODE && index > 0) {
+ // Up
+ index--;
+ }
+
+ if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
+ // Down
+ index++;
+ }
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ items[index].focus();
+ };
+
+ _createClass(Dropdown, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$4;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$2;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$2;
+ }
+ }]);
+
+ return Dropdown;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + " " + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ Dropdown._jQueryInterface.call($(this), 'toggle');
+ }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) {
+ e.stopPropagation();
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$4] = Dropdown._jQueryInterface;
+ $.fn[NAME$4].Constructor = Dropdown;
+
+ $.fn[NAME$4].noConflict = function () {
+ $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;
+ return Dropdown._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$5 = 'modal';
+ var VERSION$5 = '4.4.1';
+ var DATA_KEY$5 = 'bs.modal';
+ var EVENT_KEY$5 = "." + DATA_KEY$5;
+ var DATA_API_KEY$5 = '.data-api';
+ var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];
+ var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key
+
+ var Default$3 = {
+ backdrop: true,
+ keyboard: true,
+ focus: true,
+ show: true
+ };
+ var DefaultType$3 = {
+ backdrop: '(boolean|string)',
+ keyboard: 'boolean',
+ focus: 'boolean',
+ show: 'boolean'
+ };
+ var Event$5 = {
+ HIDE: "hide" + EVENT_KEY$5,
+ HIDE_PREVENTED: "hidePrevented" + EVENT_KEY$5,
+ HIDDEN: "hidden" + EVENT_KEY$5,
+ SHOW: "show" + EVENT_KEY$5,
+ SHOWN: "shown" + EVENT_KEY$5,
+ FOCUSIN: "focusin" + EVENT_KEY$5,
+ RESIZE: "resize" + EVENT_KEY$5,
+ CLICK_DISMISS: "click.dismiss" + EVENT_KEY$5,
+ KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY$5,
+ MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY$5,
+ MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY$5,
+ CLICK_DATA_API: "click" + EVENT_KEY$5 + DATA_API_KEY$5
+ };
+ var ClassName$5 = {
+ SCROLLABLE: 'modal-dialog-scrollable',
+ SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
+ BACKDROP: 'modal-backdrop',
+ OPEN: 'modal-open',
+ FADE: 'fade',
+ SHOW: 'show',
+ STATIC: 'modal-static'
+ };
+ var Selector$5 = {
+ DIALOG: '.modal-dialog',
+ MODAL_BODY: '.modal-body',
+ DATA_TOGGLE: '[data-toggle="modal"]',
+ DATA_DISMISS: '[data-dismiss="modal"]',
+ FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
+ STICKY_CONTENT: '.sticky-top'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Modal =
+ /*#__PURE__*/
+ function () {
+ function Modal(element, config) {
+ this._config = this._getConfig(config);
+ this._element = element;
+ this._dialog = element.querySelector(Selector$5.DIALOG);
+ this._backdrop = null;
+ this._isShown = false;
+ this._isBodyOverflowing = false;
+ this._ignoreBackdropClick = false;
+ this._isTransitioning = false;
+ this._scrollbarWidth = 0;
+ } // Getters
+
+
+ var _proto = Modal.prototype;
+
+ // Public
+ _proto.toggle = function toggle(relatedTarget) {
+ return this._isShown ? this.hide() : this.show(relatedTarget);
+ };
+
+ _proto.show = function show(relatedTarget) {
+ var _this = this;
+
+ if (this._isShown || this._isTransitioning) {
+ return;
+ }
+
+ if ($(this._element).hasClass(ClassName$5.FADE)) {
+ this._isTransitioning = true;
+ }
+
+ var showEvent = $.Event(Event$5.SHOW, {
+ relatedTarget: relatedTarget
+ });
+ $(this._element).trigger(showEvent);
+
+ if (this._isShown || showEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._isShown = true;
+
+ this._checkScrollbar();
+
+ this._setScrollbar();
+
+ this._adjustDialog();
+
+ this._setEscapeEvent();
+
+ this._setResizeEvent();
+
+ $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) {
+ return _this.hide(event);
+ });
+ $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () {
+ $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) {
+ if ($(event.target).is(_this._element)) {
+ _this._ignoreBackdropClick = true;
+ }
+ });
+ });
+
+ this._showBackdrop(function () {
+ return _this._showElement(relatedTarget);
+ });
+ };
+
+ _proto.hide = function hide(event) {
+ var _this2 = this;
+
+ if (event) {
+ event.preventDefault();
+ }
+
+ if (!this._isShown || this._isTransitioning) {
+ return;
+ }
+
+ var hideEvent = $.Event(Event$5.HIDE);
+ $(this._element).trigger(hideEvent);
+
+ if (!this._isShown || hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._isShown = false;
+ var transition = $(this._element).hasClass(ClassName$5.FADE);
+
+ if (transition) {
+ this._isTransitioning = true;
+ }
+
+ this._setEscapeEvent();
+
+ this._setResizeEvent();
+
+ $(document).off(Event$5.FOCUSIN);
+ $(this._element).removeClass(ClassName$5.SHOW);
+ $(this._element).off(Event$5.CLICK_DISMISS);
+ $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS);
+
+ if (transition) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, function (event) {
+ return _this2._hideModal(event);
+ }).emulateTransitionEnd(transitionDuration);
+ } else {
+ this._hideModal();
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ [window, this._element, this._dialog].forEach(function (htmlElement) {
+ return $(htmlElement).off(EVENT_KEY$5);
+ });
+ /**
+ * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`
+ * Do not move `document` in `htmlElements` array
+ * It will remove `Event.CLICK_DATA_API` event that should remain
+ */
+
+ $(document).off(Event$5.FOCUSIN);
+ $.removeData(this._element, DATA_KEY$5);
+ this._config = null;
+ this._element = null;
+ this._dialog = null;
+ this._backdrop = null;
+ this._isShown = null;
+ this._isBodyOverflowing = null;
+ this._ignoreBackdropClick = null;
+ this._isTransitioning = null;
+ this._scrollbarWidth = null;
+ };
+
+ _proto.handleUpdate = function handleUpdate() {
+ this._adjustDialog();
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$3, {}, config);
+ Util.typeCheckConfig(NAME$5, config, DefaultType$3);
+ return config;
+ };
+
+ _proto._triggerBackdropTransition = function _triggerBackdropTransition() {
+ var _this3 = this;
+
+ if (this._config.backdrop === 'static') {
+ var hideEventPrevented = $.Event(Event$5.HIDE_PREVENTED);
+ $(this._element).trigger(hideEventPrevented);
+
+ if (hideEventPrevented.defaultPrevented) {
+ return;
+ }
+
+ this._element.classList.add(ClassName$5.STATIC);
+
+ var modalTransitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, function () {
+ _this3._element.classList.remove(ClassName$5.STATIC);
+ }).emulateTransitionEnd(modalTransitionDuration);
+
+ this._element.focus();
+ } else {
+ this.hide();
+ }
+ };
+
+ _proto._showElement = function _showElement(relatedTarget) {
+ var _this4 = this;
+
+ var transition = $(this._element).hasClass(ClassName$5.FADE);
+ var modalBody = this._dialog ? this._dialog.querySelector(Selector$5.MODAL_BODY) : null;
+
+ if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
+ // Don't move modal's DOM position
+ document.body.appendChild(this._element);
+ }
+
+ this._element.style.display = 'block';
+
+ this._element.removeAttribute('aria-hidden');
+
+ this._element.setAttribute('aria-modal', true);
+
+ if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE) && modalBody) {
+ modalBody.scrollTop = 0;
+ } else {
+ this._element.scrollTop = 0;
+ }
+
+ if (transition) {
+ Util.reflow(this._element);
+ }
+
+ $(this._element).addClass(ClassName$5.SHOW);
+
+ if (this._config.focus) {
+ this._enforceFocus();
+ }
+
+ var shownEvent = $.Event(Event$5.SHOWN, {
+ relatedTarget: relatedTarget
+ });
+
+ var transitionComplete = function transitionComplete() {
+ if (_this4._config.focus) {
+ _this4._element.focus();
+ }
+
+ _this4._isTransitioning = false;
+ $(_this4._element).trigger(shownEvent);
+ };
+
+ if (transition) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);
+ $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);
+ } else {
+ transitionComplete();
+ }
+ };
+
+ _proto._enforceFocus = function _enforceFocus() {
+ var _this5 = this;
+
+ $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop
+ .on(Event$5.FOCUSIN, function (event) {
+ if (document !== event.target && _this5._element !== event.target && $(_this5._element).has(event.target).length === 0) {
+ _this5._element.focus();
+ }
+ });
+ };
+
+ _proto._setEscapeEvent = function _setEscapeEvent() {
+ var _this6 = this;
+
+ if (this._isShown && this._config.keyboard) {
+ $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) {
+ if (event.which === ESCAPE_KEYCODE$1) {
+ _this6._triggerBackdropTransition();
+ }
+ });
+ } else if (!this._isShown) {
+ $(this._element).off(Event$5.KEYDOWN_DISMISS);
+ }
+ };
+
+ _proto._setResizeEvent = function _setResizeEvent() {
+ var _this7 = this;
+
+ if (this._isShown) {
+ $(window).on(Event$5.RESIZE, function (event) {
+ return _this7.handleUpdate(event);
+ });
+ } else {
+ $(window).off(Event$5.RESIZE);
+ }
+ };
+
+ _proto._hideModal = function _hideModal() {
+ var _this8 = this;
+
+ this._element.style.display = 'none';
+
+ this._element.setAttribute('aria-hidden', true);
+
+ this._element.removeAttribute('aria-modal');
+
+ this._isTransitioning = false;
+
+ this._showBackdrop(function () {
+ $(document.body).removeClass(ClassName$5.OPEN);
+
+ _this8._resetAdjustments();
+
+ _this8._resetScrollbar();
+
+ $(_this8._element).trigger(Event$5.HIDDEN);
+ });
+ };
+
+ _proto._removeBackdrop = function _removeBackdrop() {
+ if (this._backdrop) {
+ $(this._backdrop).remove();
+ this._backdrop = null;
+ }
+ };
+
+ _proto._showBackdrop = function _showBackdrop(callback) {
+ var _this9 = this;
+
+ var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : '';
+
+ if (this._isShown && this._config.backdrop) {
+ this._backdrop = document.createElement('div');
+ this._backdrop.className = ClassName$5.BACKDROP;
+
+ if (animate) {
+ this._backdrop.classList.add(animate);
+ }
+
+ $(this._backdrop).appendTo(document.body);
+ $(this._element).on(Event$5.CLICK_DISMISS, function (event) {
+ if (_this9._ignoreBackdropClick) {
+ _this9._ignoreBackdropClick = false;
+ return;
+ }
+
+ if (event.target !== event.currentTarget) {
+ return;
+ }
+
+ _this9._triggerBackdropTransition();
+ });
+
+ if (animate) {
+ Util.reflow(this._backdrop);
+ }
+
+ $(this._backdrop).addClass(ClassName$5.SHOW);
+
+ if (!callback) {
+ return;
+ }
+
+ if (!animate) {
+ callback();
+ return;
+ }
+
+ var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
+ $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);
+ } else if (!this._isShown && this._backdrop) {
+ $(this._backdrop).removeClass(ClassName$5.SHOW);
+
+ var callbackRemove = function callbackRemove() {
+ _this9._removeBackdrop();
+
+ if (callback) {
+ callback();
+ }
+ };
+
+ if ($(this._element).hasClass(ClassName$5.FADE)) {
+ var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
+
+ $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);
+ } else {
+ callbackRemove();
+ }
+ } else if (callback) {
+ callback();
+ }
+ } // ----------------------------------------------------------------------
+ // the following methods are used to handle overflowing modals
+ // todo (fat): these should probably be refactored out of modal.js
+ // ----------------------------------------------------------------------
+ ;
+
+ _proto._adjustDialog = function _adjustDialog() {
+ var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+
+ if (!this._isBodyOverflowing && isModalOverflowing) {
+ this._element.style.paddingLeft = this._scrollbarWidth + "px";
+ }
+
+ if (this._isBodyOverflowing && !isModalOverflowing) {
+ this._element.style.paddingRight = this._scrollbarWidth + "px";
+ }
+ };
+
+ _proto._resetAdjustments = function _resetAdjustments() {
+ this._element.style.paddingLeft = '';
+ this._element.style.paddingRight = '';
+ };
+
+ _proto._checkScrollbar = function _checkScrollbar() {
+ var rect = document.body.getBoundingClientRect();
+ this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;
+ this._scrollbarWidth = this._getScrollbarWidth();
+ };
+
+ _proto._setScrollbar = function _setScrollbar() {
+ var _this10 = this;
+
+ if (this._isBodyOverflowing) {
+ // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
+ // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
+ var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
+ var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding
+
+ $(fixedContent).each(function (index, element) {
+ var actualPadding = element.style.paddingRight;
+ var calculatedPadding = $(element).css('padding-right');
+ $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + "px");
+ }); // Adjust sticky content margin
+
+ $(stickyContent).each(function (index, element) {
+ var actualMargin = element.style.marginRight;
+ var calculatedMargin = $(element).css('margin-right');
+ $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + "px");
+ }); // Adjust body padding
+
+ var actualPadding = document.body.style.paddingRight;
+ var calculatedPadding = $(document.body).css('padding-right');
+ $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px");
+ }
+
+ $(document.body).addClass(ClassName$5.OPEN);
+ };
+
+ _proto._resetScrollbar = function _resetScrollbar() {
+ // Restore fixed content padding
+ var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
+ $(fixedContent).each(function (index, element) {
+ var padding = $(element).data('padding-right');
+ $(element).removeData('padding-right');
+ element.style.paddingRight = padding ? padding : '';
+ }); // Restore sticky content
+
+ var elements = [].slice.call(document.querySelectorAll("" + Selector$5.STICKY_CONTENT));
+ $(elements).each(function (index, element) {
+ var margin = $(element).data('margin-right');
+
+ if (typeof margin !== 'undefined') {
+ $(element).css('margin-right', margin).removeData('margin-right');
+ }
+ }); // Restore body padding
+
+ var padding = $(document.body).data('padding-right');
+ $(document.body).removeData('padding-right');
+ document.body.style.paddingRight = padding ? padding : '';
+ };
+
+ _proto._getScrollbarWidth = function _getScrollbarWidth() {
+ // thx d.walsh
+ var scrollDiv = document.createElement('div');
+ scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER;
+ document.body.appendChild(scrollDiv);
+ var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
+ document.body.removeChild(scrollDiv);
+ return scrollbarWidth;
+ } // Static
+ ;
+
+ Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$5);
+
+ var _config = _objectSpread2({}, Default$3, {}, $(this).data(), {}, typeof config === 'object' && config ? config : {});
+
+ if (!data) {
+ data = new Modal(this, _config);
+ $(this).data(DATA_KEY$5, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config](relatedTarget);
+ } else if (_config.show) {
+ data.show(relatedTarget);
+ }
+ });
+ };
+
+ _createClass(Modal, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$5;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$3;
+ }
+ }]);
+
+ return Modal;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) {
+ var _this11 = this;
+
+ var target;
+ var selector = Util.getSelectorFromElement(this);
+
+ if (selector) {
+ target = document.querySelector(selector);
+ }
+
+ var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread2({}, $(target).data(), {}, $(this).data());
+
+ if (this.tagName === 'A' || this.tagName === 'AREA') {
+ event.preventDefault();
+ }
+
+ var $target = $(target).one(Event$5.SHOW, function (showEvent) {
+ if (showEvent.isDefaultPrevented()) {
+ // Only register focus restorer if modal will actually get shown
+ return;
+ }
+
+ $target.one(Event$5.HIDDEN, function () {
+ if ($(_this11).is(':visible')) {
+ _this11.focus();
+ }
+ });
+ });
+
+ Modal._jQueryInterface.call($(target), config, this);
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$5] = Modal._jQueryInterface;
+ $.fn[NAME$5].Constructor = Modal;
+
+ $.fn[NAME$5].noConflict = function () {
+ $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;
+ return Modal._jQueryInterface;
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.4.1): tools/sanitizer.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+ var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];
+ var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
+ var DefaultWhitelist = {
+ // Global attributes allowed on any supplied element below.
+ '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
+ a: ['target', 'href', 'title', 'rel'],
+ area: [],
+ b: [],
+ br: [],
+ col: [],
+ code: [],
+ div: [],
+ em: [],
+ hr: [],
+ h1: [],
+ h2: [],
+ h3: [],
+ h4: [],
+ h5: [],
+ h6: [],
+ i: [],
+ img: ['src', 'alt', 'title', 'width', 'height'],
+ li: [],
+ ol: [],
+ p: [],
+ pre: [],
+ s: [],
+ small: [],
+ span: [],
+ sub: [],
+ sup: [],
+ strong: [],
+ u: [],
+ ul: []
+ };
+ /**
+ * A pattern that recognizes a commonly useful subset of URLs that are safe.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+
+ var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
+ /**
+ * A pattern that matches safe data URLs. Only matches image, video and audio types.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+
+ var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
+
+ function allowedAttribute(attr, allowedAttributeList) {
+ var attrName = attr.nodeName.toLowerCase();
+
+ if (allowedAttributeList.indexOf(attrName) !== -1) {
+ if (uriAttrs.indexOf(attrName) !== -1) {
+ return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));
+ }
+
+ return true;
+ }
+
+ var regExp = allowedAttributeList.filter(function (attrRegex) {
+ return attrRegex instanceof RegExp;
+ }); // Check if a regular expression validates the attribute.
+
+ for (var i = 0, l = regExp.length; i < l; i++) {
+ if (attrName.match(regExp[i])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
+ if (unsafeHtml.length === 0) {
+ return unsafeHtml;
+ }
+
+ if (sanitizeFn && typeof sanitizeFn === 'function') {
+ return sanitizeFn(unsafeHtml);
+ }
+
+ var domParser = new window.DOMParser();
+ var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
+ var whitelistKeys = Object.keys(whiteList);
+ var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));
+
+ var _loop = function _loop(i, len) {
+ var el = elements[i];
+ var elName = el.nodeName.toLowerCase();
+
+ if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
+ el.parentNode.removeChild(el);
+ return "continue";
+ }
+
+ var attributeList = [].slice.call(el.attributes);
+ var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
+ attributeList.forEach(function (attr) {
+ if (!allowedAttribute(attr, whitelistedAttributes)) {
+ el.removeAttribute(attr.nodeName);
+ }
+ });
+ };
+
+ for (var i = 0, len = elements.length; i < len; i++) {
+ var _ret = _loop(i);
+
+ if (_ret === "continue") continue;
+ }
+
+ return createdDocument.body.innerHTML;
+ }
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$6 = 'tooltip';
+ var VERSION$6 = '4.4.1';
+ var DATA_KEY$6 = 'bs.tooltip';
+ var EVENT_KEY$6 = "." + DATA_KEY$6;
+ var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];
+ var CLASS_PREFIX = 'bs-tooltip';
+ var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
+ var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
+ var DefaultType$4 = {
+ animation: 'boolean',
+ template: 'string',
+ title: '(string|element|function)',
+ trigger: 'string',
+ delay: '(number|object)',
+ html: 'boolean',
+ selector: '(string|boolean)',
+ placement: '(string|function)',
+ offset: '(number|string|function)',
+ container: '(string|element|boolean)',
+ fallbackPlacement: '(string|array)',
+ boundary: '(string|element)',
+ sanitize: 'boolean',
+ sanitizeFn: '(null|function)',
+ whiteList: 'object',
+ popperConfig: '(null|object)'
+ };
+ var AttachmentMap$1 = {
+ AUTO: 'auto',
+ TOP: 'top',
+ RIGHT: 'right',
+ BOTTOM: 'bottom',
+ LEFT: 'left'
+ };
+ var Default$4 = {
+ animation: true,
+ template: '',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ selector: false,
+ placement: 'top',
+ offset: 0,
+ container: false,
+ fallbackPlacement: 'flip',
+ boundary: 'scrollParent',
+ sanitize: true,
+ sanitizeFn: null,
+ whiteList: DefaultWhitelist,
+ popperConfig: null
+ };
+ var HoverState = {
+ SHOW: 'show',
+ OUT: 'out'
+ };
+ var Event$6 = {
+ HIDE: "hide" + EVENT_KEY$6,
+ HIDDEN: "hidden" + EVENT_KEY$6,
+ SHOW: "show" + EVENT_KEY$6,
+ SHOWN: "shown" + EVENT_KEY$6,
+ INSERTED: "inserted" + EVENT_KEY$6,
+ CLICK: "click" + EVENT_KEY$6,
+ FOCUSIN: "focusin" + EVENT_KEY$6,
+ FOCUSOUT: "focusout" + EVENT_KEY$6,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$6,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$6
+ };
+ var ClassName$6 = {
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$6 = {
+ TOOLTIP: '.tooltip',
+ TOOLTIP_INNER: '.tooltip-inner',
+ ARROW: '.arrow'
+ };
+ var Trigger = {
+ HOVER: 'hover',
+ FOCUS: 'focus',
+ CLICK: 'click',
+ MANUAL: 'manual'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Tooltip =
+ /*#__PURE__*/
+ function () {
+ function Tooltip(element, config) {
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)');
+ } // private
+
+
+ this._isEnabled = true;
+ this._timeout = 0;
+ this._hoverState = '';
+ this._activeTrigger = {};
+ this._popper = null; // Protected
+
+ this.element = element;
+ this.config = this._getConfig(config);
+ this.tip = null;
+
+ this._setListeners();
+ } // Getters
+
+
+ var _proto = Tooltip.prototype;
+
+ // Public
+ _proto.enable = function enable() {
+ this._isEnabled = true;
+ };
+
+ _proto.disable = function disable() {
+ this._isEnabled = false;
+ };
+
+ _proto.toggleEnabled = function toggleEnabled() {
+ this._isEnabled = !this._isEnabled;
+ };
+
+ _proto.toggle = function toggle(event) {
+ if (!this._isEnabled) {
+ return;
+ }
+
+ if (event) {
+ var dataKey = this.constructor.DATA_KEY;
+ var context = $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ context._activeTrigger.click = !context._activeTrigger.click;
+
+ if (context._isWithActiveTrigger()) {
+ context._enter(null, context);
+ } else {
+ context._leave(null, context);
+ }
+ } else {
+ if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) {
+ this._leave(null, this);
+
+ return;
+ }
+
+ this._enter(null, this);
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ clearTimeout(this._timeout);
+ $.removeData(this.element, this.constructor.DATA_KEY);
+ $(this.element).off(this.constructor.EVENT_KEY);
+ $(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler);
+
+ if (this.tip) {
+ $(this.tip).remove();
+ }
+
+ this._isEnabled = null;
+ this._timeout = null;
+ this._hoverState = null;
+ this._activeTrigger = null;
+
+ if (this._popper) {
+ this._popper.destroy();
+ }
+
+ this._popper = null;
+ this.element = null;
+ this.config = null;
+ this.tip = null;
+ };
+
+ _proto.show = function show() {
+ var _this = this;
+
+ if ($(this.element).css('display') === 'none') {
+ throw new Error('Please use show on visible elements');
+ }
+
+ var showEvent = $.Event(this.constructor.Event.SHOW);
+
+ if (this.isWithContent() && this._isEnabled) {
+ $(this.element).trigger(showEvent);
+ var shadowRoot = Util.findShadowRoot(this.element);
+ var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);
+
+ if (showEvent.isDefaultPrevented() || !isInTheDom) {
+ return;
+ }
+
+ var tip = this.getTipElement();
+ var tipId = Util.getUID(this.constructor.NAME);
+ tip.setAttribute('id', tipId);
+ this.element.setAttribute('aria-describedby', tipId);
+ this.setContent();
+
+ if (this.config.animation) {
+ $(tip).addClass(ClassName$6.FADE);
+ }
+
+ var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
+
+ var attachment = this._getAttachment(placement);
+
+ this.addAttachmentClass(attachment);
+
+ var container = this._getContainer();
+
+ $(tip).data(this.constructor.DATA_KEY, this);
+
+ if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
+ $(tip).appendTo(container);
+ }
+
+ $(this.element).trigger(this.constructor.Event.INSERTED);
+ this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment));
+ $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().on('mouseover', null, $.noop);
+ }
+
+ var complete = function complete() {
+ if (_this.config.animation) {
+ _this._fixTransition();
+ }
+
+ var prevHoverState = _this._hoverState;
+ _this._hoverState = null;
+ $(_this.element).trigger(_this.constructor.Event.SHOWN);
+
+ if (prevHoverState === HoverState.OUT) {
+ _this._leave(null, _this);
+ }
+ };
+
+ if ($(this.tip).hasClass(ClassName$6.FADE)) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this.tip);
+ $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ }
+ };
+
+ _proto.hide = function hide(callback) {
+ var _this2 = this;
+
+ var tip = this.getTipElement();
+ var hideEvent = $.Event(this.constructor.Event.HIDE);
+
+ var complete = function complete() {
+ if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
+ tip.parentNode.removeChild(tip);
+ }
+
+ _this2._cleanTipClass();
+
+ _this2.element.removeAttribute('aria-describedby');
+
+ $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
+
+ if (_this2._popper !== null) {
+ _this2._popper.destroy();
+ }
+
+ if (callback) {
+ callback();
+ }
+ };
+
+ $(this.element).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().off('mouseover', null, $.noop);
+ }
+
+ this._activeTrigger[Trigger.CLICK] = false;
+ this._activeTrigger[Trigger.FOCUS] = false;
+ this._activeTrigger[Trigger.HOVER] = false;
+
+ if ($(this.tip).hasClass(ClassName$6.FADE)) {
+ var transitionDuration = Util.getTransitionDurationFromElement(tip);
+ $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+
+ this._hoverState = '';
+ };
+
+ _proto.update = function update() {
+ if (this._popper !== null) {
+ this._popper.scheduleUpdate();
+ }
+ } // Protected
+ ;
+
+ _proto.isWithContent = function isWithContent() {
+ return Boolean(this.getTitle());
+ };
+
+ _proto.addAttachmentClass = function addAttachmentClass(attachment) {
+ $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
+ };
+
+ _proto.getTipElement = function getTipElement() {
+ this.tip = this.tip || $(this.config.template)[0];
+ return this.tip;
+ };
+
+ _proto.setContent = function setContent() {
+ var tip = this.getTipElement();
+ this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle());
+ $(tip).removeClass(ClassName$6.FADE + " " + ClassName$6.SHOW);
+ };
+
+ _proto.setElementContent = function setElementContent($element, content) {
+ if (typeof content === 'object' && (content.nodeType || content.jquery)) {
+ // Content is a DOM node or a jQuery
+ if (this.config.html) {
+ if (!$(content).parent().is($element)) {
+ $element.empty().append(content);
+ }
+ } else {
+ $element.text($(content).text());
+ }
+
+ return;
+ }
+
+ if (this.config.html) {
+ if (this.config.sanitize) {
+ content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);
+ }
+
+ $element.html(content);
+ } else {
+ $element.text(content);
+ }
+ };
+
+ _proto.getTitle = function getTitle() {
+ var title = this.element.getAttribute('data-original-title');
+
+ if (!title) {
+ title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
+ }
+
+ return title;
+ } // Private
+ ;
+
+ _proto._getPopperConfig = function _getPopperConfig(attachment) {
+ var _this3 = this;
+
+ var defaultBsConfig = {
+ placement: attachment,
+ modifiers: {
+ offset: this._getOffset(),
+ flip: {
+ behavior: this.config.fallbackPlacement
+ },
+ arrow: {
+ element: Selector$6.ARROW
+ },
+ preventOverflow: {
+ boundariesElement: this.config.boundary
+ }
+ },
+ onCreate: function onCreate(data) {
+ if (data.originalPlacement !== data.placement) {
+ _this3._handlePopperPlacementChange(data);
+ }
+ },
+ onUpdate: function onUpdate(data) {
+ return _this3._handlePopperPlacementChange(data);
+ }
+ };
+ return _objectSpread2({}, defaultBsConfig, {}, this.config.popperConfig);
+ };
+
+ _proto._getOffset = function _getOffset() {
+ var _this4 = this;
+
+ var offset = {};
+
+ if (typeof this.config.offset === 'function') {
+ offset.fn = function (data) {
+ data.offsets = _objectSpread2({}, data.offsets, {}, _this4.config.offset(data.offsets, _this4.element) || {});
+ return data;
+ };
+ } else {
+ offset.offset = this.config.offset;
+ }
+
+ return offset;
+ };
+
+ _proto._getContainer = function _getContainer() {
+ if (this.config.container === false) {
+ return document.body;
+ }
+
+ if (Util.isElement(this.config.container)) {
+ return $(this.config.container);
+ }
+
+ return $(document).find(this.config.container);
+ };
+
+ _proto._getAttachment = function _getAttachment(placement) {
+ return AttachmentMap$1[placement.toUpperCase()];
+ };
+
+ _proto._setListeners = function _setListeners() {
+ var _this5 = this;
+
+ var triggers = this.config.trigger.split(' ');
+ triggers.forEach(function (trigger) {
+ if (trigger === 'click') {
+ $(_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) {
+ return _this5.toggle(event);
+ });
+ } else if (trigger !== Trigger.MANUAL) {
+ var eventIn = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN;
+ var eventOut = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT;
+ $(_this5.element).on(eventIn, _this5.config.selector, function (event) {
+ return _this5._enter(event);
+ }).on(eventOut, _this5.config.selector, function (event) {
+ return _this5._leave(event);
+ });
+ }
+ });
+
+ this._hideModalHandler = function () {
+ if (_this5.element) {
+ _this5.hide();
+ }
+ };
+
+ $(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler);
+
+ if (this.config.selector) {
+ this.config = _objectSpread2({}, this.config, {
+ trigger: 'manual',
+ selector: ''
+ });
+ } else {
+ this._fixTitle();
+ }
+ };
+
+ _proto._fixTitle = function _fixTitle() {
+ var titleType = typeof this.element.getAttribute('data-original-title');
+
+ if (this.element.getAttribute('title') || titleType !== 'string') {
+ this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
+ this.element.setAttribute('title', '');
+ }
+ };
+
+ _proto._enter = function _enter(event, context) {
+ var dataKey = this.constructor.DATA_KEY;
+ context = context || $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ if (event) {
+ context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
+ }
+
+ if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) {
+ context._hoverState = HoverState.SHOW;
+ return;
+ }
+
+ clearTimeout(context._timeout);
+ context._hoverState = HoverState.SHOW;
+
+ if (!context.config.delay || !context.config.delay.show) {
+ context.show();
+ return;
+ }
+
+ context._timeout = setTimeout(function () {
+ if (context._hoverState === HoverState.SHOW) {
+ context.show();
+ }
+ }, context.config.delay.show);
+ };
+
+ _proto._leave = function _leave(event, context) {
+ var dataKey = this.constructor.DATA_KEY;
+ context = context || $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ if (event) {
+ context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
+ }
+
+ if (context._isWithActiveTrigger()) {
+ return;
+ }
+
+ clearTimeout(context._timeout);
+ context._hoverState = HoverState.OUT;
+
+ if (!context.config.delay || !context.config.delay.hide) {
+ context.hide();
+ return;
+ }
+
+ context._timeout = setTimeout(function () {
+ if (context._hoverState === HoverState.OUT) {
+ context.hide();
+ }
+ }, context.config.delay.hide);
+ };
+
+ _proto._isWithActiveTrigger = function _isWithActiveTrigger() {
+ for (var trigger in this._activeTrigger) {
+ if (this._activeTrigger[trigger]) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ _proto._getConfig = function _getConfig(config) {
+ var dataAttributes = $(this.element).data();
+ Object.keys(dataAttributes).forEach(function (dataAttr) {
+ if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {
+ delete dataAttributes[dataAttr];
+ }
+ });
+ config = _objectSpread2({}, this.constructor.Default, {}, dataAttributes, {}, typeof config === 'object' && config ? config : {});
+
+ if (typeof config.delay === 'number') {
+ config.delay = {
+ show: config.delay,
+ hide: config.delay
+ };
+ }
+
+ if (typeof config.title === 'number') {
+ config.title = config.title.toString();
+ }
+
+ if (typeof config.content === 'number') {
+ config.content = config.content.toString();
+ }
+
+ Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);
+
+ if (config.sanitize) {
+ config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);
+ }
+
+ return config;
+ };
+
+ _proto._getDelegateConfig = function _getDelegateConfig() {
+ var config = {};
+
+ if (this.config) {
+ for (var key in this.config) {
+ if (this.constructor.Default[key] !== this.config[key]) {
+ config[key] = this.config[key];
+ }
+ }
+ }
+
+ return config;
+ };
+
+ _proto._cleanTipClass = function _cleanTipClass() {
+ var $tip = $(this.getTipElement());
+ var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
+
+ if (tabClass !== null && tabClass.length) {
+ $tip.removeClass(tabClass.join(''));
+ }
+ };
+
+ _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {
+ var popperInstance = popperData.instance;
+ this.tip = popperInstance.popper;
+
+ this._cleanTipClass();
+
+ this.addAttachmentClass(this._getAttachment(popperData.placement));
+ };
+
+ _proto._fixTransition = function _fixTransition() {
+ var tip = this.getTipElement();
+ var initConfigAnimation = this.config.animation;
+
+ if (tip.getAttribute('x-placement') !== null) {
+ return;
+ }
+
+ $(tip).removeClass(ClassName$6.FADE);
+ this.config.animation = false;
+ this.hide();
+ this.show();
+ this.config.animation = initConfigAnimation;
+ } // Static
+ ;
+
+ Tooltip._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$6);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data && /dispose|hide/.test(config)) {
+ return;
+ }
+
+ if (!data) {
+ data = new Tooltip(this, _config);
+ $(this).data(DATA_KEY$6, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Tooltip, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$6;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$4;
+ }
+ }, {
+ key: "NAME",
+ get: function get() {
+ return NAME$6;
+ }
+ }, {
+ key: "DATA_KEY",
+ get: function get() {
+ return DATA_KEY$6;
+ }
+ }, {
+ key: "Event",
+ get: function get() {
+ return Event$6;
+ }
+ }, {
+ key: "EVENT_KEY",
+ get: function get() {
+ return EVENT_KEY$6;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$4;
+ }
+ }]);
+
+ return Tooltip;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$6] = Tooltip._jQueryInterface;
+ $.fn[NAME$6].Constructor = Tooltip;
+
+ $.fn[NAME$6].noConflict = function () {
+ $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;
+ return Tooltip._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$7 = 'popover';
+ var VERSION$7 = '4.4.1';
+ var DATA_KEY$7 = 'bs.popover';
+ var EVENT_KEY$7 = "." + DATA_KEY$7;
+ var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];
+ var CLASS_PREFIX$1 = 'bs-popover';
+ var BSCLS_PREFIX_REGEX$1 = new RegExp("(^|\\s)" + CLASS_PREFIX$1 + "\\S+", 'g');
+
+ var Default$5 = _objectSpread2({}, Tooltip.Default, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: ''
+ });
+
+ var DefaultType$5 = _objectSpread2({}, Tooltip.DefaultType, {
+ content: '(string|element|function)'
+ });
+
+ var ClassName$7 = {
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$7 = {
+ TITLE: '.popover-header',
+ CONTENT: '.popover-body'
+ };
+ var Event$7 = {
+ HIDE: "hide" + EVENT_KEY$7,
+ HIDDEN: "hidden" + EVENT_KEY$7,
+ SHOW: "show" + EVENT_KEY$7,
+ SHOWN: "shown" + EVENT_KEY$7,
+ INSERTED: "inserted" + EVENT_KEY$7,
+ CLICK: "click" + EVENT_KEY$7,
+ FOCUSIN: "focusin" + EVENT_KEY$7,
+ FOCUSOUT: "focusout" + EVENT_KEY$7,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$7,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$7
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Popover =
+ /*#__PURE__*/
+ function (_Tooltip) {
+ _inheritsLoose(Popover, _Tooltip);
+
+ function Popover() {
+ return _Tooltip.apply(this, arguments) || this;
+ }
+
+ var _proto = Popover.prototype;
+
+ // Overrides
+ _proto.isWithContent = function isWithContent() {
+ return this.getTitle() || this._getContent();
+ };
+
+ _proto.addAttachmentClass = function addAttachmentClass(attachment) {
+ $(this.getTipElement()).addClass(CLASS_PREFIX$1 + "-" + attachment);
+ };
+
+ _proto.getTipElement = function getTipElement() {
+ this.tip = this.tip || $(this.config.template)[0];
+ return this.tip;
+ };
+
+ _proto.setContent = function setContent() {
+ var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events
+
+ this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle());
+
+ var content = this._getContent();
+
+ if (typeof content === 'function') {
+ content = content.call(this.element);
+ }
+
+ this.setElementContent($tip.find(Selector$7.CONTENT), content);
+ $tip.removeClass(ClassName$7.FADE + " " + ClassName$7.SHOW);
+ } // Private
+ ;
+
+ _proto._getContent = function _getContent() {
+ return this.element.getAttribute('data-content') || this.config.content;
+ };
+
+ _proto._cleanTipClass = function _cleanTipClass() {
+ var $tip = $(this.getTipElement());
+ var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);
+
+ if (tabClass !== null && tabClass.length > 0) {
+ $tip.removeClass(tabClass.join(''));
+ }
+ } // Static
+ ;
+
+ Popover._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$7);
+
+ var _config = typeof config === 'object' ? config : null;
+
+ if (!data && /dispose|hide/.test(config)) {
+ return;
+ }
+
+ if (!data) {
+ data = new Popover(this, _config);
+ $(this).data(DATA_KEY$7, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Popover, null, [{
+ key: "VERSION",
+ // Getters
+ get: function get() {
+ return VERSION$7;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$5;
+ }
+ }, {
+ key: "NAME",
+ get: function get() {
+ return NAME$7;
+ }
+ }, {
+ key: "DATA_KEY",
+ get: function get() {
+ return DATA_KEY$7;
+ }
+ }, {
+ key: "Event",
+ get: function get() {
+ return Event$7;
+ }
+ }, {
+ key: "EVENT_KEY",
+ get: function get() {
+ return EVENT_KEY$7;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$5;
+ }
+ }]);
+
+ return Popover;
+ }(Tooltip);
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$7] = Popover._jQueryInterface;
+ $.fn[NAME$7].Constructor = Popover;
+
+ $.fn[NAME$7].noConflict = function () {
+ $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;
+ return Popover._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$8 = 'scrollspy';
+ var VERSION$8 = '4.4.1';
+ var DATA_KEY$8 = 'bs.scrollspy';
+ var EVENT_KEY$8 = "." + DATA_KEY$8;
+ var DATA_API_KEY$6 = '.data-api';
+ var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];
+ var Default$6 = {
+ offset: 10,
+ method: 'auto',
+ target: ''
+ };
+ var DefaultType$6 = {
+ offset: 'number',
+ method: 'string',
+ target: '(string|element)'
+ };
+ var Event$8 = {
+ ACTIVATE: "activate" + EVENT_KEY$8,
+ SCROLL: "scroll" + EVENT_KEY$8,
+ LOAD_DATA_API: "load" + EVENT_KEY$8 + DATA_API_KEY$6
+ };
+ var ClassName$8 = {
+ DROPDOWN_ITEM: 'dropdown-item',
+ DROPDOWN_MENU: 'dropdown-menu',
+ ACTIVE: 'active'
+ };
+ var Selector$8 = {
+ DATA_SPY: '[data-spy="scroll"]',
+ ACTIVE: '.active',
+ NAV_LIST_GROUP: '.nav, .list-group',
+ NAV_LINKS: '.nav-link',
+ NAV_ITEMS: '.nav-item',
+ LIST_ITEMS: '.list-group-item',
+ DROPDOWN: '.dropdown',
+ DROPDOWN_ITEMS: '.dropdown-item',
+ DROPDOWN_TOGGLE: '.dropdown-toggle'
+ };
+ var OffsetMethod = {
+ OFFSET: 'offset',
+ POSITION: 'position'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var ScrollSpy =
+ /*#__PURE__*/
+ function () {
+ function ScrollSpy(element, config) {
+ var _this = this;
+
+ this._element = element;
+ this._scrollElement = element.tagName === 'BODY' ? window : element;
+ this._config = this._getConfig(config);
+ this._selector = this._config.target + " " + Selector$8.NAV_LINKS + "," + (this._config.target + " " + Selector$8.LIST_ITEMS + ",") + (this._config.target + " " + Selector$8.DROPDOWN_ITEMS);
+ this._offsets = [];
+ this._targets = [];
+ this._activeTarget = null;
+ this._scrollHeight = 0;
+ $(this._scrollElement).on(Event$8.SCROLL, function (event) {
+ return _this._process(event);
+ });
+ this.refresh();
+
+ this._process();
+ } // Getters
+
+
+ var _proto = ScrollSpy.prototype;
+
+ // Public
+ _proto.refresh = function refresh() {
+ var _this2 = this;
+
+ var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
+ var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
+ var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
+ this._offsets = [];
+ this._targets = [];
+ this._scrollHeight = this._getScrollHeight();
+ var targets = [].slice.call(document.querySelectorAll(this._selector));
+ targets.map(function (element) {
+ var target;
+ var targetSelector = Util.getSelectorFromElement(element);
+
+ if (targetSelector) {
+ target = document.querySelector(targetSelector);
+ }
+
+ if (target) {
+ var targetBCR = target.getBoundingClientRect();
+
+ if (targetBCR.width || targetBCR.height) {
+ // TODO (fat): remove sketch reliance on jQuery position/offset
+ return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
+ }
+ }
+
+ return null;
+ }).filter(function (item) {
+ return item;
+ }).sort(function (a, b) {
+ return a[0] - b[0];
+ }).forEach(function (item) {
+ _this2._offsets.push(item[0]);
+
+ _this2._targets.push(item[1]);
+ });
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$8);
+ $(this._scrollElement).off(EVENT_KEY$8);
+ this._element = null;
+ this._scrollElement = null;
+ this._config = null;
+ this._selector = null;
+ this._offsets = null;
+ this._targets = null;
+ this._activeTarget = null;
+ this._scrollHeight = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$6, {}, typeof config === 'object' && config ? config : {});
+
+ if (typeof config.target !== 'string') {
+ var id = $(config.target).attr('id');
+
+ if (!id) {
+ id = Util.getUID(NAME$8);
+ $(config.target).attr('id', id);
+ }
+
+ config.target = "#" + id;
+ }
+
+ Util.typeCheckConfig(NAME$8, config, DefaultType$6);
+ return config;
+ };
+
+ _proto._getScrollTop = function _getScrollTop() {
+ return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
+ };
+
+ _proto._getScrollHeight = function _getScrollHeight() {
+ return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
+ };
+
+ _proto._getOffsetHeight = function _getOffsetHeight() {
+ return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
+ };
+
+ _proto._process = function _process() {
+ var scrollTop = this._getScrollTop() + this._config.offset;
+
+ var scrollHeight = this._getScrollHeight();
+
+ var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
+
+ if (this._scrollHeight !== scrollHeight) {
+ this.refresh();
+ }
+
+ if (scrollTop >= maxScroll) {
+ var target = this._targets[this._targets.length - 1];
+
+ if (this._activeTarget !== target) {
+ this._activate(target);
+ }
+
+ return;
+ }
+
+ if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
+ this._activeTarget = null;
+
+ this._clear();
+
+ return;
+ }
+
+ var offsetLength = this._offsets.length;
+
+ for (var i = offsetLength; i--;) {
+ var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
+
+ if (isActiveTarget) {
+ this._activate(this._targets[i]);
+ }
+ }
+ };
+
+ _proto._activate = function _activate(target) {
+ this._activeTarget = target;
+
+ this._clear();
+
+ var queries = this._selector.split(',').map(function (selector) {
+ return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]";
+ });
+
+ var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));
+
+ if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) {
+ $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE);
+ $link.addClass(ClassName$8.ACTIVE);
+ } else {
+ // Set triggered link as active
+ $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active
+ // With both and markup a parent is the previous sibling of any nav ancestor
+
+ $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_LINKS + ", " + Selector$8.LIST_ITEMS).addClass(ClassName$8.ACTIVE); // Handle special case when .nav-link is inside .nav-item
+
+ $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_ITEMS).children(Selector$8.NAV_LINKS).addClass(ClassName$8.ACTIVE);
+ }
+
+ $(this._scrollElement).trigger(Event$8.ACTIVATE, {
+ relatedTarget: target
+ });
+ };
+
+ _proto._clear = function _clear() {
+ [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {
+ return node.classList.contains(ClassName$8.ACTIVE);
+ }).forEach(function (node) {
+ return node.classList.remove(ClassName$8.ACTIVE);
+ });
+ } // Static
+ ;
+
+ ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$8);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data) {
+ data = new ScrollSpy(this, _config);
+ $(this).data(DATA_KEY$8, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(ScrollSpy, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$8;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$6;
+ }
+ }]);
+
+ return ScrollSpy;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(window).on(Event$8.LOAD_DATA_API, function () {
+ var scrollSpys = [].slice.call(document.querySelectorAll(Selector$8.DATA_SPY));
+ var scrollSpysLength = scrollSpys.length;
+
+ for (var i = scrollSpysLength; i--;) {
+ var $spy = $(scrollSpys[i]);
+
+ ScrollSpy._jQueryInterface.call($spy, $spy.data());
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$8] = ScrollSpy._jQueryInterface;
+ $.fn[NAME$8].Constructor = ScrollSpy;
+
+ $.fn[NAME$8].noConflict = function () {
+ $.fn[NAME$8] = JQUERY_NO_CONFLICT$8;
+ return ScrollSpy._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$9 = 'tab';
+ var VERSION$9 = '4.4.1';
+ var DATA_KEY$9 = 'bs.tab';
+ var EVENT_KEY$9 = "." + DATA_KEY$9;
+ var DATA_API_KEY$7 = '.data-api';
+ var JQUERY_NO_CONFLICT$9 = $.fn[NAME$9];
+ var Event$9 = {
+ HIDE: "hide" + EVENT_KEY$9,
+ HIDDEN: "hidden" + EVENT_KEY$9,
+ SHOW: "show" + EVENT_KEY$9,
+ SHOWN: "shown" + EVENT_KEY$9,
+ CLICK_DATA_API: "click" + EVENT_KEY$9 + DATA_API_KEY$7
+ };
+ var ClassName$9 = {
+ DROPDOWN_MENU: 'dropdown-menu',
+ ACTIVE: 'active',
+ DISABLED: 'disabled',
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$9 = {
+ DROPDOWN: '.dropdown',
+ NAV_LIST_GROUP: '.nav, .list-group',
+ ACTIVE: '.active',
+ ACTIVE_UL: '> li > .active',
+ DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
+ DROPDOWN_TOGGLE: '.dropdown-toggle',
+ DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Tab =
+ /*#__PURE__*/
+ function () {
+ function Tab(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Tab.prototype;
+
+ // Public
+ _proto.show = function show() {
+ var _this = this;
+
+ if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName$9.ACTIVE) || $(this._element).hasClass(ClassName$9.DISABLED)) {
+ return;
+ }
+
+ var target;
+ var previous;
+ var listElement = $(this._element).closest(Selector$9.NAV_LIST_GROUP)[0];
+ var selector = Util.getSelectorFromElement(this._element);
+
+ if (listElement) {
+ var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector$9.ACTIVE_UL : Selector$9.ACTIVE;
+ previous = $.makeArray($(listElement).find(itemSelector));
+ previous = previous[previous.length - 1];
+ }
+
+ var hideEvent = $.Event(Event$9.HIDE, {
+ relatedTarget: this._element
+ });
+ var showEvent = $.Event(Event$9.SHOW, {
+ relatedTarget: previous
+ });
+
+ if (previous) {
+ $(previous).trigger(hideEvent);
+ }
+
+ $(this._element).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (selector) {
+ target = document.querySelector(selector);
+ }
+
+ this._activate(this._element, listElement);
+
+ var complete = function complete() {
+ var hiddenEvent = $.Event(Event$9.HIDDEN, {
+ relatedTarget: _this._element
+ });
+ var shownEvent = $.Event(Event$9.SHOWN, {
+ relatedTarget: previous
+ });
+ $(previous).trigger(hiddenEvent);
+ $(_this._element).trigger(shownEvent);
+ };
+
+ if (target) {
+ this._activate(target, target.parentNode, complete);
+ } else {
+ complete();
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$9);
+ this._element = null;
+ } // Private
+ ;
+
+ _proto._activate = function _activate(element, container, callback) {
+ var _this2 = this;
+
+ var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);
+ var active = activeElements[0];
+ var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);
+
+ var complete = function complete() {
+ return _this2._transitionComplete(element, active, callback);
+ };
+
+ if (active && isTransitioning) {
+ var transitionDuration = Util.getTransitionDurationFromElement(active);
+ $(active).removeClass(ClassName$9.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ };
+
+ _proto._transitionComplete = function _transitionComplete(element, active, callback) {
+ if (active) {
+ $(active).removeClass(ClassName$9.ACTIVE);
+ var dropdownChild = $(active.parentNode).find(Selector$9.DROPDOWN_ACTIVE_CHILD)[0];
+
+ if (dropdownChild) {
+ $(dropdownChild).removeClass(ClassName$9.ACTIVE);
+ }
+
+ if (active.getAttribute('role') === 'tab') {
+ active.setAttribute('aria-selected', false);
+ }
+ }
+
+ $(element).addClass(ClassName$9.ACTIVE);
+
+ if (element.getAttribute('role') === 'tab') {
+ element.setAttribute('aria-selected', true);
+ }
+
+ Util.reflow(element);
+
+ if (element.classList.contains(ClassName$9.FADE)) {
+ element.classList.add(ClassName$9.SHOW);
+ }
+
+ if (element.parentNode && $(element.parentNode).hasClass(ClassName$9.DROPDOWN_MENU)) {
+ var dropdownElement = $(element).closest(Selector$9.DROPDOWN)[0];
+
+ if (dropdownElement) {
+ var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector$9.DROPDOWN_TOGGLE));
+ $(dropdownToggleList).addClass(ClassName$9.ACTIVE);
+ }
+
+ element.setAttribute('aria-expanded', true);
+ }
+
+ if (callback) {
+ callback();
+ }
+ } // Static
+ ;
+
+ Tab._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $this = $(this);
+ var data = $this.data(DATA_KEY$9);
+
+ if (!data) {
+ data = new Tab(this);
+ $this.data(DATA_KEY$9, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Tab, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$9;
+ }
+ }]);
+
+ return Tab;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$9.CLICK_DATA_API, Selector$9.DATA_TOGGLE, function (event) {
+ event.preventDefault();
+
+ Tab._jQueryInterface.call($(this), 'show');
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$9] = Tab._jQueryInterface;
+ $.fn[NAME$9].Constructor = Tab;
+
+ $.fn[NAME$9].noConflict = function () {
+ $.fn[NAME$9] = JQUERY_NO_CONFLICT$9;
+ return Tab._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$a = 'toast';
+ var VERSION$a = '4.4.1';
+ var DATA_KEY$a = 'bs.toast';
+ var EVENT_KEY$a = "." + DATA_KEY$a;
+ var JQUERY_NO_CONFLICT$a = $.fn[NAME$a];
+ var Event$a = {
+ CLICK_DISMISS: "click.dismiss" + EVENT_KEY$a,
+ HIDE: "hide" + EVENT_KEY$a,
+ HIDDEN: "hidden" + EVENT_KEY$a,
+ SHOW: "show" + EVENT_KEY$a,
+ SHOWN: "shown" + EVENT_KEY$a
+ };
+ var ClassName$a = {
+ FADE: 'fade',
+ HIDE: 'hide',
+ SHOW: 'show',
+ SHOWING: 'showing'
+ };
+ var DefaultType$7 = {
+ animation: 'boolean',
+ autohide: 'boolean',
+ delay: 'number'
+ };
+ var Default$7 = {
+ animation: true,
+ autohide: true,
+ delay: 500
+ };
+ var Selector$a = {
+ DATA_DISMISS: '[data-dismiss="toast"]'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Toast =
+ /*#__PURE__*/
+ function () {
+ function Toast(element, config) {
+ this._element = element;
+ this._config = this._getConfig(config);
+ this._timeout = null;
+
+ this._setListeners();
+ } // Getters
+
+
+ var _proto = Toast.prototype;
+
+ // Public
+ _proto.show = function show() {
+ var _this = this;
+
+ var showEvent = $.Event(Event$a.SHOW);
+ $(this._element).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (this._config.animation) {
+ this._element.classList.add(ClassName$a.FADE);
+ }
+
+ var complete = function complete() {
+ _this._element.classList.remove(ClassName$a.SHOWING);
+
+ _this._element.classList.add(ClassName$a.SHOW);
+
+ $(_this._element).trigger(Event$a.SHOWN);
+
+ if (_this._config.autohide) {
+ _this._timeout = setTimeout(function () {
+ _this.hide();
+ }, _this._config.delay);
+ }
+ };
+
+ this._element.classList.remove(ClassName$a.HIDE);
+
+ Util.reflow(this._element);
+
+ this._element.classList.add(ClassName$a.SHOWING);
+
+ if (this._config.animation) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ };
+
+ _proto.hide = function hide() {
+ if (!this._element.classList.contains(ClassName$a.SHOW)) {
+ return;
+ }
+
+ var hideEvent = $.Event(Event$a.HIDE);
+ $(this._element).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._close();
+ };
+
+ _proto.dispose = function dispose() {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+
+ if (this._element.classList.contains(ClassName$a.SHOW)) {
+ this._element.classList.remove(ClassName$a.SHOW);
+ }
+
+ $(this._element).off(Event$a.CLICK_DISMISS);
+ $.removeData(this._element, DATA_KEY$a);
+ this._element = null;
+ this._config = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$7, {}, $(this._element).data(), {}, typeof config === 'object' && config ? config : {});
+ Util.typeCheckConfig(NAME$a, config, this.constructor.DefaultType);
+ return config;
+ };
+
+ _proto._setListeners = function _setListeners() {
+ var _this2 = this;
+
+ $(this._element).on(Event$a.CLICK_DISMISS, Selector$a.DATA_DISMISS, function () {
+ return _this2.hide();
+ });
+ };
+
+ _proto._close = function _close() {
+ var _this3 = this;
+
+ var complete = function complete() {
+ _this3._element.classList.add(ClassName$a.HIDE);
+
+ $(_this3._element).trigger(Event$a.HIDDEN);
+ };
+
+ this._element.classList.remove(ClassName$a.SHOW);
+
+ if (this._config.animation) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ } // Static
+ ;
+
+ Toast._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $element = $(this);
+ var data = $element.data(DATA_KEY$a);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data) {
+ data = new Toast(this, _config);
+ $element.data(DATA_KEY$a, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config](this);
+ }
+ });
+ };
+
+ _createClass(Toast, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$a;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$7;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$7;
+ }
+ }]);
+
+ return Toast;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$a] = Toast._jQueryInterface;
+ $.fn[NAME$a].Constructor = Toast;
+
+ $.fn[NAME$a].noConflict = function () {
+ $.fn[NAME$a] = JQUERY_NO_CONFLICT$a;
+ return Toast._jQueryInterface;
+ };
+
+ exports.Alert = Alert;
+ exports.Button = Button;
+ exports.Carousel = Carousel;
+ exports.Collapse = Collapse;
+ exports.Dropdown = Dropdown;
+ exports.Modal = Modal;
+ exports.Popover = Popover;
+ exports.Scrollspy = ScrollSpy;
+ exports.Tab = Tab;
+ exports.Toast = Toast;
+ exports.Tooltip = Tooltip;
+ exports.Util = Util;
+
+ Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
+//# sourceMappingURL=bootstrap.bundle.js.map
diff --git a/app/webroot/js/bootstrap.js b/app/webroot/js/bootstrap.js
new file mode 100644
index 0000000..f1e68d3
--- /dev/null
+++ b/app/webroot/js/bootstrap.js
@@ -0,0 +1,4521 @@
+/*!
+ * Bootstrap v4.4.1 (https://getbootstrap.com/)
+ * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) :
+ typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) :
+ (global = global || self, factory(global.bootstrap = {}, global.jQuery, global.Popper));
+}(this, (function (exports, $, Popper) { 'use strict';
+
+ $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+ Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;
+
+ function _defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ function _createClass(Constructor, protoProps, staticProps) {
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) _defineProperties(Constructor, staticProps);
+ return Constructor;
+ }
+
+ function _defineProperty(obj, key, value) {
+ if (key in obj) {
+ Object.defineProperty(obj, key, {
+ value: value,
+ enumerable: true,
+ configurable: true,
+ writable: true
+ });
+ } else {
+ obj[key] = value;
+ }
+
+ return obj;
+ }
+
+ function ownKeys(object, enumerableOnly) {
+ var keys = Object.keys(object);
+
+ if (Object.getOwnPropertySymbols) {
+ var symbols = Object.getOwnPropertySymbols(object);
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+ });
+ keys.push.apply(keys, symbols);
+ }
+
+ return keys;
+ }
+
+ function _objectSpread2(target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i] != null ? arguments[i] : {};
+
+ if (i % 2) {
+ ownKeys(Object(source), true).forEach(function (key) {
+ _defineProperty(target, key, source[key]);
+ });
+ } else if (Object.getOwnPropertyDescriptors) {
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+ } else {
+ ownKeys(Object(source)).forEach(function (key) {
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+ });
+ }
+ }
+
+ return target;
+ }
+
+ function _inheritsLoose(subClass, superClass) {
+ subClass.prototype = Object.create(superClass.prototype);
+ subClass.prototype.constructor = subClass;
+ subClass.__proto__ = superClass;
+ }
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.4.1): util.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+ /**
+ * ------------------------------------------------------------------------
+ * Private TransitionEnd Helpers
+ * ------------------------------------------------------------------------
+ */
+
+ var TRANSITION_END = 'transitionend';
+ var MAX_UID = 1000000;
+ var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
+
+ function toType(obj) {
+ return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
+ }
+
+ function getSpecialTransitionEndEvent() {
+ return {
+ bindType: TRANSITION_END,
+ delegateType: TRANSITION_END,
+ handle: function handle(event) {
+ if ($(event.target).is(this)) {
+ return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
+ }
+
+ return undefined; // eslint-disable-line no-undefined
+ }
+ };
+ }
+
+ function transitionEndEmulator(duration) {
+ var _this = this;
+
+ var called = false;
+ $(this).one(Util.TRANSITION_END, function () {
+ called = true;
+ });
+ setTimeout(function () {
+ if (!called) {
+ Util.triggerTransitionEnd(_this);
+ }
+ }, duration);
+ return this;
+ }
+
+ function setTransitionEndSupport() {
+ $.fn.emulateTransitionEnd = transitionEndEmulator;
+ $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
+ }
+ /**
+ * --------------------------------------------------------------------------
+ * Public Util Api
+ * --------------------------------------------------------------------------
+ */
+
+
+ var Util = {
+ TRANSITION_END: 'bsTransitionEnd',
+ getUID: function getUID(prefix) {
+ do {
+ // eslint-disable-next-line no-bitwise
+ prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
+ } while (document.getElementById(prefix));
+
+ return prefix;
+ },
+ getSelectorFromElement: function getSelectorFromElement(element) {
+ var selector = element.getAttribute('data-target');
+
+ if (!selector || selector === '#') {
+ var hrefAttr = element.getAttribute('href');
+ selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';
+ }
+
+ try {
+ return document.querySelector(selector) ? selector : null;
+ } catch (err) {
+ return null;
+ }
+ },
+ getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {
+ if (!element) {
+ return 0;
+ } // Get transition-duration of the element
+
+
+ var transitionDuration = $(element).css('transition-duration');
+ var transitionDelay = $(element).css('transition-delay');
+ var floatTransitionDuration = parseFloat(transitionDuration);
+ var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
+
+ if (!floatTransitionDuration && !floatTransitionDelay) {
+ return 0;
+ } // If multiple durations are defined, take the first
+
+
+ transitionDuration = transitionDuration.split(',')[0];
+ transitionDelay = transitionDelay.split(',')[0];
+ return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
+ },
+ reflow: function reflow(element) {
+ return element.offsetHeight;
+ },
+ triggerTransitionEnd: function triggerTransitionEnd(element) {
+ $(element).trigger(TRANSITION_END);
+ },
+ // TODO: Remove in v5
+ supportsTransitionEnd: function supportsTransitionEnd() {
+ return Boolean(TRANSITION_END);
+ },
+ isElement: function isElement(obj) {
+ return (obj[0] || obj).nodeType;
+ },
+ typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
+ for (var property in configTypes) {
+ if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
+ var expectedTypes = configTypes[property];
+ var value = config[property];
+ var valueType = value && Util.isElement(value) ? 'element' : toType(value);
+
+ if (!new RegExp(expectedTypes).test(valueType)) {
+ throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
+ }
+ }
+ }
+ },
+ findShadowRoot: function findShadowRoot(element) {
+ if (!document.documentElement.attachShadow) {
+ return null;
+ } // Can find the shadow root otherwise it'll return the document
+
+
+ if (typeof element.getRootNode === 'function') {
+ var root = element.getRootNode();
+ return root instanceof ShadowRoot ? root : null;
+ }
+
+ if (element instanceof ShadowRoot) {
+ return element;
+ } // when we don't find a shadow root
+
+
+ if (!element.parentNode) {
+ return null;
+ }
+
+ return Util.findShadowRoot(element.parentNode);
+ },
+ jQueryDetection: function jQueryDetection() {
+ if (typeof $ === 'undefined') {
+ throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.');
+ }
+
+ var version = $.fn.jquery.split(' ')[0].split('.');
+ var minMajor = 1;
+ var ltMajor = 2;
+ var minMinor = 9;
+ var minPatch = 1;
+ var maxMajor = 4;
+
+ if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
+ throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');
+ }
+ }
+ };
+ Util.jQueryDetection();
+ setTransitionEndSupport();
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME = 'alert';
+ var VERSION = '4.4.1';
+ var DATA_KEY = 'bs.alert';
+ var EVENT_KEY = "." + DATA_KEY;
+ var DATA_API_KEY = '.data-api';
+ var JQUERY_NO_CONFLICT = $.fn[NAME];
+ var Selector = {
+ DISMISS: '[data-dismiss="alert"]'
+ };
+ var Event = {
+ CLOSE: "close" + EVENT_KEY,
+ CLOSED: "closed" + EVENT_KEY,
+ CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
+ };
+ var ClassName = {
+ ALERT: 'alert',
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Alert =
+ /*#__PURE__*/
+ function () {
+ function Alert(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Alert.prototype;
+
+ // Public
+ _proto.close = function close(element) {
+ var rootElement = this._element;
+
+ if (element) {
+ rootElement = this._getRootElement(element);
+ }
+
+ var customEvent = this._triggerCloseEvent(rootElement);
+
+ if (customEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._removeElement(rootElement);
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY);
+ this._element = null;
+ } // Private
+ ;
+
+ _proto._getRootElement = function _getRootElement(element) {
+ var selector = Util.getSelectorFromElement(element);
+ var parent = false;
+
+ if (selector) {
+ parent = document.querySelector(selector);
+ }
+
+ if (!parent) {
+ parent = $(element).closest("." + ClassName.ALERT)[0];
+ }
+
+ return parent;
+ };
+
+ _proto._triggerCloseEvent = function _triggerCloseEvent(element) {
+ var closeEvent = $.Event(Event.CLOSE);
+ $(element).trigger(closeEvent);
+ return closeEvent;
+ };
+
+ _proto._removeElement = function _removeElement(element) {
+ var _this = this;
+
+ $(element).removeClass(ClassName.SHOW);
+
+ if (!$(element).hasClass(ClassName.FADE)) {
+ this._destroyElement(element);
+
+ return;
+ }
+
+ var transitionDuration = Util.getTransitionDurationFromElement(element);
+ $(element).one(Util.TRANSITION_END, function (event) {
+ return _this._destroyElement(element, event);
+ }).emulateTransitionEnd(transitionDuration);
+ };
+
+ _proto._destroyElement = function _destroyElement(element) {
+ $(element).detach().trigger(Event.CLOSED).remove();
+ } // Static
+ ;
+
+ Alert._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $element = $(this);
+ var data = $element.data(DATA_KEY);
+
+ if (!data) {
+ data = new Alert(this);
+ $element.data(DATA_KEY, data);
+ }
+
+ if (config === 'close') {
+ data[config](this);
+ }
+ });
+ };
+
+ Alert._handleDismiss = function _handleDismiss(alertInstance) {
+ return function (event) {
+ if (event) {
+ event.preventDefault();
+ }
+
+ alertInstance.close(this);
+ };
+ };
+
+ _createClass(Alert, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION;
+ }
+ }]);
+
+ return Alert;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME] = Alert._jQueryInterface;
+ $.fn[NAME].Constructor = Alert;
+
+ $.fn[NAME].noConflict = function () {
+ $.fn[NAME] = JQUERY_NO_CONFLICT;
+ return Alert._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$1 = 'button';
+ var VERSION$1 = '4.4.1';
+ var DATA_KEY$1 = 'bs.button';
+ var EVENT_KEY$1 = "." + DATA_KEY$1;
+ var DATA_API_KEY$1 = '.data-api';
+ var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];
+ var ClassName$1 = {
+ ACTIVE: 'active',
+ BUTTON: 'btn',
+ FOCUS: 'focus'
+ };
+ var Selector$1 = {
+ DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
+ DATA_TOGGLES: '[data-toggle="buttons"]',
+ DATA_TOGGLE: '[data-toggle="button"]',
+ DATA_TOGGLES_BUTTONS: '[data-toggle="buttons"] .btn',
+ INPUT: 'input:not([type="hidden"])',
+ ACTIVE: '.active',
+ BUTTON: '.btn'
+ };
+ var Event$1 = {
+ CLICK_DATA_API: "click" + EVENT_KEY$1 + DATA_API_KEY$1,
+ FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY$1 + DATA_API_KEY$1 + " " + ("blur" + EVENT_KEY$1 + DATA_API_KEY$1),
+ LOAD_DATA_API: "load" + EVENT_KEY$1 + DATA_API_KEY$1
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Button =
+ /*#__PURE__*/
+ function () {
+ function Button(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Button.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ var triggerChangeEvent = true;
+ var addAriaPressed = true;
+ var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLES)[0];
+
+ if (rootElement) {
+ var input = this._element.querySelector(Selector$1.INPUT);
+
+ if (input) {
+ if (input.type === 'radio') {
+ if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) {
+ triggerChangeEvent = false;
+ } else {
+ var activeElement = rootElement.querySelector(Selector$1.ACTIVE);
+
+ if (activeElement) {
+ $(activeElement).removeClass(ClassName$1.ACTIVE);
+ }
+ }
+ } else if (input.type === 'checkbox') {
+ if (this._element.tagName === 'LABEL' && input.checked === this._element.classList.contains(ClassName$1.ACTIVE)) {
+ triggerChangeEvent = false;
+ }
+ } else {
+ // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input
+ triggerChangeEvent = false;
+ }
+
+ if (triggerChangeEvent) {
+ input.checked = !this._element.classList.contains(ClassName$1.ACTIVE);
+ $(input).trigger('change');
+ }
+
+ input.focus();
+ addAriaPressed = false;
+ }
+ }
+
+ if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {
+ if (addAriaPressed) {
+ this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE));
+ }
+
+ if (triggerChangeEvent) {
+ $(this._element).toggleClass(ClassName$1.ACTIVE);
+ }
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$1);
+ this._element = null;
+ } // Static
+ ;
+
+ Button._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$1);
+
+ if (!data) {
+ data = new Button(this);
+ $(this).data(DATA_KEY$1, data);
+ }
+
+ if (config === 'toggle') {
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Button, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$1;
+ }
+ }]);
+
+ return Button;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
+ var button = event.target;
+
+ if (!$(button).hasClass(ClassName$1.BUTTON)) {
+ button = $(button).closest(Selector$1.BUTTON)[0];
+ }
+
+ if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {
+ event.preventDefault(); // work around Firefox bug #1540995
+ } else {
+ var inputBtn = button.querySelector(Selector$1.INPUT);
+
+ if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {
+ event.preventDefault(); // work around Firefox bug #1540995
+
+ return;
+ }
+
+ Button._jQueryInterface.call($(button), 'toggle');
+ }
+ }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
+ var button = $(event.target).closest(Selector$1.BUTTON)[0];
+ $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type));
+ });
+ $(window).on(Event$1.LOAD_DATA_API, function () {
+ // ensure correct active class is set to match the controls' actual values/states
+ // find all checkboxes/readio buttons inside data-toggle groups
+ var buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLES_BUTTONS));
+
+ for (var i = 0, len = buttons.length; i < len; i++) {
+ var button = buttons[i];
+ var input = button.querySelector(Selector$1.INPUT);
+
+ if (input.checked || input.hasAttribute('checked')) {
+ button.classList.add(ClassName$1.ACTIVE);
+ } else {
+ button.classList.remove(ClassName$1.ACTIVE);
+ }
+ } // find all button toggles
+
+
+ buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLE));
+
+ for (var _i = 0, _len = buttons.length; _i < _len; _i++) {
+ var _button = buttons[_i];
+
+ if (_button.getAttribute('aria-pressed') === 'true') {
+ _button.classList.add(ClassName$1.ACTIVE);
+ } else {
+ _button.classList.remove(ClassName$1.ACTIVE);
+ }
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$1] = Button._jQueryInterface;
+ $.fn[NAME$1].Constructor = Button;
+
+ $.fn[NAME$1].noConflict = function () {
+ $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;
+ return Button._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$2 = 'carousel';
+ var VERSION$2 = '4.4.1';
+ var DATA_KEY$2 = 'bs.carousel';
+ var EVENT_KEY$2 = "." + DATA_KEY$2;
+ var DATA_API_KEY$2 = '.data-api';
+ var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];
+ var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
+
+ var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
+
+ var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
+
+ var SWIPE_THRESHOLD = 40;
+ var Default = {
+ interval: 5000,
+ keyboard: true,
+ slide: false,
+ pause: 'hover',
+ wrap: true,
+ touch: true
+ };
+ var DefaultType = {
+ interval: '(number|boolean)',
+ keyboard: 'boolean',
+ slide: '(boolean|string)',
+ pause: '(string|boolean)',
+ wrap: 'boolean',
+ touch: 'boolean'
+ };
+ var Direction = {
+ NEXT: 'next',
+ PREV: 'prev',
+ LEFT: 'left',
+ RIGHT: 'right'
+ };
+ var Event$2 = {
+ SLIDE: "slide" + EVENT_KEY$2,
+ SLID: "slid" + EVENT_KEY$2,
+ KEYDOWN: "keydown" + EVENT_KEY$2,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$2,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$2,
+ TOUCHSTART: "touchstart" + EVENT_KEY$2,
+ TOUCHMOVE: "touchmove" + EVENT_KEY$2,
+ TOUCHEND: "touchend" + EVENT_KEY$2,
+ POINTERDOWN: "pointerdown" + EVENT_KEY$2,
+ POINTERUP: "pointerup" + EVENT_KEY$2,
+ DRAG_START: "dragstart" + EVENT_KEY$2,
+ LOAD_DATA_API: "load" + EVENT_KEY$2 + DATA_API_KEY$2,
+ CLICK_DATA_API: "click" + EVENT_KEY$2 + DATA_API_KEY$2
+ };
+ var ClassName$2 = {
+ CAROUSEL: 'carousel',
+ ACTIVE: 'active',
+ SLIDE: 'slide',
+ RIGHT: 'carousel-item-right',
+ LEFT: 'carousel-item-left',
+ NEXT: 'carousel-item-next',
+ PREV: 'carousel-item-prev',
+ ITEM: 'carousel-item',
+ POINTER_EVENT: 'pointer-event'
+ };
+ var Selector$2 = {
+ ACTIVE: '.active',
+ ACTIVE_ITEM: '.active.carousel-item',
+ ITEM: '.carousel-item',
+ ITEM_IMG: '.carousel-item img',
+ NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
+ INDICATORS: '.carousel-indicators',
+ DATA_SLIDE: '[data-slide], [data-slide-to]',
+ DATA_RIDE: '[data-ride="carousel"]'
+ };
+ var PointerType = {
+ TOUCH: 'touch',
+ PEN: 'pen'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Carousel =
+ /*#__PURE__*/
+ function () {
+ function Carousel(element, config) {
+ this._items = null;
+ this._interval = null;
+ this._activeElement = null;
+ this._isPaused = false;
+ this._isSliding = false;
+ this.touchTimeout = null;
+ this.touchStartX = 0;
+ this.touchDeltaX = 0;
+ this._config = this._getConfig(config);
+ this._element = element;
+ this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS);
+ this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
+ this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);
+
+ this._addEventListeners();
+ } // Getters
+
+
+ var _proto = Carousel.prototype;
+
+ // Public
+ _proto.next = function next() {
+ if (!this._isSliding) {
+ this._slide(Direction.NEXT);
+ }
+ };
+
+ _proto.nextWhenVisible = function nextWhenVisible() {
+ // Don't call next when the page isn't visible
+ // or the carousel or its parent isn't visible
+ if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {
+ this.next();
+ }
+ };
+
+ _proto.prev = function prev() {
+ if (!this._isSliding) {
+ this._slide(Direction.PREV);
+ }
+ };
+
+ _proto.pause = function pause(event) {
+ if (!event) {
+ this._isPaused = true;
+ }
+
+ if (this._element.querySelector(Selector$2.NEXT_PREV)) {
+ Util.triggerTransitionEnd(this._element);
+ this.cycle(true);
+ }
+
+ clearInterval(this._interval);
+ this._interval = null;
+ };
+
+ _proto.cycle = function cycle(event) {
+ if (!event) {
+ this._isPaused = false;
+ }
+
+ if (this._interval) {
+ clearInterval(this._interval);
+ this._interval = null;
+ }
+
+ if (this._config.interval && !this._isPaused) {
+ this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
+ }
+ };
+
+ _proto.to = function to(index) {
+ var _this = this;
+
+ this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
+
+ var activeIndex = this._getItemIndex(this._activeElement);
+
+ if (index > this._items.length - 1 || index < 0) {
+ return;
+ }
+
+ if (this._isSliding) {
+ $(this._element).one(Event$2.SLID, function () {
+ return _this.to(index);
+ });
+ return;
+ }
+
+ if (activeIndex === index) {
+ this.pause();
+ this.cycle();
+ return;
+ }
+
+ var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
+
+ this._slide(direction, this._items[index]);
+ };
+
+ _proto.dispose = function dispose() {
+ $(this._element).off(EVENT_KEY$2);
+ $.removeData(this._element, DATA_KEY$2);
+ this._items = null;
+ this._config = null;
+ this._element = null;
+ this._interval = null;
+ this._isPaused = null;
+ this._isSliding = null;
+ this._activeElement = null;
+ this._indicatorsElement = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default, {}, config);
+ Util.typeCheckConfig(NAME$2, config, DefaultType);
+ return config;
+ };
+
+ _proto._handleSwipe = function _handleSwipe() {
+ var absDeltax = Math.abs(this.touchDeltaX);
+
+ if (absDeltax <= SWIPE_THRESHOLD) {
+ return;
+ }
+
+ var direction = absDeltax / this.touchDeltaX;
+ this.touchDeltaX = 0; // swipe left
+
+ if (direction > 0) {
+ this.prev();
+ } // swipe right
+
+
+ if (direction < 0) {
+ this.next();
+ }
+ };
+
+ _proto._addEventListeners = function _addEventListeners() {
+ var _this2 = this;
+
+ if (this._config.keyboard) {
+ $(this._element).on(Event$2.KEYDOWN, function (event) {
+ return _this2._keydown(event);
+ });
+ }
+
+ if (this._config.pause === 'hover') {
+ $(this._element).on(Event$2.MOUSEENTER, function (event) {
+ return _this2.pause(event);
+ }).on(Event$2.MOUSELEAVE, function (event) {
+ return _this2.cycle(event);
+ });
+ }
+
+ if (this._config.touch) {
+ this._addTouchEventListeners();
+ }
+ };
+
+ _proto._addTouchEventListeners = function _addTouchEventListeners() {
+ var _this3 = this;
+
+ if (!this._touchSupported) {
+ return;
+ }
+
+ var start = function start(event) {
+ if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
+ _this3.touchStartX = event.originalEvent.clientX;
+ } else if (!_this3._pointerEvent) {
+ _this3.touchStartX = event.originalEvent.touches[0].clientX;
+ }
+ };
+
+ var move = function move(event) {
+ // ensure swiping with one touch and not pinching
+ if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {
+ _this3.touchDeltaX = 0;
+ } else {
+ _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;
+ }
+ };
+
+ var end = function end(event) {
+ if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
+ _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;
+ }
+
+ _this3._handleSwipe();
+
+ if (_this3._config.pause === 'hover') {
+ // If it's a touch-enabled device, mouseenter/leave are fired as
+ // part of the mouse compatibility events on first tap - the carousel
+ // would stop cycling until user tapped out of it;
+ // here, we listen for touchend, explicitly pause the carousel
+ // (as if it's the second time we tap on it, mouseenter compat event
+ // is NOT fired) and after a timeout (to allow for mouse compatibility
+ // events to fire) we explicitly restart cycling
+ _this3.pause();
+
+ if (_this3.touchTimeout) {
+ clearTimeout(_this3.touchTimeout);
+ }
+
+ _this3.touchTimeout = setTimeout(function (event) {
+ return _this3.cycle(event);
+ }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);
+ }
+ };
+
+ $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) {
+ return e.preventDefault();
+ });
+
+ if (this._pointerEvent) {
+ $(this._element).on(Event$2.POINTERDOWN, function (event) {
+ return start(event);
+ });
+ $(this._element).on(Event$2.POINTERUP, function (event) {
+ return end(event);
+ });
+
+ this._element.classList.add(ClassName$2.POINTER_EVENT);
+ } else {
+ $(this._element).on(Event$2.TOUCHSTART, function (event) {
+ return start(event);
+ });
+ $(this._element).on(Event$2.TOUCHMOVE, function (event) {
+ return move(event);
+ });
+ $(this._element).on(Event$2.TOUCHEND, function (event) {
+ return end(event);
+ });
+ }
+ };
+
+ _proto._keydown = function _keydown(event) {
+ if (/input|textarea/i.test(event.target.tagName)) {
+ return;
+ }
+
+ switch (event.which) {
+ case ARROW_LEFT_KEYCODE:
+ event.preventDefault();
+ this.prev();
+ break;
+
+ case ARROW_RIGHT_KEYCODE:
+ event.preventDefault();
+ this.next();
+ break;
+ }
+ };
+
+ _proto._getItemIndex = function _getItemIndex(element) {
+ this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : [];
+ return this._items.indexOf(element);
+ };
+
+ _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {
+ var isNextDirection = direction === Direction.NEXT;
+ var isPrevDirection = direction === Direction.PREV;
+
+ var activeIndex = this._getItemIndex(activeElement);
+
+ var lastItemIndex = this._items.length - 1;
+ var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
+
+ if (isGoingToWrap && !this._config.wrap) {
+ return activeElement;
+ }
+
+ var delta = direction === Direction.PREV ? -1 : 1;
+ var itemIndex = (activeIndex + delta) % this._items.length;
+ return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
+ };
+
+ _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
+ var targetIndex = this._getItemIndex(relatedTarget);
+
+ var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM));
+
+ var slideEvent = $.Event(Event$2.SLIDE, {
+ relatedTarget: relatedTarget,
+ direction: eventDirectionName,
+ from: fromIndex,
+ to: targetIndex
+ });
+ $(this._element).trigger(slideEvent);
+ return slideEvent;
+ };
+
+ _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
+ if (this._indicatorsElement) {
+ var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE));
+ $(indicators).removeClass(ClassName$2.ACTIVE);
+
+ var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
+
+ if (nextIndicator) {
+ $(nextIndicator).addClass(ClassName$2.ACTIVE);
+ }
+ }
+ };
+
+ _proto._slide = function _slide(direction, element) {
+ var _this4 = this;
+
+ var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
+
+ var activeElementIndex = this._getItemIndex(activeElement);
+
+ var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
+
+ var nextElementIndex = this._getItemIndex(nextElement);
+
+ var isCycling = Boolean(this._interval);
+ var directionalClassName;
+ var orderClassName;
+ var eventDirectionName;
+
+ if (direction === Direction.NEXT) {
+ directionalClassName = ClassName$2.LEFT;
+ orderClassName = ClassName$2.NEXT;
+ eventDirectionName = Direction.LEFT;
+ } else {
+ directionalClassName = ClassName$2.RIGHT;
+ orderClassName = ClassName$2.PREV;
+ eventDirectionName = Direction.RIGHT;
+ }
+
+ if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) {
+ this._isSliding = false;
+ return;
+ }
+
+ var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
+
+ if (slideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (!activeElement || !nextElement) {
+ // Some weirdness is happening, so we bail
+ return;
+ }
+
+ this._isSliding = true;
+
+ if (isCycling) {
+ this.pause();
+ }
+
+ this._setActiveIndicatorElement(nextElement);
+
+ var slidEvent = $.Event(Event$2.SLID, {
+ relatedTarget: nextElement,
+ direction: eventDirectionName,
+ from: activeElementIndex,
+ to: nextElementIndex
+ });
+
+ if ($(this._element).hasClass(ClassName$2.SLIDE)) {
+ $(nextElement).addClass(orderClassName);
+ Util.reflow(nextElement);
+ $(activeElement).addClass(directionalClassName);
+ $(nextElement).addClass(directionalClassName);
+ var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);
+
+ if (nextElementInterval) {
+ this._config.defaultInterval = this._config.defaultInterval || this._config.interval;
+ this._config.interval = nextElementInterval;
+ } else {
+ this._config.interval = this._config.defaultInterval || this._config.interval;
+ }
+
+ var transitionDuration = Util.getTransitionDurationFromElement(activeElement);
+ $(activeElement).one(Util.TRANSITION_END, function () {
+ $(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName$2.ACTIVE);
+ $(activeElement).removeClass(ClassName$2.ACTIVE + " " + orderClassName + " " + directionalClassName);
+ _this4._isSliding = false;
+ setTimeout(function () {
+ return $(_this4._element).trigger(slidEvent);
+ }, 0);
+ }).emulateTransitionEnd(transitionDuration);
+ } else {
+ $(activeElement).removeClass(ClassName$2.ACTIVE);
+ $(nextElement).addClass(ClassName$2.ACTIVE);
+ this._isSliding = false;
+ $(this._element).trigger(slidEvent);
+ }
+
+ if (isCycling) {
+ this.cycle();
+ }
+ } // Static
+ ;
+
+ Carousel._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$2);
+
+ var _config = _objectSpread2({}, Default, {}, $(this).data());
+
+ if (typeof config === 'object') {
+ _config = _objectSpread2({}, _config, {}, config);
+ }
+
+ var action = typeof config === 'string' ? config : _config.slide;
+
+ if (!data) {
+ data = new Carousel(this, _config);
+ $(this).data(DATA_KEY$2, data);
+ }
+
+ if (typeof config === 'number') {
+ data.to(config);
+ } else if (typeof action === 'string') {
+ if (typeof data[action] === 'undefined') {
+ throw new TypeError("No method named \"" + action + "\"");
+ }
+
+ data[action]();
+ } else if (_config.interval && _config.ride) {
+ data.pause();
+ data.cycle();
+ }
+ });
+ };
+
+ Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
+ var selector = Util.getSelectorFromElement(this);
+
+ if (!selector) {
+ return;
+ }
+
+ var target = $(selector)[0];
+
+ if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) {
+ return;
+ }
+
+ var config = _objectSpread2({}, $(target).data(), {}, $(this).data());
+
+ var slideIndex = this.getAttribute('data-slide-to');
+
+ if (slideIndex) {
+ config.interval = false;
+ }
+
+ Carousel._jQueryInterface.call($(target), config);
+
+ if (slideIndex) {
+ $(target).data(DATA_KEY$2).to(slideIndex);
+ }
+
+ event.preventDefault();
+ };
+
+ _createClass(Carousel, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$2;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default;
+ }
+ }]);
+
+ return Carousel;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler);
+ $(window).on(Event$2.LOAD_DATA_API, function () {
+ var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));
+
+ for (var i = 0, len = carousels.length; i < len; i++) {
+ var $carousel = $(carousels[i]);
+
+ Carousel._jQueryInterface.call($carousel, $carousel.data());
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$2] = Carousel._jQueryInterface;
+ $.fn[NAME$2].Constructor = Carousel;
+
+ $.fn[NAME$2].noConflict = function () {
+ $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;
+ return Carousel._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$3 = 'collapse';
+ var VERSION$3 = '4.4.1';
+ var DATA_KEY$3 = 'bs.collapse';
+ var EVENT_KEY$3 = "." + DATA_KEY$3;
+ var DATA_API_KEY$3 = '.data-api';
+ var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];
+ var Default$1 = {
+ toggle: true,
+ parent: ''
+ };
+ var DefaultType$1 = {
+ toggle: 'boolean',
+ parent: '(string|element)'
+ };
+ var Event$3 = {
+ SHOW: "show" + EVENT_KEY$3,
+ SHOWN: "shown" + EVENT_KEY$3,
+ HIDE: "hide" + EVENT_KEY$3,
+ HIDDEN: "hidden" + EVENT_KEY$3,
+ CLICK_DATA_API: "click" + EVENT_KEY$3 + DATA_API_KEY$3
+ };
+ var ClassName$3 = {
+ SHOW: 'show',
+ COLLAPSE: 'collapse',
+ COLLAPSING: 'collapsing',
+ COLLAPSED: 'collapsed'
+ };
+ var Dimension = {
+ WIDTH: 'width',
+ HEIGHT: 'height'
+ };
+ var Selector$3 = {
+ ACTIVES: '.show, .collapsing',
+ DATA_TOGGLE: '[data-toggle="collapse"]'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Collapse =
+ /*#__PURE__*/
+ function () {
+ function Collapse(element, config) {
+ this._isTransitioning = false;
+ this._element = element;
+ this._config = this._getConfig(config);
+ this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
+ var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE));
+
+ for (var i = 0, len = toggleList.length; i < len; i++) {
+ var elem = toggleList[i];
+ var selector = Util.getSelectorFromElement(elem);
+ var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {
+ return foundElem === element;
+ });
+
+ if (selector !== null && filterElement.length > 0) {
+ this._selector = selector;
+
+ this._triggerArray.push(elem);
+ }
+ }
+
+ this._parent = this._config.parent ? this._getParent() : null;
+
+ if (!this._config.parent) {
+ this._addAriaAndCollapsedClass(this._element, this._triggerArray);
+ }
+
+ if (this._config.toggle) {
+ this.toggle();
+ }
+ } // Getters
+
+
+ var _proto = Collapse.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ if ($(this._element).hasClass(ClassName$3.SHOW)) {
+ this.hide();
+ } else {
+ this.show();
+ }
+ };
+
+ _proto.show = function show() {
+ var _this = this;
+
+ if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) {
+ return;
+ }
+
+ var actives;
+ var activesData;
+
+ if (this._parent) {
+ actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) {
+ if (typeof _this._config.parent === 'string') {
+ return elem.getAttribute('data-parent') === _this._config.parent;
+ }
+
+ return elem.classList.contains(ClassName$3.COLLAPSE);
+ });
+
+ if (actives.length === 0) {
+ actives = null;
+ }
+ }
+
+ if (actives) {
+ activesData = $(actives).not(this._selector).data(DATA_KEY$3);
+
+ if (activesData && activesData._isTransitioning) {
+ return;
+ }
+ }
+
+ var startEvent = $.Event(Event$3.SHOW);
+ $(this._element).trigger(startEvent);
+
+ if (startEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (actives) {
+ Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');
+
+ if (!activesData) {
+ $(actives).data(DATA_KEY$3, null);
+ }
+ }
+
+ var dimension = this._getDimension();
+
+ $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING);
+ this._element.style[dimension] = 0;
+
+ if (this._triggerArray.length) {
+ $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true);
+ }
+
+ this.setTransitioning(true);
+
+ var complete = function complete() {
+ $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW);
+ _this._element.style[dimension] = '';
+
+ _this.setTransitioning(false);
+
+ $(_this._element).trigger(Event$3.SHOWN);
+ };
+
+ var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
+ var scrollSize = "scroll" + capitalizedDimension;
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ this._element.style[dimension] = this._element[scrollSize] + "px";
+ };
+
+ _proto.hide = function hide() {
+ var _this2 = this;
+
+ if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) {
+ return;
+ }
+
+ var startEvent = $.Event(Event$3.HIDE);
+ $(this._element).trigger(startEvent);
+
+ if (startEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ var dimension = this._getDimension();
+
+ this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
+ Util.reflow(this._element);
+ $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW);
+ var triggerArrayLength = this._triggerArray.length;
+
+ if (triggerArrayLength > 0) {
+ for (var i = 0; i < triggerArrayLength; i++) {
+ var trigger = this._triggerArray[i];
+ var selector = Util.getSelectorFromElement(trigger);
+
+ if (selector !== null) {
+ var $elem = $([].slice.call(document.querySelectorAll(selector)));
+
+ if (!$elem.hasClass(ClassName$3.SHOW)) {
+ $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false);
+ }
+ }
+ }
+ }
+
+ this.setTransitioning(true);
+
+ var complete = function complete() {
+ _this2.setTransitioning(false);
+
+ $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN);
+ };
+
+ this._element.style[dimension] = '';
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ };
+
+ _proto.setTransitioning = function setTransitioning(isTransitioning) {
+ this._isTransitioning = isTransitioning;
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$3);
+ this._config = null;
+ this._parent = null;
+ this._element = null;
+ this._triggerArray = null;
+ this._isTransitioning = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$1, {}, config);
+ config.toggle = Boolean(config.toggle); // Coerce string values
+
+ Util.typeCheckConfig(NAME$3, config, DefaultType$1);
+ return config;
+ };
+
+ _proto._getDimension = function _getDimension() {
+ var hasWidth = $(this._element).hasClass(Dimension.WIDTH);
+ return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
+ };
+
+ _proto._getParent = function _getParent() {
+ var _this3 = this;
+
+ var parent;
+
+ if (Util.isElement(this._config.parent)) {
+ parent = this._config.parent; // It's a jQuery object
+
+ if (typeof this._config.parent.jquery !== 'undefined') {
+ parent = this._config.parent[0];
+ }
+ } else {
+ parent = document.querySelector(this._config.parent);
+ }
+
+ var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
+ var children = [].slice.call(parent.querySelectorAll(selector));
+ $(children).each(function (i, element) {
+ _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
+ });
+ return parent;
+ };
+
+ _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
+ var isOpen = $(element).hasClass(ClassName$3.SHOW);
+
+ if (triggerArray.length) {
+ $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
+ }
+ } // Static
+ ;
+
+ Collapse._getTargetFromElement = function _getTargetFromElement(element) {
+ var selector = Util.getSelectorFromElement(element);
+ return selector ? document.querySelector(selector) : null;
+ };
+
+ Collapse._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $this = $(this);
+ var data = $this.data(DATA_KEY$3);
+
+ var _config = _objectSpread2({}, Default$1, {}, $this.data(), {}, typeof config === 'object' && config ? config : {});
+
+ if (!data && _config.toggle && /show|hide/.test(config)) {
+ _config.toggle = false;
+ }
+
+ if (!data) {
+ data = new Collapse(this, _config);
+ $this.data(DATA_KEY$3, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Collapse, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$3;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$1;
+ }
+ }]);
+
+ return Collapse;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) {
+ // preventDefault only for elements (which change the URL) not inside the collapsible element
+ if (event.currentTarget.tagName === 'A') {
+ event.preventDefault();
+ }
+
+ var $trigger = $(this);
+ var selector = Util.getSelectorFromElement(this);
+ var selectors = [].slice.call(document.querySelectorAll(selector));
+ $(selectors).each(function () {
+ var $target = $(this);
+ var data = $target.data(DATA_KEY$3);
+ var config = data ? 'toggle' : $trigger.data();
+
+ Collapse._jQueryInterface.call($target, config);
+ });
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$3] = Collapse._jQueryInterface;
+ $.fn[NAME$3].Constructor = Collapse;
+
+ $.fn[NAME$3].noConflict = function () {
+ $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;
+ return Collapse._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$4 = 'dropdown';
+ var VERSION$4 = '4.4.1';
+ var DATA_KEY$4 = 'bs.dropdown';
+ var EVENT_KEY$4 = "." + DATA_KEY$4;
+ var DATA_API_KEY$4 = '.data-api';
+ var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];
+ var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
+
+ var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
+
+ var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
+
+ var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
+
+ var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
+
+ var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
+
+ var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
+ var Event$4 = {
+ HIDE: "hide" + EVENT_KEY$4,
+ HIDDEN: "hidden" + EVENT_KEY$4,
+ SHOW: "show" + EVENT_KEY$4,
+ SHOWN: "shown" + EVENT_KEY$4,
+ CLICK: "click" + EVENT_KEY$4,
+ CLICK_DATA_API: "click" + EVENT_KEY$4 + DATA_API_KEY$4,
+ KEYDOWN_DATA_API: "keydown" + EVENT_KEY$4 + DATA_API_KEY$4,
+ KEYUP_DATA_API: "keyup" + EVENT_KEY$4 + DATA_API_KEY$4
+ };
+ var ClassName$4 = {
+ DISABLED: 'disabled',
+ SHOW: 'show',
+ DROPUP: 'dropup',
+ DROPRIGHT: 'dropright',
+ DROPLEFT: 'dropleft',
+ MENURIGHT: 'dropdown-menu-right',
+ MENULEFT: 'dropdown-menu-left',
+ POSITION_STATIC: 'position-static'
+ };
+ var Selector$4 = {
+ DATA_TOGGLE: '[data-toggle="dropdown"]',
+ FORM_CHILD: '.dropdown form',
+ MENU: '.dropdown-menu',
+ NAVBAR_NAV: '.navbar-nav',
+ VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
+ };
+ var AttachmentMap = {
+ TOP: 'top-start',
+ TOPEND: 'top-end',
+ BOTTOM: 'bottom-start',
+ BOTTOMEND: 'bottom-end',
+ RIGHT: 'right-start',
+ RIGHTEND: 'right-end',
+ LEFT: 'left-start',
+ LEFTEND: 'left-end'
+ };
+ var Default$2 = {
+ offset: 0,
+ flip: true,
+ boundary: 'scrollParent',
+ reference: 'toggle',
+ display: 'dynamic',
+ popperConfig: null
+ };
+ var DefaultType$2 = {
+ offset: '(number|string|function)',
+ flip: 'boolean',
+ boundary: '(string|element)',
+ reference: '(string|element)',
+ display: 'string',
+ popperConfig: '(null|object)'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Dropdown =
+ /*#__PURE__*/
+ function () {
+ function Dropdown(element, config) {
+ this._element = element;
+ this._popper = null;
+ this._config = this._getConfig(config);
+ this._menu = this._getMenuElement();
+ this._inNavbar = this._detectNavbar();
+
+ this._addEventListeners();
+ } // Getters
+
+
+ var _proto = Dropdown.prototype;
+
+ // Public
+ _proto.toggle = function toggle() {
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) {
+ return;
+ }
+
+ var isActive = $(this._menu).hasClass(ClassName$4.SHOW);
+
+ Dropdown._clearMenus();
+
+ if (isActive) {
+ return;
+ }
+
+ this.show(true);
+ };
+
+ _proto.show = function show(usePopper) {
+ if (usePopper === void 0) {
+ usePopper = false;
+ }
+
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) {
+ return;
+ }
+
+ var relatedTarget = {
+ relatedTarget: this._element
+ };
+ var showEvent = $.Event(Event$4.SHOW, relatedTarget);
+
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ $(parent).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented()) {
+ return;
+ } // Disable totally Popper.js for Dropdown in Navbar
+
+
+ if (!this._inNavbar && usePopper) {
+ /**
+ * Check for Popper dependency
+ * Popper - https://popper.js.org
+ */
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)');
+ }
+
+ var referenceElement = this._element;
+
+ if (this._config.reference === 'parent') {
+ referenceElement = parent;
+ } else if (Util.isElement(this._config.reference)) {
+ referenceElement = this._config.reference; // Check if it's jQuery element
+
+ if (typeof this._config.reference.jquery !== 'undefined') {
+ referenceElement = this._config.reference[0];
+ }
+ } // If boundary is not `scrollParent`, then set position to `static`
+ // to allow the menu to "escape" the scroll parent's boundaries
+ // https://github.com/twbs/bootstrap/issues/24251
+
+
+ if (this._config.boundary !== 'scrollParent') {
+ $(parent).addClass(ClassName$4.POSITION_STATIC);
+ }
+
+ this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());
+ } // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+
+
+ if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) {
+ $(document.body).children().on('mouseover', null, $.noop);
+ }
+
+ this._element.focus();
+
+ this._element.setAttribute('aria-expanded', true);
+
+ $(this._menu).toggleClass(ClassName$4.SHOW);
+ $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));
+ };
+
+ _proto.hide = function hide() {
+ if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) {
+ return;
+ }
+
+ var relatedTarget = {
+ relatedTarget: this._element
+ };
+ var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
+
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ $(parent).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (this._popper) {
+ this._popper.destroy();
+ }
+
+ $(this._menu).toggleClass(ClassName$4.SHOW);
+ $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$4);
+ $(this._element).off(EVENT_KEY$4);
+ this._element = null;
+ this._menu = null;
+
+ if (this._popper !== null) {
+ this._popper.destroy();
+
+ this._popper = null;
+ }
+ };
+
+ _proto.update = function update() {
+ this._inNavbar = this._detectNavbar();
+
+ if (this._popper !== null) {
+ this._popper.scheduleUpdate();
+ }
+ } // Private
+ ;
+
+ _proto._addEventListeners = function _addEventListeners() {
+ var _this = this;
+
+ $(this._element).on(Event$4.CLICK, function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ _this.toggle();
+ });
+ };
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, this.constructor.Default, {}, $(this._element).data(), {}, config);
+ Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);
+ return config;
+ };
+
+ _proto._getMenuElement = function _getMenuElement() {
+ if (!this._menu) {
+ var parent = Dropdown._getParentFromElement(this._element);
+
+ if (parent) {
+ this._menu = parent.querySelector(Selector$4.MENU);
+ }
+ }
+
+ return this._menu;
+ };
+
+ _proto._getPlacement = function _getPlacement() {
+ var $parentDropdown = $(this._element.parentNode);
+ var placement = AttachmentMap.BOTTOM; // Handle dropup
+
+ if ($parentDropdown.hasClass(ClassName$4.DROPUP)) {
+ placement = AttachmentMap.TOP;
+
+ if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
+ placement = AttachmentMap.TOPEND;
+ }
+ } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) {
+ placement = AttachmentMap.RIGHT;
+ } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) {
+ placement = AttachmentMap.LEFT;
+ } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
+ placement = AttachmentMap.BOTTOMEND;
+ }
+
+ return placement;
+ };
+
+ _proto._detectNavbar = function _detectNavbar() {
+ return $(this._element).closest('.navbar').length > 0;
+ };
+
+ _proto._getOffset = function _getOffset() {
+ var _this2 = this;
+
+ var offset = {};
+
+ if (typeof this._config.offset === 'function') {
+ offset.fn = function (data) {
+ data.offsets = _objectSpread2({}, data.offsets, {}, _this2._config.offset(data.offsets, _this2._element) || {});
+ return data;
+ };
+ } else {
+ offset.offset = this._config.offset;
+ }
+
+ return offset;
+ };
+
+ _proto._getPopperConfig = function _getPopperConfig() {
+ var popperConfig = {
+ placement: this._getPlacement(),
+ modifiers: {
+ offset: this._getOffset(),
+ flip: {
+ enabled: this._config.flip
+ },
+ preventOverflow: {
+ boundariesElement: this._config.boundary
+ }
+ }
+ }; // Disable Popper.js if we have a static display
+
+ if (this._config.display === 'static') {
+ popperConfig.modifiers.applyStyle = {
+ enabled: false
+ };
+ }
+
+ return _objectSpread2({}, popperConfig, {}, this._config.popperConfig);
+ } // Static
+ ;
+
+ Dropdown._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$4);
+
+ var _config = typeof config === 'object' ? config : null;
+
+ if (!data) {
+ data = new Dropdown(this, _config);
+ $(this).data(DATA_KEY$4, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ Dropdown._clearMenus = function _clearMenus(event) {
+ if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
+ return;
+ }
+
+ var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE));
+
+ for (var i = 0, len = toggles.length; i < len; i++) {
+ var parent = Dropdown._getParentFromElement(toggles[i]);
+
+ var context = $(toggles[i]).data(DATA_KEY$4);
+ var relatedTarget = {
+ relatedTarget: toggles[i]
+ };
+
+ if (event && event.type === 'click') {
+ relatedTarget.clickEvent = event;
+ }
+
+ if (!context) {
+ continue;
+ }
+
+ var dropdownMenu = context._menu;
+
+ if (!$(parent).hasClass(ClassName$4.SHOW)) {
+ continue;
+ }
+
+ if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {
+ continue;
+ }
+
+ var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
+ $(parent).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ continue;
+ } // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().off('mouseover', null, $.noop);
+ }
+
+ toggles[i].setAttribute('aria-expanded', 'false');
+
+ if (context._popper) {
+ context._popper.destroy();
+ }
+
+ $(dropdownMenu).removeClass(ClassName$4.SHOW);
+ $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
+ }
+ };
+
+ Dropdown._getParentFromElement = function _getParentFromElement(element) {
+ var parent;
+ var selector = Util.getSelectorFromElement(element);
+
+ if (selector) {
+ parent = document.querySelector(selector);
+ }
+
+ return parent || element.parentNode;
+ } // eslint-disable-next-line complexity
+ ;
+
+ Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
+ // If not input/textarea:
+ // - And not a key in REGEXP_KEYDOWN => not a dropdown command
+ // If input/textarea:
+ // - If space key => not a dropdown command
+ // - If key is other than escape
+ // - If key is not up or down => not a dropdown command
+ // - If trigger inside the menu => not a dropdown command
+ if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) {
+ return;
+ }
+
+ var parent = Dropdown._getParentFromElement(this);
+
+ var isActive = $(parent).hasClass(ClassName$4.SHOW);
+
+ if (!isActive && event.which === ESCAPE_KEYCODE) {
+ return;
+ }
+
+ if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
+ if (event.which === ESCAPE_KEYCODE) {
+ var toggle = parent.querySelector(Selector$4.DATA_TOGGLE);
+ $(toggle).trigger('focus');
+ }
+
+ $(this).trigger('click');
+ return;
+ }
+
+ var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS)).filter(function (item) {
+ return $(item).is(':visible');
+ });
+
+ if (items.length === 0) {
+ return;
+ }
+
+ var index = items.indexOf(event.target);
+
+ if (event.which === ARROW_UP_KEYCODE && index > 0) {
+ // Up
+ index--;
+ }
+
+ if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
+ // Down
+ index++;
+ }
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ items[index].focus();
+ };
+
+ _createClass(Dropdown, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$4;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$2;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$2;
+ }
+ }]);
+
+ return Dropdown;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + " " + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ Dropdown._jQueryInterface.call($(this), 'toggle');
+ }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) {
+ e.stopPropagation();
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$4] = Dropdown._jQueryInterface;
+ $.fn[NAME$4].Constructor = Dropdown;
+
+ $.fn[NAME$4].noConflict = function () {
+ $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;
+ return Dropdown._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$5 = 'modal';
+ var VERSION$5 = '4.4.1';
+ var DATA_KEY$5 = 'bs.modal';
+ var EVENT_KEY$5 = "." + DATA_KEY$5;
+ var DATA_API_KEY$5 = '.data-api';
+ var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];
+ var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key
+
+ var Default$3 = {
+ backdrop: true,
+ keyboard: true,
+ focus: true,
+ show: true
+ };
+ var DefaultType$3 = {
+ backdrop: '(boolean|string)',
+ keyboard: 'boolean',
+ focus: 'boolean',
+ show: 'boolean'
+ };
+ var Event$5 = {
+ HIDE: "hide" + EVENT_KEY$5,
+ HIDE_PREVENTED: "hidePrevented" + EVENT_KEY$5,
+ HIDDEN: "hidden" + EVENT_KEY$5,
+ SHOW: "show" + EVENT_KEY$5,
+ SHOWN: "shown" + EVENT_KEY$5,
+ FOCUSIN: "focusin" + EVENT_KEY$5,
+ RESIZE: "resize" + EVENT_KEY$5,
+ CLICK_DISMISS: "click.dismiss" + EVENT_KEY$5,
+ KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY$5,
+ MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY$5,
+ MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY$5,
+ CLICK_DATA_API: "click" + EVENT_KEY$5 + DATA_API_KEY$5
+ };
+ var ClassName$5 = {
+ SCROLLABLE: 'modal-dialog-scrollable',
+ SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
+ BACKDROP: 'modal-backdrop',
+ OPEN: 'modal-open',
+ FADE: 'fade',
+ SHOW: 'show',
+ STATIC: 'modal-static'
+ };
+ var Selector$5 = {
+ DIALOG: '.modal-dialog',
+ MODAL_BODY: '.modal-body',
+ DATA_TOGGLE: '[data-toggle="modal"]',
+ DATA_DISMISS: '[data-dismiss="modal"]',
+ FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
+ STICKY_CONTENT: '.sticky-top'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Modal =
+ /*#__PURE__*/
+ function () {
+ function Modal(element, config) {
+ this._config = this._getConfig(config);
+ this._element = element;
+ this._dialog = element.querySelector(Selector$5.DIALOG);
+ this._backdrop = null;
+ this._isShown = false;
+ this._isBodyOverflowing = false;
+ this._ignoreBackdropClick = false;
+ this._isTransitioning = false;
+ this._scrollbarWidth = 0;
+ } // Getters
+
+
+ var _proto = Modal.prototype;
+
+ // Public
+ _proto.toggle = function toggle(relatedTarget) {
+ return this._isShown ? this.hide() : this.show(relatedTarget);
+ };
+
+ _proto.show = function show(relatedTarget) {
+ var _this = this;
+
+ if (this._isShown || this._isTransitioning) {
+ return;
+ }
+
+ if ($(this._element).hasClass(ClassName$5.FADE)) {
+ this._isTransitioning = true;
+ }
+
+ var showEvent = $.Event(Event$5.SHOW, {
+ relatedTarget: relatedTarget
+ });
+ $(this._element).trigger(showEvent);
+
+ if (this._isShown || showEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._isShown = true;
+
+ this._checkScrollbar();
+
+ this._setScrollbar();
+
+ this._adjustDialog();
+
+ this._setEscapeEvent();
+
+ this._setResizeEvent();
+
+ $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) {
+ return _this.hide(event);
+ });
+ $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () {
+ $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) {
+ if ($(event.target).is(_this._element)) {
+ _this._ignoreBackdropClick = true;
+ }
+ });
+ });
+
+ this._showBackdrop(function () {
+ return _this._showElement(relatedTarget);
+ });
+ };
+
+ _proto.hide = function hide(event) {
+ var _this2 = this;
+
+ if (event) {
+ event.preventDefault();
+ }
+
+ if (!this._isShown || this._isTransitioning) {
+ return;
+ }
+
+ var hideEvent = $.Event(Event$5.HIDE);
+ $(this._element).trigger(hideEvent);
+
+ if (!this._isShown || hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._isShown = false;
+ var transition = $(this._element).hasClass(ClassName$5.FADE);
+
+ if (transition) {
+ this._isTransitioning = true;
+ }
+
+ this._setEscapeEvent();
+
+ this._setResizeEvent();
+
+ $(document).off(Event$5.FOCUSIN);
+ $(this._element).removeClass(ClassName$5.SHOW);
+ $(this._element).off(Event$5.CLICK_DISMISS);
+ $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS);
+
+ if (transition) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, function (event) {
+ return _this2._hideModal(event);
+ }).emulateTransitionEnd(transitionDuration);
+ } else {
+ this._hideModal();
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ [window, this._element, this._dialog].forEach(function (htmlElement) {
+ return $(htmlElement).off(EVENT_KEY$5);
+ });
+ /**
+ * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`
+ * Do not move `document` in `htmlElements` array
+ * It will remove `Event.CLICK_DATA_API` event that should remain
+ */
+
+ $(document).off(Event$5.FOCUSIN);
+ $.removeData(this._element, DATA_KEY$5);
+ this._config = null;
+ this._element = null;
+ this._dialog = null;
+ this._backdrop = null;
+ this._isShown = null;
+ this._isBodyOverflowing = null;
+ this._ignoreBackdropClick = null;
+ this._isTransitioning = null;
+ this._scrollbarWidth = null;
+ };
+
+ _proto.handleUpdate = function handleUpdate() {
+ this._adjustDialog();
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$3, {}, config);
+ Util.typeCheckConfig(NAME$5, config, DefaultType$3);
+ return config;
+ };
+
+ _proto._triggerBackdropTransition = function _triggerBackdropTransition() {
+ var _this3 = this;
+
+ if (this._config.backdrop === 'static') {
+ var hideEventPrevented = $.Event(Event$5.HIDE_PREVENTED);
+ $(this._element).trigger(hideEventPrevented);
+
+ if (hideEventPrevented.defaultPrevented) {
+ return;
+ }
+
+ this._element.classList.add(ClassName$5.STATIC);
+
+ var modalTransitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, function () {
+ _this3._element.classList.remove(ClassName$5.STATIC);
+ }).emulateTransitionEnd(modalTransitionDuration);
+
+ this._element.focus();
+ } else {
+ this.hide();
+ }
+ };
+
+ _proto._showElement = function _showElement(relatedTarget) {
+ var _this4 = this;
+
+ var transition = $(this._element).hasClass(ClassName$5.FADE);
+ var modalBody = this._dialog ? this._dialog.querySelector(Selector$5.MODAL_BODY) : null;
+
+ if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
+ // Don't move modal's DOM position
+ document.body.appendChild(this._element);
+ }
+
+ this._element.style.display = 'block';
+
+ this._element.removeAttribute('aria-hidden');
+
+ this._element.setAttribute('aria-modal', true);
+
+ if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE) && modalBody) {
+ modalBody.scrollTop = 0;
+ } else {
+ this._element.scrollTop = 0;
+ }
+
+ if (transition) {
+ Util.reflow(this._element);
+ }
+
+ $(this._element).addClass(ClassName$5.SHOW);
+
+ if (this._config.focus) {
+ this._enforceFocus();
+ }
+
+ var shownEvent = $.Event(Event$5.SHOWN, {
+ relatedTarget: relatedTarget
+ });
+
+ var transitionComplete = function transitionComplete() {
+ if (_this4._config.focus) {
+ _this4._element.focus();
+ }
+
+ _this4._isTransitioning = false;
+ $(_this4._element).trigger(shownEvent);
+ };
+
+ if (transition) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);
+ $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);
+ } else {
+ transitionComplete();
+ }
+ };
+
+ _proto._enforceFocus = function _enforceFocus() {
+ var _this5 = this;
+
+ $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop
+ .on(Event$5.FOCUSIN, function (event) {
+ if (document !== event.target && _this5._element !== event.target && $(_this5._element).has(event.target).length === 0) {
+ _this5._element.focus();
+ }
+ });
+ };
+
+ _proto._setEscapeEvent = function _setEscapeEvent() {
+ var _this6 = this;
+
+ if (this._isShown && this._config.keyboard) {
+ $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) {
+ if (event.which === ESCAPE_KEYCODE$1) {
+ _this6._triggerBackdropTransition();
+ }
+ });
+ } else if (!this._isShown) {
+ $(this._element).off(Event$5.KEYDOWN_DISMISS);
+ }
+ };
+
+ _proto._setResizeEvent = function _setResizeEvent() {
+ var _this7 = this;
+
+ if (this._isShown) {
+ $(window).on(Event$5.RESIZE, function (event) {
+ return _this7.handleUpdate(event);
+ });
+ } else {
+ $(window).off(Event$5.RESIZE);
+ }
+ };
+
+ _proto._hideModal = function _hideModal() {
+ var _this8 = this;
+
+ this._element.style.display = 'none';
+
+ this._element.setAttribute('aria-hidden', true);
+
+ this._element.removeAttribute('aria-modal');
+
+ this._isTransitioning = false;
+
+ this._showBackdrop(function () {
+ $(document.body).removeClass(ClassName$5.OPEN);
+
+ _this8._resetAdjustments();
+
+ _this8._resetScrollbar();
+
+ $(_this8._element).trigger(Event$5.HIDDEN);
+ });
+ };
+
+ _proto._removeBackdrop = function _removeBackdrop() {
+ if (this._backdrop) {
+ $(this._backdrop).remove();
+ this._backdrop = null;
+ }
+ };
+
+ _proto._showBackdrop = function _showBackdrop(callback) {
+ var _this9 = this;
+
+ var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : '';
+
+ if (this._isShown && this._config.backdrop) {
+ this._backdrop = document.createElement('div');
+ this._backdrop.className = ClassName$5.BACKDROP;
+
+ if (animate) {
+ this._backdrop.classList.add(animate);
+ }
+
+ $(this._backdrop).appendTo(document.body);
+ $(this._element).on(Event$5.CLICK_DISMISS, function (event) {
+ if (_this9._ignoreBackdropClick) {
+ _this9._ignoreBackdropClick = false;
+ return;
+ }
+
+ if (event.target !== event.currentTarget) {
+ return;
+ }
+
+ _this9._triggerBackdropTransition();
+ });
+
+ if (animate) {
+ Util.reflow(this._backdrop);
+ }
+
+ $(this._backdrop).addClass(ClassName$5.SHOW);
+
+ if (!callback) {
+ return;
+ }
+
+ if (!animate) {
+ callback();
+ return;
+ }
+
+ var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
+ $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);
+ } else if (!this._isShown && this._backdrop) {
+ $(this._backdrop).removeClass(ClassName$5.SHOW);
+
+ var callbackRemove = function callbackRemove() {
+ _this9._removeBackdrop();
+
+ if (callback) {
+ callback();
+ }
+ };
+
+ if ($(this._element).hasClass(ClassName$5.FADE)) {
+ var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
+
+ $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);
+ } else {
+ callbackRemove();
+ }
+ } else if (callback) {
+ callback();
+ }
+ } // ----------------------------------------------------------------------
+ // the following methods are used to handle overflowing modals
+ // todo (fat): these should probably be refactored out of modal.js
+ // ----------------------------------------------------------------------
+ ;
+
+ _proto._adjustDialog = function _adjustDialog() {
+ var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+
+ if (!this._isBodyOverflowing && isModalOverflowing) {
+ this._element.style.paddingLeft = this._scrollbarWidth + "px";
+ }
+
+ if (this._isBodyOverflowing && !isModalOverflowing) {
+ this._element.style.paddingRight = this._scrollbarWidth + "px";
+ }
+ };
+
+ _proto._resetAdjustments = function _resetAdjustments() {
+ this._element.style.paddingLeft = '';
+ this._element.style.paddingRight = '';
+ };
+
+ _proto._checkScrollbar = function _checkScrollbar() {
+ var rect = document.body.getBoundingClientRect();
+ this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;
+ this._scrollbarWidth = this._getScrollbarWidth();
+ };
+
+ _proto._setScrollbar = function _setScrollbar() {
+ var _this10 = this;
+
+ if (this._isBodyOverflowing) {
+ // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
+ // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
+ var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
+ var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding
+
+ $(fixedContent).each(function (index, element) {
+ var actualPadding = element.style.paddingRight;
+ var calculatedPadding = $(element).css('padding-right');
+ $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + "px");
+ }); // Adjust sticky content margin
+
+ $(stickyContent).each(function (index, element) {
+ var actualMargin = element.style.marginRight;
+ var calculatedMargin = $(element).css('margin-right');
+ $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + "px");
+ }); // Adjust body padding
+
+ var actualPadding = document.body.style.paddingRight;
+ var calculatedPadding = $(document.body).css('padding-right');
+ $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px");
+ }
+
+ $(document.body).addClass(ClassName$5.OPEN);
+ };
+
+ _proto._resetScrollbar = function _resetScrollbar() {
+ // Restore fixed content padding
+ var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
+ $(fixedContent).each(function (index, element) {
+ var padding = $(element).data('padding-right');
+ $(element).removeData('padding-right');
+ element.style.paddingRight = padding ? padding : '';
+ }); // Restore sticky content
+
+ var elements = [].slice.call(document.querySelectorAll("" + Selector$5.STICKY_CONTENT));
+ $(elements).each(function (index, element) {
+ var margin = $(element).data('margin-right');
+
+ if (typeof margin !== 'undefined') {
+ $(element).css('margin-right', margin).removeData('margin-right');
+ }
+ }); // Restore body padding
+
+ var padding = $(document.body).data('padding-right');
+ $(document.body).removeData('padding-right');
+ document.body.style.paddingRight = padding ? padding : '';
+ };
+
+ _proto._getScrollbarWidth = function _getScrollbarWidth() {
+ // thx d.walsh
+ var scrollDiv = document.createElement('div');
+ scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER;
+ document.body.appendChild(scrollDiv);
+ var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
+ document.body.removeChild(scrollDiv);
+ return scrollbarWidth;
+ } // Static
+ ;
+
+ Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$5);
+
+ var _config = _objectSpread2({}, Default$3, {}, $(this).data(), {}, typeof config === 'object' && config ? config : {});
+
+ if (!data) {
+ data = new Modal(this, _config);
+ $(this).data(DATA_KEY$5, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config](relatedTarget);
+ } else if (_config.show) {
+ data.show(relatedTarget);
+ }
+ });
+ };
+
+ _createClass(Modal, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$5;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$3;
+ }
+ }]);
+
+ return Modal;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) {
+ var _this11 = this;
+
+ var target;
+ var selector = Util.getSelectorFromElement(this);
+
+ if (selector) {
+ target = document.querySelector(selector);
+ }
+
+ var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread2({}, $(target).data(), {}, $(this).data());
+
+ if (this.tagName === 'A' || this.tagName === 'AREA') {
+ event.preventDefault();
+ }
+
+ var $target = $(target).one(Event$5.SHOW, function (showEvent) {
+ if (showEvent.isDefaultPrevented()) {
+ // Only register focus restorer if modal will actually get shown
+ return;
+ }
+
+ $target.one(Event$5.HIDDEN, function () {
+ if ($(_this11).is(':visible')) {
+ _this11.focus();
+ }
+ });
+ });
+
+ Modal._jQueryInterface.call($(target), config, this);
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$5] = Modal._jQueryInterface;
+ $.fn[NAME$5].Constructor = Modal;
+
+ $.fn[NAME$5].noConflict = function () {
+ $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;
+ return Modal._jQueryInterface;
+ };
+
+ /**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.4.1): tools/sanitizer.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+ var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];
+ var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
+ var DefaultWhitelist = {
+ // Global attributes allowed on any supplied element below.
+ '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
+ a: ['target', 'href', 'title', 'rel'],
+ area: [],
+ b: [],
+ br: [],
+ col: [],
+ code: [],
+ div: [],
+ em: [],
+ hr: [],
+ h1: [],
+ h2: [],
+ h3: [],
+ h4: [],
+ h5: [],
+ h6: [],
+ i: [],
+ img: ['src', 'alt', 'title', 'width', 'height'],
+ li: [],
+ ol: [],
+ p: [],
+ pre: [],
+ s: [],
+ small: [],
+ span: [],
+ sub: [],
+ sup: [],
+ strong: [],
+ u: [],
+ ul: []
+ };
+ /**
+ * A pattern that recognizes a commonly useful subset of URLs that are safe.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+
+ var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
+ /**
+ * A pattern that matches safe data URLs. Only matches image, video and audio types.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+
+ var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
+
+ function allowedAttribute(attr, allowedAttributeList) {
+ var attrName = attr.nodeName.toLowerCase();
+
+ if (allowedAttributeList.indexOf(attrName) !== -1) {
+ if (uriAttrs.indexOf(attrName) !== -1) {
+ return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));
+ }
+
+ return true;
+ }
+
+ var regExp = allowedAttributeList.filter(function (attrRegex) {
+ return attrRegex instanceof RegExp;
+ }); // Check if a regular expression validates the attribute.
+
+ for (var i = 0, l = regExp.length; i < l; i++) {
+ if (attrName.match(regExp[i])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
+ if (unsafeHtml.length === 0) {
+ return unsafeHtml;
+ }
+
+ if (sanitizeFn && typeof sanitizeFn === 'function') {
+ return sanitizeFn(unsafeHtml);
+ }
+
+ var domParser = new window.DOMParser();
+ var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
+ var whitelistKeys = Object.keys(whiteList);
+ var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));
+
+ var _loop = function _loop(i, len) {
+ var el = elements[i];
+ var elName = el.nodeName.toLowerCase();
+
+ if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
+ el.parentNode.removeChild(el);
+ return "continue";
+ }
+
+ var attributeList = [].slice.call(el.attributes);
+ var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
+ attributeList.forEach(function (attr) {
+ if (!allowedAttribute(attr, whitelistedAttributes)) {
+ el.removeAttribute(attr.nodeName);
+ }
+ });
+ };
+
+ for (var i = 0, len = elements.length; i < len; i++) {
+ var _ret = _loop(i);
+
+ if (_ret === "continue") continue;
+ }
+
+ return createdDocument.body.innerHTML;
+ }
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$6 = 'tooltip';
+ var VERSION$6 = '4.4.1';
+ var DATA_KEY$6 = 'bs.tooltip';
+ var EVENT_KEY$6 = "." + DATA_KEY$6;
+ var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];
+ var CLASS_PREFIX = 'bs-tooltip';
+ var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
+ var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
+ var DefaultType$4 = {
+ animation: 'boolean',
+ template: 'string',
+ title: '(string|element|function)',
+ trigger: 'string',
+ delay: '(number|object)',
+ html: 'boolean',
+ selector: '(string|boolean)',
+ placement: '(string|function)',
+ offset: '(number|string|function)',
+ container: '(string|element|boolean)',
+ fallbackPlacement: '(string|array)',
+ boundary: '(string|element)',
+ sanitize: 'boolean',
+ sanitizeFn: '(null|function)',
+ whiteList: 'object',
+ popperConfig: '(null|object)'
+ };
+ var AttachmentMap$1 = {
+ AUTO: 'auto',
+ TOP: 'top',
+ RIGHT: 'right',
+ BOTTOM: 'bottom',
+ LEFT: 'left'
+ };
+ var Default$4 = {
+ animation: true,
+ template: '',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ selector: false,
+ placement: 'top',
+ offset: 0,
+ container: false,
+ fallbackPlacement: 'flip',
+ boundary: 'scrollParent',
+ sanitize: true,
+ sanitizeFn: null,
+ whiteList: DefaultWhitelist,
+ popperConfig: null
+ };
+ var HoverState = {
+ SHOW: 'show',
+ OUT: 'out'
+ };
+ var Event$6 = {
+ HIDE: "hide" + EVENT_KEY$6,
+ HIDDEN: "hidden" + EVENT_KEY$6,
+ SHOW: "show" + EVENT_KEY$6,
+ SHOWN: "shown" + EVENT_KEY$6,
+ INSERTED: "inserted" + EVENT_KEY$6,
+ CLICK: "click" + EVENT_KEY$6,
+ FOCUSIN: "focusin" + EVENT_KEY$6,
+ FOCUSOUT: "focusout" + EVENT_KEY$6,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$6,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$6
+ };
+ var ClassName$6 = {
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$6 = {
+ TOOLTIP: '.tooltip',
+ TOOLTIP_INNER: '.tooltip-inner',
+ ARROW: '.arrow'
+ };
+ var Trigger = {
+ HOVER: 'hover',
+ FOCUS: 'focus',
+ CLICK: 'click',
+ MANUAL: 'manual'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Tooltip =
+ /*#__PURE__*/
+ function () {
+ function Tooltip(element, config) {
+ if (typeof Popper === 'undefined') {
+ throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)');
+ } // private
+
+
+ this._isEnabled = true;
+ this._timeout = 0;
+ this._hoverState = '';
+ this._activeTrigger = {};
+ this._popper = null; // Protected
+
+ this.element = element;
+ this.config = this._getConfig(config);
+ this.tip = null;
+
+ this._setListeners();
+ } // Getters
+
+
+ var _proto = Tooltip.prototype;
+
+ // Public
+ _proto.enable = function enable() {
+ this._isEnabled = true;
+ };
+
+ _proto.disable = function disable() {
+ this._isEnabled = false;
+ };
+
+ _proto.toggleEnabled = function toggleEnabled() {
+ this._isEnabled = !this._isEnabled;
+ };
+
+ _proto.toggle = function toggle(event) {
+ if (!this._isEnabled) {
+ return;
+ }
+
+ if (event) {
+ var dataKey = this.constructor.DATA_KEY;
+ var context = $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ context._activeTrigger.click = !context._activeTrigger.click;
+
+ if (context._isWithActiveTrigger()) {
+ context._enter(null, context);
+ } else {
+ context._leave(null, context);
+ }
+ } else {
+ if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) {
+ this._leave(null, this);
+
+ return;
+ }
+
+ this._enter(null, this);
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ clearTimeout(this._timeout);
+ $.removeData(this.element, this.constructor.DATA_KEY);
+ $(this.element).off(this.constructor.EVENT_KEY);
+ $(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler);
+
+ if (this.tip) {
+ $(this.tip).remove();
+ }
+
+ this._isEnabled = null;
+ this._timeout = null;
+ this._hoverState = null;
+ this._activeTrigger = null;
+
+ if (this._popper) {
+ this._popper.destroy();
+ }
+
+ this._popper = null;
+ this.element = null;
+ this.config = null;
+ this.tip = null;
+ };
+
+ _proto.show = function show() {
+ var _this = this;
+
+ if ($(this.element).css('display') === 'none') {
+ throw new Error('Please use show on visible elements');
+ }
+
+ var showEvent = $.Event(this.constructor.Event.SHOW);
+
+ if (this.isWithContent() && this._isEnabled) {
+ $(this.element).trigger(showEvent);
+ var shadowRoot = Util.findShadowRoot(this.element);
+ var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);
+
+ if (showEvent.isDefaultPrevented() || !isInTheDom) {
+ return;
+ }
+
+ var tip = this.getTipElement();
+ var tipId = Util.getUID(this.constructor.NAME);
+ tip.setAttribute('id', tipId);
+ this.element.setAttribute('aria-describedby', tipId);
+ this.setContent();
+
+ if (this.config.animation) {
+ $(tip).addClass(ClassName$6.FADE);
+ }
+
+ var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
+
+ var attachment = this._getAttachment(placement);
+
+ this.addAttachmentClass(attachment);
+
+ var container = this._getContainer();
+
+ $(tip).data(this.constructor.DATA_KEY, this);
+
+ if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
+ $(tip).appendTo(container);
+ }
+
+ $(this.element).trigger(this.constructor.Event.INSERTED);
+ this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment));
+ $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra
+ // empty mouseover listeners to the body's immediate children;
+ // only needed because of broken event delegation on iOS
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().on('mouseover', null, $.noop);
+ }
+
+ var complete = function complete() {
+ if (_this.config.animation) {
+ _this._fixTransition();
+ }
+
+ var prevHoverState = _this._hoverState;
+ _this._hoverState = null;
+ $(_this.element).trigger(_this.constructor.Event.SHOWN);
+
+ if (prevHoverState === HoverState.OUT) {
+ _this._leave(null, _this);
+ }
+ };
+
+ if ($(this.tip).hasClass(ClassName$6.FADE)) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this.tip);
+ $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ }
+ };
+
+ _proto.hide = function hide(callback) {
+ var _this2 = this;
+
+ var tip = this.getTipElement();
+ var hideEvent = $.Event(this.constructor.Event.HIDE);
+
+ var complete = function complete() {
+ if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
+ tip.parentNode.removeChild(tip);
+ }
+
+ _this2._cleanTipClass();
+
+ _this2.element.removeAttribute('aria-describedby');
+
+ $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
+
+ if (_this2._popper !== null) {
+ _this2._popper.destroy();
+ }
+
+ if (callback) {
+ callback();
+ }
+ };
+
+ $(this.element).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra
+ // empty mouseover listeners we added for iOS support
+
+ if ('ontouchstart' in document.documentElement) {
+ $(document.body).children().off('mouseover', null, $.noop);
+ }
+
+ this._activeTrigger[Trigger.CLICK] = false;
+ this._activeTrigger[Trigger.FOCUS] = false;
+ this._activeTrigger[Trigger.HOVER] = false;
+
+ if ($(this.tip).hasClass(ClassName$6.FADE)) {
+ var transitionDuration = Util.getTransitionDurationFromElement(tip);
+ $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+
+ this._hoverState = '';
+ };
+
+ _proto.update = function update() {
+ if (this._popper !== null) {
+ this._popper.scheduleUpdate();
+ }
+ } // Protected
+ ;
+
+ _proto.isWithContent = function isWithContent() {
+ return Boolean(this.getTitle());
+ };
+
+ _proto.addAttachmentClass = function addAttachmentClass(attachment) {
+ $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
+ };
+
+ _proto.getTipElement = function getTipElement() {
+ this.tip = this.tip || $(this.config.template)[0];
+ return this.tip;
+ };
+
+ _proto.setContent = function setContent() {
+ var tip = this.getTipElement();
+ this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle());
+ $(tip).removeClass(ClassName$6.FADE + " " + ClassName$6.SHOW);
+ };
+
+ _proto.setElementContent = function setElementContent($element, content) {
+ if (typeof content === 'object' && (content.nodeType || content.jquery)) {
+ // Content is a DOM node or a jQuery
+ if (this.config.html) {
+ if (!$(content).parent().is($element)) {
+ $element.empty().append(content);
+ }
+ } else {
+ $element.text($(content).text());
+ }
+
+ return;
+ }
+
+ if (this.config.html) {
+ if (this.config.sanitize) {
+ content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);
+ }
+
+ $element.html(content);
+ } else {
+ $element.text(content);
+ }
+ };
+
+ _proto.getTitle = function getTitle() {
+ var title = this.element.getAttribute('data-original-title');
+
+ if (!title) {
+ title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
+ }
+
+ return title;
+ } // Private
+ ;
+
+ _proto._getPopperConfig = function _getPopperConfig(attachment) {
+ var _this3 = this;
+
+ var defaultBsConfig = {
+ placement: attachment,
+ modifiers: {
+ offset: this._getOffset(),
+ flip: {
+ behavior: this.config.fallbackPlacement
+ },
+ arrow: {
+ element: Selector$6.ARROW
+ },
+ preventOverflow: {
+ boundariesElement: this.config.boundary
+ }
+ },
+ onCreate: function onCreate(data) {
+ if (data.originalPlacement !== data.placement) {
+ _this3._handlePopperPlacementChange(data);
+ }
+ },
+ onUpdate: function onUpdate(data) {
+ return _this3._handlePopperPlacementChange(data);
+ }
+ };
+ return _objectSpread2({}, defaultBsConfig, {}, this.config.popperConfig);
+ };
+
+ _proto._getOffset = function _getOffset() {
+ var _this4 = this;
+
+ var offset = {};
+
+ if (typeof this.config.offset === 'function') {
+ offset.fn = function (data) {
+ data.offsets = _objectSpread2({}, data.offsets, {}, _this4.config.offset(data.offsets, _this4.element) || {});
+ return data;
+ };
+ } else {
+ offset.offset = this.config.offset;
+ }
+
+ return offset;
+ };
+
+ _proto._getContainer = function _getContainer() {
+ if (this.config.container === false) {
+ return document.body;
+ }
+
+ if (Util.isElement(this.config.container)) {
+ return $(this.config.container);
+ }
+
+ return $(document).find(this.config.container);
+ };
+
+ _proto._getAttachment = function _getAttachment(placement) {
+ return AttachmentMap$1[placement.toUpperCase()];
+ };
+
+ _proto._setListeners = function _setListeners() {
+ var _this5 = this;
+
+ var triggers = this.config.trigger.split(' ');
+ triggers.forEach(function (trigger) {
+ if (trigger === 'click') {
+ $(_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) {
+ return _this5.toggle(event);
+ });
+ } else if (trigger !== Trigger.MANUAL) {
+ var eventIn = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN;
+ var eventOut = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT;
+ $(_this5.element).on(eventIn, _this5.config.selector, function (event) {
+ return _this5._enter(event);
+ }).on(eventOut, _this5.config.selector, function (event) {
+ return _this5._leave(event);
+ });
+ }
+ });
+
+ this._hideModalHandler = function () {
+ if (_this5.element) {
+ _this5.hide();
+ }
+ };
+
+ $(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler);
+
+ if (this.config.selector) {
+ this.config = _objectSpread2({}, this.config, {
+ trigger: 'manual',
+ selector: ''
+ });
+ } else {
+ this._fixTitle();
+ }
+ };
+
+ _proto._fixTitle = function _fixTitle() {
+ var titleType = typeof this.element.getAttribute('data-original-title');
+
+ if (this.element.getAttribute('title') || titleType !== 'string') {
+ this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
+ this.element.setAttribute('title', '');
+ }
+ };
+
+ _proto._enter = function _enter(event, context) {
+ var dataKey = this.constructor.DATA_KEY;
+ context = context || $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ if (event) {
+ context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
+ }
+
+ if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) {
+ context._hoverState = HoverState.SHOW;
+ return;
+ }
+
+ clearTimeout(context._timeout);
+ context._hoverState = HoverState.SHOW;
+
+ if (!context.config.delay || !context.config.delay.show) {
+ context.show();
+ return;
+ }
+
+ context._timeout = setTimeout(function () {
+ if (context._hoverState === HoverState.SHOW) {
+ context.show();
+ }
+ }, context.config.delay.show);
+ };
+
+ _proto._leave = function _leave(event, context) {
+ var dataKey = this.constructor.DATA_KEY;
+ context = context || $(event.currentTarget).data(dataKey);
+
+ if (!context) {
+ context = new this.constructor(event.currentTarget, this._getDelegateConfig());
+ $(event.currentTarget).data(dataKey, context);
+ }
+
+ if (event) {
+ context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
+ }
+
+ if (context._isWithActiveTrigger()) {
+ return;
+ }
+
+ clearTimeout(context._timeout);
+ context._hoverState = HoverState.OUT;
+
+ if (!context.config.delay || !context.config.delay.hide) {
+ context.hide();
+ return;
+ }
+
+ context._timeout = setTimeout(function () {
+ if (context._hoverState === HoverState.OUT) {
+ context.hide();
+ }
+ }, context.config.delay.hide);
+ };
+
+ _proto._isWithActiveTrigger = function _isWithActiveTrigger() {
+ for (var trigger in this._activeTrigger) {
+ if (this._activeTrigger[trigger]) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ _proto._getConfig = function _getConfig(config) {
+ var dataAttributes = $(this.element).data();
+ Object.keys(dataAttributes).forEach(function (dataAttr) {
+ if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {
+ delete dataAttributes[dataAttr];
+ }
+ });
+ config = _objectSpread2({}, this.constructor.Default, {}, dataAttributes, {}, typeof config === 'object' && config ? config : {});
+
+ if (typeof config.delay === 'number') {
+ config.delay = {
+ show: config.delay,
+ hide: config.delay
+ };
+ }
+
+ if (typeof config.title === 'number') {
+ config.title = config.title.toString();
+ }
+
+ if (typeof config.content === 'number') {
+ config.content = config.content.toString();
+ }
+
+ Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);
+
+ if (config.sanitize) {
+ config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);
+ }
+
+ return config;
+ };
+
+ _proto._getDelegateConfig = function _getDelegateConfig() {
+ var config = {};
+
+ if (this.config) {
+ for (var key in this.config) {
+ if (this.constructor.Default[key] !== this.config[key]) {
+ config[key] = this.config[key];
+ }
+ }
+ }
+
+ return config;
+ };
+
+ _proto._cleanTipClass = function _cleanTipClass() {
+ var $tip = $(this.getTipElement());
+ var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
+
+ if (tabClass !== null && tabClass.length) {
+ $tip.removeClass(tabClass.join(''));
+ }
+ };
+
+ _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {
+ var popperInstance = popperData.instance;
+ this.tip = popperInstance.popper;
+
+ this._cleanTipClass();
+
+ this.addAttachmentClass(this._getAttachment(popperData.placement));
+ };
+
+ _proto._fixTransition = function _fixTransition() {
+ var tip = this.getTipElement();
+ var initConfigAnimation = this.config.animation;
+
+ if (tip.getAttribute('x-placement') !== null) {
+ return;
+ }
+
+ $(tip).removeClass(ClassName$6.FADE);
+ this.config.animation = false;
+ this.hide();
+ this.show();
+ this.config.animation = initConfigAnimation;
+ } // Static
+ ;
+
+ Tooltip._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$6);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data && /dispose|hide/.test(config)) {
+ return;
+ }
+
+ if (!data) {
+ data = new Tooltip(this, _config);
+ $(this).data(DATA_KEY$6, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Tooltip, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$6;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$4;
+ }
+ }, {
+ key: "NAME",
+ get: function get() {
+ return NAME$6;
+ }
+ }, {
+ key: "DATA_KEY",
+ get: function get() {
+ return DATA_KEY$6;
+ }
+ }, {
+ key: "Event",
+ get: function get() {
+ return Event$6;
+ }
+ }, {
+ key: "EVENT_KEY",
+ get: function get() {
+ return EVENT_KEY$6;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$4;
+ }
+ }]);
+
+ return Tooltip;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$6] = Tooltip._jQueryInterface;
+ $.fn[NAME$6].Constructor = Tooltip;
+
+ $.fn[NAME$6].noConflict = function () {
+ $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;
+ return Tooltip._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$7 = 'popover';
+ var VERSION$7 = '4.4.1';
+ var DATA_KEY$7 = 'bs.popover';
+ var EVENT_KEY$7 = "." + DATA_KEY$7;
+ var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];
+ var CLASS_PREFIX$1 = 'bs-popover';
+ var BSCLS_PREFIX_REGEX$1 = new RegExp("(^|\\s)" + CLASS_PREFIX$1 + "\\S+", 'g');
+
+ var Default$5 = _objectSpread2({}, Tooltip.Default, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: ''
+ });
+
+ var DefaultType$5 = _objectSpread2({}, Tooltip.DefaultType, {
+ content: '(string|element|function)'
+ });
+
+ var ClassName$7 = {
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$7 = {
+ TITLE: '.popover-header',
+ CONTENT: '.popover-body'
+ };
+ var Event$7 = {
+ HIDE: "hide" + EVENT_KEY$7,
+ HIDDEN: "hidden" + EVENT_KEY$7,
+ SHOW: "show" + EVENT_KEY$7,
+ SHOWN: "shown" + EVENT_KEY$7,
+ INSERTED: "inserted" + EVENT_KEY$7,
+ CLICK: "click" + EVENT_KEY$7,
+ FOCUSIN: "focusin" + EVENT_KEY$7,
+ FOCUSOUT: "focusout" + EVENT_KEY$7,
+ MOUSEENTER: "mouseenter" + EVENT_KEY$7,
+ MOUSELEAVE: "mouseleave" + EVENT_KEY$7
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Popover =
+ /*#__PURE__*/
+ function (_Tooltip) {
+ _inheritsLoose(Popover, _Tooltip);
+
+ function Popover() {
+ return _Tooltip.apply(this, arguments) || this;
+ }
+
+ var _proto = Popover.prototype;
+
+ // Overrides
+ _proto.isWithContent = function isWithContent() {
+ return this.getTitle() || this._getContent();
+ };
+
+ _proto.addAttachmentClass = function addAttachmentClass(attachment) {
+ $(this.getTipElement()).addClass(CLASS_PREFIX$1 + "-" + attachment);
+ };
+
+ _proto.getTipElement = function getTipElement() {
+ this.tip = this.tip || $(this.config.template)[0];
+ return this.tip;
+ };
+
+ _proto.setContent = function setContent() {
+ var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events
+
+ this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle());
+
+ var content = this._getContent();
+
+ if (typeof content === 'function') {
+ content = content.call(this.element);
+ }
+
+ this.setElementContent($tip.find(Selector$7.CONTENT), content);
+ $tip.removeClass(ClassName$7.FADE + " " + ClassName$7.SHOW);
+ } // Private
+ ;
+
+ _proto._getContent = function _getContent() {
+ return this.element.getAttribute('data-content') || this.config.content;
+ };
+
+ _proto._cleanTipClass = function _cleanTipClass() {
+ var $tip = $(this.getTipElement());
+ var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);
+
+ if (tabClass !== null && tabClass.length > 0) {
+ $tip.removeClass(tabClass.join(''));
+ }
+ } // Static
+ ;
+
+ Popover._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$7);
+
+ var _config = typeof config === 'object' ? config : null;
+
+ if (!data && /dispose|hide/.test(config)) {
+ return;
+ }
+
+ if (!data) {
+ data = new Popover(this, _config);
+ $(this).data(DATA_KEY$7, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Popover, null, [{
+ key: "VERSION",
+ // Getters
+ get: function get() {
+ return VERSION$7;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$5;
+ }
+ }, {
+ key: "NAME",
+ get: function get() {
+ return NAME$7;
+ }
+ }, {
+ key: "DATA_KEY",
+ get: function get() {
+ return DATA_KEY$7;
+ }
+ }, {
+ key: "Event",
+ get: function get() {
+ return Event$7;
+ }
+ }, {
+ key: "EVENT_KEY",
+ get: function get() {
+ return EVENT_KEY$7;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$5;
+ }
+ }]);
+
+ return Popover;
+ }(Tooltip);
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$7] = Popover._jQueryInterface;
+ $.fn[NAME$7].Constructor = Popover;
+
+ $.fn[NAME$7].noConflict = function () {
+ $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;
+ return Popover._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$8 = 'scrollspy';
+ var VERSION$8 = '4.4.1';
+ var DATA_KEY$8 = 'bs.scrollspy';
+ var EVENT_KEY$8 = "." + DATA_KEY$8;
+ var DATA_API_KEY$6 = '.data-api';
+ var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];
+ var Default$6 = {
+ offset: 10,
+ method: 'auto',
+ target: ''
+ };
+ var DefaultType$6 = {
+ offset: 'number',
+ method: 'string',
+ target: '(string|element)'
+ };
+ var Event$8 = {
+ ACTIVATE: "activate" + EVENT_KEY$8,
+ SCROLL: "scroll" + EVENT_KEY$8,
+ LOAD_DATA_API: "load" + EVENT_KEY$8 + DATA_API_KEY$6
+ };
+ var ClassName$8 = {
+ DROPDOWN_ITEM: 'dropdown-item',
+ DROPDOWN_MENU: 'dropdown-menu',
+ ACTIVE: 'active'
+ };
+ var Selector$8 = {
+ DATA_SPY: '[data-spy="scroll"]',
+ ACTIVE: '.active',
+ NAV_LIST_GROUP: '.nav, .list-group',
+ NAV_LINKS: '.nav-link',
+ NAV_ITEMS: '.nav-item',
+ LIST_ITEMS: '.list-group-item',
+ DROPDOWN: '.dropdown',
+ DROPDOWN_ITEMS: '.dropdown-item',
+ DROPDOWN_TOGGLE: '.dropdown-toggle'
+ };
+ var OffsetMethod = {
+ OFFSET: 'offset',
+ POSITION: 'position'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var ScrollSpy =
+ /*#__PURE__*/
+ function () {
+ function ScrollSpy(element, config) {
+ var _this = this;
+
+ this._element = element;
+ this._scrollElement = element.tagName === 'BODY' ? window : element;
+ this._config = this._getConfig(config);
+ this._selector = this._config.target + " " + Selector$8.NAV_LINKS + "," + (this._config.target + " " + Selector$8.LIST_ITEMS + ",") + (this._config.target + " " + Selector$8.DROPDOWN_ITEMS);
+ this._offsets = [];
+ this._targets = [];
+ this._activeTarget = null;
+ this._scrollHeight = 0;
+ $(this._scrollElement).on(Event$8.SCROLL, function (event) {
+ return _this._process(event);
+ });
+ this.refresh();
+
+ this._process();
+ } // Getters
+
+
+ var _proto = ScrollSpy.prototype;
+
+ // Public
+ _proto.refresh = function refresh() {
+ var _this2 = this;
+
+ var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
+ var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
+ var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
+ this._offsets = [];
+ this._targets = [];
+ this._scrollHeight = this._getScrollHeight();
+ var targets = [].slice.call(document.querySelectorAll(this._selector));
+ targets.map(function (element) {
+ var target;
+ var targetSelector = Util.getSelectorFromElement(element);
+
+ if (targetSelector) {
+ target = document.querySelector(targetSelector);
+ }
+
+ if (target) {
+ var targetBCR = target.getBoundingClientRect();
+
+ if (targetBCR.width || targetBCR.height) {
+ // TODO (fat): remove sketch reliance on jQuery position/offset
+ return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
+ }
+ }
+
+ return null;
+ }).filter(function (item) {
+ return item;
+ }).sort(function (a, b) {
+ return a[0] - b[0];
+ }).forEach(function (item) {
+ _this2._offsets.push(item[0]);
+
+ _this2._targets.push(item[1]);
+ });
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$8);
+ $(this._scrollElement).off(EVENT_KEY$8);
+ this._element = null;
+ this._scrollElement = null;
+ this._config = null;
+ this._selector = null;
+ this._offsets = null;
+ this._targets = null;
+ this._activeTarget = null;
+ this._scrollHeight = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$6, {}, typeof config === 'object' && config ? config : {});
+
+ if (typeof config.target !== 'string') {
+ var id = $(config.target).attr('id');
+
+ if (!id) {
+ id = Util.getUID(NAME$8);
+ $(config.target).attr('id', id);
+ }
+
+ config.target = "#" + id;
+ }
+
+ Util.typeCheckConfig(NAME$8, config, DefaultType$6);
+ return config;
+ };
+
+ _proto._getScrollTop = function _getScrollTop() {
+ return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
+ };
+
+ _proto._getScrollHeight = function _getScrollHeight() {
+ return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
+ };
+
+ _proto._getOffsetHeight = function _getOffsetHeight() {
+ return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
+ };
+
+ _proto._process = function _process() {
+ var scrollTop = this._getScrollTop() + this._config.offset;
+
+ var scrollHeight = this._getScrollHeight();
+
+ var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
+
+ if (this._scrollHeight !== scrollHeight) {
+ this.refresh();
+ }
+
+ if (scrollTop >= maxScroll) {
+ var target = this._targets[this._targets.length - 1];
+
+ if (this._activeTarget !== target) {
+ this._activate(target);
+ }
+
+ return;
+ }
+
+ if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
+ this._activeTarget = null;
+
+ this._clear();
+
+ return;
+ }
+
+ var offsetLength = this._offsets.length;
+
+ for (var i = offsetLength; i--;) {
+ var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
+
+ if (isActiveTarget) {
+ this._activate(this._targets[i]);
+ }
+ }
+ };
+
+ _proto._activate = function _activate(target) {
+ this._activeTarget = target;
+
+ this._clear();
+
+ var queries = this._selector.split(',').map(function (selector) {
+ return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]";
+ });
+
+ var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));
+
+ if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) {
+ $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE);
+ $link.addClass(ClassName$8.ACTIVE);
+ } else {
+ // Set triggered link as active
+ $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active
+ // With both and markup a parent is the previous sibling of any nav ancestor
+
+ $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_LINKS + ", " + Selector$8.LIST_ITEMS).addClass(ClassName$8.ACTIVE); // Handle special case when .nav-link is inside .nav-item
+
+ $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_ITEMS).children(Selector$8.NAV_LINKS).addClass(ClassName$8.ACTIVE);
+ }
+
+ $(this._scrollElement).trigger(Event$8.ACTIVATE, {
+ relatedTarget: target
+ });
+ };
+
+ _proto._clear = function _clear() {
+ [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {
+ return node.classList.contains(ClassName$8.ACTIVE);
+ }).forEach(function (node) {
+ return node.classList.remove(ClassName$8.ACTIVE);
+ });
+ } // Static
+ ;
+
+ ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var data = $(this).data(DATA_KEY$8);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data) {
+ data = new ScrollSpy(this, _config);
+ $(this).data(DATA_KEY$8, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(ScrollSpy, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$8;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$6;
+ }
+ }]);
+
+ return ScrollSpy;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(window).on(Event$8.LOAD_DATA_API, function () {
+ var scrollSpys = [].slice.call(document.querySelectorAll(Selector$8.DATA_SPY));
+ var scrollSpysLength = scrollSpys.length;
+
+ for (var i = scrollSpysLength; i--;) {
+ var $spy = $(scrollSpys[i]);
+
+ ScrollSpy._jQueryInterface.call($spy, $spy.data());
+ }
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$8] = ScrollSpy._jQueryInterface;
+ $.fn[NAME$8].Constructor = ScrollSpy;
+
+ $.fn[NAME$8].noConflict = function () {
+ $.fn[NAME$8] = JQUERY_NO_CONFLICT$8;
+ return ScrollSpy._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$9 = 'tab';
+ var VERSION$9 = '4.4.1';
+ var DATA_KEY$9 = 'bs.tab';
+ var EVENT_KEY$9 = "." + DATA_KEY$9;
+ var DATA_API_KEY$7 = '.data-api';
+ var JQUERY_NO_CONFLICT$9 = $.fn[NAME$9];
+ var Event$9 = {
+ HIDE: "hide" + EVENT_KEY$9,
+ HIDDEN: "hidden" + EVENT_KEY$9,
+ SHOW: "show" + EVENT_KEY$9,
+ SHOWN: "shown" + EVENT_KEY$9,
+ CLICK_DATA_API: "click" + EVENT_KEY$9 + DATA_API_KEY$7
+ };
+ var ClassName$9 = {
+ DROPDOWN_MENU: 'dropdown-menu',
+ ACTIVE: 'active',
+ DISABLED: 'disabled',
+ FADE: 'fade',
+ SHOW: 'show'
+ };
+ var Selector$9 = {
+ DROPDOWN: '.dropdown',
+ NAV_LIST_GROUP: '.nav, .list-group',
+ ACTIVE: '.active',
+ ACTIVE_UL: '> li > .active',
+ DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
+ DROPDOWN_TOGGLE: '.dropdown-toggle',
+ DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Tab =
+ /*#__PURE__*/
+ function () {
+ function Tab(element) {
+ this._element = element;
+ } // Getters
+
+
+ var _proto = Tab.prototype;
+
+ // Public
+ _proto.show = function show() {
+ var _this = this;
+
+ if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName$9.ACTIVE) || $(this._element).hasClass(ClassName$9.DISABLED)) {
+ return;
+ }
+
+ var target;
+ var previous;
+ var listElement = $(this._element).closest(Selector$9.NAV_LIST_GROUP)[0];
+ var selector = Util.getSelectorFromElement(this._element);
+
+ if (listElement) {
+ var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector$9.ACTIVE_UL : Selector$9.ACTIVE;
+ previous = $.makeArray($(listElement).find(itemSelector));
+ previous = previous[previous.length - 1];
+ }
+
+ var hideEvent = $.Event(Event$9.HIDE, {
+ relatedTarget: this._element
+ });
+ var showEvent = $.Event(Event$9.SHOW, {
+ relatedTarget: previous
+ });
+
+ if (previous) {
+ $(previous).trigger(hideEvent);
+ }
+
+ $(this._element).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (selector) {
+ target = document.querySelector(selector);
+ }
+
+ this._activate(this._element, listElement);
+
+ var complete = function complete() {
+ var hiddenEvent = $.Event(Event$9.HIDDEN, {
+ relatedTarget: _this._element
+ });
+ var shownEvent = $.Event(Event$9.SHOWN, {
+ relatedTarget: previous
+ });
+ $(previous).trigger(hiddenEvent);
+ $(_this._element).trigger(shownEvent);
+ };
+
+ if (target) {
+ this._activate(target, target.parentNode, complete);
+ } else {
+ complete();
+ }
+ };
+
+ _proto.dispose = function dispose() {
+ $.removeData(this._element, DATA_KEY$9);
+ this._element = null;
+ } // Private
+ ;
+
+ _proto._activate = function _activate(element, container, callback) {
+ var _this2 = this;
+
+ var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);
+ var active = activeElements[0];
+ var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);
+
+ var complete = function complete() {
+ return _this2._transitionComplete(element, active, callback);
+ };
+
+ if (active && isTransitioning) {
+ var transitionDuration = Util.getTransitionDurationFromElement(active);
+ $(active).removeClass(ClassName$9.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ };
+
+ _proto._transitionComplete = function _transitionComplete(element, active, callback) {
+ if (active) {
+ $(active).removeClass(ClassName$9.ACTIVE);
+ var dropdownChild = $(active.parentNode).find(Selector$9.DROPDOWN_ACTIVE_CHILD)[0];
+
+ if (dropdownChild) {
+ $(dropdownChild).removeClass(ClassName$9.ACTIVE);
+ }
+
+ if (active.getAttribute('role') === 'tab') {
+ active.setAttribute('aria-selected', false);
+ }
+ }
+
+ $(element).addClass(ClassName$9.ACTIVE);
+
+ if (element.getAttribute('role') === 'tab') {
+ element.setAttribute('aria-selected', true);
+ }
+
+ Util.reflow(element);
+
+ if (element.classList.contains(ClassName$9.FADE)) {
+ element.classList.add(ClassName$9.SHOW);
+ }
+
+ if (element.parentNode && $(element.parentNode).hasClass(ClassName$9.DROPDOWN_MENU)) {
+ var dropdownElement = $(element).closest(Selector$9.DROPDOWN)[0];
+
+ if (dropdownElement) {
+ var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector$9.DROPDOWN_TOGGLE));
+ $(dropdownToggleList).addClass(ClassName$9.ACTIVE);
+ }
+
+ element.setAttribute('aria-expanded', true);
+ }
+
+ if (callback) {
+ callback();
+ }
+ } // Static
+ ;
+
+ Tab._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $this = $(this);
+ var data = $this.data(DATA_KEY$9);
+
+ if (!data) {
+ data = new Tab(this);
+ $this.data(DATA_KEY$9, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config]();
+ }
+ });
+ };
+
+ _createClass(Tab, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$9;
+ }
+ }]);
+
+ return Tab;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+
+ $(document).on(Event$9.CLICK_DATA_API, Selector$9.DATA_TOGGLE, function (event) {
+ event.preventDefault();
+
+ Tab._jQueryInterface.call($(this), 'show');
+ });
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME$9] = Tab._jQueryInterface;
+ $.fn[NAME$9].Constructor = Tab;
+
+ $.fn[NAME$9].noConflict = function () {
+ $.fn[NAME$9] = JQUERY_NO_CONFLICT$9;
+ return Tab._jQueryInterface;
+ };
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var NAME$a = 'toast';
+ var VERSION$a = '4.4.1';
+ var DATA_KEY$a = 'bs.toast';
+ var EVENT_KEY$a = "." + DATA_KEY$a;
+ var JQUERY_NO_CONFLICT$a = $.fn[NAME$a];
+ var Event$a = {
+ CLICK_DISMISS: "click.dismiss" + EVENT_KEY$a,
+ HIDE: "hide" + EVENT_KEY$a,
+ HIDDEN: "hidden" + EVENT_KEY$a,
+ SHOW: "show" + EVENT_KEY$a,
+ SHOWN: "shown" + EVENT_KEY$a
+ };
+ var ClassName$a = {
+ FADE: 'fade',
+ HIDE: 'hide',
+ SHOW: 'show',
+ SHOWING: 'showing'
+ };
+ var DefaultType$7 = {
+ animation: 'boolean',
+ autohide: 'boolean',
+ delay: 'number'
+ };
+ var Default$7 = {
+ animation: true,
+ autohide: true,
+ delay: 500
+ };
+ var Selector$a = {
+ DATA_DISMISS: '[data-dismiss="toast"]'
+ };
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ var Toast =
+ /*#__PURE__*/
+ function () {
+ function Toast(element, config) {
+ this._element = element;
+ this._config = this._getConfig(config);
+ this._timeout = null;
+
+ this._setListeners();
+ } // Getters
+
+
+ var _proto = Toast.prototype;
+
+ // Public
+ _proto.show = function show() {
+ var _this = this;
+
+ var showEvent = $.Event(Event$a.SHOW);
+ $(this._element).trigger(showEvent);
+
+ if (showEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ if (this._config.animation) {
+ this._element.classList.add(ClassName$a.FADE);
+ }
+
+ var complete = function complete() {
+ _this._element.classList.remove(ClassName$a.SHOWING);
+
+ _this._element.classList.add(ClassName$a.SHOW);
+
+ $(_this._element).trigger(Event$a.SHOWN);
+
+ if (_this._config.autohide) {
+ _this._timeout = setTimeout(function () {
+ _this.hide();
+ }, _this._config.delay);
+ }
+ };
+
+ this._element.classList.remove(ClassName$a.HIDE);
+
+ Util.reflow(this._element);
+
+ this._element.classList.add(ClassName$a.SHOWING);
+
+ if (this._config.animation) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ };
+
+ _proto.hide = function hide() {
+ if (!this._element.classList.contains(ClassName$a.SHOW)) {
+ return;
+ }
+
+ var hideEvent = $.Event(Event$a.HIDE);
+ $(this._element).trigger(hideEvent);
+
+ if (hideEvent.isDefaultPrevented()) {
+ return;
+ }
+
+ this._close();
+ };
+
+ _proto.dispose = function dispose() {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+
+ if (this._element.classList.contains(ClassName$a.SHOW)) {
+ this._element.classList.remove(ClassName$a.SHOW);
+ }
+
+ $(this._element).off(Event$a.CLICK_DISMISS);
+ $.removeData(this._element, DATA_KEY$a);
+ this._element = null;
+ this._config = null;
+ } // Private
+ ;
+
+ _proto._getConfig = function _getConfig(config) {
+ config = _objectSpread2({}, Default$7, {}, $(this._element).data(), {}, typeof config === 'object' && config ? config : {});
+ Util.typeCheckConfig(NAME$a, config, this.constructor.DefaultType);
+ return config;
+ };
+
+ _proto._setListeners = function _setListeners() {
+ var _this2 = this;
+
+ $(this._element).on(Event$a.CLICK_DISMISS, Selector$a.DATA_DISMISS, function () {
+ return _this2.hide();
+ });
+ };
+
+ _proto._close = function _close() {
+ var _this3 = this;
+
+ var complete = function complete() {
+ _this3._element.classList.add(ClassName$a.HIDE);
+
+ $(_this3._element).trigger(Event$a.HIDDEN);
+ };
+
+ this._element.classList.remove(ClassName$a.SHOW);
+
+ if (this._config.animation) {
+ var transitionDuration = Util.getTransitionDurationFromElement(this._element);
+ $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
+ } else {
+ complete();
+ }
+ } // Static
+ ;
+
+ Toast._jQueryInterface = function _jQueryInterface(config) {
+ return this.each(function () {
+ var $element = $(this);
+ var data = $element.data(DATA_KEY$a);
+
+ var _config = typeof config === 'object' && config;
+
+ if (!data) {
+ data = new Toast(this, _config);
+ $element.data(DATA_KEY$a, data);
+ }
+
+ if (typeof config === 'string') {
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError("No method named \"" + config + "\"");
+ }
+
+ data[config](this);
+ }
+ });
+ };
+
+ _createClass(Toast, null, [{
+ key: "VERSION",
+ get: function get() {
+ return VERSION$a;
+ }
+ }, {
+ key: "DefaultType",
+ get: function get() {
+ return DefaultType$7;
+ }
+ }, {
+ key: "Default",
+ get: function get() {
+ return Default$7;
+ }
+ }]);
+
+ return Toast;
+ }();
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+
+ $.fn[NAME$a] = Toast._jQueryInterface;
+ $.fn[NAME$a].Constructor = Toast;
+
+ $.fn[NAME$a].noConflict = function () {
+ $.fn[NAME$a] = JQUERY_NO_CONFLICT$a;
+ return Toast._jQueryInterface;
+ };
+
+ exports.Alert = Alert;
+ exports.Button = Button;
+ exports.Carousel = Carousel;
+ exports.Collapse = Collapse;
+ exports.Dropdown = Dropdown;
+ exports.Modal = Modal;
+ exports.Popover = Popover;
+ exports.Scrollspy = ScrollSpy;
+ exports.Tab = Tab;
+ exports.Toast = Toast;
+ exports.Tooltip = Tooltip;
+ exports.Util = Util;
+
+ Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
+//# sourceMappingURL=bootstrap.js.map
diff --git a/app/webroot/js/font-awesome-helper.js b/app/webroot/js/font-awesome-helper.js
new file mode 100644
index 0000000..ddfe25f
--- /dev/null
+++ b/app/webroot/js/font-awesome-helper.js
@@ -0,0 +1,433 @@
+function getFontAwesomeNamespace(icon) {
+ var fab_icons = [
+ "500px",
+ "accessible-icon",
+ "accusoft",
+ "acquisitions-incorporated",
+ "adn",
+ "adobe",
+ "adversal",
+ "affiliatetheme",
+ "airbnb",
+ "algolia",
+ "alipay",
+ "amazon",
+ "amazon-pay",
+ "amilia",
+ "android",
+ "angellist",
+ "angrycreative",
+ "angular",
+ "app-store",
+ "app-store-ios",
+ "apper",
+ "apple",
+ "apple-pay",
+ "artstation",
+ "asymmetrik",
+ "atlassian",
+ "audible",
+ "autoprefixer",
+ "avianex",
+ "aviato",
+ "aws",
+ "bandcamp",
+ "battle-net",
+ "behance",
+ "behance-square",
+ "bimobject",
+ "bitbucket",
+ "bitcoin",
+ "bity",
+ "black-tie",
+ "blackberry",
+ "blogger",
+ "blogger-b",
+ "bluetooth",
+ "bluetooth-b",
+ "bootstrap",
+ "btc",
+ "buffer",
+ "buromobelexperte",
+ "canadian-maple-leaf",
+ "cc-amazon-pay",
+ "cc-amex",
+ "cc-apple-pay",
+ "cc-diners-club",
+ "cc-discover",
+ "cc-jcb",
+ "cc-mastercard",
+ "cc-paypal",
+ "cc-stripe",
+ "cc-visa",
+ "centercode",
+ "centos",
+ "chrome",
+ "chromecast",
+ "cloudscale",
+ "cloudsmith",
+ "cloudversify",
+ "codepen",
+ "codiepie",
+ "confluence",
+ "connectdevelop",
+ "contao",
+ "cpanel",
+ "creative-commons",
+ "creative-commons-by",
+ "creative-commons-nc",
+ "creative-commons-nc-eu",
+ "creative-commons-nc-jp",
+ "creative-commons-nd",
+ "creative-commons-pd",
+ "creative-commons-pd-alt",
+ "creative-commons-remix",
+ "creative-commons-sa",
+ "creative-commons-sampling",
+ "creative-commons-sampling-plus",
+ "creative-commons-share",
+ "creative-commons-zero",
+ "critical-role",
+ "css3",
+ "css3-alt",
+ "cuttlefish",
+ "d-and-d",
+ "d-and-d-beyond",
+ "dashcube",
+ "delicious",
+ "deploydog",
+ "deskpro",
+ "dev",
+ "deviantart",
+ "dhl",
+ "diaspora",
+ "digg",
+ "digital-ocean",
+ "discord",
+ "discourse",
+ "dochub",
+ "docker",
+ "draft2digital",
+ "dribbble",
+ "dribbble-square",
+ "dropbox",
+ "drupal",
+ "dyalog",
+ "earlybirds",
+ "ebay",
+ "edge",
+ "elementor",
+ "ello",
+ "ember",
+ "empire",
+ "envira",
+ "erlang",
+ "ethereum",
+ "etsy",
+ "evernote",
+ "expeditedssl",
+ "facebook",
+ "facebook-f",
+ "facebook-messenger",
+ "facebook-square",
+ "fantasy-flight-games",
+ "fedex",
+ "fedora",
+ "figma",
+ "firefox",
+ "first-order",
+ "first-order-alt",
+ "firstdraft",
+ "flickr",
+ "flipboard",
+ "fly",
+ "font-awesome",
+ "font-awesome-alt",
+ "font-awesome-flag",
+ "fonticons",
+ "fonticons-fi",
+ "fort-awesome",
+ "fort-awesome-alt",
+ "forumbee",
+ "foursquare",
+ "free-code-camp",
+ "freebsd",
+ "fulcrum",
+ "galactic-republic",
+ "galactic-senate",
+ "get-pocket",
+ "gg",
+ "gg-circle",
+ "git",
+ "git-square",
+ "github",
+ "github-alt",
+ "github-square",
+ "gitkraken",
+ "gitlab",
+ "gitter",
+ "glide",
+ "glide-g",
+ "gofore",
+ "goodreads",
+ "goodreads-g",
+ "google",
+ "google-drive",
+ "google-play",
+ "google-plus",
+ "google-plus-g",
+ "google-plus-square",
+ "google-wallet",
+ "gratipay",
+ "grav",
+ "gripfire",
+ "grunt",
+ "gulp",
+ "hacker-news",
+ "hacker-news-square",
+ "hackerrank",
+ "hips",
+ "hire-a-helper",
+ "hooli",
+ "hornbill",
+ "hotjar",
+ "houzz",
+ "html5",
+ "hubspot",
+ "imdb",
+ "instagram",
+ "intercom",
+ "internet-explorer",
+ "invision",
+ "ioxhost",
+ "itch-io",
+ "itunes",
+ "itunes-note",
+ "java",
+ "jedi-order",
+ "jenkins",
+ "jira",
+ "joget",
+ "joomla",
+ "js",
+ "js-square",
+ "jsfiddle",
+ "kaggle",
+ "keybase",
+ "keycdn",
+ "kickstarter",
+ "kickstarter-k",
+ "korvue",
+ "laravel",
+ "lastfm",
+ "lastfm-square",
+ "leanpub",
+ "less",
+ "line",
+ "linkedin",
+ "linkedin-in",
+ "linode",
+ "linux",
+ "lyft",
+ "magento",
+ "mailchimp",
+ "mandalorian",
+ "markdown",
+ "mastodon",
+ "maxcdn",
+ "medapps",
+ "medium",
+ "medium-m",
+ "medrt",
+ "meetup",
+ "megaport",
+ "mendeley",
+ "microsoft",
+ "mix",
+ "mixcloud",
+ "mizuni",
+ "modx",
+ "monero",
+ "napster",
+ "neos",
+ "nimblr",
+ "nintendo-switch",
+ "node",
+ "node-js",
+ "npm",
+ "ns8",
+ "nutritionix",
+ "odnoklassniki",
+ "odnoklassniki-square",
+ "old-republic",
+ "opencart",
+ "openid",
+ "opera",
+ "optin-monster",
+ "osi",
+ "page4",
+ "pagelines",
+ "palfed",
+ "patreon",
+ "paypal",
+ "penny-arcade",
+ "periscope",
+ "phabricator",
+ "phoenix-framework",
+ "phoenix-squadron",
+ "php",
+ "pied-piper",
+ "pied-piper-alt",
+ "pied-piper-hat",
+ "pied-piper-pp",
+ "pinterest",
+ "pinterest-p",
+ "pinterest-square",
+ "playstation",
+ "product-hunt",
+ "pushed",
+ "python",
+ "qq",
+ "quinscape",
+ "quora",
+ "r-project",
+ "raspberry-pi",
+ "ravelry",
+ "react",
+ "reacteurope",
+ "readme",
+ "rebel",
+ "red-river",
+ "reddit",
+ "reddit-alien",
+ "reddit-square",
+ "redhat",
+ "renren",
+ "replyd",
+ "researchgate",
+ "resolving",
+ "rev",
+ "rocketchat",
+ "rockrms",
+ "safari",
+ "salesforce",
+ "sass",
+ "schlix",
+ "scribd",
+ "searchengin",
+ "sellcast",
+ "sellsy",
+ "servicestack",
+ "shirtsinbulk",
+ "shopware",
+ "simplybuilt",
+ "sistrix",
+ "sith",
+ "sketch",
+ "skyatlas",
+ "skype",
+ "slack",
+ "slack-hash",
+ "slideshare",
+ "snapchat",
+ "snapchat-ghost",
+ "snapchat-square",
+ "soundcloud",
+ "sourcetree",
+ "speakap",
+ "speaker-deck",
+ "spotify",
+ "squarespace",
+ "stack-exchange",
+ "stack-overflow",
+ "staylinked",
+ "steam",
+ "steam-square",
+ "steam-symbol",
+ "sticker-mule",
+ "strava",
+ "stripe",
+ "stripe-s",
+ "studiovinari",
+ "stumbleupon",
+ "stumbleupon-circle",
+ "superpowers",
+ "supple",
+ "suse",
+ "symfony",
+ "teamspeak",
+ "telegram",
+ "telegram-plane",
+ "tencent-weibo",
+ "the-red-yeti",
+ "themeco",
+ "themeisle",
+ "think-peaks",
+ "trade-federation",
+ "trello",
+ "tripadvisor",
+ "tumblr",
+ "tumblr-square",
+ "twitch",
+ "twitter",
+ "twitter-square",
+ "typo3",
+ "uber",
+ "ubuntu",
+ "uikit",
+ "uniregistry",
+ "untappd",
+ "ups",
+ "usb",
+ "usps",
+ "ussunnah",
+ "vaadin",
+ "viacoin",
+ "viadeo",
+ "viadeo-square",
+ "viber",
+ "vimeo",
+ "vimeo-square",
+ "vimeo-v",
+ "vine",
+ "vk",
+ "vnv",
+ "vuejs",
+ "waze",
+ "weebly",
+ "weibo",
+ "weixin",
+ "whatsapp",
+ "whatsapp-square",
+ "whmcs",
+ "wikipedia-w",
+ "windows",
+ "wix",
+ "wizards-of-the-coast",
+ "wolf-pack-battalion",
+ "wordpress",
+ "wordpress-simple",
+ "wpbeginner",
+ "wpexplorer",
+ "wpforms",
+ "wpressr",
+ "xbox",
+ "xing",
+ "xing-square",
+ "y-combinator",
+ "yahoo",
+ "yammer",
+ "yandex",
+ "yandex-international",
+ "yarn",
+ "yelp",
+ "yoast",
+ "youtube",
+ "youtube-square",
+ "zhihu"
+ ];
+ if (fab_icons.indexOf(icon) >= 0) {
+ return 'fab';
+ }
+ return 'fas'
+}
diff --git a/app/webroot/js/jquery-3.4.1.slim.min.js b/app/webroot/js/jquery-3.4.1.slim.min.js
new file mode 100644
index 0000000..af151cf
--- /dev/null
+++ b/app/webroot/js/jquery-3.4.1.slim.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.4.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],v=g.document,r=Object.getPrototypeOf,s=t.slice,y=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,m=n.hasOwnProperty,a=m.toString,l=a.call(Object),b={},x=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},w=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||v).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)},d=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function p(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!x(e)&&!w(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+R+"?|("+R+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&((e?e.ownerDocument||e:m)!==T&&C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!S[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=N),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+be(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){S(t,!0)}finally{s===N&&e.removeAttribute("id")}}}return g(t.replace(F,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[N]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),m!==T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=N,!T.getElementsByName||!T.getElementsByName(N).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=" ",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+N+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+N+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML=" ";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument===m&&y(m,e)?-1:t===T||t.ownerDocument===m&&y(m,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===T?-1:t===T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==T&&C(e),p.matchesSelector&&E&&!S[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){S(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=d[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&d(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function L(e,n,r){return x(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:v,!0)),D.test(r[1])&&E.isPlainObject(t))for(r in t)x(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=v.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):x(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,j=E(v);var O=/^(?:parents|prev(?:Until|All))/,P={children:!0,contents:!0,next:!0,prev:!0};function H(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i,he={option:[1,""," "],thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;nx",b.noCloneChecked=!!ye.cloneNode(!0).lastChild.defaultValue;var we=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function Ne(){return!1}function Ae(e,t){return e===function(){try{return v.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ne;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return E().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=E.guid++)),e.each(function(){E.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(G.set(e,i,!1),E.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=G.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(E.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),G.set(this,i,r),t=o(this,i),this[i](),r!==(n=G.get(this,i))||t?G.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(G.set(this,i,{value:E.event.trigger(E.extend(r[0],E.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===G.get(e,i)&&E.event.add(e,i,Ee)}E.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=G.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&E.find.matchesSelector(ie,i),n.guid||(n.guid=E.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof E&&E.event.triggered!==e.type?E.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(I)||[""]).length;while(l--)p=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),p&&(f=E.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=E.event.special[p]||{},c=E.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&E.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=u[p])||((d=u[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(p,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,c):d.push(c),E.event.global[p]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=G.hasData(e)&&G.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(I)||[""]).length;while(l--)if(p=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),p){f=E.event.special[p]||{},d=u[p=(r?f.delegateType:f.bindType)||p]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=d.length;while(o--)c=d[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(d.splice(o,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||E.removeEvent(e,p,v.handle),delete u[p])}else for(p in u)E.event.remove(e,p+t[l],n,r,!0);E.isEmptyObject(u)&&G.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=E.event.fix(e),u=new Array(arguments.length),l=(G.get(this,"events")||{})[s.type]||[],c=E.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,Le=/