diff --git a/application/layouts/rtx_layout01/config/config.php b/application/layouts/rtx_layout01/config/config.php
new file mode 100644
index 000000000..d0a9b8433
--- /dev/null
+++ b/application/layouts/rtx_layout01/config/config.php
@@ -0,0 +1,24 @@
+ 'rtx_layout01',
+ 'version' => '1.0.0',
+ 'author' => 'RTX2070',
+ 'link' => 'https://ilch.de',
+ 'desc' => 'Bootstrap 5 Standard Layout (flexbox)',
+
+ //'modulekey' => 'Name of Module'
+ ];
+
+ public function getUpdate($installedVersion)
+ {
+ }
+}
diff --git a/application/layouts/rtx_layout01/css/style.css b/application/layouts/rtx_layout01/css/style.css
new file mode 100644
index 000000000..a017d3938
--- /dev/null
+++ b/application/layouts/rtx_layout01/css/style.css
@@ -0,0 +1,605 @@
+/*----------------------------------------------------------------------------------------------------------------------
+# Generelle Einstellungen
+----------------------------------------------------------------------------------------------------------------------*/
+
+/* Standardschrift und Farbe festlegen */
+body {
+ font-family: "Open Sans", sans-serif;
+ color: #444444;
+}
+
+/* Alle Überschriften Standardmäßig gleiche Schriftart */
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: "Jost", sans-serif;
+}
+
+/* Alle Links in bestimmter Farbe und ohne Unterstrich */
+a {
+ color: #c10f20;
+ text-decoration: none;
+}
+
+/* Beim überfahren von Links ändert sich die Farbe leicht. */
+a:hover {
+ color: rgba(191, 15, 33, 0.72);
+ text-decoration: none;
+}
+
+/*--------------------------------------------------------------
+# Back to top button
+--------------------------------------------------------------*/
+.back-to-top {
+ position: fixed;
+ visibility: hidden;
+ opacity: 0;
+ right: 15px;
+ bottom: 15px;
+ z-index: 996;
+ background: rgba(218, 53, 69, 0.64);
+ width: 40px;
+ height: 40px;
+ border-radius: 50px;
+ transition: all 0.4s;
+}
+
+.back-to-top i {
+ font-size: 24px;
+ color: #fff;
+ line-height: 0;
+}
+
+.back-to-top:hover {
+ background: #da3545;
+
+}
+
+.back-to-top.active {
+ visibility: visible;
+ opacity: 1;
+}
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Header
+----------------------------------------------------------------------------------------------------------------------*/
+#header{
+ z-index: 1000;
+ padding: 15px 0;
+ background: rgba(17, 19, 22, 0.9);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.30);
+}
+
+#header .logo {
+ font-size: 30px;
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+ font-weight: 500;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+}
+
+#header .logo a {
+ color: #bf0f21;
+}
+
+#header .logo img {
+ max-height: 50px;
+
+
+}
+
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Navigation Menu
+----------------------------------------------------------------------------------------------------------------------*/
+/**
+* Desktop Navigation
+*/
+.navbar {
+ padding: 0;
+}
+
+.navbar ul {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ list-style: none;
+ align-items: center;
+}
+
+.navbar li {
+ position: relative;
+}
+
+.navbar a,
+.navbar a:focus {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 0 10px 30px;
+ font-size: 15px;
+ font-weight: 500;
+ color: #fff;
+ white-space: nowrap;
+ transition: 0.3s;
+}
+
+.navbar a i,
+.navbar a:focus i {
+ font-size: 12px;
+ line-height: 0;
+ margin-left: 5px;
+}
+
+.navbar a:hover,
+.navbar .active,
+.navbar .active:focus,
+.navbar li:hover>a {
+ color: #d5001d;
+}
+
+/**
+* Mobile Navigation
+*/
+.mobile-nav-toggle {
+ color: #a51c25;
+ font-size: 28px;
+ cursor: pointer;
+ display: none;
+ line-height: 0;
+ transition: 0.5s;
+}
+
+
+@media (max-width: 991px) {
+ .mobile-nav-toggle {
+ display: block;
+ }
+
+ .navbar ul {
+ display: none;
+ }
+}
+
+.navbar-mobile {
+ position: fixed;
+ overflow: hidden;
+ top: 0;
+ right: 0;
+ left: 0;
+ bottom: 0;
+ background: rgb(36, 40, 45);
+ transition: 0.3s;
+ z-index: 1000;
+}
+
+.navbar-mobile .mobile-nav-toggle {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+}
+
+.navbar-mobile ul {
+ display: block;
+ position: absolute;
+ top: 55px;
+ right: 15px;
+ bottom: 15px;
+ left: 15px;
+ padding: 10px 0;
+ border-radius: 10px;
+ background-color: #fff;
+ overflow-y: auto;
+ transition: 0.3s;
+}
+
+.navbar-mobile a,
+.navbar-mobile a:focus {
+ padding: 10px 20px;
+ font-size: 15px;
+ color: #b81422;
+}
+
+.navbar-mobile a:hover,
+.navbar-mobile .active,
+.navbar-mobile li:hover>a {
+ color: #c9c9cb;
+}
+
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Navigation oben -> Link Styles -> Ilch Menu #1
+----------------------------------------------------------------------------------------------------------------------*/
+
+.rtx {
+ line-height: 50px;
+ max-height: 30px;
+ text-align: center;
+ max-width: 155px;
+ cursor: pointer;
+}
+
+.rtx-one {
+ color: #be1121;
+ transition: all 0.3s;
+ position: relative;
+ transition: all 0.3s;
+}
+
+.rtx-one::before {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ opacity: 0;
+ transition: all 0.3s;
+ border-top-width: 1px;
+ border-bottom-width: 1px;
+ border-top-style: solid;
+ border-bottom-style: solid;
+ border-top-color: rgba(255,255,255,0.5);
+ border-bottom-color: rgba(255,255,255,0.5);
+ transform: scale(0.1, 1);
+}
+.rtx-one:hover {
+ letter-spacing: 3px;
+}
+.rtx-one:hover::before {
+ opacity: 1;
+ transform: scale(1, 1);
+}
+.rtx-one::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ transition: all 0.3s;
+}
+.rtx-one:hover::after {
+ opacity: 0;
+ transform: scale(0.1, 1);
+}
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Navigation links -> Link Styles -> Ilch Menu #2
+----------------------------------------------------------------------------------------------------------------------*/
+
+.btn {
+ text-decoration: none;
+ border: 1px solid #000000;
+ position: relative;
+ overflow: hidden;
+}
+
+.btn:hover {
+ box-shadow: 1px 1px 25px 10px rgb(43, 43, 44);
+ border: 1px solid #fff;
+}
+
+.btn:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(
+ 120deg,
+ transparent,
+ rgb(165, 28, 37),
+ transparent
+ );
+ transition: all 1000ms;
+}
+
+.btn:hover:before {
+ left: 100%;
+}
+
+
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Card-Header Hintergrund
+----------------------------------------------------------------------------------------------------------------------*/
+
+.card-header-bg{
+ background: #1e1f23;
+ color: #fff;
+}
+
+.card-menu-bg{
+ background: #2e353a;
+}
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Ilch Main Content
+----------------------------------------------------------------------------------------------------------------------*/
+.ilch-content{
+ margin-left: 10px;
+ margin-right: 10px;
+
+}
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Generlle Einstellungen für Sections
+----------------------------------------------------------------------------------------------------------------------*/
+section {
+ padding: 60px 0;
+ overflow: hidden;
+}
+
+
+/*----------------------------------------------------------------------------------------------------------------------
+# Hero Section
+----------------------------------------------------------------------------------------------------------------------*/
+#hero {
+ width: 100%;
+ height: 50vh;
+ background: url(../img/hero_bg.webp) #1e1f23 no-repeat;
+ background-size: cover;
+}
+
+#hero .container {
+ padding-top: 72px;
+}
+
+#hero h1 {
+ margin: 0 0 10px 0;
+ font-size: 48px;
+ font-weight: 700;
+ line-height: 56px;
+ color: #b91421;
+}
+
+#hero h2 {
+ color: rgba(255, 255, 255, 0.6);
+ margin-bottom: 50px;
+ font-size: 24px;
+}
+
+#hero .btn-download {
+ font-family: "Jost", sans-serif;
+ font-weight: 500;
+ font-size: 16px;
+ letter-spacing: 1px;
+ display: inline-block;
+ padding: 10px 28px 11px 28px;
+ border-radius: 50px;
+ transition: 0.5s;
+ margin: 10px 0 0 0;
+ color: #fff;
+ background: #a61c24;
+}
+
+#hero .btn-download:hover {
+ background: #949598;
+ border: 3px dotted #A61C24FF;
+}
+
+
+#hero .animated {
+ animation: up-down 10s ease-in-out infinite alternate-reverse both;
+}
+
+@media (max-width: 991px) {
+ #hero {
+ height: 100vh;
+ text-align: center;
+ }
+
+ #hero .animated {
+ -webkit-animation: none;
+ animation: none;
+ }
+
+ #hero .hero-img {
+ text-align: center;
+ }
+
+ #hero .hero-img img {
+ width: 50%;
+ }
+}
+
+@media (max-width: 768px) {
+ #hero h1 {
+ font-size: 28px;
+ line-height: 36px;
+ }
+
+ #hero h2 {
+ font-size: 18px;
+ line-height: 24px;
+ margin-bottom: 30px;
+ }
+
+ #hero .hero-img img {
+ width: 70%;
+ }
+}
+
+@media (max-width: 575px) {
+ #hero .hero-img img {
+ width: 80%;
+ }
+
+ #hero .btn-get-started {
+ font-size: 16px;
+ padding: 10px 24px 11px 24px;
+ }
+}
+
+@-webkit-keyframes up-down {
+ 0% {
+ transform: translateY(10px);
+ }
+
+ 100% {
+ transform: translateY(-10px);
+ }
+}
+
+@keyframes up-down {
+ 0% {
+ transform: translateY(10px);
+ }
+
+ 100% {
+ transform: translateY(-10px);
+ }
+}
+
+/*--------------------------------------------------------------
+# Footer
+--------------------------------------------------------------*/
+#footer {
+ font-size: 14px;
+ background: #1e1f23;
+}
+
+
+#footer .footer-top {
+ padding: 60px 0 30px 0;
+ background: #fff;
+}
+
+#footer .footer-top .footer-contact {
+ margin-bottom: 30px;
+}
+
+#footer .footer-top .footer-contact h3 {
+ font-size: 28px;
+ margin: 0 0 10px 0;
+ padding: 2px 0 2px 0;
+ line-height: 1;
+ text-transform: uppercase;
+ font-weight: 600;
+ color: #37517e;
+}
+
+#footer .footer-top .footer-contact p {
+ font-size: 14px;
+ line-height: 24px;
+ margin-bottom: 0;
+ font-family: "Jost", sans-serif;
+ color: #5e5e5e;
+}
+
+#footer .footer-top h4 {
+ font-size: 16px;
+ font-weight: bold;
+ color: #a51c25;
+ position: relative;
+ padding-bottom: 12px;
+}
+
+#footer .footer-top .footer-links {
+ margin-bottom: 30px;
+}
+
+#footer .footer-top .footer-links ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+#footer .footer-top .footer-links ul i {
+ padding-right: 2px;
+ color: #47b2e4;
+ font-size: 18px;
+ line-height: 1;
+}
+
+#footer .footer-top .footer-links ul li {
+ padding: 10px 0;
+ display: flex;
+ align-items: center;
+}
+
+#footer .footer-top .footer-links ul li:first-child {
+ padding-top: 0;
+}
+
+#footer .footer-top .footer-links ul a {
+ color: #777777;
+ transition: 0.3s;
+ display: inline-block;
+ line-height: 1;
+}
+
+#footer .footer-top .footer-links ul a:hover {
+ text-decoration: none;
+ color: #da3545;
+}
+
+#footer .footer-top .social-links a {
+ font-size: 18px;
+ display: inline-block;
+ background: #da3545;
+ color: #fff;
+ line-height: 1;
+ padding: 8px 0;
+ margin-right: 4px;
+ border-radius: 50%;
+ text-align: center;
+ width: 36px;
+ height: 36px;
+ transition: 0.3s;
+}
+
+#footer .footer-top .social-links a:hover {
+ background: #2b2b2c;
+ color: #fff;
+ text-decoration: none;
+}
+
+#footer .footer-bottom {
+ padding-top: 30px;
+ padding-bottom: 30px;
+ color: #fff;
+}
+
+#footer .copyright {
+ float: left;
+}
+
+#footer .credits {
+ float: right;
+ font-size: 13px;
+}
+
+#footer .credits a {
+ transition: 0.3s;
+}
+
+@media (max-width: 768px) {
+ #footer .footer-bottom {
+ padding-top: 20px;
+ padding-bottom: 20px;
+ }
+
+ #footer .copyright,
+ #footer .credits {
+ text-align: center;
+ float: none;
+ }
+
+ #footer .credits {
+ padding-top: 4px;
+ }
+}
+
+
+
+
diff --git a/application/layouts/rtx_layout01/img/hero_bg.webp b/application/layouts/rtx_layout01/img/hero_bg.webp
new file mode 100644
index 000000000..087cb8d82
Binary files /dev/null and b/application/layouts/rtx_layout01/img/hero_bg.webp differ
diff --git a/application/layouts/rtx_layout01/index.php b/application/layouts/rtx_layout01/index.php
new file mode 100644
index 000000000..e29b2b392
--- /dev/null
+++ b/application/layouts/rtx_layout01/index.php
@@ -0,0 +1,188 @@
+
+
+
+
+ = $this->getHeader() ?>
+
+
+
+ = $this->getCustomCSS() ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
=$this->getTrans('heroH1')?>
+
=$this->getTrans('heroH2')?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ =$this->getMenu(2, '', [
+ 'menus' => [
+ 'ul-class-root' => 'list-group',
+ 'li-class-root' => 'btn m-1',
+ 'a-class' => 'text-white',
+ ],
+ 'boxes' => [
+ 'render' => false
+ ],
+ ])
+ ?>
+
+
+ =$this->getContent()?>
+
+
+
+ =$this->getMenu(3, '', [
+ 'menus' => [
+ 'ul-class-root' => 'list-group',
+ 'li-class-root' => 'btn m-1',
+ 'a-class' => 'text-white',
+ ],
+ 'boxes' => [
+ 'render' => false
+ ],
+ ])
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/application/layouts/rtx_layout01/js/main.js b/application/layouts/rtx_layout01/js/main.js
new file mode 100644
index 000000000..6e8dc7479
--- /dev/null
+++ b/application/layouts/rtx_layout01/js/main.js
@@ -0,0 +1,76 @@
+
+(function() {
+ "use strict";
+
+ /**
+ * Easy selector helper function
+ */
+ const select = (el, all = false) => {
+ el = el.trim()
+ if (all) {
+ return [...document.querySelectorAll(el)]
+ } else {
+ return document.querySelector(el)
+ }
+ }
+
+ /**
+ * Easy event listener function
+ */
+ const on = (type, el, listener, all = false) => {
+ let selectEl = select(el, all)
+ if (selectEl) {
+ if (all) {
+ selectEl.forEach(e => e.addEventListener(type, listener))
+ } else {
+ selectEl.addEventListener(type, listener)
+ }
+ }
+ }
+
+ /**
+ * Easy on scroll event listener
+ */
+ const onscroll = (el, listener) => {
+ el.addEventListener('scroll', listener)
+ }
+
+ /**
+ * Mobile nav toggle
+ */
+ on('click', '.mobile-nav-toggle', function(e) {
+ select('#navbar').classList.toggle('navbar-mobile')
+ this.classList.toggle('fa-solid fa-list')
+
+ })
+
+
+
+ /**
+ * Back to top button
+ */
+ let backtotop = select('.back-to-top')
+ if (backtotop) {
+ const toggleBacktotop = () => {
+ if (window.scrollY > 100) {
+ backtotop.classList.add('active')
+ } else {
+ backtotop.classList.remove('active')
+ }
+ }
+ window.addEventListener('load', toggleBacktotop)
+ onscroll(document, toggleBacktotop)
+ }
+
+ /**
+ * Animation on scroll
+ */
+ window.addEventListener('load', () => {
+ AOS.init({
+ duration: 1000,
+ easing: "ease-in-out",
+ once: true,
+ mirror: false
+ });
+ });
+})()
diff --git a/application/layouts/rtx_layout01/translations/de.php b/application/layouts/rtx_layout01/translations/de.php
new file mode 100644
index 000000000..e8c4c3b5b
--- /dev/null
+++ b/application/layouts/rtx_layout01/translations/de.php
@@ -0,0 +1,17 @@
+ 'Ilch CMS',
+ 'heroH2' => 'Du hast einen Clan, eine Community oder willst eine eigene private Homepage erstellen?',
+ 'heroButton' => 'Kostenloser Download',
+ /* Footer */
+ 'footerLinksH4' => 'Soziale Netzwerke',
+ 'footerLinksText' => 'Besuche uns auf diesen Plattformen',
+
+
+];
diff --git a/application/layouts/rtx_layout01/translations/en.php b/application/layouts/rtx_layout01/translations/en.php
new file mode 100644
index 000000000..fd35baf64
--- /dev/null
+++ b/application/layouts/rtx_layout01/translations/en.php
@@ -0,0 +1,15 @@
+ 'Ilch CMS',
+ 'heroH2' => 'Do you have a clan, a community or want to create your own private homepage?',
+ 'heroButton' => 'Free Download',
+ /* Footer */
+ 'footerLinks' => 'Social networks',
+ 'footerLinksText' => 'Visit us on these platforms',
+];
diff --git a/application/layouts/rtx_layout01/vendor/aos/aos.css b/application/layouts/rtx_layout01/vendor/aos/aos.css
new file mode 100644
index 000000000..66923fe6a
--- /dev/null
+++ b/application/layouts/rtx_layout01/vendor/aos/aos.css
@@ -0,0 +1 @@
+[data-aos][data-aos][data-aos-duration="50"],body[data-aos-duration="50"] [data-aos]{transition-duration:50ms}[data-aos][data-aos][data-aos-delay="50"],body[data-aos-delay="50"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="50"].aos-animate,body[data-aos-delay="50"] [data-aos].aos-animate{transition-delay:50ms}[data-aos][data-aos][data-aos-duration="100"],body[data-aos-duration="100"] [data-aos]{transition-duration:.1s}[data-aos][data-aos][data-aos-delay="100"],body[data-aos-delay="100"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="100"].aos-animate,body[data-aos-delay="100"] [data-aos].aos-animate{transition-delay:.1s}[data-aos][data-aos][data-aos-duration="150"],body[data-aos-duration="150"] [data-aos]{transition-duration:.15s}[data-aos][data-aos][data-aos-delay="150"],body[data-aos-delay="150"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="150"].aos-animate,body[data-aos-delay="150"] [data-aos].aos-animate{transition-delay:.15s}[data-aos][data-aos][data-aos-duration="200"],body[data-aos-duration="200"] [data-aos]{transition-duration:.2s}[data-aos][data-aos][data-aos-delay="200"],body[data-aos-delay="200"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="200"].aos-animate,body[data-aos-delay="200"] [data-aos].aos-animate{transition-delay:.2s}[data-aos][data-aos][data-aos-duration="250"],body[data-aos-duration="250"] [data-aos]{transition-duration:.25s}[data-aos][data-aos][data-aos-delay="250"],body[data-aos-delay="250"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="250"].aos-animate,body[data-aos-delay="250"] [data-aos].aos-animate{transition-delay:.25s}[data-aos][data-aos][data-aos-duration="300"],body[data-aos-duration="300"] [data-aos]{transition-duration:.3s}[data-aos][data-aos][data-aos-delay="300"],body[data-aos-delay="300"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="300"].aos-animate,body[data-aos-delay="300"] [data-aos].aos-animate{transition-delay:.3s}[data-aos][data-aos][data-aos-duration="350"],body[data-aos-duration="350"] [data-aos]{transition-duration:.35s}[data-aos][data-aos][data-aos-delay="350"],body[data-aos-delay="350"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="350"].aos-animate,body[data-aos-delay="350"] [data-aos].aos-animate{transition-delay:.35s}[data-aos][data-aos][data-aos-duration="400"],body[data-aos-duration="400"] [data-aos]{transition-duration:.4s}[data-aos][data-aos][data-aos-delay="400"],body[data-aos-delay="400"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="400"].aos-animate,body[data-aos-delay="400"] [data-aos].aos-animate{transition-delay:.4s}[data-aos][data-aos][data-aos-duration="450"],body[data-aos-duration="450"] [data-aos]{transition-duration:.45s}[data-aos][data-aos][data-aos-delay="450"],body[data-aos-delay="450"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="450"].aos-animate,body[data-aos-delay="450"] [data-aos].aos-animate{transition-delay:.45s}[data-aos][data-aos][data-aos-duration="500"],body[data-aos-duration="500"] [data-aos]{transition-duration:.5s}[data-aos][data-aos][data-aos-delay="500"],body[data-aos-delay="500"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="500"].aos-animate,body[data-aos-delay="500"] [data-aos].aos-animate{transition-delay:.5s}[data-aos][data-aos][data-aos-duration="550"],body[data-aos-duration="550"] [data-aos]{transition-duration:.55s}[data-aos][data-aos][data-aos-delay="550"],body[data-aos-delay="550"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="550"].aos-animate,body[data-aos-delay="550"] [data-aos].aos-animate{transition-delay:.55s}[data-aos][data-aos][data-aos-duration="600"],body[data-aos-duration="600"] [data-aos]{transition-duration:.6s}[data-aos][data-aos][data-aos-delay="600"],body[data-aos-delay="600"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="600"].aos-animate,body[data-aos-delay="600"] [data-aos].aos-animate{transition-delay:.6s}[data-aos][data-aos][data-aos-duration="650"],body[data-aos-duration="650"] [data-aos]{transition-duration:.65s}[data-aos][data-aos][data-aos-delay="650"],body[data-aos-delay="650"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="650"].aos-animate,body[data-aos-delay="650"] [data-aos].aos-animate{transition-delay:.65s}[data-aos][data-aos][data-aos-duration="700"],body[data-aos-duration="700"] [data-aos]{transition-duration:.7s}[data-aos][data-aos][data-aos-delay="700"],body[data-aos-delay="700"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="700"].aos-animate,body[data-aos-delay="700"] [data-aos].aos-animate{transition-delay:.7s}[data-aos][data-aos][data-aos-duration="750"],body[data-aos-duration="750"] [data-aos]{transition-duration:.75s}[data-aos][data-aos][data-aos-delay="750"],body[data-aos-delay="750"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="750"].aos-animate,body[data-aos-delay="750"] [data-aos].aos-animate{transition-delay:.75s}[data-aos][data-aos][data-aos-duration="800"],body[data-aos-duration="800"] [data-aos]{transition-duration:.8s}[data-aos][data-aos][data-aos-delay="800"],body[data-aos-delay="800"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="800"].aos-animate,body[data-aos-delay="800"] [data-aos].aos-animate{transition-delay:.8s}[data-aos][data-aos][data-aos-duration="850"],body[data-aos-duration="850"] [data-aos]{transition-duration:.85s}[data-aos][data-aos][data-aos-delay="850"],body[data-aos-delay="850"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="850"].aos-animate,body[data-aos-delay="850"] [data-aos].aos-animate{transition-delay:.85s}[data-aos][data-aos][data-aos-duration="900"],body[data-aos-duration="900"] [data-aos]{transition-duration:.9s}[data-aos][data-aos][data-aos-delay="900"],body[data-aos-delay="900"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="900"].aos-animate,body[data-aos-delay="900"] [data-aos].aos-animate{transition-delay:.9s}[data-aos][data-aos][data-aos-duration="950"],body[data-aos-duration="950"] [data-aos]{transition-duration:.95s}[data-aos][data-aos][data-aos-delay="950"],body[data-aos-delay="950"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="950"].aos-animate,body[data-aos-delay="950"] [data-aos].aos-animate{transition-delay:.95s}[data-aos][data-aos][data-aos-duration="1000"],body[data-aos-duration="1000"] [data-aos]{transition-duration:1s}[data-aos][data-aos][data-aos-delay="1000"],body[data-aos-delay="1000"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1000"].aos-animate,body[data-aos-delay="1000"] [data-aos].aos-animate{transition-delay:1s}[data-aos][data-aos][data-aos-duration="1050"],body[data-aos-duration="1050"] [data-aos]{transition-duration:1.05s}[data-aos][data-aos][data-aos-delay="1050"],body[data-aos-delay="1050"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1050"].aos-animate,body[data-aos-delay="1050"] [data-aos].aos-animate{transition-delay:1.05s}[data-aos][data-aos][data-aos-duration="1100"],body[data-aos-duration="1100"] [data-aos]{transition-duration:1.1s}[data-aos][data-aos][data-aos-delay="1100"],body[data-aos-delay="1100"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1100"].aos-animate,body[data-aos-delay="1100"] [data-aos].aos-animate{transition-delay:1.1s}[data-aos][data-aos][data-aos-duration="1150"],body[data-aos-duration="1150"] [data-aos]{transition-duration:1.15s}[data-aos][data-aos][data-aos-delay="1150"],body[data-aos-delay="1150"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1150"].aos-animate,body[data-aos-delay="1150"] [data-aos].aos-animate{transition-delay:1.15s}[data-aos][data-aos][data-aos-duration="1200"],body[data-aos-duration="1200"] [data-aos]{transition-duration:1.2s}[data-aos][data-aos][data-aos-delay="1200"],body[data-aos-delay="1200"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1200"].aos-animate,body[data-aos-delay="1200"] [data-aos].aos-animate{transition-delay:1.2s}[data-aos][data-aos][data-aos-duration="1250"],body[data-aos-duration="1250"] [data-aos]{transition-duration:1.25s}[data-aos][data-aos][data-aos-delay="1250"],body[data-aos-delay="1250"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1250"].aos-animate,body[data-aos-delay="1250"] [data-aos].aos-animate{transition-delay:1.25s}[data-aos][data-aos][data-aos-duration="1300"],body[data-aos-duration="1300"] [data-aos]{transition-duration:1.3s}[data-aos][data-aos][data-aos-delay="1300"],body[data-aos-delay="1300"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1300"].aos-animate,body[data-aos-delay="1300"] [data-aos].aos-animate{transition-delay:1.3s}[data-aos][data-aos][data-aos-duration="1350"],body[data-aos-duration="1350"] [data-aos]{transition-duration:1.35s}[data-aos][data-aos][data-aos-delay="1350"],body[data-aos-delay="1350"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1350"].aos-animate,body[data-aos-delay="1350"] [data-aos].aos-animate{transition-delay:1.35s}[data-aos][data-aos][data-aos-duration="1400"],body[data-aos-duration="1400"] [data-aos]{transition-duration:1.4s}[data-aos][data-aos][data-aos-delay="1400"],body[data-aos-delay="1400"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1400"].aos-animate,body[data-aos-delay="1400"] [data-aos].aos-animate{transition-delay:1.4s}[data-aos][data-aos][data-aos-duration="1450"],body[data-aos-duration="1450"] [data-aos]{transition-duration:1.45s}[data-aos][data-aos][data-aos-delay="1450"],body[data-aos-delay="1450"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1450"].aos-animate,body[data-aos-delay="1450"] [data-aos].aos-animate{transition-delay:1.45s}[data-aos][data-aos][data-aos-duration="1500"],body[data-aos-duration="1500"] [data-aos]{transition-duration:1.5s}[data-aos][data-aos][data-aos-delay="1500"],body[data-aos-delay="1500"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1500"].aos-animate,body[data-aos-delay="1500"] [data-aos].aos-animate{transition-delay:1.5s}[data-aos][data-aos][data-aos-duration="1550"],body[data-aos-duration="1550"] [data-aos]{transition-duration:1.55s}[data-aos][data-aos][data-aos-delay="1550"],body[data-aos-delay="1550"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1550"].aos-animate,body[data-aos-delay="1550"] [data-aos].aos-animate{transition-delay:1.55s}[data-aos][data-aos][data-aos-duration="1600"],body[data-aos-duration="1600"] [data-aos]{transition-duration:1.6s}[data-aos][data-aos][data-aos-delay="1600"],body[data-aos-delay="1600"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1600"].aos-animate,body[data-aos-delay="1600"] [data-aos].aos-animate{transition-delay:1.6s}[data-aos][data-aos][data-aos-duration="1650"],body[data-aos-duration="1650"] [data-aos]{transition-duration:1.65s}[data-aos][data-aos][data-aos-delay="1650"],body[data-aos-delay="1650"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1650"].aos-animate,body[data-aos-delay="1650"] [data-aos].aos-animate{transition-delay:1.65s}[data-aos][data-aos][data-aos-duration="1700"],body[data-aos-duration="1700"] [data-aos]{transition-duration:1.7s}[data-aos][data-aos][data-aos-delay="1700"],body[data-aos-delay="1700"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1700"].aos-animate,body[data-aos-delay="1700"] [data-aos].aos-animate{transition-delay:1.7s}[data-aos][data-aos][data-aos-duration="1750"],body[data-aos-duration="1750"] [data-aos]{transition-duration:1.75s}[data-aos][data-aos][data-aos-delay="1750"],body[data-aos-delay="1750"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1750"].aos-animate,body[data-aos-delay="1750"] [data-aos].aos-animate{transition-delay:1.75s}[data-aos][data-aos][data-aos-duration="1800"],body[data-aos-duration="1800"] [data-aos]{transition-duration:1.8s}[data-aos][data-aos][data-aos-delay="1800"],body[data-aos-delay="1800"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1800"].aos-animate,body[data-aos-delay="1800"] [data-aos].aos-animate{transition-delay:1.8s}[data-aos][data-aos][data-aos-duration="1850"],body[data-aos-duration="1850"] [data-aos]{transition-duration:1.85s}[data-aos][data-aos][data-aos-delay="1850"],body[data-aos-delay="1850"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1850"].aos-animate,body[data-aos-delay="1850"] [data-aos].aos-animate{transition-delay:1.85s}[data-aos][data-aos][data-aos-duration="1900"],body[data-aos-duration="1900"] [data-aos]{transition-duration:1.9s}[data-aos][data-aos][data-aos-delay="1900"],body[data-aos-delay="1900"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1900"].aos-animate,body[data-aos-delay="1900"] [data-aos].aos-animate{transition-delay:1.9s}[data-aos][data-aos][data-aos-duration="1950"],body[data-aos-duration="1950"] [data-aos]{transition-duration:1.95s}[data-aos][data-aos][data-aos-delay="1950"],body[data-aos-delay="1950"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="1950"].aos-animate,body[data-aos-delay="1950"] [data-aos].aos-animate{transition-delay:1.95s}[data-aos][data-aos][data-aos-duration="2000"],body[data-aos-duration="2000"] [data-aos]{transition-duration:2s}[data-aos][data-aos][data-aos-delay="2000"],body[data-aos-delay="2000"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2000"].aos-animate,body[data-aos-delay="2000"] [data-aos].aos-animate{transition-delay:2s}[data-aos][data-aos][data-aos-duration="2050"],body[data-aos-duration="2050"] [data-aos]{transition-duration:2.05s}[data-aos][data-aos][data-aos-delay="2050"],body[data-aos-delay="2050"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2050"].aos-animate,body[data-aos-delay="2050"] [data-aos].aos-animate{transition-delay:2.05s}[data-aos][data-aos][data-aos-duration="2100"],body[data-aos-duration="2100"] [data-aos]{transition-duration:2.1s}[data-aos][data-aos][data-aos-delay="2100"],body[data-aos-delay="2100"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2100"].aos-animate,body[data-aos-delay="2100"] [data-aos].aos-animate{transition-delay:2.1s}[data-aos][data-aos][data-aos-duration="2150"],body[data-aos-duration="2150"] [data-aos]{transition-duration:2.15s}[data-aos][data-aos][data-aos-delay="2150"],body[data-aos-delay="2150"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2150"].aos-animate,body[data-aos-delay="2150"] [data-aos].aos-animate{transition-delay:2.15s}[data-aos][data-aos][data-aos-duration="2200"],body[data-aos-duration="2200"] [data-aos]{transition-duration:2.2s}[data-aos][data-aos][data-aos-delay="2200"],body[data-aos-delay="2200"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2200"].aos-animate,body[data-aos-delay="2200"] [data-aos].aos-animate{transition-delay:2.2s}[data-aos][data-aos][data-aos-duration="2250"],body[data-aos-duration="2250"] [data-aos]{transition-duration:2.25s}[data-aos][data-aos][data-aos-delay="2250"],body[data-aos-delay="2250"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2250"].aos-animate,body[data-aos-delay="2250"] [data-aos].aos-animate{transition-delay:2.25s}[data-aos][data-aos][data-aos-duration="2300"],body[data-aos-duration="2300"] [data-aos]{transition-duration:2.3s}[data-aos][data-aos][data-aos-delay="2300"],body[data-aos-delay="2300"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2300"].aos-animate,body[data-aos-delay="2300"] [data-aos].aos-animate{transition-delay:2.3s}[data-aos][data-aos][data-aos-duration="2350"],body[data-aos-duration="2350"] [data-aos]{transition-duration:2.35s}[data-aos][data-aos][data-aos-delay="2350"],body[data-aos-delay="2350"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2350"].aos-animate,body[data-aos-delay="2350"] [data-aos].aos-animate{transition-delay:2.35s}[data-aos][data-aos][data-aos-duration="2400"],body[data-aos-duration="2400"] [data-aos]{transition-duration:2.4s}[data-aos][data-aos][data-aos-delay="2400"],body[data-aos-delay="2400"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2400"].aos-animate,body[data-aos-delay="2400"] [data-aos].aos-animate{transition-delay:2.4s}[data-aos][data-aos][data-aos-duration="2450"],body[data-aos-duration="2450"] [data-aos]{transition-duration:2.45s}[data-aos][data-aos][data-aos-delay="2450"],body[data-aos-delay="2450"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2450"].aos-animate,body[data-aos-delay="2450"] [data-aos].aos-animate{transition-delay:2.45s}[data-aos][data-aos][data-aos-duration="2500"],body[data-aos-duration="2500"] [data-aos]{transition-duration:2.5s}[data-aos][data-aos][data-aos-delay="2500"],body[data-aos-delay="2500"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2500"].aos-animate,body[data-aos-delay="2500"] [data-aos].aos-animate{transition-delay:2.5s}[data-aos][data-aos][data-aos-duration="2550"],body[data-aos-duration="2550"] [data-aos]{transition-duration:2.55s}[data-aos][data-aos][data-aos-delay="2550"],body[data-aos-delay="2550"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2550"].aos-animate,body[data-aos-delay="2550"] [data-aos].aos-animate{transition-delay:2.55s}[data-aos][data-aos][data-aos-duration="2600"],body[data-aos-duration="2600"] [data-aos]{transition-duration:2.6s}[data-aos][data-aos][data-aos-delay="2600"],body[data-aos-delay="2600"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2600"].aos-animate,body[data-aos-delay="2600"] [data-aos].aos-animate{transition-delay:2.6s}[data-aos][data-aos][data-aos-duration="2650"],body[data-aos-duration="2650"] [data-aos]{transition-duration:2.65s}[data-aos][data-aos][data-aos-delay="2650"],body[data-aos-delay="2650"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2650"].aos-animate,body[data-aos-delay="2650"] [data-aos].aos-animate{transition-delay:2.65s}[data-aos][data-aos][data-aos-duration="2700"],body[data-aos-duration="2700"] [data-aos]{transition-duration:2.7s}[data-aos][data-aos][data-aos-delay="2700"],body[data-aos-delay="2700"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2700"].aos-animate,body[data-aos-delay="2700"] [data-aos].aos-animate{transition-delay:2.7s}[data-aos][data-aos][data-aos-duration="2750"],body[data-aos-duration="2750"] [data-aos]{transition-duration:2.75s}[data-aos][data-aos][data-aos-delay="2750"],body[data-aos-delay="2750"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2750"].aos-animate,body[data-aos-delay="2750"] [data-aos].aos-animate{transition-delay:2.75s}[data-aos][data-aos][data-aos-duration="2800"],body[data-aos-duration="2800"] [data-aos]{transition-duration:2.8s}[data-aos][data-aos][data-aos-delay="2800"],body[data-aos-delay="2800"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2800"].aos-animate,body[data-aos-delay="2800"] [data-aos].aos-animate{transition-delay:2.8s}[data-aos][data-aos][data-aos-duration="2850"],body[data-aos-duration="2850"] [data-aos]{transition-duration:2.85s}[data-aos][data-aos][data-aos-delay="2850"],body[data-aos-delay="2850"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2850"].aos-animate,body[data-aos-delay="2850"] [data-aos].aos-animate{transition-delay:2.85s}[data-aos][data-aos][data-aos-duration="2900"],body[data-aos-duration="2900"] [data-aos]{transition-duration:2.9s}[data-aos][data-aos][data-aos-delay="2900"],body[data-aos-delay="2900"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2900"].aos-animate,body[data-aos-delay="2900"] [data-aos].aos-animate{transition-delay:2.9s}[data-aos][data-aos][data-aos-duration="2950"],body[data-aos-duration="2950"] [data-aos]{transition-duration:2.95s}[data-aos][data-aos][data-aos-delay="2950"],body[data-aos-delay="2950"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="2950"].aos-animate,body[data-aos-delay="2950"] [data-aos].aos-animate{transition-delay:2.95s}[data-aos][data-aos][data-aos-duration="3000"],body[data-aos-duration="3000"] [data-aos]{transition-duration:3s}[data-aos][data-aos][data-aos-delay="3000"],body[data-aos-delay="3000"] [data-aos]{transition-delay:0}[data-aos][data-aos][data-aos-delay="3000"].aos-animate,body[data-aos-delay="3000"] [data-aos].aos-animate{transition-delay:3s}[data-aos][data-aos][data-aos-easing=linear],body[data-aos-easing=linear] [data-aos]{transition-timing-function:cubic-bezier(.25,.25,.75,.75)}[data-aos][data-aos][data-aos-easing=ease],body[data-aos-easing=ease] [data-aos]{transition-timing-function:ease}[data-aos][data-aos][data-aos-easing=ease-in],body[data-aos-easing=ease-in] [data-aos]{transition-timing-function:ease-in}[data-aos][data-aos][data-aos-easing=ease-out],body[data-aos-easing=ease-out] [data-aos]{transition-timing-function:ease-out}[data-aos][data-aos][data-aos-easing=ease-in-out],body[data-aos-easing=ease-in-out] [data-aos]{transition-timing-function:ease-in-out}[data-aos][data-aos][data-aos-easing=ease-in-back],body[data-aos-easing=ease-in-back] [data-aos]{transition-timing-function:cubic-bezier(.6,-.28,.735,.045)}[data-aos][data-aos][data-aos-easing=ease-out-back],body[data-aos-easing=ease-out-back] [data-aos]{transition-timing-function:cubic-bezier(.175,.885,.32,1.275)}[data-aos][data-aos][data-aos-easing=ease-in-out-back],body[data-aos-easing=ease-in-out-back] [data-aos]{transition-timing-function:cubic-bezier(.68,-.55,.265,1.55)}[data-aos][data-aos][data-aos-easing=ease-in-sine],body[data-aos-easing=ease-in-sine] [data-aos]{transition-timing-function:cubic-bezier(.47,0,.745,.715)}[data-aos][data-aos][data-aos-easing=ease-out-sine],body[data-aos-easing=ease-out-sine] [data-aos]{transition-timing-function:cubic-bezier(.39,.575,.565,1)}[data-aos][data-aos][data-aos-easing=ease-in-out-sine],body[data-aos-easing=ease-in-out-sine] [data-aos]{transition-timing-function:cubic-bezier(.445,.05,.55,.95)}[data-aos][data-aos][data-aos-easing=ease-in-quad],body[data-aos-easing=ease-in-quad] [data-aos]{transition-timing-function:cubic-bezier(.55,.085,.68,.53)}[data-aos][data-aos][data-aos-easing=ease-out-quad],body[data-aos-easing=ease-out-quad] [data-aos]{transition-timing-function:cubic-bezier(.25,.46,.45,.94)}[data-aos][data-aos][data-aos-easing=ease-in-out-quad],body[data-aos-easing=ease-in-out-quad] [data-aos]{transition-timing-function:cubic-bezier(.455,.03,.515,.955)}[data-aos][data-aos][data-aos-easing=ease-in-cubic],body[data-aos-easing=ease-in-cubic] [data-aos]{transition-timing-function:cubic-bezier(.55,.085,.68,.53)}[data-aos][data-aos][data-aos-easing=ease-out-cubic],body[data-aos-easing=ease-out-cubic] [data-aos]{transition-timing-function:cubic-bezier(.25,.46,.45,.94)}[data-aos][data-aos][data-aos-easing=ease-in-out-cubic],body[data-aos-easing=ease-in-out-cubic] [data-aos]{transition-timing-function:cubic-bezier(.455,.03,.515,.955)}[data-aos][data-aos][data-aos-easing=ease-in-quart],body[data-aos-easing=ease-in-quart] [data-aos]{transition-timing-function:cubic-bezier(.55,.085,.68,.53)}[data-aos][data-aos][data-aos-easing=ease-out-quart],body[data-aos-easing=ease-out-quart] [data-aos]{transition-timing-function:cubic-bezier(.25,.46,.45,.94)}[data-aos][data-aos][data-aos-easing=ease-in-out-quart],body[data-aos-easing=ease-in-out-quart] [data-aos]{transition-timing-function:cubic-bezier(.455,.03,.515,.955)}[data-aos^=fade][data-aos^=fade]{opacity:0;transition-property:opacity,transform}[data-aos^=fade][data-aos^=fade].aos-animate{opacity:1;transform:translateZ(0)}[data-aos=fade-up]{transform:translate3d(0,100px,0)}[data-aos=fade-down]{transform:translate3d(0,-100px,0)}[data-aos=fade-right]{transform:translate3d(-100px,0,0)}[data-aos=fade-left]{transform:translate3d(100px,0,0)}[data-aos=fade-up-right]{transform:translate3d(-100px,100px,0)}[data-aos=fade-up-left]{transform:translate3d(100px,100px,0)}[data-aos=fade-down-right]{transform:translate3d(-100px,-100px,0)}[data-aos=fade-down-left]{transform:translate3d(100px,-100px,0)}[data-aos^=zoom][data-aos^=zoom]{opacity:0;transition-property:opacity,transform}[data-aos^=zoom][data-aos^=zoom].aos-animate{opacity:1;transform:translateZ(0) scale(1)}[data-aos=zoom-in]{transform:scale(.6)}[data-aos=zoom-in-up]{transform:translate3d(0,100px,0) scale(.6)}[data-aos=zoom-in-down]{transform:translate3d(0,-100px,0) scale(.6)}[data-aos=zoom-in-right]{transform:translate3d(-100px,0,0) scale(.6)}[data-aos=zoom-in-left]{transform:translate3d(100px,0,0) scale(.6)}[data-aos=zoom-out]{transform:scale(1.2)}[data-aos=zoom-out-up]{transform:translate3d(0,100px,0) scale(1.2)}[data-aos=zoom-out-down]{transform:translate3d(0,-100px,0) scale(1.2)}[data-aos=zoom-out-right]{transform:translate3d(-100px,0,0) scale(1.2)}[data-aos=zoom-out-left]{transform:translate3d(100px,0,0) scale(1.2)}[data-aos^=slide][data-aos^=slide]{transition-property:transform}[data-aos^=slide][data-aos^=slide].aos-animate{transform:translateZ(0)}[data-aos=slide-up]{transform:translate3d(0,100%,0)}[data-aos=slide-down]{transform:translate3d(0,-100%,0)}[data-aos=slide-right]{transform:translate3d(-100%,0,0)}[data-aos=slide-left]{transform:translate3d(100%,0,0)}[data-aos^=flip][data-aos^=flip]{backface-visibility:hidden;transition-property:transform}[data-aos=flip-left]{transform:perspective(2500px) rotateY(-100deg)}[data-aos=flip-left].aos-animate{transform:perspective(2500px) rotateY(0)}[data-aos=flip-right]{transform:perspective(2500px) rotateY(100deg)}[data-aos=flip-right].aos-animate{transform:perspective(2500px) rotateY(0)}[data-aos=flip-up]{transform:perspective(2500px) rotateX(-100deg)}[data-aos=flip-up].aos-animate{transform:perspective(2500px) rotateX(0)}[data-aos=flip-down]{transform:perspective(2500px) rotateX(100deg)}[data-aos=flip-down].aos-animate{transform:perspective(2500px) rotateX(0)}
\ No newline at end of file
diff --git a/application/layouts/rtx_layout01/vendor/aos/aos.js b/application/layouts/rtx_layout01/vendor/aos/aos.js
new file mode 100644
index 000000000..86dc4bfac
--- /dev/null
+++ b/application/layouts/rtx_layout01/vendor/aos/aos.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.AOS=t():e.AOS=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="dist/",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}var i=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]&&arguments[0];if(e&&(k=!0),k)return w=(0,y.default)(w,x),(0,b.default)(w,x.once),w},O=function(){w=(0,h.default)(),j()},M=function(){w.forEach(function(e,t){e.node.removeAttribute("data-aos"),e.node.removeAttribute("data-aos-easing"),e.node.removeAttribute("data-aos-duration"),e.node.removeAttribute("data-aos-delay")})},S=function(e){return e===!0||"mobile"===e&&p.default.mobile()||"phone"===e&&p.default.phone()||"tablet"===e&&p.default.tablet()||"function"==typeof e&&e()===!0},_=function(e){x=i(x,e),w=(0,h.default)();var t=document.all&&!window.atob;return S(x.disable)||t?M():(x.disableMutationObserver||d.default.isSupported()||(console.info('\n aos: MutationObserver is not supported on this browser,\n code mutations observing has been disabled.\n You may have to call "refreshHard()" by yourself.\n '),x.disableMutationObserver=!0),document.querySelector("body").setAttribute("data-aos-easing",x.easing),document.querySelector("body").setAttribute("data-aos-duration",x.duration),document.querySelector("body").setAttribute("data-aos-delay",x.delay),"DOMContentLoaded"===x.startEvent&&["complete","interactive"].indexOf(document.readyState)>-1?j(!0):"load"===x.startEvent?window.addEventListener(x.startEvent,function(){j(!0)}):document.addEventListener(x.startEvent,function(){j(!0)}),window.addEventListener("resize",(0,s.default)(j,x.debounceDelay,!0)),window.addEventListener("orientationchange",(0,s.default)(j,x.debounceDelay,!0)),window.addEventListener("scroll",(0,u.default)(function(){(0,b.default)(w,x.once)},x.throttleDelay)),x.disableMutationObserver||d.default.ready("[data-aos]",O),w)};e.exports={init:_,refresh:j,refreshHard:O}},function(e,t){},,,,,function(e,t){(function(t){"use strict";function n(e,t,n){function o(t){var n=b,o=v;return b=v=void 0,k=t,g=e.apply(o,n)}function r(e){return k=e,h=setTimeout(f,t),M?o(e):g}function a(e){var n=e-w,o=e-k,i=t-n;return S?j(i,y-o):i}function c(e){var n=e-w,o=e-k;return void 0===w||n>=t||n<0||S&&o>=y}function f(){var e=O();return c(e)?d(e):void(h=setTimeout(f,a(e)))}function d(e){return h=void 0,_&&b?o(e):(b=v=void 0,g)}function l(){void 0!==h&&clearTimeout(h),k=0,b=w=v=h=void 0}function p(){return void 0===h?g:d(O())}function m(){var e=O(),n=c(e);if(b=arguments,v=this,w=e,n){if(void 0===h)return r(w);if(S)return h=setTimeout(f,t),o(w)}return void 0===h&&(h=setTimeout(f,t)),g}var b,v,y,g,h,w,k=0,M=!1,S=!1,_=!0;if("function"!=typeof e)throw new TypeError(s);return t=u(t)||0,i(n)&&(M=!!n.leading,S="maxWait"in n,y=S?x(u(n.maxWait)||0,t):y,_="trailing"in n?!!n.trailing:_),m.cancel=l,m.flush=p,m}function o(e,t,o){var r=!0,a=!0;if("function"!=typeof e)throw new TypeError(s);return i(o)&&(r="leading"in o?!!o.leading:r,a="trailing"in o?!!o.trailing:a),n(e,t,{leading:r,maxWait:t,trailing:a})}function i(e){var t="undefined"==typeof e?"undefined":c(e);return!!e&&("object"==t||"function"==t)}function r(e){return!!e&&"object"==("undefined"==typeof e?"undefined":c(e))}function a(e){return"symbol"==("undefined"==typeof e?"undefined":c(e))||r(e)&&k.call(e)==d}function u(e){if("number"==typeof e)return e;if(a(e))return f;if(i(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=i(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(l,"");var n=m.test(e);return n||b.test(e)?v(e.slice(2),n?2:8):p.test(e)?f:+e}var c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},s="Expected a function",f=NaN,d="[object Symbol]",l=/^\s+|\s+$/g,p=/^[-+]0x[0-9a-f]+$/i,m=/^0b[01]+$/i,b=/^0o[0-7]+$/i,v=parseInt,y="object"==("undefined"==typeof t?"undefined":c(t))&&t&&t.Object===Object&&t,g="object"==("undefined"==typeof self?"undefined":c(self))&&self&&self.Object===Object&&self,h=y||g||Function("return this")(),w=Object.prototype,k=w.toString,x=Math.max,j=Math.min,O=function(){return h.Date.now()};e.exports=o}).call(t,function(){return this}())},function(e,t){(function(t){"use strict";function n(e,t,n){function i(t){var n=b,o=v;return b=v=void 0,O=t,g=e.apply(o,n)}function r(e){return O=e,h=setTimeout(f,t),M?i(e):g}function u(e){var n=e-w,o=e-O,i=t-n;return S?x(i,y-o):i}function s(e){var n=e-w,o=e-O;return void 0===w||n>=t||n<0||S&&o>=y}function f(){var e=j();return s(e)?d(e):void(h=setTimeout(f,u(e)))}function d(e){return h=void 0,_&&b?i(e):(b=v=void 0,g)}function l(){void 0!==h&&clearTimeout(h),O=0,b=w=v=h=void 0}function p(){return void 0===h?g:d(j())}function m(){var e=j(),n=s(e);if(b=arguments,v=this,w=e,n){if(void 0===h)return r(w);if(S)return h=setTimeout(f,t),i(w)}return void 0===h&&(h=setTimeout(f,t)),g}var b,v,y,g,h,w,O=0,M=!1,S=!1,_=!0;if("function"!=typeof e)throw new TypeError(c);return t=a(t)||0,o(n)&&(M=!!n.leading,S="maxWait"in n,y=S?k(a(n.maxWait)||0,t):y,_="trailing"in n?!!n.trailing:_),m.cancel=l,m.flush=p,m}function o(e){var t="undefined"==typeof e?"undefined":u(e);return!!e&&("object"==t||"function"==t)}function i(e){return!!e&&"object"==("undefined"==typeof e?"undefined":u(e))}function r(e){return"symbol"==("undefined"==typeof e?"undefined":u(e))||i(e)&&w.call(e)==f}function a(e){if("number"==typeof e)return e;if(r(e))return s;if(o(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=o(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(d,"");var n=p.test(e);return n||m.test(e)?b(e.slice(2),n?2:8):l.test(e)?s:+e}var u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},c="Expected a function",s=NaN,f="[object Symbol]",d=/^\s+|\s+$/g,l=/^[-+]0x[0-9a-f]+$/i,p=/^0b[01]+$/i,m=/^0o[0-7]+$/i,b=parseInt,v="object"==("undefined"==typeof t?"undefined":u(t))&&t&&t.Object===Object&&t,y="object"==("undefined"==typeof self?"undefined":u(self))&&self&&self.Object===Object&&self,g=v||y||Function("return this")(),h=Object.prototype,w=h.toString,k=Math.max,x=Math.min,j=function(){return g.Date.now()};e.exports=n}).call(t,function(){return this}())},function(e,t){"use strict";function n(e){var t=void 0,o=void 0,i=void 0;for(t=0;te.position?e.node.classList.add("aos-animate"):"undefined"!=typeof o&&("false"===o||!n&&"true"!==o)&&e.node.classList.remove("aos-animate")},o=function(e,t){var o=window.pageYOffset,i=window.innerHeight;e.forEach(function(e,r){n(e,i+o,t)})};t.default=o},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(12),r=o(i),a=function(e,t){return e.forEach(function(e,n){e.node.classList.add("aos-init"),e.position=(0,r.default)(e.node,t.offset)}),e};t.default=a},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(13),r=o(i),a=function(e,t){var n=0,o=0,i=window.innerHeight,a={offset:e.getAttribute("data-aos-offset"),anchor:e.getAttribute("data-aos-anchor"),anchorPlacement:e.getAttribute("data-aos-anchor-placement")};switch(a.offset&&!isNaN(a.offset)&&(o=parseInt(a.offset)),a.anchor&&document.querySelectorAll(a.anchor)&&(e=document.querySelectorAll(a.anchor)[0]),n=(0,r.default)(e).top,a.anchorPlacement){case"top-bottom":break;case"center-bottom":n+=e.offsetHeight/2;break;case"bottom-bottom":n+=e.offsetHeight;break;case"top-center":n+=i/2;break;case"bottom-center":n+=i/2+e.offsetHeight;break;case"center-center":n+=i/2+e.offsetHeight/2;break;case"top-top":n+=i;break;case"bottom-top":n+=e.offsetHeight+i;break;case"center-top":n+=e.offsetHeight/2+i}return a.anchorPlacement||a.offset||isNaN(t)||(o=t),n+o};t.default=a},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e){for(var t=0,n=0;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)t+=e.offsetLeft-("BODY"!=e.tagName?e.scrollLeft:0),n+=e.offsetTop-("BODY"!=e.tagName?e.scrollTop:0),e=e.offsetParent;return{top:n,left:t}};t.default=n},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e){return e=e||document.querySelectorAll("[data-aos]"),Array.prototype.map.call(e,function(e){return{node:e}})};t.default=n}])});
\ No newline at end of file
diff --git a/application/libraries/Ilch/Upload.php b/application/libraries/Ilch/Upload.php
index 16d0fefa6..b595365ef 100644
--- a/application/libraries/Ilch/Upload.php
+++ b/application/libraries/Ilch/Upload.php
@@ -6,6 +6,8 @@
namespace Ilch;
+use Thumb\Thumbnail;
+
/**
* Ilch/Upload class.
*/
@@ -77,7 +79,7 @@ public function __construct()
/**
* Resets
*/
- public function reset()
+ public function reset(): Upload
{
$this->file = null;
$this->ending = null;
@@ -94,9 +96,9 @@ public function reset()
/**
* @param string $file
*
- * @return string File
+ * @return Upload File
*/
- public function setFile($file)
+ public function setFile(string $file): Upload
{
$this->file = $file;
@@ -106,7 +108,7 @@ public function setFile($file)
/**
* @return string
*/
- public function getFile()
+ public function getFile(): string
{
return $this->file;
}
@@ -114,9 +116,9 @@ public function getFile()
/**
* @param string $ending
*
- * @return string Ending
+ * @return Upload Ending
*/
- public function setEnding($ending)
+ public function setEnding(string $ending): Upload
{
$this->ending = $ending;
@@ -126,7 +128,7 @@ public function setEnding($ending)
/**
* @return string
*/
- public function getEnding()
+ public function getEnding(): string
{
$this->ending = strtolower(pathinfo($this->file, PATHINFO_EXTENSION));
@@ -136,9 +138,9 @@ public function getEnding()
/**
* @param string $name
*
- * @return string Name
+ * @return Upload Name
*/
- public function setName($name)
+ public function setName(string $name): Upload
{
$this->name = $name;
@@ -148,7 +150,7 @@ public function setName($name)
/**
* @return string
*/
- public function getName()
+ public function getName(): string
{
$this->name = pathinfo($this->file, PATHINFO_FILENAME);
@@ -158,9 +160,9 @@ public function getName()
/**
* @param string $fileName
*
- * @return string fileName
+ * @return Upload fileName
*/
- public function setFileName($fileName)
+ public function setFileName(string $fileName): Upload
{
$this->fileName = $fileName;
@@ -170,7 +172,7 @@ public function setFileName($fileName)
/**
* @return string
*/
- public function getFileName()
+ public function getFileName(): string
{
return $this->fileName;
}
@@ -178,9 +180,9 @@ public function getFileName()
/**
* @param string $url
*
- * @return string url
+ * @return Upload url
*/
- public function setUrl($url)
+ public function setUrl(string $url): Upload
{
$this->url = $url;
@@ -190,7 +192,7 @@ public function setUrl($url)
/**
* @return string
*/
- public function getUrl()
+ public function getUrl(): string
{
return $this->url;
}
@@ -198,9 +200,9 @@ public function getUrl()
/**
* @param string $types
*
- * @return string types
+ * @return Upload types
*/
- public function setTypes($types)
+ public function setTypes(string $types): Upload
{
$this->types = $types;
@@ -210,7 +212,7 @@ public function setTypes($types)
/**
* @return string
*/
- public function getTypes()
+ public function getTypes(): string
{
return $this->types;
}
@@ -218,9 +220,9 @@ public function getTypes()
/**
* @param string $allowedExtensions
*
- * @return string allowedExtensions
+ * @return Upload allowedExtensions
*/
- public function setAllowedExtensions($allowedExtensions)
+ public function setAllowedExtensions(string $allowedExtensions): Upload
{
$this->allowedExtensions = $allowedExtensions;
@@ -230,7 +232,7 @@ public function setAllowedExtensions($allowedExtensions)
/**
* @return string
*/
- public function getAllowedExtensions()
+ public function getAllowedExtensions(): string
{
return $this->allowedExtensions;
}
@@ -238,9 +240,9 @@ public function getAllowedExtensions()
/**
* @param string $path
*
- * @return string path
+ * @return Upload path
*/
- public function setPath($path)
+ public function setPath(string $path): Upload
{
$this->path = $path;
@@ -250,7 +252,7 @@ public function setPath($path)
/**
* @return string
*/
- public function getPath()
+ public function getPath(): string
{
return $this->path;
}
@@ -258,9 +260,9 @@ public function getPath()
/**
* @param string $urlThumb
*
- * @return string urlThumb
+ * @return Upload urlThumb
*/
- public function setUrlThumb($urlThumb)
+ public function setUrlThumb(string $urlThumb): Upload
{
$this->urlThumb = $urlThumb;
@@ -270,25 +272,23 @@ public function setUrlThumb($urlThumb)
/**
* @return string
*/
- public function getUrlThumb()
+ public function getUrlThumb(): string
{
return $this->urlThumb;
}
/**
+ * Get size of the file in a human readable form.
+ *
* @return string
+ * @since 2.0.0
*/
- public function getSize()
+ public function getSize(): string
{
$bytes = sprintf('%u', filesize($this->file));
if ($bytes > 0) {
- $unit = (int)log($bytes, 1024);
- $units = ['B', 'KB', 'MB', 'GB'];
-
- if (array_key_exists($unit, $units) === true) {
- return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]);
- }
+ return formatBytes($bytes);
}
return $bytes;
@@ -296,12 +296,20 @@ public function getSize()
/**
* Take an educated guess on how big the image is going to be in memory.
+ *
* @param string $imageFilePath
- * @return int required memory in bytes
+ * @return int|false required memory in bytes or false in case of an error.
+ * @since 2.0.0
+ * @since 2.1.54 returns false in case of an error.
*/
- public function guessRequiredMemory($imageFilePath)
+ public function guessRequiredMemory(string $imageFilePath)
{
$imageInfo = getimagesize($imageFilePath);
+
+ if ($imageInfo === false) {
+ return false;
+ }
+
if (empty($imageInfo['channels'])) {
$imageInfo['channels'] = 4;
}
@@ -309,24 +317,32 @@ public function guessRequiredMemory($imageFilePath)
// channels will be 3 for RGB pictures and 4 for CMYK pictures
// bits is the number of bits for each color.
// The tweak-factor might be overly careful and could therefore be lowered if necessary.
+ // After testing with >10k pictures the tweak factor got lowered to 1.9 (90 %) from 2.5 (150 %)
+ // With a tweak factor of 1.9 there were still no out of memory errors.
return ($imageInfo[0] * $imageInfo[1] * ($imageInfo['bits'] / 8) * $imageInfo['channels'] * 1.9);
}
/**
* Returns if there would likely be enough free memory for the image.
* Returns true in case of memory_limit = -1 e.g. no memory limit.
+ * Returns false if not an image or an error occured.
*
* @param string $imageFilePath
* @return bool
* @since 2.1.20
+ * @since 2.1.54 Returns false if not an image or an error occured.
*/
- public function enoughFreeMemory($imageFilePath)
+ public function enoughFreeMemory(string $imageFilePath): bool
{
$memoryLimit = ini_get('memory_limit');
if ($memoryLimit == '-1') {
return true;
}
+ if (getimagesize($imageFilePath) === false) {
+ return false;
+ }
+
if (($this->returnBytes($memoryLimit) - memory_get_usage(true)) < $this->guessRequiredMemory($imageFilePath)) {
return false;
}
@@ -356,7 +372,7 @@ public function upload()
*
* @return bool
*/
- public function isAllowedExtension()
+ public function isAllowedExtension(): bool
{
return in_array($this->getEnding(), explode(' ', $this->getAllowedExtensions()));
}
@@ -364,10 +380,11 @@ public function isAllowedExtension()
/**
* Convert for example the memory_limit of php (example: 128M) to bytes.
*
- * @param $size_str
+ * @param string $size_str
* @return float|int
+ * @since 2.0.0
*/
- public function returnBytes($size_str)
+ public function returnBytes(string $size_str)
{
switch (substr($size_str, -1)) {
case 'M':
@@ -406,14 +423,15 @@ public function save()
* Create thumbnail
*
* @return bool
+ * @since 2.1.20
*/
- public function createThumbnail()
+ public function createThumbnail(): bool
{
if (!$this->enoughFreeMemory($this->getUrl())) {
return false;
}
- $thumb = new \Thumb\Thumbnail();
+ $thumb = new Thumbnail();
$thumb->Thumbprefix = 'thumb_';
$thumb->Thumblocation = $this->path;
$thumb->Thumbsize = 300;
diff --git a/application/modules/forum/config/config.php b/application/modules/forum/config/config.php
index 24d145a54..1a367ba71 100644
--- a/application/modules/forum/config/config.php
+++ b/application/modules/forum/config/config.php
@@ -10,7 +10,7 @@ class Config extends \Ilch\Config\Install
{
public $config = [
'key' => 'forum',
- 'version' => '1.34.0',
+ 'version' => '1.34.1',
'icon_small' => 'fa-solid fa-list',
'author' => 'Stantin Thomas',
'link' => 'https://ilch.de',
@@ -124,15 +124,17 @@ public function getInstallSql()
CREATE TABLE IF NOT EXISTS `[prefix]_forum_topics` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
+ `forum_id` INT(11) NOT NULL,
`topic_prefix` INT(11) NOT NULL DEFAULT 0,
`topic_title` VARCHAR(255) NOT NULL,
`visits` INT(11) NOT NULL DEFAULT 0,
`creator_id` INT(10) NOT NULL,
`date_created` DATETIME NOT NULL,
- `forum_id` INT(11) NOT NULL,
`type` TINYINT(1) NOT NULL DEFAULT 0,
`status` TINYINT(1) NOT NULL DEFAULT 0,
- PRIMARY KEY (`id`)
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `FK_[prefix]_forum_topics_[prefix]_forum_items` (`forum_id`) USING BTREE,
+ CONSTRAINT `FK_[prefix]_forum_topics_[prefix]_forum_items` FOREIGN KEY (`forum_id`) REFERENCES `[prefix]_forum_items` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `[prefix]_forum_topicsubscription` (
@@ -150,12 +152,14 @@ public function getInstallSql()
CREATE TABLE IF NOT EXISTS `[prefix]_forum_posts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`topic_id` INT(11) NOT NULL,
+ `forum_id` INT(11) NOT NULL DEFAULT 0,
`text` TEXT NOT NULL,
`user_id` INT(10) NOT NULL,
`date_created` DATETIME NOT NULL,
- `forum_id` INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
INDEX `FK_[prefix]_forum_posts_[prefix]_forum_topics` (`topic_id`) USING BTREE,
+ INDEX `FK_[prefix]_forum_posts_[prefix]_forum_items` (`forum_id`) USING BTREE,
+ CONSTRAINT `FK_[prefix]_forum_posts_[prefix]_forum_items` FOREIGN KEY (`forum_id`) REFERENCES `[prefix]_forum_items` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT `FK_[prefix]_forum_posts_[prefix]_forum_topics` FOREIGN KEY (`topic_id`) REFERENCES `[prefix]_forum_topics` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
@@ -711,7 +715,7 @@ public function getUpdate($installedVersion)
$this->db()->query('ALTER TABLE `[prefix]_forum_topicsubscription` ADD CONSTRAINT `FK_[prefix]_forum_topicsubscription_[prefix]_users` FOREIGN KEY (`user_id`) REFERENCES `[prefix]_users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE;');
- // Add FKC for the 'topic_id' and 'user_id' columns in the 'forum_topicsubscription' table after deleting possibly orphaned remembered posts.
+ // Add FKC for the 'topic_id' and 'user_id' columns in the 'forum_remember' table after deleting possibly orphaned remembered posts.
$existingPosts = $this->db()->select('id')
->from('forum_posts')
->execute()
@@ -749,6 +753,48 @@ public function getUpdate($installedVersion)
$this->db()->query('ALTER TABLE `[prefix]_forum_remember` ADD CONSTRAINT `FK_[prefix]_forum_remember_[prefix]_forum_posts` FOREIGN KEY (`post_id`) REFERENCES `[prefix]_forum_posts` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE;');
$this->db()->query('ALTER TABLE `[prefix]_forum_remember` ADD CONSTRAINT `FK_[prefix]_forum_remember_[prefix]_users` FOREIGN KEY (`user_id`) REFERENCES `[prefix]_users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE;');
+ // no break
+ case "1.34.0":
+ // Add FKCs for the 'forum_id' columns in the tables 'forum_posts' and 'forum_topics' after deleting possibly orphaned posts and topics.
+ // Added additional FKCs and therefore indices to the posts and topics table to improve the performance of a query.
+ $existingForums = $this->db()->select('id')
+ ->from('forum_items')
+ ->execute()
+ ->fetchList();
+
+ $referencedForumsInPosts = $this->db()->select('forum_id')
+ ->from('forum_posts')
+ ->execute()
+ ->fetchList();
+
+ $orphanedRows = array_diff($referencedForumsInPosts ?? [], $existingForums ?? []);
+ if (count($orphanedRows) > 0) {
+ $this->db()->delete()
+ ->from('forum_posts')
+ ->where(['forum_id' => $orphanedRows])
+ ->execute();
+ }
+
+ $referencedForumsInTopics = $this->db()->select('forum_id')
+ ->from('forum_topics')
+ ->execute()
+ ->fetchList();
+
+ $orphanedRows = array_diff($referencedForumsInTopics ?? [], $existingForums ?? []);
+ if (count($orphanedRows) > 0) {
+ $this->db()->delete()
+ ->from('forum_topics')
+ ->where(['forum_id' => $orphanedRows])
+ ->execute();
+ }
+
+ // Change the order of column 'forum_id' of the tables 'forum_posts' and 'forum_topics'. Move them closer to the front.
+ $this->db()->query('ALTER TABLE `[prefix]_forum_posts` CHANGE COLUMN `forum_id` `forum_id` INT(11) NOT NULL DEFAULT 0 AFTER `topic_id`;');
+ $this->db()->query('ALTER TABLE `[prefix]_forum_topics` CHANGE COLUMN `forum_id` `forum_id` INT(11) NOT NULL AFTER `id`;');
+
+ $this->db()->query('ALTER TABLE `[prefix]_forum_posts` ADD CONSTRAINT `FK_[prefix]_forum_posts_[prefix]_forum_items` FOREIGN KEY (`forum_id`) REFERENCES `[prefix]_forum_items` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE;');
+ $this->db()->query('ALTER TABLE `[prefix]_forum_topics` ADD CONSTRAINT `FK_[prefix]_forum_topics_[prefix]_forum_items` FOREIGN KEY (`forum_id`) REFERENCES `[prefix]_forum_items` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE;');
+
// no break
}
}
diff --git a/application/modules/user/controllers/Panel.php b/application/modules/user/controllers/Panel.php
index 996cdbcc2..cec50b0e8 100644
--- a/application/modules/user/controllers/Panel.php
+++ b/application/modules/user/controllers/Panel.php
@@ -452,8 +452,6 @@ public function dialogAction()
} else {
$dialogMapper->markAllAsRead($c_id, $this->getUser()->getId());
}
-
- $this->getView()->set('inbox', $dialogMapper->getDialogMessage($c_id));
} else {
$this->redirect(['action' => 'dialog']);
}
diff --git a/application/modules/user/mappers/Dialog.php b/application/modules/user/mappers/Dialog.php
index d5f1c58ac..ce715a968 100644
--- a/application/modules/user/mappers/Dialog.php
+++ b/application/modules/user/mappers/Dialog.php
@@ -105,7 +105,11 @@ public function getDialogByCId(int $cId): ?DialogModel
$dialogModel = new DialogModel();
$dialogModel->setId($dialogRow['id']);
- $dialogModel->setName($dialogRow['name']);
+ if (!empty($dialogRow['name'])) {
+ $dialogModel->setName($dialogRow['name']);
+ } else {
+ $dialogModel->setName('No longer exists');
+ }
if (file_exists($dialogRow['avatar'])) {
$dialogModel->setAvatar($dialogRow['avatar']);
} else {
diff --git a/application/modules/user/models/Dialog.php b/application/modules/user/models/Dialog.php
index 9954b0ac9..252426e35 100644
--- a/application/modules/user/models/Dialog.php
+++ b/application/modules/user/models/Dialog.php
@@ -91,10 +91,10 @@ class Dialog extends \Ilch\Model
/**
* Set the ID of the message
*
- * @param int $id
+ * @param int|null $id
* @return $this
*/
- public function setId(int $id): Dialog
+ public function setId(?int $id): Dialog
{
$this->id = $id;
diff --git a/application/modules/user/plugins/AfterDatabaseLoad.php b/application/modules/user/plugins/AfterDatabaseLoad.php
index e8474910a..e6fde7052 100644
--- a/application/modules/user/plugins/AfterDatabaseLoad.php
+++ b/application/modules/user/plugins/AfterDatabaseLoad.php
@@ -6,6 +6,9 @@
namespace Modules\User\Plugins;
+use Ilch\Database\Exception;
+use Ilch\Redirect;
+use Ilch\Registry;
use Modules\Statistic\Mappers\Statistic;
use Modules\User\Mappers\User as UserMapper;
use Modules\User\Service\Remember as RememberMe;
@@ -18,7 +21,7 @@ class AfterDatabaseLoad
* If no user id is given a default user will be created.
*
* @param array $pluginData
- * @throws \Ilch\Database\Exception
+ * @throws Exception
*/
public function __construct(array $pluginData)
{
@@ -40,16 +43,16 @@ public function __construct(array $pluginData)
$mapper = new UserMapper();
$user = $mapper->getUserById($userId);
- \Ilch\Registry::set('user', $user);
+ Registry::set('user', $user);
- // Check if user is locked out. If that is the case log him out.
- if (\is_object($user) && $user->getLocked()) {
+ // Check if user is locked out or deleted. If that is the case log him out.
+ if ($userId && !$user || \is_object($user) && $user->getLocked()) {
if (!empty($_COOKIE['remember'])) {
setcookieIlch('remember', '', strtotime('-1 hours'));
}
$_SESSION = [];
- \Ilch\Registry::remove('user');
+ Registry::remove('user');
if (ini_get('session.use_cookies')) {
setcookieIlch(session_name(), '', strtotime('-12 hours'));
@@ -89,20 +92,23 @@ public function __construct(array $pluginData)
if ($request->getParam('language')) {
$_SESSION['language'] = $request->getParam('language');
$pluginData['translator']->setLocale($_SESSION['language']);
- $Redirect = new \Ilch\Redirect($request, $pluginData['translator']);
+ $Redirect = new Redirect($request, $pluginData['translator']);
$Redirect->to($request->unsetParam('language')->getArray());
}
if ($request->getParam('ilch_layout')) {
$_SESSION['layout'] = $pluginData['request']->getParam('ilch_layout');
- $Redirect = new \Ilch\Redirect($request, $pluginData['translator']);
+ $Redirect = new Redirect($request, $pluginData['translator']);
$Redirect->to($request->unsetParam('ilch_layout')->getArray());
}
- if (!$request->isAdmin() && !strpos($site, 'user/ajax/checknewmessage') && !strpos($site,
- 'user/ajax/checknewfriendrequests')) {
+ $sessionId = session_id();
+
+ // Ignore activity within the admincenter and the ajax requests for new messages or friend requests. Don't save
+ // the visit either if the session id is an empty string. This is the case for a just deleted or locked user.
+ if (!$request->isAdmin() && !strpos($site, 'user/ajax/checknewmessage') && !strpos($site, 'user/ajax/checknewfriendrequests') && $sessionId) {
$statisticMapper = new Statistic();
- $statisticMapper->saveVisit(['user_id' => $userId, 'session_id' => session_id(), 'site' => $site, 'referer' => $referer, 'os' => $statisticMapper->getOS('1'), 'os_version' => $statisticMapper->getOS('', '1'), 'browser' => $statisticMapper->getBrowser('1'), 'browser_version' => $statisticMapper->getBrowser(), 'ip' => $ip, 'lang' => $lang]);
+ $statisticMapper->saveVisit(['user_id' => $userId, 'session_id' => $sessionId, 'site' => $site, 'referer' => $referer, 'os' => $statisticMapper->getOS('1'), 'os_version' => $statisticMapper->getOS('', '1'), 'browser' => $statisticMapper->getBrowser('1'), 'browser_version' => $statisticMapper->getBrowser(), 'ip' => $ip, 'lang' => $lang]);
}
$pluginData['translator']->setLocale($pluginData['config']->get('locale') ?? '');
diff --git a/application/modules/user/plugins/BeforeControllerLoad.php b/application/modules/user/plugins/BeforeControllerLoad.php
index b7da8354a..7352ec149 100644
--- a/application/modules/user/plugins/BeforeControllerLoad.php
+++ b/application/modules/user/plugins/BeforeControllerLoad.php
@@ -7,6 +7,7 @@
namespace Modules\User\Plugins;
+use Ilch\Database\Exception;
use Modules\User\Mappers\User as UserMapper;
class BeforeControllerLoad
@@ -15,7 +16,7 @@ class BeforeControllerLoad
* Checks if the user has enough rights to access the requested page.
*
* @param array $pluginData
- * @throws \Ilch\Database\Exception
+ * @throws Exception
*/
public function __construct(array $pluginData)
{