From d35b50d5e46e8c6bc291f2c172304570729fdb70 Mon Sep 17 00:00:00 2001
From: Zan <62830223+Zan1456@users.noreply.github.com>
Date: Fri, 17 Oct 2025 21:10:54 +0200
Subject: [PATCH] -w
---
firka/LICENSE | 661 ------
firka/README.md | 96 -
firka/absences/absences.css | 485 ----
firka/absences/absences.js | 638 ------
firka/dashboard/dashboard.css | 449 ----
firka/dashboard/dashboard.js | 588 -----
firka/fonts/Figtree-Regular.woff2 | Bin 23324 -> 0 bytes
firka/fonts/Icons.woff2 | Bin 173620 -> 0 bytes
firka/fonts/Montserrat-Medium.woff2 | Bin 127352 -> 0 bytes
firka/fonts/Montserrat-Regular.woff2 | Bin 126576 -> 0 bytes
firka/fonts/Montserrat-SemiBold.woff2 | Bin 128544 -> 0 bytes
firka/forgotpassword/forgotpassword.css | 57 -
firka/forgotpassword/forgotpassword.js | 290 ---
firka/global/language.js | 189 --
firka/global/maintenance.css | 57 -
firka/global/maintenance.js | 106 -
firka/global/navigation.css | 332 ---
firka/global/navigation.js | 177 --
firka/global/theme.css | 129 --
firka/global/theme.js | 197 --
firka/grades/chart.js | 14 -
firka/grades/grades.css | 827 -------
firka/grades/grades.js | 790 -------
firka/i18n/en.json | 463 ----
firka/i18n/hu.json | 465 ----
firka/icons/ArrowsExpandFull.svg | 1 -
firka/icons/BadgeCheck.svg | 1 -
firka/icons/Calendar.svg | 1 -
firka/icons/ChevronLeftCircle.svg | 1 -
firka/icons/ChevronRightCircle.svg | 1 -
firka/icons/CloseCircle.svg | 1 -
firka/icons/Subject.svg | 1 -
firka/icons/absences-active.svg | 1 -
firka/icons/absences-inactive.svg | 5 -
firka/icons/assigment.svg | 1 -
firka/icons/close.svg | 1 -
firka/icons/dashboard-active.svg | 3 -
firka/icons/dashboard-inactive.svg | 5 -
firka/icons/delete.svg | 1 -
firka/icons/dkt.svg | 5 -
firka/icons/eye-off.svg | 1 -
firka/icons/eye-on.svg | 1 -
firka/icons/grades-active.svg | 3 -
firka/icons/grades-inactive.svg | 5 -
firka/icons/homework.svg | 1 -
firka/icons/logout.svg | 4 -
firka/icons/messages-active.svg | 1 -
firka/icons/messages-inactive.svg | 1 -
firka/icons/naplo.svg | 3 -
firka/icons/open-link.svg | 1 -
firka/icons/others.svg | 5 -
firka/icons/pipa.svg | 1 -
firka/icons/plus.svg | 1 -
firka/icons/profile.svg | 1 -
firka/icons/settings.svg | 1 -
firka/icons/timetable-active.svg | 4 -
firka/icons/timetable-inactive.svg | 5 -
firka/images/cactus.png | Bin 43397 -> 0 bytes
firka/images/chrome.png | Bin 21845 -> 0 bytes
firka/images/firefox.png | Bin 54652 -> 0 bytes
firka/images/firefoxact.png | Bin 46372 -> 0 bytes
firka/images/firka_logo.png | Bin 1427 -> 0 bytes
firka/images/firka_logo_128.png | Bin 10004 -> 0 bytes
firka/images/loading.gif | Bin 16742 -> 0 bytes
firka/login/login.css | 306 ---
firka/login/login.js | 201 --
firka/login/twofactor.css | 254 ---
firka/login/twofactor.js | 186 --
firka/logout/logout.css | 117 -
firka/logout/logout.js | 82 -
firka/manifest.json | 230 --
firka/manifest_fox.json | 232 --
firka/messages/messages.css | 547 -----
firka/messages/messages.js | 340 ---
firka/profile/profile.css | 485 ----
firka/profile/profile.js | 228 --
firka/roleselect/roleselect.css | 323 ---
firka/roleselect/roleselect.js | 179 --
firka/search/search.css | 196 --
firka/search/search.js | 144 --
firka/settings/index.css | 606 -----
firka/settings/index.html | 236 --
firka/settings/index.js | 570 -----
firka/timetable/timetable.css | 1534 -------------
firka/timetable/timetable.js | 2751 -----------------------
firka/tools/background.js | 106 -
firka/tools/createTemplate.js | 119 -
firka/tools/helper.js | 40 -
firka/tools/loadingScreen.css | 53 -
firka/tools/loadingScreen.js | 77 -
firka/tools/storageManager.js | 144 --
91 files changed, 17364 deletions(-)
delete mode 100644 firka/LICENSE
delete mode 100644 firka/README.md
delete mode 100644 firka/absences/absences.css
delete mode 100644 firka/absences/absences.js
delete mode 100644 firka/dashboard/dashboard.css
delete mode 100644 firka/dashboard/dashboard.js
delete mode 100644 firka/fonts/Figtree-Regular.woff2
delete mode 100644 firka/fonts/Icons.woff2
delete mode 100644 firka/fonts/Montserrat-Medium.woff2
delete mode 100644 firka/fonts/Montserrat-Regular.woff2
delete mode 100644 firka/fonts/Montserrat-SemiBold.woff2
delete mode 100644 firka/forgotpassword/forgotpassword.css
delete mode 100644 firka/forgotpassword/forgotpassword.js
delete mode 100644 firka/global/language.js
delete mode 100644 firka/global/maintenance.css
delete mode 100644 firka/global/maintenance.js
delete mode 100644 firka/global/navigation.css
delete mode 100644 firka/global/navigation.js
delete mode 100644 firka/global/theme.css
delete mode 100644 firka/global/theme.js
delete mode 100644 firka/grades/chart.js
delete mode 100644 firka/grades/grades.css
delete mode 100644 firka/grades/grades.js
delete mode 100644 firka/i18n/en.json
delete mode 100644 firka/i18n/hu.json
delete mode 100644 firka/icons/ArrowsExpandFull.svg
delete mode 100644 firka/icons/BadgeCheck.svg
delete mode 100644 firka/icons/Calendar.svg
delete mode 100644 firka/icons/ChevronLeftCircle.svg
delete mode 100644 firka/icons/ChevronRightCircle.svg
delete mode 100644 firka/icons/CloseCircle.svg
delete mode 100644 firka/icons/Subject.svg
delete mode 100644 firka/icons/absences-active.svg
delete mode 100644 firka/icons/absences-inactive.svg
delete mode 100644 firka/icons/assigment.svg
delete mode 100644 firka/icons/close.svg
delete mode 100644 firka/icons/dashboard-active.svg
delete mode 100644 firka/icons/dashboard-inactive.svg
delete mode 100644 firka/icons/delete.svg
delete mode 100644 firka/icons/dkt.svg
delete mode 100644 firka/icons/eye-off.svg
delete mode 100644 firka/icons/eye-on.svg
delete mode 100644 firka/icons/grades-active.svg
delete mode 100644 firka/icons/grades-inactive.svg
delete mode 100644 firka/icons/homework.svg
delete mode 100644 firka/icons/logout.svg
delete mode 100644 firka/icons/messages-active.svg
delete mode 100644 firka/icons/messages-inactive.svg
delete mode 100644 firka/icons/naplo.svg
delete mode 100644 firka/icons/open-link.svg
delete mode 100644 firka/icons/others.svg
delete mode 100644 firka/icons/pipa.svg
delete mode 100644 firka/icons/plus.svg
delete mode 100644 firka/icons/profile.svg
delete mode 100644 firka/icons/settings.svg
delete mode 100644 firka/icons/timetable-active.svg
delete mode 100644 firka/icons/timetable-inactive.svg
delete mode 100644 firka/images/cactus.png
delete mode 100644 firka/images/chrome.png
delete mode 100644 firka/images/firefox.png
delete mode 100644 firka/images/firefoxact.png
delete mode 100644 firka/images/firka_logo.png
delete mode 100644 firka/images/firka_logo_128.png
delete mode 100644 firka/images/loading.gif
delete mode 100644 firka/login/login.css
delete mode 100644 firka/login/login.js
delete mode 100644 firka/login/twofactor.css
delete mode 100644 firka/login/twofactor.js
delete mode 100644 firka/logout/logout.css
delete mode 100644 firka/logout/logout.js
delete mode 100644 firka/manifest.json
delete mode 100644 firka/manifest_fox.json
delete mode 100644 firka/messages/messages.css
delete mode 100644 firka/messages/messages.js
delete mode 100644 firka/profile/profile.css
delete mode 100644 firka/profile/profile.js
delete mode 100644 firka/roleselect/roleselect.css
delete mode 100644 firka/roleselect/roleselect.js
delete mode 100644 firka/search/search.css
delete mode 100644 firka/search/search.js
delete mode 100644 firka/settings/index.css
delete mode 100644 firka/settings/index.html
delete mode 100644 firka/settings/index.js
delete mode 100644 firka/timetable/timetable.css
delete mode 100644 firka/timetable/timetable.js
delete mode 100644 firka/tools/background.js
delete mode 100644 firka/tools/createTemplate.js
delete mode 100644 firka/tools/helper.js
delete mode 100644 firka/tools/loadingScreen.css
delete mode 100644 firka/tools/loadingScreen.js
delete mode 100644 firka/tools/storageManager.js
diff --git a/firka/LICENSE b/firka/LICENSE
deleted file mode 100644
index 0ad25db..0000000
--- a/firka/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
-
- Firka extension
-
- Modern, testre szabható felhasználói felület az e-KRÉTA rendszerhez -
- - - - - -## 📱 Funkciók - -- **Modern Dizájn**: Teljesen újratervezett, modern felhasználói felület -- **Személyre Szabható Témák**: Világos és sötét mód vagy akár egyedi témáddal -- **Továbbfejlesztett Felületek**: - - Átdolgozott bejelentkezési képernyő - - Átláthatóbb jegynapló - - Modernizált órarend - - Fejlett hiányzás kezelés - - Egyszerűsített szerepkör választó - - Új kezdőlap elrendezés - -## 🚀 Telepítés - -1. Töltsd le a legfrissebb verziót a fenti gombok segítségével a böngésződnek megfelelően. - -## ⚙️ Beállítások - -A bővítmény beállításait a böngésző eszköztárán található Firka ikonra kattintva érheted el. Itt módosíthatod: - -- A felület témáját, legyen az világos, sötét vagy akár egyedi témáddal. - -## 💡 Támogatott Oldalak - -A bővítmény jelenleg az alábbi e-KRÉTA oldalakat támogatja: - -- Bejelentkezés -- Kijelentkezés -- Szerepkörválasztó -- Órarend (Házi feladatok, Számonkérések) -- Faliújság -- Hiányzások -- Jegyek -- Intézménykereső -- Üzenetek -- Profil (Béta) - -## 👥 Csapat - -- **[Zan1456](https://github.com/Zan1456)** - Vezető Fejlesztő -- **[Xou](https://yoursit.ee/xou)** - Designer - -## 🤝 Közreműködés - -Örömmel fogadunk minden fejlesztési javaslatot és hibajelentést! Ha szeretnél hozzájárulni a projekthez: - -1. Fork-old a repository-t -2. Hozz létre egy új branch-et a fejlesztésednek -3. Commit-old a változtatásaidat -4. Push-old a branch-et -5. Nyiss egy Pull Request-et - -## 📝 Licensz - -A projekt [GNU Affero General Public License v3.0](LICENSE) alatt jelent meg. További információért lásd a LICENSE fájlt. - -## 💬 Kapcsolat - -- Discord: [discord.gg/6DvjyPAw2T](https://discord.gg/6DvjyPAw2T) -- GitHub: [QwIT-Development](https://github.com/QwIT-Development/) - ---- - -- Készült ❤️-vel diákoktól diákoknak -
diff --git a/firka/absences/absences.css b/firka/absences/absences.css deleted file mode 100644 index 747bd52..0000000 --- a/firka/absences/absences.css +++ /dev/null @@ -1,485 +0,0 @@ -* { - box-sizing:border-box; - margin:0; - padding:0; -} -body { - margin:0; - padding:0; - color:var(--text-primary); - background-color:var(--background) !important; - font-family:"Montserrat",serif !important; - min-height:100vh; - font-size:16px; -} -@media (max-width:768px) { - body { - font-size:14px; -} -}.kreta-container { - min-height:100vh; - display:flex; - flex-direction:column; -} -.kreta-header { - padding:clamp(1rem,3vw,2rem); - display:grid; - grid-template-columns:minmax(300px,400px) 1fr minmax(200px,300px); - align-items:center; - gap:1rem; -} -@media (max-width:1200px) { - .kreta-header { - grid-template-columns:minmax(250px,350px) 1fr minmax(180px,250px); -} -}@media (max-width:768px) { - .kreta-header { - grid-template-columns:1fr auto auto; - grid-template-areas:"school toggle user" - "nav nav nav"; - padding:1rem; - gap:0.5rem; -} -}.school-info { - margin:0; -} -@media (max-width:768px) { - .school-info { - grid-area:school; - max-width:none; - display:flex; - align-items:center; - gap:0.5rem; -} -}.logo-text { - color:var(--text-primary); - font-size:24px; - font-weight:600; - margin:0 0 0.5rem; - display:flex; - align-items:center; -} -@media (max-width:768px) { - .logo-text { - margin:0; - font-size:20px; -} -}.logo { - width:24px; - border-radius:8px; - margin-right:0.5rem; -} -.school-details { - color:var(--text-secondary); - font-size:14px; -} -.school-details span { - display:block; - white-space:nowrap; - overflow:hidden; - text-overflow:ellipsis; - max-width:300px; -} -@media (max-width:768px) { - .school-details span { - max-width:200px; -} -.school-details { - font-size:12px; -} -}.user-profile { - position:relative; - justify-self:flex-end; -} -@media (max-width:768px) { - .user-profile { - grid-area:user; -} -}.user-dropdown-btn { - display:flex; - align-items:center; - gap:1rem; - background:none; - border:none; - cursor:pointer; - padding:0.5rem; - border-radius:8px; - transition:background-color 0.2s; -} -.user-dropdown-btn:hover { - background:var(--card-card); -} -.user-info { - text-align:right; -} -.user-dropdown { - position:absolute; - top:100%; - right:0; - margin-top:0.5rem; - background:var(--card-card); - border-radius:12px; - box-shadow:0 4px 6px -1px rgba(0,0,0,0.1); - width:200px; - display:none; - z-index:1000; -} -.user-dropdown.show { - display:block; - animation:dropdownShow 0.2s ease; -} -.dropdown-item { - display:flex; - align-items:center; - gap:0.75rem; - padding:0.75rem 1rem; - color:var(--text-primary); - text-decoration:none; - transition:background-color 0.2s; -} -.dropdown-item:hover { - background:var(--button-secondaryFill); - text-decoration:none; -} -.kreta-main { - flex:1; - padding:clamp(1rem,3vw,2rem); - max-width:1200px; - margin:0 auto; - width:100%; -} -.filter-card { - background:var(--card-card); - border-radius:24px; - padding:20px; - margin-bottom:24px; - box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow); -} -.filter-header { - margin-bottom:16px; -} -.filter-header h2 { - font-size:18px; - font-weight:600; - color:var(--text-primary); - background-color:var(--card-card); -} -.filter-content { - display:grid; - grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); - gap:16px; -} -.filter-group { - display:flex; - flex-direction:column; - gap:8px; -} -.filter-group label { - display:flex; - align-items:center; - gap:8px; - color:var(--text-secondary); - font-size:14px; -} -.filter-input { - padding:10px; - border:none; - border-radius:8px; - background:var(--button-secondaryFill); - color:var(--text-primary); - font-family:inherit; - font-size:14px; - transition:all 0.2s ease; -} -.filter-input:focus { - outline:none; - box-shadow:0 0 0 2px var(--accent-accent); -} -.stats-overview { - display:grid; - grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); - gap:16px; - margin-bottom:24px; -} -.stat-card { - background:var(--card-card); - border-radius:16px; - padding:20px; - text-align:center; - box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow); - transition:transform 0.2s ease; -} -.stat-card:hover { - transform:translateY(-2px); -} -.stat-number { - font-size:32px; - font-weight:700; - color:var(--accent-accent); - margin-bottom:8px; -} -.stat-label { - color:var(--text-secondary); - font-size:14px; - font-weight:500; -} -.absences-container { - background:var(--card-card); - border-radius:16px; - overflow:hidden; - box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow); -} -.absences-table { - width:100%; - border-collapse:collapse; -} -.table-header { - background:var(--accent-15); - border-bottom:1px solid var(--accent-30); -} -.table-header th { - padding:16px; - text-align:left; - font-weight:600; - color:var(--text-primary); - font-size:14px; - text-transform:uppercase; - letter-spacing:0.5px; -} -.table-row { - border-bottom:1px solid var(--accent-15); - transition:background-color 0.2s ease; -} -.table-row:hover { - background:var(--accent-10); -} -.table-row:last-child { - border-bottom:none; -} -.table-cell { - padding:16px; - color:var(--text-primary); - vertical-align:middle; -} -.date-cell { - font-weight:600; - color:var(--accent-accent); -} -.lesson-cell { - text-align:center; - font-weight:500; -} -.subject-cell { - font-weight:600; -} -.topic-cell { - color:var(--text-secondary); - font-size:14px; - max-width:200px; - overflow:hidden; - text-overflow:ellipsis; - white-space:nowrap; -} -.status-cell { - text-align:center; -} -.status-badge { - display:inline-flex; - align-items:center; - gap:4px; - padding:6px 12px; - border-radius:20px; - font-size:12px; - font-weight:600; - text-transform:uppercase; - letter-spacing:0.5px; -} -.status-badge.justified { - background:var(--grades-4-bg); - color:var(--grades-4); -} -.status-badge.unjustified { - background:var(--grades-1-bg); - color:var(--grades-1); -} -.status-badge.pending { - background:var(--grades-3-bg); - color:var(--grades-3); -} -@media (max-width:768px) { - .absences-table { - font-size:14px; -} -.table-header th,.table-cell { - padding:12px 8px; -} -.topic-cell { - max-width:120px; -} -.stats-overview { - grid-template-columns:repeat(2,1fr); -} -}@media (max-width:480px) { - .absences-table,.table-header,.table-row { - display:block; -} -.table-header { - display:none; -} -.date-group { - margin-bottom:24px; -} -.date-group-header { - background:var(--accent-accent); - color:white; - padding:12px 16px; - border-radius:12px 12px 0 0; - font-weight:600; - font-size:16px; - margin-bottom:0; -} -.date-group-content { - background:var(--card-card); - border:1px solid var(--accent-15); - border-radius:0 0 12px 12px; - overflow:hidden; -} -.table-row { - width:100%; - margin-bottom:0; - border:none; - border-bottom:1px solid var(--accent-15); - border-radius:0; - padding:16px; - background:transparent; -} -.table-row:last-child { - border-bottom:none; -} -.table-cell { - display:flex; - justify-content:space-between; - align-items:flex-start; - padding:6px 0; - border-bottom:1px solid var(--accent-15); -} -.table-cell:last-child { - border-bottom:none; -} -.table-cell::before { - content:attr(data-label); - font-weight:600; - color:var(--text-secondary); - font-size:12px; - text-transform:uppercase; - flex-shrink:0; -} -.topic-cell { - max-width:none; - white-space:normal; - text-overflow:initial; - overflow:visible; - text-align:right; - flex:1; -} -.stats-overview { - grid-template-columns:1fr; -} -}.absence-details { - display:flex; - flex-direction:column; - gap:4px; -} -.absence-subject { - font-weight:600; - color:var(--text-primary); -} -.absence-topic { - color:var(--text-secondary); - font-size:14px; -} -.absence-status { - display:flex; - align-items:center; - gap:4px; - font-size:14px; - font-weight:500; -} -.absence-status.justified { - color:var(--grades-4); -} -.absence-status.unjustified { - color:var(--grades-1); -} -.absence-status.pending { - color:var(--grades-3); -} -.loading-overlay { - position:fixed; - top:0; - left:0; - width:100%; - height:100%; - background:var(--background); - display:flex; - flex-direction:column; - align-items:center; - justify-content:center; - z-index:9999; -} -.loading-container { - display:flex; - flex-direction:column; - align-items:center; - gap:1rem; - padding:2rem; - border-radius:24px; -} -.loading-text { - color:var(--Text-Primary); - text-align:center; - font-family:Montserrat; - font-size:20px; - font-style:normal; - font-weight:700; - line-height:normal; -} -.loading-text2 { - align-self:stretch; - color:var(--Text-Secondary); - text-align:center; - font-family:Figtree; - font-size:16px; - font-style:normal; - font-weight:500; - line-height:130%; -} -.loading-logo { - width:48px; - height:48px; - margin-bottom:1rem; - border-radius:8px; -} -@keyframes fadeIn { - from { - opacity:0; - transform:translateY(-10px); -} -to { - opacity:1; - transform:translateY(0); -} -}@keyframes dropdownShow { - from { - opacity:0; - transform:translateY(-10px); -} -to { - opacity:1; - transform:translateY(0); -} -}@keyframes spin { - to { - transform:rotate(360deg); -} -} \ No newline at end of file diff --git a/firka/absences/absences.js b/firka/absences/absences.js deleted file mode 100644 index 0729a96..0000000 --- a/firka/absences/absences.js +++ /dev/null @@ -1,638 +0,0 @@ -async function collectAbsencesData() { - const basicData = { - schoolInfo: { - name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"), - id: await storageManager.get("schoolCode", ""), - }, - userData: { - name: await storageManager.get("userName", "Felhasználónév"), - time: - document.querySelector(".usermenu_timer")?.textContent?.trim() || - "45:00", - }, - }; - - try { - const currentDomain = window.location.hostname; - const response = await fetch( - `https://${currentDomain}/api/HianyzasokApi/GetHianyzasGrid?sort=MulasztasDatum-desc&page=1&pageSize=100&group=&filter=&data=%7B%7D&_=${Date.now()}`, - { - method: "GET", - credentials: "include", - headers: { - Accept: "application/json, text/javascript, */*; q=0.01", - "X-Requested-With": "XMLHttpRequest", - }, - }, - ); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const apiData = await response.json(); - const absences = []; - - if (apiData.Data && Array.isArray(apiData.Data)) { - apiData.Data.forEach((item) => { - const date = new Date(item.MulasztasDatum); - const formattedDate = `${date.getFullYear()}.${(date.getMonth() + 1).toString().padStart(2, "0")}.${date.getDate().toString().padStart(2, "0")}.`; - - let justificationStatus = "pending"; - if (item.Igazolt_BOOL === true) { - justificationStatus = "justified"; - } else if (item.Igazolt_BOOL === false && item.IgazolasTipus !== null) { - justificationStatus = "unjustified"; - } - - absences.push({ - date: formattedDate, - lesson: item.Oraszam?.toString() || "", - subject: item.Targy || "", - topic: item.Tema || "", - type: item.MulasztasTipus_DNAME || "", - justified: item.Igazolt_BOOL === true, - justificationStatus: justificationStatus, - purposeful: item.TanoraiCeluMulasztas_BNAME || "", - justificationType: item.IgazolasTipus_DNAME || "", - }); - }); - } - - const groupedAbsences = {}; - absences.forEach((absence) => { - if (!groupedAbsences[absence.date]) { - groupedAbsences[absence.date] = []; - } - groupedAbsences[absence.date].push(absence); - }); - - return { basicData, absences, groupedAbsences }; - } catch (error) { - console.error("Hiba az API hívás során:", error); - return { basicData, absences: [], groupedAbsences: {} }; - } -} - -function createFilterCard(absences) { - const filterCard = document.createElement('div'); - filterCard.className = 'filter-card'; - - const filterHeader = document.createElement('div'); - filterHeader.className = 'filter-header'; - const h2 = document.createElement('h2'); - h2.textContent = LanguageManager.t('absences.filter_title'); - filterHeader.appendChild(h2); - - const filterContent = document.createElement('div'); - filterContent.className = 'filter-content'; - - const dateGroup = createFilterGroup( - 'Calendar.svg', - 'Dátum', - LanguageManager.t('absences.date'), - 'input', - { type: 'date', id: 'dateFilter', className: 'filter-input' } - ); - filterContent.appendChild(dateGroup); - - const subjectGroup = createSubjectFilterGroup(absences); - filterContent.appendChild(subjectGroup); - - const justificationGroup = createJustificationFilterGroup(); - filterContent.appendChild(justificationGroup); - - filterCard.appendChild(filterHeader); - filterCard.appendChild(filterContent); - - return filterCard; -} - -function createFilterGroup(iconName, altText, labelText, elementType, attributes) { - const group = document.createElement('div'); - group.className = 'filter-group'; - - const label = document.createElement('label'); - const img = document.createElement('img'); - img.src = chrome.runtime.getURL(`icons/${iconName}`); - img.alt = altText; - img.style.width = '24px'; - img.style.height = '24px'; - - label.appendChild(img); - label.appendChild(document.createTextNode(' ' + labelText)); - - const element = document.createElement(elementType); - Object.assign(element, attributes); - - group.appendChild(label); - group.appendChild(element); - - return group; -} - -function createSubjectFilterGroup(absences) { - const group = document.createElement('div'); - group.className = 'filter-group'; - - const label = document.createElement('label'); - const img = document.createElement('img'); - img.src = chrome.runtime.getURL('icons/Subject.svg'); - img.alt = 'Tantárgy'; - img.style.width = '24px'; - img.style.height = '24px'; - - label.appendChild(img); - label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.subject'))); - - const select = document.createElement('select'); - select.id = 'subjectFilter'; - select.className = 'filter-input'; - - const defaultOption = document.createElement('option'); - defaultOption.value = ''; - defaultOption.textContent = LanguageManager.t('absences.all_subjects'); - select.appendChild(defaultOption); - - const subjects = [...new Set(absences.map(a => a.subject))].sort(); - subjects.forEach(subject => { - const option = document.createElement('option'); - option.value = subject; - option.textContent = subject; - select.appendChild(option); - }); - - group.appendChild(label); - group.appendChild(select); - - return group; -} - -function createJustificationFilterGroup() { - const group = document.createElement('div'); - group.className = 'filter-group'; - - const label = document.createElement('label'); - const img = document.createElement('img'); - img.src = chrome.runtime.getURL('icons/BadgeCheck.svg'); - img.alt = 'Igazolás'; - img.style.width = '24px'; - img.style.height = '24px'; - - label.appendChild(img); - label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justification'))); - - const select = document.createElement('select'); - select.id = 'justificationFilter'; - select.className = 'filter-input'; - - const options = [ - { value: '', text: LanguageManager.t('absences.all_types') }, - { value: 'justified', text: LanguageManager.t('absences.justified') }, - { value: 'unjustified', text: LanguageManager.t('absences.unjustified') }, - { value: 'pending', text: LanguageManager.t('absences.pending') } - ]; - - options.forEach(optionData => { - const option = document.createElement('option'); - option.value = optionData.value; - option.textContent = optionData.text; - select.appendChild(option); - }); - - group.appendChild(label); - group.appendChild(select); - - return group; -} - -function createStatsOverview(absences) { - const statsOverview = document.createElement('div'); - statsOverview.className = 'stats-overview'; - - const stats = [ - { number: absences.length, label: LanguageManager.t('absences.total_absences') }, - { number: absences.filter(a => a.justificationStatus === 'justified').length, label: LanguageManager.t('absences.justified') }, - { number: absences.filter(a => a.justificationStatus === 'unjustified').length, label: LanguageManager.t('absences.unjustified') }, - { number: absences.filter(a => a.justificationStatus === 'pending').length, label: LanguageManager.t('absences.pending') } - ]; - - stats.forEach(stat => { - const statCard = document.createElement('div'); - statCard.className = 'stat-card'; - - const statNumber = document.createElement('div'); - statNumber.className = 'stat-number'; - statNumber.textContent = stat.number; - - const statLabel = document.createElement('div'); - statLabel.className = 'stat-label'; - statLabel.textContent = stat.label; - - statCard.appendChild(statNumber); - statCard.appendChild(statLabel); - statsOverview.appendChild(statCard); - }); - - return statsOverview; -} - -function createAbsencesContainer(absences) { - const container = document.createElement('div'); - container.className = 'absences-container'; - - const table = document.createElement('table'); - table.className = 'absences-table'; - - const thead = document.createElement('thead'); - thead.className = 'table-header'; - - const headerRow = document.createElement('tr'); - const headers = [ - LanguageManager.t('absences.date'), - LanguageManager.t('absences.lesson'), - LanguageManager.t('absences.subject'), - LanguageManager.t('absences.topic'), - LanguageManager.t('absences.status') - ]; - - headers.forEach(headerText => { - const th = document.createElement('th'); - th.textContent = headerText; - headerRow.appendChild(th); - }); - - thead.appendChild(headerRow); - - const tbody = document.createElement('tbody'); - generateAbsencesRows(absences, tbody); - - table.appendChild(thead); - table.appendChild(tbody); - container.appendChild(table); - - return container; -} - -async function transformAbsencesPage() { - const { basicData, absences, groupedAbsences } = await collectAbsencesData(); - document.body.textContent = ''; - const container = document.createElement('div'); - container.className = 'kreta-container'; - const headerDiv = document.createElement('div'); - const parser = new DOMParser(); - const doc = parser.parseFromString(await createTemplate.header(), 'text/html'); - const tempDiv = doc.body; - while (tempDiv.firstChild) { - headerDiv.appendChild(tempDiv.firstChild); - } - container.appendChild(headerDiv); - const main = document.createElement('main'); - main.className = 'kreta-main'; - const filterCard = createFilterCard(absences); - main.appendChild(filterCard); - const statsOverview = createStatsOverview(absences); - main.appendChild(statsOverview); - const absencesContainer = createAbsencesContainer(absences); - main.appendChild(absencesContainer); - - container.appendChild(main); - document.body.appendChild(container); - - - setupUserDropdown(); - setupMobileNavigation(); - - setupEventListeners(); - setupFilters(); - - loadingScreen.hide(); -} - -function generateAbsencesRows(absences, tbody) { - const groupedByDate = absences.reduce((groups, absence) => { - const date = absence.date; - if (!groups[date]) { - groups[date] = []; - } - groups[date].push(absence); - return groups; - }, {}); - - const sortedDates = Object.keys(groupedByDate).sort( - (a, b) => new Date(b) - new Date(a), - ); - - sortedDates.forEach((date) => { - const dateAbsences = groupedByDate[date]; - const divider = document.createElement('tr'); - divider.className = 'date-group-divider'; - divider.style.display = 'none'; - tbody.appendChild(divider); - - dateAbsences.forEach((absence) => { - const row = document.createElement('tr'); - row.className = 'table-row'; - row.dataset.subject = absence.subject; - row.dataset.justified = absence.justified; - row.dataset.date = absence.date; - row.dataset.dateGroup = date; - - const dateCell = document.createElement('td'); - dateCell.className = 'table-cell date-cell'; - dateCell.dataset.label = LanguageManager.t('absences.date'); - dateCell.textContent = absence.date; - row.appendChild(dateCell); - - const lessonCell = document.createElement('td'); - lessonCell.className = 'table-cell lesson-cell'; - lessonCell.dataset.label = LanguageManager.t('absences.lesson'); - lessonCell.textContent = absence.lesson + '.'; - row.appendChild(lessonCell); - - const subjectCell = document.createElement('td'); - subjectCell.className = 'table-cell subject-cell'; - subjectCell.dataset.label = LanguageManager.t('absences.subject'); - subjectCell.textContent = absence.subject; - row.appendChild(subjectCell); - - const topicCell = document.createElement('td'); - topicCell.className = 'table-cell topic-cell'; - topicCell.dataset.label = LanguageManager.t('absences.topic'); - topicCell.title = absence.topic; - topicCell.textContent = absence.topic; - row.appendChild(topicCell); - - const statusCell = document.createElement('td'); - statusCell.className = 'table-cell status-cell'; - statusCell.dataset.label = LanguageManager.t('absences.status'); - - const statusBadge = document.createElement('span'); - statusBadge.className = `status-badge ${absence.justificationStatus}`; - - if (absence.justificationStatus === 'justified') { - const img = document.createElement('img'); - img.src = chrome.runtime.getURL('icons/BadgeCheck.svg'); - img.alt = 'Igazolt'; - img.style.width = '16px'; - img.style.height = '16px'; - statusBadge.appendChild(img); - statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justified'))); - } else if (absence.justificationStatus === 'unjustified') { - const span = document.createElement('span'); - span.className = 'material-icons-round'; - span.textContent = 'cancel'; - statusBadge.appendChild(span); - statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.unjustified'))); - } else { - const span = document.createElement('span'); - span.className = 'material-icons-round'; - span.textContent = 'pending'; - statusBadge.appendChild(span); - statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.pending'))); - } - - statusCell.appendChild(statusBadge); - row.appendChild(statusCell); - - tbody.appendChild(row); - }); - }); -} - -function setupEventListeners() { - function setupMobileGrouping() { - if (window.innerWidth <= 480) { - createMobileGroups(); - } else { - removeMobileGroups(); - } - } - - window.addEventListener("resize", setupMobileGrouping); - - setupMobileGrouping(); -} - -function createMobileGroups() { - const tbody = document.querySelector(".absences-table tbody"); - if (!tbody) return; - - removeMobileGroups(); - - const rows = Array.from(tbody.querySelectorAll(".table-row")); - const groupedRows = {}; - - rows.forEach((row) => { - const date = row.dataset.date; - if (!groupedRows[date]) { - groupedRows[date] = []; - } - groupedRows[date].push(row); - }); - - const sortedDates = Object.keys(groupedRows).sort( - (a, b) => new Date(b) - new Date(a), - ); - - while (tbody.firstChild) { - tbody.removeChild(tbody.firstChild); - } - - sortedDates.forEach((date) => { - const dateRows = groupedRows[date]; - - const dateGroup = document.createElement("div"); - dateGroup.className = "date-group"; - - const dateHeader = document.createElement("div"); - dateHeader.className = "date-group-header"; - dateHeader.textContent = date; - - const dateContent = document.createElement("div"); - dateContent.className = "date-group-content"; - - dateRows.forEach((row) => { - dateContent.appendChild(row); - }); - - dateGroup.appendChild(dateHeader); - dateGroup.appendChild(dateContent); - tbody.appendChild(dateGroup); - }); -} - -function removeMobileGroups() { - const tbody = document.querySelector(".absences-table tbody"); - if (!tbody) return; - - const dateGroups = tbody.querySelectorAll(".date-group"); - if (dateGroups.length === 0) return; - - const allRows = []; - dateGroups.forEach((group) => { - const rows = group.querySelectorAll(".table-row"); - rows.forEach((row) => allRows.push(row)); - }); - - while (tbody.firstChild) { - tbody.removeChild(tbody.firstChild); - } - allRows.forEach((row) => tbody.appendChild(row)); -} - -function updateDateGroupsVisibility() { - if (window.innerWidth > 480) return; - - const dateGroups = document.querySelectorAll(".date-group"); - - dateGroups.forEach((group) => { - const visibleRows = group.querySelectorAll( - '.table-row[style=""], .table-row:not([style])', - ); - - if (visibleRows.length > 0) { - group.style.display = ""; - } else { - group.style.display = "none"; - } - }); -} - -function setupFilters() { - try { - const filters = { - dateFilter: document.getElementById("dateFilter"), - subject: document.getElementById("subjectFilter"), - justified: document.getElementById("justificationFilter"), - }; - - if (!filters.dateFilter || !filters.subject || !filters.justified) { - console.warn("Some filter elements were not found in the DOM"); - return; - } - - const filterAbsences = () => { - try { - const dateFilterValue = filters.dateFilter.value; - const subject = filters.subject.value; - const justified = filters.justified.value; - const selectedDate = dateFilterValue ? new Date(dateFilterValue) : null; - - document.querySelectorAll(".table-row").forEach((row) => { - const dateStr = row.dataset.date; - const dateParts = dateStr.split("."); - - if (dateParts.length < 3) { - console.error(`Invalid date format: ${dateStr}`); - return; - } - - const parsedYear = parseInt(dateParts[0].trim(), 10); - const parsedMonth = parseInt(dateParts[1].trim(), 10) - 1; - const parsedDay = parseInt(dateParts[2].trim(), 10); - - if (isNaN(parsedDay) || isNaN(parsedMonth) || isNaN(parsedYear)) { - console.error(`Invalid date components: ${dateStr}`); - return; - } - - const rowDate = new Date(parsedYear, parsedMonth, parsedDay); - - let showRow = true; - - if (selectedDate) { - if ( - rowDate.getFullYear() !== selectedDate.getFullYear() || - rowDate.getMonth() !== selectedDate.getMonth() || - rowDate.getDate() !== selectedDate.getDate() - ) { - showRow = false; - } - } - - if (subject && row.dataset.subject !== subject) { - showRow = false; - } - - if (justified) { - const statusElement = row.querySelector(".status-badge"); - const hasStatus = statusElement.classList.contains(justified); - if (!hasStatus) showRow = false; - } - - row.style.display = showRow ? "" : "none"; - }); - - updateDateGroupsVisibility(); - updateStatistics(); - } catch (err) { - console.error("Error during filtering absences:", err); - } - }; - - Object.values(filters).forEach((filter) => { - try { - if (filter) { - filter.addEventListener("change", filterAbsences); - } - } catch (err) { - if ( - err.message && - err.message.includes("Extension context invalidated") - ) { - console.warn( - "Extension context invalidated during event listener setup", - ); - } else { - console.error("Error setting up filter event listener:", err); - } - } - }); - - filterAbsences(); - } catch (err) { - if (err.message && err.message.includes("Extension context invalidated")) { - console.warn("Extension context invalidated during filter setup"); - } else { - console.error("Error setting up filters:", err); - } - } -} - -function updateStatistics() { - try { - const visibleRows = document.querySelectorAll( - '.table-row:not([style*="display: none"])', - ); - const totalVisible = visibleRows.length; - const justifiedVisible = Array.from(visibleRows).filter((row) => - row.querySelector(".status-badge.justified"), - ).length; - const unjustifiedVisible = Array.from(visibleRows).filter((row) => - row.querySelector(".status-badge.unjustified"), - ).length; - const pendingVisible = Array.from(visibleRows).filter((row) => - row.querySelector(".status-badge.pending"), - ).length; - - const statCards = document.querySelectorAll(".stat-card"); - if (statCards[0]) - statCards[0].querySelector(".stat-number").textContent = totalVisible; - if (statCards[1]) - statCards[1].querySelector(".stat-number").textContent = justifiedVisible; - if (statCards[2]) - statCards[2].querySelector(".stat-number").textContent = - unjustifiedVisible; - if (statCards[3]) - statCards[3].querySelector(".stat-number").textContent = pendingVisible; - } catch (err) { - console.error("Error updating statistics:", err); - } -} - -if (window.location.href.includes("/Hianyzas/Hianyzasok")) { - transformAbsencesPage().catch((error) => { - console.error(LanguageManager.t("absences.page_transform_error"), error); - }); -} \ No newline at end of file diff --git a/firka/dashboard/dashboard.css b/firka/dashboard/dashboard.css deleted file mode 100644 index ed105e7..0000000 --- a/firka/dashboard/dashboard.css +++ /dev/null @@ -1,449 +0,0 @@ -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - margin: 0; - padding: 0; - color: var(--text-primary); - background-color: var(--background) !important; - font-family: "Montserrat", serif !important; - min-height: 100vh; - font-size: 16px; -} - -h2 { - background-color: #00000000 !important; -} - -.kreta-container { - min-height: 100vh; - display: flex; - flex-direction: column; -} - - -.kreta-main { - flex: 1; - padding: clamp(1rem, 3vw, 2rem); - max-width: 1400px; - margin: 0 auto; - width: 100%; -} - -.grid-container { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); - gap: 20px; -} - -.widget-card { - background: var(--card-card); - border-radius: 24px; - overflow: hidden; - animation: fadeIn 0.5s ease forwards; - box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow); - display: flex; - flex-direction: column; - height: 100%; - border: none; - min-height: 400px; -} - -.widget-header { - padding: 20px 20px 0 20px; - background: var(--card-card) !important; -} - -.widget-card-title { - font-size: 18px; - font-weight: 600; - color: var(--text-primary); - margin: 0; - padding-bottom: 16px; -} - -.widget-content { - flex: 1; - padding: 0 20px; - background: var(--card-card); - display: flex; - flex-direction: column; - justify-content: flex-start; -} - -.widget-footer { - padding: 0px 20px 20px 20px; - background: var(--card-card); -} - -.widget-link { - margin: 0; - padding: 0; -} - -.card h2 { - font-size: 18px; - font-weight: 600; - color: var(--text-primary); - margin: 0; - padding: 20px 0 16px 0; -} - -.card:last-child { - grid-column: 1 / -1; -} - -.widget-item { - border-radius: 12px; - transition: transform 0.2s ease, box-shadow 0.2s ease; - border: none; - background: var(--card-card); - display: flex; - flex-direction: column; - padding: 8px; - position: relative; - min-height: 80px; -} - -.widget-row { - display: flex; - align-items: flex-start; - justify-content: space-between; - width: 100%; - gap: 12px; - min-height: 40px; -} - -.widget-row.grade-row { - align-items: center; - justify-content: flex-start; -} - -.widget-details { - flex: 1; - display: flex; - flex-direction: column; - gap: 6px; - min-width: 0; -} - -.widget-details.grade-details { - flex: 1; - margin-right: auto; -} - -.widget-title { - color: var(--text-primary); - font-weight: 600; - font-size: 16px; - line-height: 1.3; - word-wrap: break-word; - overflow-wrap: break-word; - hyphens: auto; - max-width: 100%; -} - -.widget-subtitle { - color: var(--text-secondary); - font-weight: 500; - font-size: 14px; - line-height: 1.2; - word-wrap: break-word; - overflow-wrap: break-word; -} - -.widget-content { - color: var(--text-secondary); - font-size: 14px; - line-height: 1.4; - margin-top: 4px; -} - -.widget-date { - color: var(--text-secondary); - font-size: 14px; - font-weight: 500; - white-space: nowrap; - text-align: right; - align-self: center; -} - -.grade-type-with-date { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - gap: 8px; -} - -.grade-type-with-date .grade-type { - flex: 1; - min-width: 0; -} - -.note-author { - color: var(--text-tertiary); - font-size: 12px; - font-weight: 400; - margin-top: 4px; - word-wrap: break-word; - overflow-wrap: break-word; -} - -.grade-date { - color: var(--text-secondary); - font-size: 13px; - font-weight: 400; - white-space: nowrap; - text-align: right; -} - -.widget-author { - color: var(--text-tertiary); - font-size: 12px; - font-weight: 400; - word-wrap: break-word; - overflow-wrap: break-word; - max-width: 100%; -} - -.news-author { - display: flex; - flex-direction: column; - align-items: flex-end; - gap: 4px; - text-align: right; - word-wrap: break-word; - overflow-wrap: break-word; - hyphens: auto; - max-width: 200px; -} - -/* Mobile view: author below content */ -@media (max-width: 768px) { - .news-item .widget-row { - flex-direction: column; - align-items: stretch; - } - - .news-item .widget-meta { - order: 2; - display: flex; - flex-direction: column; - align-items: center; - margin-top: 8px; - } - - .news-item .widget-details { - order: 1; - } - - .news-author { - align-items: center; - text-align: center; - max-width: 100%; - margin-top: 4px; - } - - .widget-date { - order: 1; - } - - .news-author { - order: 2; - } -} - -/* Desktop view: limit author width and wrap text */ -@media (min-width: 769px) { - .news-author { - max-width: 180px; - white-space: normal; - line-height: 1.3; - } -} - -.widget-empty { - color: var(--text-secondary); - font-style: italic; - text-align: center; - padding: 20px; -} - -.grade { - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 16px; - font-weight: 700; - margin-right: 1rem; - color: var(--text-primary); - font-size: 22px; -} - -.news-title { - font-size: 16px; - font-weight: 600; - margin-bottom: 8px; - word-wrap: break-word; - overflow-wrap: break-word; - hyphens: auto; - line-height: 1.4; -} - -.news-content { - font-size: 14px; - line-height: 1.4; - color: var(--text-secondary); - word-wrap: break-word; - overflow-wrap: break-word; - hyphens: auto; -} - -.exam-type { - font-size: 12px; - font-weight: 500; - letter-spacing: 0.5px; -} - -.more-link { - margin-top: auto; - display: inline-flex; - align-items: center; - gap: 0.5rem; - color: var(--accent-accent); - text-decoration: none; - font-weight: 500; - padding-top: 16px; - transition: gap 0.2s ease; - font-size: clamp(0.875rem, 1.5vw, 1rem); -} -@media (hover: hover) { - .more-link:hover { - color: var(--accent-secondary); - gap: 0.75rem; - } -} -.more-link i { - font-size: 0.875rem; -} -.grade-1 {color: var(--grades-1); background-color: var(--grades-background-1);} -.grade-2 {color: var(--grades-2); background-color: var(--grades-background-2);} -.grade-3 {color: var(--grades-3); background-color: var(--grades-background-3);} -.grade-4 {color: var(--grades-4); background-color: var(--grades-background-4);} -.grade-5 {color: var(--grades-5); background-color: var(--grades-background-5);} -.grade-Sz {color: var(--grades-3); background-color: var(--grades-background-3);} - -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} -.user-profile { - position: relative; -} - -.user-dropdown-btn { - background: none; - border: none; - cursor: pointer; - padding: 8px; - display: flex; - align-items: center; - color: var(--text-primary); -} - -.user-dropdown { - position: absolute; - top: 100%; - right: 0; - background: var(--card-card); - border-radius: 12px; - box-shadow: 0 4px 12px var(--accent-shadow); - min-width: 200px; - display: none; - z-index: 1000; -} - -.user-dropdown.active { - display: block; -} - -.dropdown-item { - display: flex; - align-items: center; - gap: 8px; - padding: 12px 16px; - color: var(--text-primary); - text-decoration: none; - transition: background-color 0.2s ease; -} - -.dropdown-item:hover { - background-color: var(--accent-15); - text-decoration: none; -} - -.dropdown-item svg { - width: 20px; - height: 20px; -} - -.news-title { - font-size: 16px; - font-weight: 600; - margin-bottom: 8px; -} - -.news-content { - font-size: 14px; - line-height: 1.4; - color: var(--text-secondary); -} -.more-link { - margin-top: auto; - display: inline-flex; - align-items: center; - gap: 0.5rem; - color: var(--accent-accent); - text-decoration: none; - font-weight: 500; - padding-top: 16px; - transition: gap 0.2s ease; - font-size: clamp(0.875rem, 1.5vw, 1rem); -} -@media (hover: hover) { - .more-link:hover { - color: var(--accent-secondary); - gap: 0.75rem; - } -} -.more-link i { - font-size: 0.875rem; -} - -.exam-info { - display: flex; - gap: 8px; - margin-top: 4px; - color: var(--text-secondary); - font-size: 14px; -} - -.exam-info { - display: flex; - gap: 8px; - margin-top: 4px; - color: var(--text-secondary); - font-size: 14px; -} \ No newline at end of file diff --git a/firka/dashboard/dashboard.js b/firka/dashboard/dashboard.js deleted file mode 100644 index fdedd2f..0000000 --- a/firka/dashboard/dashboard.js +++ /dev/null @@ -1,588 +0,0 @@ -const DashboardUtils = { - formatGradeValue(value) { - const trimmedValue = value?.trim() || ""; - if (trimmedValue.toLowerCase() === "szöveges") { - return "Sz"; - } - return trimmedValue; - }, - - parseDate(dateStr) { - return dateStr?.trim() || ""; - }, - - formatHungarianDate(dateStr) { - if (!dateStr) return ""; - - const dateParts = dateStr.trim().split("."); - if (dateParts.length < 3) return dateStr; - - const month = parseInt(dateParts[1], 10); - const day = parseInt(dateParts[2], 10); - - if (isNaN(month) || month < 1 || month > 12) return dateStr; - - if (typeof window.LanguageManager !== "undefined") { - const monthKeys = [ - "months.january", - "months.february", - "months.march", - "months.april", - "months.may", - "months.june", - "months.july", - "months.august", - "months.september", - "months.october", - "months.november", - "months.december", - ]; - const monthName = window.LanguageManager.t(monthKeys[month - 1]); - return `${monthName} ${day}.`; - } - - const monthKeys = [ - "months.january", - "months.february", - "months.march", - "months.april", - "months.may", - "months.june", - "months.july", - "months.august", - "months.september", - "months.october", - "months.november", - "months.december", - ]; - - return `${LanguageManager.t(monthKeys[month - 1])} ${day}.`; - }, -}; - -class DashboardDataManager { - constructor() { - this.dashboardData = { - grades: [], - absences: [], - notes: [], - upcomingExams: [], - news: [], - }; - } - - extractGradeData() { - const gradeRows = document.querySelectorAll( - "#legutobbiErtekelesek tr:not(:first-child)", - ); - - this.dashboardData.grades = Array.from(gradeRows) - .map((row) => { - const gradeValue = row.querySelector( - 'span[style*="font-size: 200%"]', - )?.textContent; - const gradeInfo = row.querySelector( - 'span[style*="float: right"]', - )?.textContent; - - if (!gradeValue || !gradeInfo) return null; - - const [fullSubject, date] = gradeInfo - .split("\n") - .map((str) => str.trim()); - const { subject, type, dateInSubject } = - this.parseSubjectInformation(fullSubject); - - return { - value: DashboardUtils.formatGradeValue(gradeValue), - subject, - date: DashboardUtils.parseDate(date), - type: type || LanguageManager.t("dashboard.evaluation"), - dateInSubject: dateInSubject || null, - }; - }) - .filter(Boolean); - } - - parseSubjectInformation(fullSubject) { - const hungarianMonths = [ - "január", - "február", - "március", - "április", - "május", - "június", - "július", - "augusztus", - "szeptember", - "október", - "november", - "december", - ]; - const monthPattern = hungarianMonths.join("|"); - const datePattern = new RegExp(`(${monthPattern})\\s+(\\d{1,2})\\.?$`, "i"); - const dateMatch = fullSubject.match(datePattern); - - if (dateMatch) { - const subjectPart = fullSubject.substring(0, dateMatch.index).trim(); - const datePart = dateMatch[0].trim(); - return { - subject: subjectPart, - type: "", - dateInSubject: datePart, - }; - } - - const months = [ - LanguageManager.t("months.january"), - LanguageManager.t("months.february"), - LanguageManager.t("months.march"), - LanguageManager.t("months.april"), - LanguageManager.t("months.may"), - LanguageManager.t("months.june"), - LanguageManager.t("months.july"), - LanguageManager.t("months.august"), - LanguageManager.t("months.september"), - LanguageManager.t("months.october"), - LanguageManager.t("months.november"), - LanguageManager.t("months.december"), - ]; - const fallbackMonthPattern = new RegExp(months.join("|"), "i"); - const monthMatch = fullSubject.match(fallbackMonthPattern); - - if (monthMatch) { - const monthIndex = fullSubject.lastIndexOf(monthMatch[0]); - return { - subject: fullSubject.substring(0, monthIndex).trim(), - type: fullSubject.substring(monthIndex).trim(), - }; - } - - return { subject: fullSubject, type: "" }; - } - - extractAbsenceData() { - const absenceRows = document.querySelectorAll( - "#legutobbiMulasztasok tr:not(:first-child)", - ); - - this.dashboardData.absences = Array.from(absenceRows) - .map((row) => { - const spans = row.querySelectorAll("span"); - if (spans.length < 4) return null; - - return { - date: spans[0]?.textContent?.trim() || "", - day: spans[2]?.textContent?.trim() || "", - type: spans[1]?.textContent?.trim() || "", - count: spans[3]?.textContent?.trim() || "", - }; - }) - .filter(Boolean); - } - - extractNoteData() { - const noteRows = document.querySelectorAll( - "#legutobbiFeljegyzesek tr:not(:first-child)", - ); - - this.dashboardData.notes = Array.from(noteRows) - .map((row) => { - const spans = row.querySelectorAll("span"); - if (spans.length < 3) return null; - - return { - title: spans[0]?.textContent?.trim() || "", - author: spans[1]?.textContent?.trim() || "", - date: spans[2]?.textContent?.trim() || "", - }; - }) - .filter(Boolean); - } - - extractExamData() { - const examRows = document.querySelectorAll( - "#legutobbiBejelentettSzamonkeres tr:not(:first-child)", - ); - - this.dashboardData.upcomingExams = Array.from(examRows) - .map((row) => { - const spans = row.querySelectorAll("span"); - if (spans.length < 4) return null; - - return { - date: spans[0]?.textContent?.trim() || "", - subject: spans[1]?.textContent?.trim() || "", - day: spans[2]?.textContent?.trim() || "", - type: spans[3]?.textContent?.trim() || "", - }; - }) - .filter(Boolean); - } - - async extractNewsData() { - try { - const timestamp = Date.now(); - const apiUrl = `https://${window.location.hostname}/Intezmeny/Faliujsag/GetMoreEntries?startindex=0&range=10&_=${timestamp}`; - - const response = await fetch(apiUrl, { - method: "GET", - credentials: "include", - headers: { - Accept: "application/json, text/javascript, */*; q=0.01", - "X-Requested-With": "XMLHttpRequest", - }, - }); - - if (!response.ok) { - throw new Error(`API request failed with status: ${response.status}`); - } - - const data = await response.json(); - - if (!data.FaliujsagElemek || !Array.isArray(data.FaliujsagElemek)) { - return; - } - - data.FaliujsagElemek.forEach((item, index) => { - let formattedDate = ""; - if (item.DatumNap && item.DatumHonap && item.DatumEv) { - formattedDate = `${item.DatumEv}. ${item.DatumHonap} ${item.DatumNap}.`; - } else if (item.Idopont) { - const match = item.Idopont.match(/\/Date\((\d+)\)\//); - if (match) { - const timestamp = parseInt(match[1]); - const date = new Date(timestamp); - formattedDate = date.toLocaleDateString("hu-HU"); - } - } - - if (!formattedDate) { - formattedDate = new Date().toLocaleDateString("hu-HU"); - } - - let cleanContent = item.EsemenySzovege || ""; - cleanContent = cleanContent.replace(/<[^>]*>/g, ""); - cleanContent = cleanContent.replace(/\r\n/g, " "); - cleanContent = cleanContent.replace(/\s+/g, " ").trim(); - - const newsItem = { - title: item.EsemenyCime || `Hír ${index + 1}`, - content: cleanContent || "Nincs elérhető tartalom", - date: formattedDate, - author: `${item.Nev || "Ismeretlen"} (${item.Munkakor || "Ismeretlen"})`, - }; - - this.dashboardData.news.push(newsItem); - }); - } catch (error) { - console.error("❌ Error fetching news from API:", error); - } - } - - async extractAllData() { - this.extractGradeData(); - this.extractAbsenceData(); - this.extractNoteData(); - this.extractExamData(); - await this.extractNewsData(); - return this.dashboardData; - } -} - -class DashboardRenderer { - constructor(data) { - this.baseData = data; - } - - async init() { - this.data = { - ...this.baseData, - schoolInfo: { - name: - await storageManager.get("schoolName", "OM azonosító - Iskola neve"), - id: await storageManager.get("schoolCode", ""), - }, - userData: { - name: await storageManager.get("userName", "Felhasználónév"), - time: - document.querySelector(".usermenu_timer")?.textContent?.trim() || - "45:00", - }, - }; - this.schoolNameFull = `${this.data.schoolInfo.id} - ${this.data.schoolInfo.name}`; - this.shortenedSchoolName = helper.shortenSchoolName(this.schoolNameFull); - } - - generateMainContent() { - return ` -{qGKrIVl`&yia4Z&SF7O8$nZ@4r=#9e#L1(rDFE zk*il-pUSd_E}f^gVPaYMF%^#MQ(dD9pFJ$NrK%8Qv`q3#r%&yy&41?HPCkGB%fY3e z-pOZkh|aHGv8Ta0C{emBK7##d}lZ# CPR(Fx#UpyCaI~bj|8TPE {<_d2r_P8R;(u=C9ssoYaad^N|Vwm&Fzx+mwJpvG_~Ve3r$ zNjvXxa@B0)oyK*A$M3wqWWe5v_DM2_7CoCQB5vt$;(WUNJ~0hhE4_=$9v00_%G!M_ z_lA )_I4;F|$`}FLv)vDO`nWk!d!bRuWWn!L6 z=eI4JGP%7bq)&8rpkU#(L+f0`6WyM_yfrl?+tlbwPj|)tGSj~=9! 1Sl@%B|wx#`y*zxw*!Gr4=GaDU%o z?jmWCJ W7Z=$*aXe&eG4;YU=YHbki!U&$r+HD=Bu} z_dBZJH*P-kOy;cY?i>7>a{8ZH)kP;(zDajH=3|?aT;#Jv&}h+*zamq6cJ4cINO6%{ zh}WbK`+ClYuWhj1Jgdv_<}>bD 5|ONhc{-mdLFjFF#R MN^IjP63ww~5MNta5ocu96sCI8lIL2% zU77t^p}Fn(L1GsByA}mmJ}OZ@pyqJSf8yjDsT;j`)1`HKI`3C5unJu39r#0AebV!M z3EtBwFY?-s&sck_Ce3l7^^=!g#}^$o^t{{YB-j-4$&0@*oUtr%>5&I(Ig`EoWqngB zgu}lWI^R3PzV)MN;+5>u)jW}sf2N8^6 Q^(;NQqTL3gUkLY3dP(kCRU(v9QJRlj+;#=BIu>(xx{hpr`6 z96_AwbrZV+H!L``AS=Qm?9{hyd0Kl8eZHioUt#v$AkY6Y%l{c0XZ&BZDXM|BI>f&3 zaHX-n(ccBHxbxbAoK;_5GyfX?Rr~KQNv`WJ8)o+fd`YQTEuZv}IdG-P{g?GDm+zkK zER5AVQe-WAv9b5j-?_`5SlC>MxjFL^_j)zE_cy~2v&yNyx>a;U-{8yRygs9SQKFZ1 zkMHF?lc5`U#>XNxC%7uDcYW6!F%_$jkBWL~Rc9M7?DG(K^e{<0)nnoZ24`2llW}LQ zCzqUJk#Kp=QLy9LYK`?ejydtiq$e;qh_0!;b&6MOc1pr;i=Y`6tjGAG6ok7XW!J^> ztZDz7!y+EE@z3W^3Le52@~3~-{b(2Fn0xKk{*U*+X{23my1Hf6%BxHvyS8LHu6nU4 z_>88Y`W}sdch@2s `C?bV91qwPe}L5LCJMdmBL-ZyXRbgZ?xlUaQorv?5I+^>c|M!sn4Un zh)+)3zKVN+)7@Pqc{as=ip3RPXL&Y#zm~!N$z;cYUlwJ8rv=JPL|F@--TL$-#FI}p zFNd|)Z+ElJ>;^HbPi6`1?+)eNO8b3%k>>Na9LtwEUA&qjt1h F1neVQoURu7_a)H|Q%136i4}MdgHThE) zm+11_FN^s8tENP3t`4;R-I|+vv`;r+*XziOuXe=whc39`m3TQ$;Lzg-N;+TdEDPk* z!i;b4de?aSQETkHdoEKty~I5x-|3yGv?lF#{Qbu=MXG;RSDsnckXhrhI^`kz<7+qf z9M*{vi_NPn_?DW#q6Ee1ct5#AKs)zKxNa=-%`-XBRCl zz7@$kmrayiV#T2!yh{%VA7OTW8s3%iywAe<+WPxz3`1u>H<-LgpepocwWtx>Zo_or z)9Z4|L)9O*OPtyBy!{z()HNI3ICX``?{+%BTeU9JiLd?igauVSQ;%(YpIouw>CEW+ zrW2c$-c34J{Gwv6;@OtM7vE3!D)vv0eR2H>msH%JN{M#!Ck9v6em}*1j_38XkjK2Y zJokN?GTYAm^4tY!>W269W7 rb~maJ;`d zgoF1`=q#QdMHRhJjvreOly5rHo#u8{Q@h-hQ>nI}Z*m0x^B$|Eg$~zh9u_{^yXX4b zAIsY|%)R@0XB%VWmU*vzTRU|xcl~qCuR9c+VLbcu9 ^D91CCW4`CZqeb@ K?M*sAXXj*lk8_$)#dDhXeDN3Hig>-h>%-e$yW5wm z6jaY?J{;`mwq@Rov phk^?ojV$w&2?z zDp01Qwch=m{1?mFGF&nf{2#2IdHP0R`0Je5qrdOZVz6@maDi S?r*@s$T(6(drMcjdoPvr}qbXDL pr^~YJ?tPQ@eolOM+~GF=2cf6@0`DzCPyJR{>char>GIb{V|wlb;~>{RSIUp7 zA5jV`E 2 zTVsv<*KZ3Vw(H&uTBjQFbfJp%{%YULGv)~$lDznk;YEI;e3s{7?`N|ArpVq3ja5Gu z!6q=(i>rKR0QZB%ugjBvG&TO*G2I}jv~)|rfuyg-7R#o5S#^A4O{4SC&g4&5Pj?7x zd~3FO-K-6{x6bUhv6>ZLKEZ9-ZSlu;Dtl*{PP5 tBAa{O7$0|C0F1 z`MPGPcuHG;o|xIw*1cC3=}ek2v&bcm=TV;IqD2$5`#MkLAE@HBeaJ7gJA~;>+dYrx z-!xt%OZCiJbKz=nVHxW}srts0C_CR{8|rjF9=mxkZl-&q%tw=-#yW*1%5jg51~cc+ z`*!O};P#jwM}F$+FZE2i?Y3R_tkAZKnkQB+aklsF$DW%l{kDAj>3|$o?QIiNX55)C z-qW}`^U
-CXe8k26zA4{5QF7XqqA!AbYIf|-H9MOYv3^?Z?;ty${dZ0) zi5?3zomyECEI8}qr^RP7BBkHXy~(lICjW3wTI rTwKIiY9{%vBCd$ec) z$Ap|;skIhWEBu0!vpLxl9+poMn{xa2UK=mXd7<5Bf(0z*Brkk)c7~&8u*jm|i@%-- zEsgPFt2sHBMLfAkPB4Ju9OIfphknoe{QW_aTE)q2H-%SkQ$E`4EmB``L;O$Y(tYQW z4QD9XOi{K--)^@<=9;tKJaxq!?i0qGf(upK9+ZFU&OAK-TB>UWSKWHC*uyg0HtAZ6 z8#c|)I=~#_z3$;$i@%$Mo%b}(xNfxWtcOvUtO%3d!c=L#hqlG$XD^pk{Pf%M^6(A5 zsqXJDG$k-@-`MQ5CMj&`(YvhuX@`#pPptaVs?x9_vn62OOUK_IGK_cU?g&YHS7Tq? z#hw>^s_#hq=X*MHJyr8ADBd<==@ybO{8-ApOIxKxLE`Ym(kq<%XZP@ZNNBknbj+K7 zkFaS*_c1RKt50(bqnJOQ{t _X@u)OB { z!>N~+{{QGC6HoPSgZ2C?x jD>e**+JL@A$wi zH1m{utQlkDo@8%+j(n{(npez@1+nk>yqv?UbPp4c+Kx$%!Fl$vIoXe*PPTp55UyXH zVA9+9`0j-t4x3d9BYG#edfC}Iu6i8v@n47F$CkWMh0v?Yv+hjyj^ JwWrQ(A&c&pFKImCw2e8|Ne{F8#l048*XXxWSuxyW8d3g- CtiFIn0TAXRbdkGh8s^x>UklnHKSboL~A}WWPU^_0Q#FnO9w)d~k==gfI>3MF9&t z5A|PlkSsm-<(PrgLGOizi`A}5uP{6-J3DJ(+>G9kux)W4<}!KzwdiMET5esncHz~Z zHuvS4vi(eqSY&VB@MoCP$;93{wb|UYUDjNFF>`FizWE)EH{A~ReNtMvUB TFMs!LTq$KIzh-ixgW0Ph$=+>WHgA}4wOn+M{M%=p`KPmFjxx%a za@R2H@~i7Tx7aUsMWO$Z$gU)X1vwM7t_g%0>a6%IQS<(CT!)#$KjuFbSAO0; bIe_~{)X> yALIsErHi)(?I<_+$*mwQ?Zb0+yGu~%Pu zQD=Us>)J^nJ4U$=mw(wz3cnay8+vlrd*_eulWkOQD}B|` 8sJVdiMDVFBZF D`NZhR^Lv)<)TKBDVH^vPWsEw^lOwn$`q@@ebK$C?)SypOt(8UXRk@q zyXq?aFg#r9-Tu!0d~MdN2d4V(*j^i6P}`H(TB)~N{#gEXiTL{u{2O9V%`%@UzS2hd z>->cl6MScADJI7pt2 `o5oy-5_?j1?rO)G z@(?qfRmV<6Xx!tyR5C~D+SYSf7FVtK`*)eG;@DanGC|^6 _x z{pt0GTsoxW%9bek8(nqbowvH@Gwa`?ghT)A(;Q=YIdpy%JN13fq2rT*Wqczxy> zkFWbaWz1bR?cx3C>q0aACfIyof43 ztTIKe94ahs1tOf$H4NcQE4y5_2_0l#y(D1yY7zVWt7M)o4d3~vYTc>F7avyDg*se5 zT9tU!ZqmFMEup%g^{ot# ^`2K z7Qsa`=Sth%us&TGe@S6ox!l~fPK_b| w6ZQn*lyU>W%f?_Ns7`{ho1NH7pA^l zE@qfG$L4b4Jk_n`;ak$58EKYJJ-n_-FZjh& ~h2KqrE^bPd{2$#VqG8<9<)p&e z%W>>R;q@bVr#xilfA3SfeJ0Lr_H!-k&TgxMTB%c?Lg%T8uP$M|x_rBH E`1YG01nBm7h{A?UgCgqGq C?IF(hExo%b7Z5 z^TQ_3KK#`5#QDp6#I|hs$&^^VWUt4&-z9bvBPPYKKl#ttG{f}ng%z8`q|KL1nLT6H z%<#C@)}>QRr?UROwrulXr?T3__YYn?dGknX>PgXhZw3LDHizictrzpJ^z5E^v*=0N z!QQvKo`R1`gPan!*m#DHS^Me7+$~BQU1lB4IN4;h(`jYU?B7#wyyQKmbiS?rZ-4dX z&E*9pMP;2OrQF3v+VMa87T$75S|7Y@Q~&H4J9oSH#chgD=j8MbI?PgZRg(RR#fu5K z+g2CLsPDR#mST34=ki&Tz)kwT1(#H|zOmUmE2r?iOYOI%vd66capi2dz$Cr2>GzS( ztaD(;n1uv|1%?Kz3xJOWTe$M7{;F~b-$iDvZc5o1SJjUBSw50HzB0Y+a#}=*V`mM2 z_r7=4clIrhKXdYD>Y?55SG-bJtTCR%k;K&^TkgU%L+oU|`pcgiuEeROuFOmM9W!~e z#MSDJ*CN_p)b;rGo)q!F^{8{@ezR*gb>l6U&DpklTZs{S#KZ!V`9UggqcbA+?@7)L zKY3X`yv=gS;Y(La6>c0{?P#5GdrjT$MWvfI_m}Q}ZGW2crs3Y_4?4dUs+?1|TJ!#5 zfBU_z_O>m>-nZJ9&n>yIa{8{z!TJ8HPVQGqI9%E%=NMM*dC_&sqU^uQ@7C>}?8CB| zr`T%drj>IvxJp}omnk=~rWs98Id$%x&MT)jp(9!DO6%q}KhR(bf8oQ)?7TN df0%U!GO6k{7(L=Qx35hG)p YSu1$tRfbaQ z%#F+&FFx{Lym5Y$fO0+W*=-fmR4iZS%gN>c5!*MhXT!>wFTWm1Q#4<1xY1_Ou_G(f zw~5%7{66rnr*Z1LXX!e}m$3cQn|kH`G9gc`UuvQrS(TG+NvVn6SlGikjqQ-3K!k_Z z1P=v+2`8L_xEl|+IooyGn95mg3lX|sE^*L)i|Em3UF%-C_vomfi`h~1_}qaA8O0;q zy9;@D$d{fzaKJ$!p=a05qi^C~e0wcvxv{8T;b(1yNXVW4-DiInZi_lUcUx}K+E>r7 z9J?~%vqI6+N~s9#OAL nO2$J@4+8*2A7Dg>3onPVV{3+537)>{<&`nRBu{=?hGnkNEor|Cg@({r2l&`(L-Z zO4Q!AUP}sgc(gvD)~-PR(VOSrAMF1!>(l1F3EMyLGdz}U>nT4!KUL(l(oYfh_V8eV zJ16&9S?>KHU-Eb5zeRGM0aI$3WWAZbubv?!_E(R=eV+7=<%=s7LfjN99wy4|xP4&J z`#s;k{R?xie4L=YPhs!+Ce1z5or{`mSB4iV-PB)_`YGkw_Bprz9XPoo=|w&h00?b4 AYybcN diff --git a/firka/fonts/Icons.woff2 b/firka/fonts/Icons.woff2 deleted file mode 100644 index e9e305f27d5e78ec2d5047f9660e01b0de6a1ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173620 zcmXT-cQf)23GruOT4ut)#lXP8CUu8_Y3VZtMh2{acS?)DO!IXWwgiR^0gPr$D$I+d zSlC#bbJ!K4HKevN?dwT@cb2ik!E<$C+1$U=vx2QveKu` O@&G-q%drsXpJnzUN&j_bJ%J`*?Z zT<^+q=V5`krIX~uskY50Ti?njES`~DZXxn6YhjknrEk8mGW)FT?#V8WPvTy0Vfi-4 zZ>mrI+fDBG*%lp_JZBvpICs Q=(t)^;)&$ z)R)~eubs*ID%aC7qdPUGW2ebx?Z~}<7e*f1yUYFUrE8`84xH%dsDA0I8fx^@(Y`t) zj=xf(?Qe9Bm!|8 m!nS%V-|2 VN z5qbA6`^$Bcv~J#f>$f^>YoC&mQjLh9*2+nD?=G#%-@0p(`t#;rfoENg_;hxDZh7um z>9b?;AC_tD=e^8kB(Y64IV55{ V!R#f3I-(x%W)N&5|eXBt-P+7F<%ECRmYkLh12c zFT+)m@<& z^Z)k%W89y%j+#?e6NE-%r;2TvGf(qJC xl#8NpLFS_*>0OXv9nuyYRJun z3lpv{{v~&RiSEDP-~U6)stjE_w60%X6901R?&*<-`;~6_KXNepyU@5SL~YU5%D)?K zhG+l!>#`^JeEHh7S8n; ugz!R5uCdunO#qk|$xcI@td^<(a>)21x~ht6}@+9#h;tSi@h`C25^ z=bBIPF`nRQwuhr;uaD+%Nqt>6Pr-mK_0GSYHOANGyVWbMt_f{j8L)NNuB^AewV$v( z b1>@V=2aJ%nMPt$GXQ{lx||Ig9-#9(kDmGy$%z20Sg?21P#|EGJMyYN4f!{m7D z?u?1Gduq}d7?>o?Zm!EZ)+n?ol;x9TbFu0niM2DrE^C;qQr8F$@|Y}icjN#6^DTeR zf4A!Ato@ggKB|RSf1aiAAw+PJ#N_qO2ZDrKe5VR66zm9CI>E}zV}YPhkoK*R=7|kz z9T%Q5Y*S@V+$|$yBxf07`9Q(i|NF(L-OK-*{r>+yYKeW_imZsz>$?`6f3oA;H^a_8 zSDuY|85vs|#afT4cnEO_&i$B@zyHy^{*VR+3Bzr-y;^cqU1!a(O%ph>W7geid^zG= zb3P;`hfEf_)4`&) !HL zq5(5ACr?j-%TBdlKVGy~ |6DAcQwoP@L$dbSs#t7a^AGeiCQLc zMMaCDXMU3U3!8gS+D@^k>6tn-ygD-H seb^)>79>4gu9TehWWp>yhFu}OZ+ B^In=MbmGbz2{&@iir7A=mp^5FV5_@F;OrS^EUfOyT5RR}$uKP_Y R9@CgWG;Uq5^x~3>+iemR_5Py zw?;T <|G)k7|Mh40em{O*CVB4O`!{~CxV~V~7YAvV;Kk3E*hUq4 Mk3UkV5 z%iIh4j`{~9)b|{zd(HXi_BZLINoSPZ8(Skyw@u5~rY|-zZDK{!3=_8d^OHiiNvqG? z`*ziThLq@Z2Pw}Rh3o#E{rP|M^4aUZo3GN{&DA1YcFZwbhC#43f_0M0rZQ0huf*_M zOL#qnyre}htrPNaYGB!&(8zf+uIaF ?1ngcV%lzU0-~CU2{kN>vz5Dyl zb&Eo|s>Yz)n1`;aTbd8uICA6A4xKm6hul~1iazvH#7`(}hE9+68ojAPaRrV-=7wQ6 z#3FC7*-BkrJI6XHbkF~vSAPEgzVG{qlgInxPiw1vRar7aWgDkJR3}p#!?N2&3nk2V zdaU>oxUnV0(^zY<-6qwYCzg8Z?YOLaAVhlClm^cvuUT97UQ7G8f91db{>GR4<-gwh zz2I%4hRlOa!71z~=18!JojG%Fv*+wK(@8ovjgFMfQS-}EXSF$EP`>u%mH&2I|L+Q_ z|Fa^?uRQd7vQL?O(1*Phn-iw!-rgv3bDD1Ei+j}zehZk$?s8yWak0lO qbNZ*=)y##d{P zkgdkSS7o1^68#@C(Xh>i{R78@JB4@u-nuz6wt$go0qa>y$=627%`OZ7o&A1)zLAgO z={e`(j!&>WJSA0Q@BQmfLB=W-S#-p^==}?NHN}qY>S^D~<%{R9p6~m+JfdoTCHp?_ zrVbWPB_$yj7Z()|4xu-NGQsa(#vJpTd+OfC!?*T+UcMnW^-NQrSY6R3)+rw@JAeJh zc8!6ViR1tOeIcvg{%&O8oDibraMA4PtQ9hTmrPIXj0l`^>gAcpmocH=i)6y=-|c?C z|3Lr$gAe+DFi0?Suqt_IF lvuI3>m1KXxp~RW+Elb4=$y{Yb&luOBuaUt@~?|onYHv)Xy{t4 z@~v+!ub#CmR^L2w_q{Ux>f5XD@pfM|cqg_ua_j&9+dkcww|nqHT9J# aTHfa+ z_gB4|8GhAvQk2xoY8SSK>eal;k0lI#30M^?GWwc6IPh10?ULBl%XyzKiL*Q-6&ru1 z|F^Eu9O>DNrKMB7_OGsAz5my*x8JsH*{qnIroSvRchXap=chTPChRQbV3c%V&PrBh zPJ45vLvcrXN>*8eqH)G6`F9@!!wVSvH|FtoA7o%_zW*_4!@vKl!)6M_+FpJ$HQUS1 zM32*bDX) 0<=%OBF)e(~P>!!t%yMK-) z{g=DNC7P1MnzCo&o83?JD)Tw#M*g2%^5;d={hCYX8yGkRPOvn+-CXNjuKsdKnc&=y z|L X93lE1H~Lb8`9Vxcl{g z_Iu5*zW;e|e0tBdTbH6V13~#>(UhB?|5yL>x0>_4W`42!?TBMW)0S#!ty-m}rKFTr z%w!_P(G*aVDzHcN YYL zbCt=hohMQj{`)^w$vp3*(O1C$7pqMZ+m(I)!1siu)xk1=_X -LHe$p$ntthM^Y09FSsjGr(rLHduD_OOFlHo=n zuf*ttwQKtVmd=v0nyfdm=GDt5F)o1@)wV9#`u0`A_Lr=wrhk7qdaT^M >c z=kE9Ze^B=SGv)mMRrx>n&ENI+Q?Q}Z`s8Ep%D&~<{{EQ$+F?Q06t?RX3}L@!zk0na zC(P<~xa!%`YwZDro1Uz?;@XvSRO{--QwJ*)n3r`J|KD=s!x=ug?v6>*1ld?UPG0)@ zdfM}Qzuzv}9rxoAfAX@NTZQT8rX_EW?EJiRw(mR7rE`7ln%n&+Svp<$aWW|V;@Wwx z(XnB7zekzg%R0XI%l@3BvwClRiQ2v7?X|KuamANY=ck6 !%^y7>( z ns*FJR-RhI9{EJ)`_Gepe$Tw#J@u_n*tTJfp{A{b z7bAOtPDDYQ`X2@ZhYroY3T_q&j)Dynl3IDB8NHH}WM@|IdBSWT@wB0MUgd%V6LiC~ zT-HRYh-_Wy>i;V^dSBWvE^$rQiC(&kQnarnT)D7m?d@%{(Kol+MqfOjBYo@GySCd0 zMZ9y(4%(c~eRk@mxy|1*@BbdoURV7hd;iaKmHc}?U92>ht$5KH{!jm+N^;wsC)#sE z!Zy#Iy@y-W)brJy$7-hovhG*D&Ao4ZDQxl0t#V)XReW8x_xcOpbsFaj`RgU*O*S6m zXK+!8IN;RSER&p9uqX2A4C{R}Qs=wZ1*RToV`j~2smTh@P-IZBn(??ne3rwF841nm z85so=9`{e7JboIB-tkNnZIin|+&|{dPW>Tg{Z!V;QjI=p0+upYf_sk2tl*{qi_@ zDI|RE5zlFh >a0^Zo_F#D4Y!0Rch9!yHmf3_>L$S>NVdviUSo)a%=e zf Hlm#@RYjwbIjDz7;$lg|Bd zV_SUuyuoRi&zczyKP*mea^X59oyOdkaOj{X@1evKoIG5T)8|ZE{~>}w$?M;i8`Xt1 zUk~SB*L_>@YO&zsw458|@2;7zX7jV{Q-3xodYXS$ -@rM`yc-=HCYHLU*nOf zd@$K;v5&!Vt>`%gCzUyPxXd_Jg-xvNW^|QLGc;@DP;OS5m66;d8YPj`&%EyjLqmI~ zlyHOu!wSPTZ_V8W&mSB$-yf2>^VvRgrFSZ!XV&DzPPxh|^t_;;TlOU5a~ ua!YgM7-Rj(Q=9AFmQ<_;Tc5d5salg#juOf=>%{pJ#RXuIKzvkwr z6Wa2;lBUnE%*`ym#_OvyZPV(jvejSieXskv{A$+L*X37o>s41@&AYWO#?kY(-unx# zKUZyyU%vH9s_oVE(5_Q!*Gwzb+p?u=)mnSjReASzn*UxifA^JDU;U~se?K-WYwhQK zCin9mzjODScXp-a{Nq2REcbp?oA+|fa|3y{nSTS6`;8ASF+TS;W3rEJgwCA{QhTdD zKb$RJSM^K%)eGzL_n|Ry_xhX? z)4jI0b@lxUjZ>B_x!7*@C`I$4ieI16)mc^Nr@x-}>&fiHein~s{f?`6&M&`q*9Y_L zZL&K*9yvWdX_Da?rQb166|b&%(K#t?R`3Obi;tF_m9n&m-Ma9yUiGW=>Qd`>%dRWA zo(@@ie_zPeMb}y_&Sgz8fBmM|+vH}+rc;XN8;g3TsiZ#JuyJzA$A_Ua*F-Fhn)O2M zde^xxdVZ^%Orun}S2jn8vH4gg^i0&*bdEE8PcvgefWe28GZz-FnDagBwEy{^7w)T_ zjoSYH%+~eWV%(I4gO|*7oObisoU&z`=FLvHIC%-Tu(p9p>A$MOnK@c}%m0eLD!t|Y zeX7)!m*-Dy<&MtDPJI*cUG_}OuCIEBkDrg+T6*Wq!rpVX>1qDo((Sr$OjvuP`NJn^ z-RMB0=zAp$N89;Y^q*WjD3kuj$*GG|$>)cM!J(#X5q+^6&*waA%vZbltW*BZ#3iR1 zG}F1ZME+ICj$giGL7&^EYrC#5p7(WW{9Dx%VM|v_yzB~HJ$=gZThmHcE^pp9B{ #2CZ{kq|@pZvhs7=$Md26HQ%;t&-?KtT>fmt_Sa{cBTtw0#5jE2b^LWh zcV6_pUr*TWf1dq+Z^rhwC${RR dL6u z@w0!y0vG;ZosCCXZFwd{9N_c&z`-HGAd#`+qp)I>V`Pegu%)MamC*#(o70?kPU|lc z31-_V7+B*t=|sp}y<68? CyA^US9acK#G6)9a)NdG z-R(Wx1MrQhd~{CsheY`UIp i~}xR`jRb@%1C>igU4zW4e6SoQwb(*3(1OuZjd`eLX5 z65&HN-Btl>_f1*IchK y93N`fYm1wasOrS4|5i$t{^7d(Ph@ zq_a=k>AL@qE&C1f7oDAPKD79CwbkmQohLplUeFvTz3b^$+r5obcORNF(R8< 7)d8acc&y;$IjO#JIWL=C<90s7>oOrElK- zV0TnL)8mzLj~CqgWyP~A;)vRegIj0%%yzt(`%?7DBjqke^G}_Bnb%%qQrx|4*Ej3< z@|o{n|JD?G;Wpz=P3wI(u?U`d%?Fy9exK-mJkPC~Q}XNrgNw=cgbZIC^W+0XLX+Pw1|1GZ7|oMdDqe?)!d{B)8aoaYdZS$wAKQbrCU57 z>D^WKyDTO7{$SPY@7b~^zR&d(nERy1eZxWa3yYpS^4@M$acA1Hy}mhf{xuYHUATQa zw%jAxTkr0Iw*Rt@zrQ=5>ot?BU=gpe6fmv6Y1(;bx9U3A*Uzu<-!XEGKcDxw)#hi< z``^5>?)glKcgp{B%l)f4Jlmf6e!9zImCoa~aa{Youa(N^Sh+S=C(Kiy@bdQG18(`% zPgXu<^R{bT_x?;?-`vQodzUxq*cfp+|MypU<54(4=+q`Q0SC3qf?xi VuY}xMGyaWE3bP)@{cV)~ zrEm7=i|^0oSLIdzMU8hJcx8UkoUyxnfkAM8F^fXOy0wch%(P; S<^jzb8>_+vbzTmw=LVF}CpZK5avv|>)AX-0RasQ0g z+k6TOu8G>+`gVWe$5g)hBOWW9-u-{1FnNK|o+ggTclBPZc3!zr?BIl!f7?a=o?b9j zV=cq1Hv)f5I#xDDe~-;jo^^>Q 9klV| zbz875Y5uj|fVZ!ur~ZFAOZ#c!&wWad>+Y!hNSV3ZXSaZ{gU A i;+7L*JV1w7iq)QTgt&w!$&(;`~KbZM7m@>Q^GV?p`-P zEi7{(z-9VFu0TGa>U-xcnkKY1N_^j0pgyy|>&He9m!n~gJF@fUS8m(<)OMNqPHRVz zR6Y++Q6X)G7j}AaZy$C%x$%OtbN0K2nJ-tAP1ttOz%Q56T|4Un!}2yRf5S3o{ryIp zwlFNJkcjEwyCP+#wb}2ka{QvKT}>+&`rAD+4a%PArG4K(oagJ^OG`9A-kJJ8!bObR z@#u~dbz9bQR4xs8s(Gqt!;Z(gzRHS%Y{|-;^As!Gw>?-CFrCLz?$puc`uG3+2#<5P zm6sQhvE^BPevzfnO5tkz)*h>bdg1k|0&A|{mTY;E-tm0XzX^#R4A Cg@%| zwA7WYac`sX1;@N5)fO(1zDLF-{R%gh{p8zyLgPkU#Rknw8|Q?j<{Z0L?v>pn-W2-c z-$};1`yw?t{JZaW9A-_xLvp;!M0}Mtwar$_C?(Ojvp3SKiuTM+Eag$`$O4Db2E<^ z)F0(~85NcOy_n(bq+_N!Cxw{iGwv>yZTC-)e#EONa(SEZOvl$8Ju?~fKK>H!Uo2X+ zRhHM-s>WHM^CElX4Q{o>7lAIKhh{g5zn6HX#pqQ&v*%aN4x=fzUbF`sw_h{A+)iOr zBj-v11^(BT8!v6!6!+7%OO5MA;l!u1;fxh>C5Dq{7+e+qvcsR7W$QIYMlmNv7DE}v z)MaNF?L#hvHVQlyJ7oOn!)-~HqDWamY5BXX56fpu#ozf@+WqeMcT0|ECpSzj5^>S| z8D{n1Zg~2IfXd#xN`BJn=TBZLpVR;8NVvn{L(LT>Hx4X0q^758+stjvn0qsclbt0b z;+DB_NI>%YppW$llQ;DR#D~67U19n-#<*p5Y|Hklw_FkPBh1(Ep1&0@I(eeOVU-JE zYmP5-Q@XT7(ukF%=cOFy;UMP|zE`A;r$lwn)=__EHOI1uZNBI$(ceo~xRpISb+qDF z%IezVv;S`Y|Fq%2G@}ZWRmr stC^`)eZ| =U4;t2wqD(HHAL}ITfkSw @Bp=Wt&?u`lzwj&uj>)w2_1j}>q1lAJyFtc_LuXX!aBzsp_gkCd}l z-(56y^ZVCHQD%aY*)ccr=kAei@)WKPI{R|d^4Z&_|9`izH=!l|(9XHuQfxZ6#0sA& z<)3O)b+6l5k#JXeZ}#Qi+H+)g^sM0C#ZmA +$Nf)TLbiVWRW0=N+ottSe(vYIcI>~;e#D?Yer}Ne;f>lG-f#H2 zH~*IUr3v;0)~oH$oVYSm!;kUF+ my*Z4D0ZU`;w*F3J;g;{QI~rm&;iHhzpJ`iuPHJBELwQk1 z M0L@ zbeQ|^Pl@{XCE2 gs_6nJonEn5u^fLaSQG*Fv$ICtk(V~ mUlmSwD ))o9~uqn=KR#NO@Pb(t9tv zWO+YNy{h%^2)7v;GcD)aJTa_z-Sc9Z*~Z>^_TJ*W^<5Hc50`iBGrRen=kEQj_pe@> z(0Fm_QPHq{+9i{#4p^qVIK1!l-wWI4cz($_v3Eb;v(u0Nt#NbncydSU5a&tR<1KD3 zXHK?kn!aP7hudYrCUHTtuQG?1cYcqJC^oN1FWJ0J=S|a+>l36}I{$49pS7@P4r|=f z=cjwTxu?E5c`Lhg?S4U@rI$Cy vbU {hj%KuFroBjs=%JVg-~+ zLJq%|oW=hw{e%4G!;TpRMj}#Ers=WoHCA>hP z&5}Pc*J8=bKieABw)`+&n0WW#`Me*qpZEVybGBakQ){!UVblG;-=n{=e=GF1b_gls z5w@THhHu{E#?}7wKUX(7tyq2`Lh{g@!d5*gHI--cZrKFbYH#7q-_)t)_Qd4>>yYhT zxoqrC4i6)P|L!ern67#F$yNgv-E(Iji9D9})$?|JX?Q~9ip0zLIeYdkWOv( - a)w%WfNs4vMqK-v2AiHurk<(u-V|X6(EzeLHf$x0s9N3!`NZ&2;9=2cKly z(B#aZxL}jApZaaViqh922eV7`_~x&l@of6?i5oThyEZj%-MPIvNBGfC!wan8I(hrj zH?LOJtMQ+>`$f_luB?sM(=YD- ?{rO|&!NarCCkeT7E1N!z@?Bb1u+EIR zZlC9F=Cw8q!jhZsn$*gQKUDX1&N|&~JX3n-Pv^%^_NaVUijAnxeCu7`YQDyEfuPpy z3ei;cTQ)xo4&T0g|CG$n`5$VZ{q=EOy!BV%4e`T9b#LDD|1Dn-v^YdRd8&G&S*O~Y zYue>EbK4E-%WlmV)c2j4-f<>E&g|REb#tdI_+R4sLvn85hc#|;))Ki3QupggCb)09 z`HrVN&*I{iPhb7d9*Ui~>~HYl2Um`IG@Oc }fJQtg6JNW6Mxs2`kY2PzmrE2}X zv3SkeU9YD0T;#mx9v4}4$yzh#l d(xVcW!876t8SGJ> cwd zJ((iTAvbGJ@0Y}fFJkUZk2@#N!*^%GYD3SxCI+fc%ryjOPc7QId7{Tk&TP~D9K1~# z3KBf+qQ4sty_EmB=f{h$7k@97zru5P{V`RG)1N~o`7`f3dcyYU-NJbvb5=V=Z^*g5 z_RcF$PNuYX_9+bKq|(Bkh=!)Um|pxseo1A8e#E}|4>kW=FB%Gj`Rtyjc0GG7Pj&76 z;>#>*^Ukhq*yv%JKjT$HLxIcHsdg9d8eE!`d*QBc*GI{Bt1Ir_dBFLte$G?lJHH;r zTggw0I<)dmvz5}T ^O8dWCnk$bMp^_6OmsM zPrmJ1l>19`hxg)rbF9V7of{4msQyloHGZ*r!v)@M&n
Pfvww;$B9?h#gV(Yfx zp@G)KsXJ#VOt~=W{aIh;9zKVw=bQKcHY#27^7TTQe|93~s~p_yGp(3@IgRgUWTA8K> z)5{-Ab)N?AR}J3%acYTcpQ_f`=d*Oy6-=Ad*0%qk%_GBKS2Rx;NuQtpOgczda7ygA zSJO7dzu6IyvD=^~$aS|_VC`YK)4R2!SeV;owceMy?0QuDNj#|A?lai? z&-2^YO{>Hj@6Og+IWKC%M$f!^>TagKjD}*}C${x#9j?2sxwX0E>8%IbPJ}f_%!!w` zjhfKRxnk}5Jt^u8?V4r0^YhhZYL_$Zv2ZHBxV~Vi)~`p4*co5j*}QI#udC UAIVOiSL8SSj8~<8@>|X5 DHZ&5nUcytE#tbyO{6YKe=heiY_ZBUwx=* zCf4#UEJ{RRI;YX`Ykm$#CA<2p*=kLzs*-YN&HL&$?fT0Y>7C~f-b;O1A0E7FW$8En zuDItLzaHg$#@;)>E8q7bN7tv$ypvVGIcIrZd?dP5j@dXueM1wUWbW?RwOx^o>)g9a z4ScTDX#9Kfotdre>H1gqXU*FXQ}gG~gQd+oJGcCaeZ(jyUU}%EeZam&HEVqq1e+!2 zR~hC>d=L50vr4Po^$1JO@g+N-_f@3?ue>o))+CF~Q~!NQ`t*<;o-f)({6c~!o8DNl ziD~VG&YFcqa+hZ8n0?sf2E!%wsylWI`<5%MvN^@bdMdHm`f!&+W3|iU)h~-;mve6} zHCD4y`|f{J=W;^m#%+81KB&y_i84D8eANBO+33mw TkJ|7(LZ{j ze$F*>+7*=-ewwpIZHJ_6yhq{jIXi`>CFWJS@;8;ujF^*oC9>x0*Q!17w@yWz5&2e9 z`2C}Dw4B}Y-ukc!w?y+ecS}_6K5M}})n{q<@;h-GSh*67`<3hUa%+VDKM7o`VrefP zRQE@(c=FNxlRh<;UQau}h4H5N+X4~izKf!37aAxSuAE>dm|c3|>pB}T`&%bNn6##< za@<$f))RlH+Mdq-S1>8_=nc-(A*M$@%$R>vBFU-$m1M%kOY4gwdH%_iC@};iHTzvC z6}xEFw6D1?@09>kK<}A|h3f^^+*o9kVd%fgQQVfHp_EDI)dbgyz0F-6+ju8r6}O6M z2n6{So@(Rt(+IxCy5~;!>TQmTgj{C2_E-Ef{b6BYk+_rNtE 9UF?) zh&*Fdnc41;x?%CB85^fK%&hud<=ve)wX?BR!1~~VKHe3(lo^ULH ~`Du=W6{JOa#IkR?Md=WV7{cNSfpQIK}pHn2bT6=*rf08Zlm03 Idb_8Qd-}`; zd|wRZ7ACFUy)QSi{%J^e!AYg<+wu$puNrx5I;C(h?ti59#%`J5)CX2;d|Sl#8gDIP z7PI8%b4XicnBMWsIe@Jw$7HqL?ChgwyXH?(-=QNdw#q>9ZP^X8Z)SZ>Z^TTt2(D;M zobLa#>uAOkwe;_P(*=(&zvk DFPwi<={*hz5YuO98#&}ud*`M<+hFIV9i59+Q@n~H-uk59Q{mdory)LI-nPVm3 zcIQCI3&)jST4j?KJ82|4$Cloy`;>oi+T_kzwimcpE%ul@=kHvu687g3-g^^2J@eMN zKkLjSOTYgewPn?otop~kPFU0bWrxSi%MUxA9}(cut25G`%{MbkXW!-KN=?lN!3(6l z+f0|Sp49oezIV#xfOq2h9NYdqemVQ?R%7cbZO#7)GS22cZEM?nHXNGPx8d#QGY7s` zs+}pV$QO>Y|6K9v?;XxX*KVzvBsKL(!Rr(AFY2?ETPzhy`uFi%NmFnEbH&DvXWY{? zb?hVdJoswoy6;4$@>%|87v$}${Z;QOeV%(V __F?dX|6~}h!fY0 zBkPVg^JnZ9HA?-;eqg)QMk$t68)tr;ymyCpe8SPly)%AJ*6S5~`B{ v!1t+{m*XJvgyIQeoy_Uty^ne|Ju{k;=tZLAN5oJ zZuavZlFuYsigIaq*24r`yb(<8sPd((1 }xz zZk5Q^u19w}YhKQi-+1fB3yH?7bKg7V+e}_!YbIl`#`&cKuTEUSe!eFkk{&yVAC0^t z*cHY+ahFW> &z_abh(_>wHJ|!VD51NL~C|lkf{rE*o@=MJ;>9nK=oZR&? zJ^{TZt{2PSzqpsQ#qOf=kM_68FP+v} DE6{LHtX-_{Tp{aWe-$6 z`=ob@lfJ;?TaEd#{)V$HT#d@EP0@d{)%yCO@=le|O)@WLE_;2}_8rgZnP*eEo@`Qo z`Kal2=3nnBX32^OPUr16EpE-=e<~u$cVfB4U5N=xR%Vx3zPwm!ul_g5(yv`X?- zrFz$#pR8MJ{4Q(uDjlN>mZm=I3{LP|7P*yJ`r_}_BR?m)_3KE@Xw6;bXZwduuQn*& zpg*ndLYVuS)35&RT0ZUFZ|M@-oo{L{EU@A$J#a$hn*CR~M@Ad+CGXDrShOiuw!it~ zvW_|KNkX -R59EeK3J>Ndr$==p~{gOF%UTJ$;K3THouzy3j#_AIv6sKFdhs{4) z;g+TIV5XUWpYi!@jmKu+(_ZOZ{yB%Klau?yn%OaD7Bcwl+?hA!#fP*VPF-KakGM~; zFYMoP(o9p5y-1+h_0yFNOD`Kv%X_)|-S(Sdf#;s8d8fta?R+ucsETWeP3M&Rsun$p zO$#QcRNntoAi7-Rpy!SEA`9 ?1wC$US8|r%j1y{Ty_vOds>pR`l30}vTu(>LJQ|YWtwmTBP&VPEu_PAh% zl2%#41ua|0z8&w37_UvxoHHvucGv#O_m}#w)l{#sPqh8PVflpX#Cn+`?&$SVLHyxz zlP~Jcf6RD1R%Frh^b4sEc2vknY-i42e!kgv>O9svmnSq8US09r-Gr}N*k(hn__Q#F z2CwG1V)<*6DmiZo_rGXbaLmiIqxbH1vD6zEmInDUT=e2wV&L$Puj!8ScEk2dNfvn% z${LLvZnLsnUUIW%OFPd=!-`3TMVr-H1$Go%Ffc#1L+#%!;|BrXgZAt`yj;G*&{brk z`raJAJr;hKcORS5XY=jVvNKC|R|b8UFx|6~(|@KS+m+WAo!Nh1s!EvUDQ=#8YG3cJ zl$|nNU)f*Y^pZZ)`m8G;%HP|v?B b;!^nXzovmS?)%W=T8bK8(RhM(OrI} zX31Vfk4-}J)b17s8@Go(INUkqipCk&DMlw!E^REo6MV$i!QIQH>#nA!mi4SBD-Wnw z#s$q^_|Kv$UwQkd_{Bfk`8h3@GX`%IOX0mM(bpgTYU;Vi|F2!IZn@XV`91UIM6>!| zdUn^@+l~uWsr6mxbuTVI{(8pc-~$`o!~Z_`_~~2ur{rNVr!{cc@Bbo|DbH zNg%6@KSycbzeuY)?_ATpo*fhmU{hH)yXE;gr$dH|(oa6jeQG!3S0L+J(SMhIue`>@ zx8uQ*L${uqgmhdu_K`pINJf6!tn$)>2b)q>GRDlQ<+!ANoHs@vox=f7q+@W|%)jrB*Ar-$sX zncDp+`gVBR3bAcHa@G )7vv}3^-=|wUXFi?b@KG!^S*1OOr(2!h@zg%? zmCKfRNNiJbxN)H6qQ*PJUnL(6rpQKq-1EVpr$pdPuj>6}54IMFby+Scy5O}^#lW`h zgRz{Q@Fee?C0`qk2Oed8q|YCJ?T3cuvie?EQ8C-ZM>|{+o43kVW+WsxH)k$ulQ(-L zz9ar@O4|S0)h8sMG|V|U^UtkP>({$%A5EEm=wn*i+; a#4S5$dIxoS&tBWKL*&3p;hiqC6go&L&R&+yA6VH;DK*rG=Q zUm5?TD!gG?6nFmx{}Ppm=ETj;J<3VBeZ{_hci$VVJ2 DVn#rGtw4sz1#od*`o5_zq%e; z9qX4@3$B=H*>iON;$Mlc-tw5$pWl#P*>-pX+yBC2-xAalw(^%RNUtcldn|jQeA&Nq zKMsYqW@$>-eBOS$eDdBFd%igZ_CgVE1_u fOyc=o>kl~pA{ zr@qWT# (_k$b$VHm{$|?~=Nz?vzj(~uZXlgk zyy;Tl+&Qmf9wzO`-;wwHn9a9>^;=W5{dKj&;`4X!GPAom?;~$f$NU8S&-{v7yLAlC zx;ie~#~t@%r9fQb+RuS2Vha7Zg`ZrOv~O8|(@-Z$$> JI%KQ{L)omG23e(Rn8=4NsFr+9R4 uGxmm3dil76^{!a_U`%dFxRTQ$8*ai_Q!qa ze;5b0mme;))aqSU`kpoI*^Ip})9uz}C>>jUr8YNFB%d#9Tgv^)-f5{^Zx+by`CfKs z)%vpRdsp8Dz7EfA$=Dcq!ax{_jJ2;*2~KZ*gq^jyVSk9OkjW9&T}`|^Kw4wx9)wlPVWE3 zD^C>D<16R%#k=mSI9GCY{Vmx82eQ^*ioI!nFR$`?>E-snabGLX&;RxJ{rjN*J6d-= zvDf;>`DN{@2doQXYYxXTPH41d=$t<@m!a!hq+|Sr?+j-&7*?|!kX$C(@Z6A5!C)nW zz{bs)8UL9j-5FAtGa0yA4H>2e*)=R%D`&M{)nLk#gC)0(H@rJ=u7JC5M{Pmr9)=3b zYX{QdTUXGGc(7hdR`>Zxj`H1mdM?4gC**E1}a(A%|}!`w{HXwSqS zM_ztpwG{5IaXlHZJ3mD7t;YSwAG!0p g04il@~;f$6GOP04P-~HQM#wYvmZ*QKMty}kt%i4(w@7SD6KTCYfOi=o? z@9>v?`Ly5}+c!N(kUYt?Y0K%)JzMY0OPYLW+GW$SW!2raTI^oV7GBl|J=a^YTO>bO zGnv~tSFbSF?jLjej_;ojD0ZrE;frH>pIKA=^Ws+jAJ4f2gcK&+X;@%l%`*A=t7!tE z^_*8j6?-hVKURNesr1QZ)+24Ni}{OEzjipDIbgG~h_560ZtA1CssVP-?{{9D#G-O{ z!W=zUS1lJmkHcqt)|MDcr@WZ*|NGQ49+3i{% >R &o@ZzC@??0^ix?u=_%eXwg=y8m#@6D z{DZ*JGjbCz8EjYQT3EfzGVYsqxjs*Is&ZETp343I-|ao${=x3#sT)`7PQUy2@5ej+ z$-Dkew%hj2Ud1Io;LN>-36=^|oL-) a1nZk8>4i&ZQ6`I-w1tz-N zb+kO;aG7>9OW>%4%h3l6ivnME{99|1p0q+j?DGA_2(z>!-}3J4wU|>mLp=QSq6#y< zqsymGVQ{Q+GIQ({;Idn%^3G3b+LX3yDKj)Brp^gZ DlYC^i6 FDai`v_Mt6)A6R-AI6)NTpRV-qnB3erAMxd z`G4JLqtf~Cz{-ggPY>UH5bshqb$#yjKXw!15ACs!`EIVE5Eig8r(V?PmU3&p=*DYd zQ-0qI)7iWujr04Y6HlfmZC<@)Gk5Bte%;iWryou`9(W*bbwZq=XRzwDOLtf0 2;y&5|tMSnJ25%%(Kp!ayDbjT=Qe8I(f^M z^$MHi?r9MeHu0U=5%6-}j1>Es_3M2<&N%h>=oW$4%UgA3JWM(4!`Pj6@#PHNcL(Pb z{4HL2^qjNqtsOsQW=^{}<-V9i_4W-1_PQ>4rjw?7X_=~vrNqW5XSbwEbxnUPxzXv; zhN%J{SH`-g9?a6tzSdH;{aQu(+U~gXTl&qG !rE3j?Qea-ff$EBRT6}9Mj$31;yX<>RZ*>dA^@>EN(9;yZg}A-NXAvs{2-1=C77| zA*be9EquRZf4twx=z>|!Q;l1y=7^d;^WV~wYQa9g#q{~vH9H$ZH)V=<_eW2ciIFQ< z+GQNhnzD;6cuVbd*DbpzKDl TBkKZ*^@2LF!cwcC3oXv!5&lR_Z z^eap*eztLvn}2}O#h02zfxoXC=bpd%tzWz}Zc@tT*f`cIUa_o$(vs`%aYcMOcV^~y zEx($8o6d5v6