From 56368d1de75cb4a98aa63bc69e93f249ebec8291 Mon Sep 17 00:00:00 2001
From: iglocska
Date: Fri, 29 May 2020 13:41:58 +0200
Subject: [PATCH] new: [initial] import of the project files
- Cerebrate v0.1 initial WIP version
[Features]
- initial version of TrustDB
- Organisation
- User scope
- Alignments between Users and Organisations
- semi-implemented encryption key store
[Internals]
- MISP systems transposed to CakePHP4 / Bootstrap 4 / Cerebrate
- UI factories
- Index factories
- Form factories
- internal:
- RestResponse library
- ACL library in progress
- new clean UI using BS4
- New systems:
- UI factories
- view factories
- Datamodel import/cleaning via SQL scripts
---
app/.editorconfig | 23 +
app/.gitattributes | 54 +
app/.gitignore | 43 +
app/.htaccess | 5 +
app/INSTALL/MYSQL.sql | 176 +
app/INSTALL/clean.sql | 14 +
app/INSTALL/data.sql | 6 +
app/README.md | 53 +
app/bin/cake | 75 +
app/bin/cake.bat | 27 +
app/bin/cake.php | 12 +
app/composer.json | 56 +
app/composer.lock | 4548 +++++++
app/config/.env.example | 38 +
app/config/app.php | 401 +
app/config/app_local.example.php | 92 +
app/config/bootstrap.php | 215 +
app/config/bootstrap_cli.php | 31 +
app/config/cerebrate-pagination-templates.php | 11 +
app/config/paths.php | 94 +
app/config/requirements.php | 46 +
app/config/routes.php | 99 +
app/config/schema/i18n.sql | 18 +
app/config/schema/sessions.sql | 15 +
app/index.php | 16 +
app/phpunit.xml.dist | 40 +
app/plugins/.gitkeep | 0
app/resources/.gitkeep | 0
app/src/Application.php | 108 +
app/src/Command/ConsoleCommand.php | 86 +
app/src/Console/Installer.php | 246 +
app/src/Controller/AlignmentsController.php | 130 +
app/src/Controller/AppController.php | 104 +
app/src/Controller/Component/.gitkeep | 0
app/src/Controller/Component/ACLComponent.php | 875 ++
.../Component/RestResponseComponent.php | 1782 +++
.../Controller/EncryptionKeysController.php | 117 +
app/src/Controller/ErrorController.php | 70 +
app/src/Controller/IndividualsController.php | 155 +
.../Controller/OrganisationsController.php | 153 +
app/src/Controller/PagesController.php | 75 +
app/src/Model/Behavior/.gitkeep | 0
app/src/Model/Entity/.gitkeep | 0
app/src/Model/Entity/Alignment.php | 11 +
app/src/Model/Entity/AppModel.php | 10 +
app/src/Model/Entity/EncryptionKey.php | 11 +
app/src/Model/Entity/Individual.php | 11 +
app/src/Model/Entity/Orgnaisation.php | 11 +
app/src/Model/Table/.gitkeep | 0
app/src/Model/Table/AlignmentsTable.php | 26 +
app/src/Model/Table/AppTable.php | 13 +
app/src/Model/Table/EncryptionKeysTable.php | 41 +
app/src/Model/Table/IndividualsTable.php | 32 +
app/src/Model/Table/OrganisationsTable.php | 32 +
.../Model/Validation/ValidationCollection.php | 13 +
app/src/View/AjaxView.php | 46 +
app/src/View/AppView.php | 45 +
app/src/View/Cell/.gitkeep | 0
app/src/View/Helper/.gitkeep | 0
app/src/View/Helper/FontAwesomeHelper.php | 450 +
app/src/View/Helper/HashHelper.php | 14 +
app/templates/Alignments/add.php | 23 +
app/templates/EncryptionKeys/add.php | 30 +
app/templates/Error/error400.php | 38 +
app/templates/Error/error500.php | 42 +
app/templates/Individuals/add.php | 35 +
app/templates/Individuals/index.php | 74 +
app/templates/Individuals/view.php | 41 +
app/templates/Organisations/add.php | 42 +
app/templates/Organisations/index.php | 84 +
app/templates/Organisations/view.php | 49 +
app/templates/Pages/home.php | 222 +
app/templates/cell/.gitkeep | 1 +
app/templates/element/flash/default.php | 20 +
app/templates/element/flash/error.php | 16 +
app/templates/element/flash/success.php | 16 +
.../Form/Fields/checkboxField.php | 8 +
.../Form/Fields/genericField.php | 9 +
.../genericElements/Form/Fields/uuidField.php | 42 +
.../element/genericElements/Form/formInfo.php | 47 +
.../genericElements/Form/genericForm.php | 160 +
.../genericElements/Form/submitButton.php | 17 +
.../IndexTable/Fields/actions.php | 96 +
.../IndexTable/Fields/alignments.php | 43 +
.../IndexTable/Fields/array_lookup_field.php | 4 +
.../IndexTable/Fields/boolean.php | 57 +
.../IndexTable/Fields/caching.php | 32 +
.../IndexTable/Fields/correlations.php | 20 +
.../IndexTable/Fields/count_summary.php | 25 +
.../IndexTable/Fields/datetime.php | 26 +
.../IndexTable/Fields/distribution_levels.php | 15 +
.../IndexTable/Fields/generic_field.php | 37 +
.../IndexTable/Fields/icon.php | 5 +
.../IndexTable/Fields/json.php | 16 +
.../IndexTable/Fields/links.php | 47 +
.../IndexTable/Fields/list.php | 16 +
.../genericElements/IndexTable/Fields/org.php | 38 +
.../IndexTable/Fields/role.php | 22 +
.../IndexTable/Fields/selector.php | 20 +
.../IndexTable/Fields/self_registration.php | 17 +
.../IndexTable/Fields/sparkline.php | 4 +
.../IndexTable/Fields/tags.php | 17 +
.../IndexTable/Fields/target_event.php | 33 +
.../IndexTable/Fields/tester.php | 30 +
.../IndexTable/Fields/timestamp.php | 7 +
.../IndexTable/Fields/toggle.php | 59 +
.../genericElements/IndexTable/headers.php | 51 +
.../IndexTable/index_table.php | 125 +
.../genericElements/IndexTable/pagination.php | 36 +
.../IndexTable/pagination_counter.php | 17 +
.../IndexTable/pagination_limiter.php | 11 +
.../IndexTable/pagination_links.php | 8 +
.../genericElements/IndexTable/row.php | 63 +
.../ListTopBar/element_embedded.php | 47 +
.../ListTopBar/element_group.php | 33 +
.../ListTopBar/element_simple.php | 56 +
.../ListTopBar/group_live_search.php | 13 +
.../ListTopBar/group_search.php | 58 +
.../ListTopBar/group_simple.php | 13 +
.../genericElements/ListTopBar/scaffold.php | 17 +
.../genericElements/SideMenu/side_menu.php | 106 +
.../SingleViews/Fields/alignmentField.php | 51 +
.../SingleViews/Fields/genericField.php | 3 +
.../genericElements/SingleViews/child.php | 25 +
.../SingleViews/single_view.php | 64 +
.../element/genericElements/footer.php | 3 +
.../element/genericElements/genericModal.php | 24 +
.../element/genericElements/header.php | 146 +
app/templates/email/html/default.php | 21 +
app/templates/email/text/default.php | 17 +
app/templates/genericTemplates/delete.php | 29 +
app/templates/layout/ajax.php | 17 +
app/templates/layout/default.php | 63 +
app/templates/layout/email/html/default.php | 25 +
app/templates/layout/email/text/default.php | 17 +
app/templates/layout/error.php | 43 +
app/tests/Fixture/.gitkeep | 0
app/tests/TestCase/ApplicationTest.php | 87 +
.../TestCase/Controller/Component/.gitkeep | 0
.../Controller/PagesControllerTest.php | 126 +
app/tests/TestCase/Model/Behavior/.gitkeep | 0
app/tests/TestCase/View/Helper/.gitkeep | 0
app/tests/bootstrap.php | 52 +
app/webroot/.htaccess | 12 +
app/webroot/bootstrap | 1 +
app/webroot/css/bootstrap.css | 10224 ++++++++++++++++
app/webroot/css/cake.css | 177 +
app/webroot/css/font-awesome.css | 4336 +++++++
app/webroot/css/home.css | 72 +
app/webroot/css/main.css | 111 +
app/webroot/css/milligram.min.css | 11 +
app/webroot/debug_kit | 1 +
app/webroot/favicon.ico | Bin 0 -> 1470 bytes
app/webroot/font/cakedingbats-webfont.eot | Bin 0 -> 75538 bytes
app/webroot/font/cakedingbats-webfont.svg | 78 +
app/webroot/font/cakedingbats-webfont.ttf | Bin 0 -> 75412 bytes
app/webroot/font/cakedingbats-webfont.woff | Bin 0 -> 43484 bytes
app/webroot/font/cakedingbats-webfont.woff2 | Bin 0 -> 35456 bytes
app/webroot/img/cake-logo.png | Bin 0 -> 2683 bytes
app/webroot/img/cake.icon.png | Bin 0 -> 943 bytes
app/webroot/img/cake.logo.svg | 41 +
app/webroot/img/cake.power.gif | Bin 0 -> 201 bytes
app/webroot/img/favicon.ico | Bin 0 -> 1470 bytes
app/webroot/img/zicon.png | Bin 0 -> 695 bytes
app/webroot/index.php | 40 +
app/webroot/js/.gitkeep | 0
app/webroot/js/bootstrap.bundle.js | 7134 +++++++++++
app/webroot/js/bootstrap.js | 4521 +++++++
app/webroot/js/font-awesome-helper.js | 433 +
app/webroot/js/jquery-3.4.1.slim.min.js | 2 +
app/webroot/js/jquery-3.5.1.min.js | 2 +
app/webroot/js/main.js | 23 +
app/webroot/js/popper.min.js | 5 +
app/webroot/scss/custom.scss | 1 +
app/webroot/webfonts/fa-brands-400.eot | Bin 0 -> 129648 bytes
app/webroot/webfonts/fa-brands-400.svg | 3452 ++++++
app/webroot/webfonts/fa-brands-400.ttf | Bin 0 -> 129344 bytes
app/webroot/webfonts/fa-brands-400.woff | Bin 0 -> 87544 bytes
app/webroot/webfonts/fa-brands-400.woff2 | Bin 0 -> 74656 bytes
app/webroot/webfonts/fa-regular-400.eot | Bin 0 -> 34388 bytes
app/webroot/webfonts/fa-regular-400.svg | 803 ++
app/webroot/webfonts/fa-regular-400.ttf | Bin 0 -> 34092 bytes
app/webroot/webfonts/fa-regular-400.woff | Bin 0 -> 16804 bytes
app/webroot/webfonts/fa-regular-400.woff2 | Bin 0 -> 13584 bytes
app/webroot/webfonts/fa-solid-900.eot | Bin 0 -> 186708 bytes
app/webroot/webfonts/fa-solid-900.svg | 4527 +++++++
app/webroot/webfonts/fa-solid-900.ttf | Bin 0 -> 186424 bytes
app/webroot/webfonts/fa-solid-900.woff | Bin 0 -> 96256 bytes
app/webroot/webfonts/fa-solid-900.woff2 | Bin 0 -> 74328 bytes
189 files changed, 50051 insertions(+)
create mode 100644 app/.editorconfig
create mode 100644 app/.gitattributes
create mode 100644 app/.gitignore
create mode 100644 app/.htaccess
create mode 100644 app/INSTALL/MYSQL.sql
create mode 100644 app/INSTALL/clean.sql
create mode 100644 app/INSTALL/data.sql
create mode 100644 app/README.md
create mode 100755 app/bin/cake
create mode 100644 app/bin/cake.bat
create mode 100644 app/bin/cake.php
create mode 100644 app/composer.json
create mode 100644 app/composer.lock
create mode 100644 app/config/.env.example
create mode 100644 app/config/app.php
create mode 100644 app/config/app_local.example.php
create mode 100644 app/config/bootstrap.php
create mode 100644 app/config/bootstrap_cli.php
create mode 100644 app/config/cerebrate-pagination-templates.php
create mode 100644 app/config/paths.php
create mode 100644 app/config/requirements.php
create mode 100644 app/config/routes.php
create mode 100644 app/config/schema/i18n.sql
create mode 100644 app/config/schema/sessions.sql
create mode 100644 app/index.php
create mode 100644 app/phpunit.xml.dist
create mode 100644 app/plugins/.gitkeep
create mode 100644 app/resources/.gitkeep
create mode 100644 app/src/Application.php
create mode 100644 app/src/Command/ConsoleCommand.php
create mode 100644 app/src/Console/Installer.php
create mode 100644 app/src/Controller/AlignmentsController.php
create mode 100644 app/src/Controller/AppController.php
create mode 100644 app/src/Controller/Component/.gitkeep
create mode 100644 app/src/Controller/Component/ACLComponent.php
create mode 100644 app/src/Controller/Component/RestResponseComponent.php
create mode 100644 app/src/Controller/EncryptionKeysController.php
create mode 100644 app/src/Controller/ErrorController.php
create mode 100644 app/src/Controller/IndividualsController.php
create mode 100644 app/src/Controller/OrganisationsController.php
create mode 100644 app/src/Controller/PagesController.php
create mode 100644 app/src/Model/Behavior/.gitkeep
create mode 100644 app/src/Model/Entity/.gitkeep
create mode 100644 app/src/Model/Entity/Alignment.php
create mode 100644 app/src/Model/Entity/AppModel.php
create mode 100644 app/src/Model/Entity/EncryptionKey.php
create mode 100644 app/src/Model/Entity/Individual.php
create mode 100644 app/src/Model/Entity/Orgnaisation.php
create mode 100644 app/src/Model/Table/.gitkeep
create mode 100644 app/src/Model/Table/AlignmentsTable.php
create mode 100644 app/src/Model/Table/AppTable.php
create mode 100644 app/src/Model/Table/EncryptionKeysTable.php
create mode 100644 app/src/Model/Table/IndividualsTable.php
create mode 100644 app/src/Model/Table/OrganisationsTable.php
create mode 100644 app/src/Model/Validation/ValidationCollection.php
create mode 100644 app/src/View/AjaxView.php
create mode 100644 app/src/View/AppView.php
create mode 100644 app/src/View/Cell/.gitkeep
create mode 100644 app/src/View/Helper/.gitkeep
create mode 100644 app/src/View/Helper/FontAwesomeHelper.php
create mode 100644 app/src/View/Helper/HashHelper.php
create mode 100644 app/templates/Alignments/add.php
create mode 100644 app/templates/EncryptionKeys/add.php
create mode 100644 app/templates/Error/error400.php
create mode 100644 app/templates/Error/error500.php
create mode 100644 app/templates/Individuals/add.php
create mode 100644 app/templates/Individuals/index.php
create mode 100644 app/templates/Individuals/view.php
create mode 100644 app/templates/Organisations/add.php
create mode 100644 app/templates/Organisations/index.php
create mode 100644 app/templates/Organisations/view.php
create mode 100644 app/templates/Pages/home.php
create mode 100644 app/templates/cell/.gitkeep
create mode 100644 app/templates/element/flash/default.php
create mode 100644 app/templates/element/flash/error.php
create mode 100644 app/templates/element/flash/success.php
create mode 100644 app/templates/element/genericElements/Form/Fields/checkboxField.php
create mode 100644 app/templates/element/genericElements/Form/Fields/genericField.php
create mode 100644 app/templates/element/genericElements/Form/Fields/uuidField.php
create mode 100644 app/templates/element/genericElements/Form/formInfo.php
create mode 100644 app/templates/element/genericElements/Form/genericForm.php
create mode 100644 app/templates/element/genericElements/Form/submitButton.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/actions.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/alignments.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/boolean.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/caching.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/correlations.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/count_summary.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/datetime.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/generic_field.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/icon.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/json.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/links.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/list.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/org.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/role.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/selector.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/self_registration.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/sparkline.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/tags.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/target_event.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/tester.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/timestamp.php
create mode 100644 app/templates/element/genericElements/IndexTable/Fields/toggle.php
create mode 100644 app/templates/element/genericElements/IndexTable/headers.php
create mode 100644 app/templates/element/genericElements/IndexTable/index_table.php
create mode 100644 app/templates/element/genericElements/IndexTable/pagination.php
create mode 100644 app/templates/element/genericElements/IndexTable/pagination_counter.php
create mode 100644 app/templates/element/genericElements/IndexTable/pagination_limiter.php
create mode 100644 app/templates/element/genericElements/IndexTable/pagination_links.php
create mode 100644 app/templates/element/genericElements/IndexTable/row.php
create mode 100644 app/templates/element/genericElements/ListTopBar/element_embedded.php
create mode 100644 app/templates/element/genericElements/ListTopBar/element_group.php
create mode 100644 app/templates/element/genericElements/ListTopBar/element_simple.php
create mode 100644 app/templates/element/genericElements/ListTopBar/group_live_search.php
create mode 100644 app/templates/element/genericElements/ListTopBar/group_search.php
create mode 100644 app/templates/element/genericElements/ListTopBar/group_simple.php
create mode 100644 app/templates/element/genericElements/ListTopBar/scaffold.php
create mode 100644 app/templates/element/genericElements/SideMenu/side_menu.php
create mode 100644 app/templates/element/genericElements/SingleViews/Fields/alignmentField.php
create mode 100644 app/templates/element/genericElements/SingleViews/Fields/genericField.php
create mode 100644 app/templates/element/genericElements/SingleViews/child.php
create mode 100644 app/templates/element/genericElements/SingleViews/single_view.php
create mode 100644 app/templates/element/genericElements/footer.php
create mode 100644 app/templates/element/genericElements/genericModal.php
create mode 100644 app/templates/element/genericElements/header.php
create mode 100644 app/templates/email/html/default.php
create mode 100644 app/templates/email/text/default.php
create mode 100644 app/templates/genericTemplates/delete.php
create mode 100644 app/templates/layout/ajax.php
create mode 100644 app/templates/layout/default.php
create mode 100644 app/templates/layout/email/html/default.php
create mode 100644 app/templates/layout/email/text/default.php
create mode 100644 app/templates/layout/error.php
create mode 100644 app/tests/Fixture/.gitkeep
create mode 100644 app/tests/TestCase/ApplicationTest.php
create mode 100644 app/tests/TestCase/Controller/Component/.gitkeep
create mode 100644 app/tests/TestCase/Controller/PagesControllerTest.php
create mode 100644 app/tests/TestCase/Model/Behavior/.gitkeep
create mode 100644 app/tests/TestCase/View/Helper/.gitkeep
create mode 100644 app/tests/bootstrap.php
create mode 100644 app/webroot/.htaccess
create mode 160000 app/webroot/bootstrap
create mode 100644 app/webroot/css/bootstrap.css
create mode 100644 app/webroot/css/cake.css
create mode 100644 app/webroot/css/font-awesome.css
create mode 100644 app/webroot/css/home.css
create mode 100644 app/webroot/css/main.css
create mode 100644 app/webroot/css/milligram.min.css
create mode 120000 app/webroot/debug_kit
create mode 100644 app/webroot/favicon.ico
create mode 100644 app/webroot/font/cakedingbats-webfont.eot
create mode 100644 app/webroot/font/cakedingbats-webfont.svg
create mode 100644 app/webroot/font/cakedingbats-webfont.ttf
create mode 100644 app/webroot/font/cakedingbats-webfont.woff
create mode 100644 app/webroot/font/cakedingbats-webfont.woff2
create mode 100644 app/webroot/img/cake-logo.png
create mode 100644 app/webroot/img/cake.icon.png
create mode 100644 app/webroot/img/cake.logo.svg
create mode 100644 app/webroot/img/cake.power.gif
create mode 100644 app/webroot/img/favicon.ico
create mode 100644 app/webroot/img/zicon.png
create mode 100644 app/webroot/index.php
create mode 100644 app/webroot/js/.gitkeep
create mode 100644 app/webroot/js/bootstrap.bundle.js
create mode 100644 app/webroot/js/bootstrap.js
create mode 100644 app/webroot/js/font-awesome-helper.js
create mode 100644 app/webroot/js/jquery-3.4.1.slim.min.js
create mode 100644 app/webroot/js/jquery-3.5.1.min.js
create mode 100644 app/webroot/js/main.js
create mode 100644 app/webroot/js/popper.min.js
create mode 100644 app/webroot/scss/custom.scss
create mode 100644 app/webroot/webfonts/fa-brands-400.eot
create mode 100644 app/webroot/webfonts/fa-brands-400.svg
create mode 100644 app/webroot/webfonts/fa-brands-400.ttf
create mode 100644 app/webroot/webfonts/fa-brands-400.woff
create mode 100644 app/webroot/webfonts/fa-brands-400.woff2
create mode 100644 app/webroot/webfonts/fa-regular-400.eot
create mode 100644 app/webroot/webfonts/fa-regular-400.svg
create mode 100644 app/webroot/webfonts/fa-regular-400.ttf
create mode 100644 app/webroot/webfonts/fa-regular-400.woff
create mode 100644 app/webroot/webfonts/fa-regular-400.woff2
create mode 100644 app/webroot/webfonts/fa-solid-900.eot
create mode 100644 app/webroot/webfonts/fa-solid-900.svg
create mode 100644 app/webroot/webfonts/fa-solid-900.ttf
create mode 100644 app/webroot/webfonts/fa-solid-900.woff
create mode 100644 app/webroot/webfonts/fa-solid-900.woff2
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 0000000000000000000000000000000000000000..b38a3a0a374a66849d63ce73346096d5566e6ce9
GIT binary patch
literal 1470
zcmeH_don@h(f+F3Lt
z7K$Tv=C~~+=a}1EHj=aD)RDaC@5s0sF;b8QWna}S*WOFp{kmVnwkuC^&B)b
za?sQ~ftJ<@w6$~5(aA$sHy=H{0`&C@FfjNSW8*?hObRhIEyB#KSfm7V^G~p_D8-K+8N_ySMQ
z8oaz}@b>-^AD>!$ee3Y^`wD;mdIAC(2n=i_D5#O(;I9b@`G(NYCc?s+2oG;2BBGhd
z$QGiaT8NJRme^Q{R^sAXiI4w|goN)&N@^oHxt)}h4pLJ)Nl))2BcqGV%r0cIZjti{
z!g+FXB!1xJ$sTfZd&$e|B|pEHf`UE@3xA}jsGs8Eeo9LEDJ}hpva$in%Ll2b805^E
z3shEKpsH$!>gr)?YKEz;9igsnl(T0?sjnZSq2VHpjTdQZ8mGB=f|iy^T3e?$ckVK6
zZI@|ppQfWjVusGn8M?Y==)jAsW-{VM%gQ3zwQ&Sd9c&YI$Cna4nMv7
zo~Xl0dT&0*Zr7*6B$s&5*;M86h-U+1jc?I5^hw=5ci;2+@>WM*dPr{P0SEUi$q6Y(
zU%pRA_2wN4T6b!B$H}(bM}B)PVjniT|2DT^HMi}%2tr!S@fY{F#2K2sWgBtb2||>~
d-k?xJ+w_F28}9wYl+3^*X+pNB#Qpwl{0%E*c1ZvL
literal 0
HcmV?d00001
diff --git a/app/webroot/font/cakedingbats-webfont.eot b/app/webroot/font/cakedingbats-webfont.eot
new file mode 100644
index 0000000000000000000000000000000000000000..e8605d92685dc69e3555a2d46c934332ade64789
GIT binary patch
literal 75538
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
J{3OkB{|TIQ9Sr~g
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..13d54454e71f4ed2ca3ad46bf8910b77acff1b24
GIT binary patch
literal 75412
zcmb?^37izg^?z6Qbobo%eeK+{vpYL`%$~690qnwZ9}2r%$_B*qvK52BHTL=(k$kf=#a)Nt(Z|5o+vi1{V?{Xc*H=y&S%tE$&k)zztm*?hR*MjR_plAN-RUzq7>1&P?Mj}4AX!+ucq^>*baJ>NWD;LjQxg2~mZuT35
z>cz{}E~lB@5>+XnOrhJx7XYy4odRG+$WvCaxdGb!^E+tJXxX;YQ>7
zHOMnB``-MydmgyxuN(=zi};?4=B`=JUtztABjF{u4qZI=qJ@z!R$YnfO(=tT`S(_?
z%Ia5s!I9YQ$X~yF#lq#gRy?_lBk@B>-+$S{d5b=6m_C^!i67uv0%+@SuMPY0n>2h|
z|6~sfFT1^$#TaqrrW}sPHQ`18Xf0gfcIvt0Mo#2Z;sO!Z#IA(G*Z@#tmIlaL;RHZi<}L`c%D0sIF?3QEPety#I6KT6n-U+yB1e8l^?DB1y&0K
za?IdXbN7a{q4Lmq@l&TyBc9_Zzm=N{K3Cuir@uP=$I~yJ-go-e_iNv`{^7&lj>^kt
zS-$&2&_=Wf^dF(Mra1E-%0nCEzy1>?S*_9P^ai8JY_Zzx4yViQ@%sFMppva96pln=
z@kFvXRZ^NR%am7CR%NUItH}Si$eRDRY#f*3s<={aEO#No6qn(SQb8i^