summaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-08-10 00:04:25 +0200
committerMinteck <contact@minteck.org>2022-08-10 00:04:25 +0200
commit0417260bf158c5d7b62888dae2e202b0de115a05 (patch)
tree7f54ee56da118813f2d1b3a324d322d0c74fa51b /pages
downloadpluralconnect-0417260bf158c5d7b62888dae2e202b0de115a05.tar.gz
pluralconnect-0417260bf158c5d7b62888dae2e202b0de115a05.tar.bz2
pluralconnect-0417260bf158c5d7b62888dae2e202b0de115a05.zip
Initial commit
Diffstat (limited to 'pages')
-rw-r--r--pages/api.php15
-rw-r--r--pages/disclaimers.php10
-rw-r--r--pages/edit.php68
-rw-r--r--pages/emergency.php213
-rw-r--r--pages/fronting.php879
-rw-r--r--pages/home.php48
-rw-r--r--pages/login.php2
-rw-r--r--pages/logout.php16
-rw-r--r--pages/page.php40
-rw-r--r--pages/parser.php247
-rw-r--r--pages/prefix.php444
-rw-r--r--pages/relations.php66
-rw-r--r--pages/score.php210
-rw-r--r--pages/terminology.php10
14 files changed, 2268 insertions, 0 deletions
diff --git a/pages/api.php b/pages/api.php
new file mode 100644
index 0000000..a1f13d9
--- /dev/null
+++ b/pages/api.php
@@ -0,0 +1,15 @@
+<?php
+
+if (str_ends_with($_GET['_'], "/")) {
+ $pagename = substr($_GET['_'], 0, strlen($_GET['_']) - 1);
+} else {
+ $pagename = $_GET['_'];
+}
+
+$toplevel = explode("/", $pagename)[1];
+
+if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/api/" . $toplevel . ".php")) {
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/api/" . $toplevel . ".php";
+} else {
+ header("Location: /?error=Endpoint not found: " . strip_tags($toplevel)) and die();
+} \ No newline at end of file
diff --git a/pages/disclaimers.php b/pages/disclaimers.php
new file mode 100644
index 0000000..2983909
--- /dev/null
+++ b/pages/disclaimers.php
@@ -0,0 +1,10 @@
+<?php $title = "Disclaimers"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <?= file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/content/disclaimers.html") ?>
+ </div>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/edit.php b/pages/edit.php
new file mode 100644
index 0000000..c031c22
--- /dev/null
+++ b/pages/edit.php
@@ -0,0 +1,68 @@
+<?php
+
+function getSubsystemByID(string $id) {
+ global $subsystems;
+ $subsystem = null;
+
+ foreach ($subsystems as $ss) {
+ if ($ss["source"] === $id) {
+ $subsystem = $ss;
+ }
+ }
+
+ return $subsystem;
+}
+
+require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $isLoggedIn;
+if (!$isLoggedIn) header("Location: /login") and die();
+
+if (!isset($_GET['_']) || trim($_GET['_']) === "") header("Location: /?error=Invalid request") and die();
+
+$parts = explode("/", $_GET['_']);
+array_shift($parts);
+$system = $parts[0];
+$member = ($parts[1] ?? null) === "" ? null : $parts[1];
+
+if ($system !== "cloudburst" && $system !== "raindrops") header("Location: /?error=Invalid system name") and die();
+$systemCommonName = $system === "cloudburst" ? "Cloudburst System" : "Raindrops System";
+$systemID = $system === "cloudburst" ? "ynmuc" : "gdapd";
+
+$subsystems = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/$systemID-subsystems.json"), true) ?? [];
+
+if ($member === null) {
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/sysedit.php';
+} else {
+ $isSubsystem = false;
+ $members = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/" . $systemID . "-members.json"), true);
+ $memberData = null;
+ $memberCommonName = null;
+ $memberID = null;
+
+ foreach ($members as $m) {
+ if ($m['name'] === $member) {
+ $memberData = $m;
+ $memberCommonName = $m['display_name'] ?? $m['name'];
+ $memberID = $m['id'];
+ }
+ }
+
+ if ($memberData === null) {
+ if (in_array($member, array_map(function ($i) {
+ return $i["source"];
+ }, $subsystems))) {
+ $isSubsystem = true;
+ $subsystemID = $member;
+ $subsystem = getSubsystemByID($subsystemID);
+ $subsystemData = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/$systemID-subsystem-$subsystem[source].json"), true);
+ $subsystemCommonName = $subsystemData["name"] ?? $subsystemID;
+
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/subsysedit.php';
+ } else {
+ header("Location: /?error=System member or subsystem not found") and die();
+ }
+ }
+
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/edit.php';
+}
+
+exit; \ No newline at end of file
diff --git a/pages/emergency.php b/pages/emergency.php
new file mode 100644
index 0000000..02e483d
--- /dev/null
+++ b/pages/emergency.php
@@ -0,0 +1,213 @@
+<?php
+
+require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $isLoggedIn;
+if (!$isLoggedIn) header("Location: /login") and die();
+
+$emergencyHeader = true;
+$title = "Emergency Alert"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php';
+
+?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <h2>Emergency Alert
+ <details style="display: inline-block;font-size:12px;">
+ <summary class="text-muted" style="opacity:.5;"></summary>
+ <label><input id="test-mode" type="checkbox"> Test Mode</label> · <label><input id="fake-requests" type="checkbox"> Fake Requests</label>
+ </details>
+ </h2>
+ <span data-bs-toggle="modal" data-bs-target="#turn-on" id="btn-on" style="background: #7f0000;font-size: 48px;padding: 10px 50px;border-radius: 10px;width: max-content;display: block;margin-left: auto;margin-right: auto;cursor: pointer;">Turn <b>ON</b></span>
+ <span data-bs-toggle="modal" data-bs-target="#turn-off" id="btn-off" style="display:none;background: #007f0b;font-size: 48px;padding: 10px 50px;border-radius: 10px;width: max-content;margin-left: auto;margin-right: auto;cursor: pointer;">Turn <b>OFF</b></span>
+ <p style="text-align:center;margin-top:10px;">Sending next notification <b><span id="next-notification">never</span></b></p>
+ </div>
+</div>
+
+<style>
+ .modal-header {
+ border-bottom: 1px solid #353738;
+ }
+
+ .modal-content {
+ border: 1px solid rgba(255, 255, 255, .2);
+ background-color: #111;
+ }
+
+ .btn-close {
+ filter: invert(1);
+ }
+</style>
+
+<div class="modal fade" id="turn-on">
+ <div class="modal-dialog">
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <h4 class="modal-title">This is to be treated seriously.</h4>
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+
+ <div class="modal-body">
+ <div class="alert alert-danger">
+ <b>WARNING:</b> This alert should be used IF AND ONLY IF you are in a situation that requires immediate help from a loved one. If your life is at immediate risk, please do not use this emergency system and call your local emergency services.
+ </div>
+ <div class="alert alert-danger">
+ Keep this page open until you receive help. If you close the page, alert notifications will not be sent.
+ </div>
+
+ <button onclick="enableAlert();" data-bs-dismiss="modal" class="btn btn-danger" style="font-size:20px;font-weight:bold;display:block;width:100%;">I understand the risk, enable the alert now.</button>
+
+ <hr>
+
+ <div class="alert alert-danger">
+ Once enabled, disable the alert system ONLY once you are safe. <b>Your mental health is more important than sleep.</b>
+ </div>
+
+ <div class="alert alert-warning">
+ This emergency alert system is designed to make sure a loved one can get in touch with you as soon as possible. Therefore, it will emit sudden alerts, and may surprise somecreature if e.g. they are sleeping. Keep that in mind.
+ </div>
+
+ <p>
+ <b>Disclaimer:</b> This emergency alert system MUST NOT be used in life-threatening situations. Although it has been extensively tested in multiple conditions, it may stop working correctly or stop working at all at any time and without warning. If your life is at immediate risk, call your local emergency services.
+ </p>
+ <p>
+ This service makes use of the ntfy platform, provided by a third party. Do note that their privacy policy applies when delivering the notifications; although they should not contain personal information in any way.
+ </p>
+ <p>
+ © <?= date('Y') ?> Equestria.dev
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="modal fade" id="turn-off">
+ <div class="modal-dialog">
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <h4 class="modal-title">Make sure you are safe.</h4>
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+
+ <div class="modal-body">
+ <div class="alert alert-danger">
+ Make sure you are safe, and you got in touch with a loved one before disabling this alert system. It can be re-enabled later at any time. Remember, <b>your mental health is more important than sleep.</b>
+ </div>
+
+ <p class="text-muted">
+ Scroll until the bottom of the page to disable the alert.
+ </p>
+
+ <p>
+ <b>Read this if you want to disable the alert before receiving help:</b> Remember you are loved, cared for. Ponies rely on you, need you, love you. We never want to lose any of you, so please, keep the alert enabled until you are safe. If you are unsure, always keep the alert enabled.
+ </p>
+ <p>
+ <b>Disclaimer:</b> This emergency alert system MUST NOT be used in life-threatening situations. Although it has been extensively tested in multiple conditions, it may stop working correctly or stop working at all at any time and without warning. If your life is at immediate risk, call your local emergency services.
+ </p>
+ <p>
+ This service makes use of the ntfy platform, provided by a third party. Do note that their privacy policy applies when delivering the notifications; although they should not contain personal information in any way.
+ </p>
+ <p>
+ © <?= date('Y') ?> Equestria.dev
+ </p>
+
+ <button id="disable-button" onclick="disableAlert();" data-bs-dismiss="modal" class="btn btn-success disabled" style="display:block;width:100%;">I am safe, disable the alert now. <span id="disable-timer">(X)</span></button>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+ window.alertInterval = null;
+ window.alertIntervalCounter = 15;
+ window.alertDisablerCounter = 9;
+ window.alertDisablerEnabled = false;
+ window.alertDisablerCounterInterval = null;
+
+ setInterval(() => {
+ if (document.getElementById("turn-off").offsetWidth > 0 || document.getElementById("turn-off").offsetHeight > 0) {
+ if (!window.alertDisablerEnabled) {
+ window.alertDisablerEnabled = true;
+ window.alertDisablerCounter = 9;
+
+ document.getElementById("disable-timer").innerText = "(" + window.alertDisablerCounter + ")";
+ document.getElementById("disable-button").classList.add("disabled");
+
+ window.alertDisablerCounterInterval = setInterval(() => {
+ window.alertDisablerCounter--;
+
+ if (window.alertDisablerCounter > 0) {
+ document.getElementById("disable-timer").innerText = "(" + window.alertDisablerCounter + ")";
+ document.getElementById("disable-button").classList.add("disabled");
+ } else {
+ document.getElementById("disable-timer").innerText = "";
+ document.getElementById("disable-button").classList.remove("disabled");
+ }
+ }, 1000);
+ }
+ } else {
+ window.alertDisablerEnabled = false;
+ try { clearInterval(window.alertDisablerCounterInterval) } catch (e) {}
+ window.alertDisablerCounter = 9;
+ }
+ });
+
+ function sendNotification() {
+ window.alertIntervalCounter = -1;
+
+ if (document.getElementById("test-mode").checked) {
+ document.getElementById("next-notification").innerText = "now";
+ if (document.getElementById("fake-requests").checked) {
+ window.alertIntervalCounter = 15;
+ document.getElementById("next-notification").innerText = "15 seconds";
+ } else {
+ window.fetch("/api/emergency").then(() => {
+ window.alertIntervalCounter = 15;
+ document.getElementById("next-notification").innerText = "15 seconds";
+ })
+ }
+ } else {
+ document.getElementById("next-notification").innerText = "now";
+ if (document.getElementById("fake-requests").checked) {
+ window.alertIntervalCounter = 15;
+ document.getElementById("next-notification").innerText = "15 seconds";
+ } else {
+ window.fetch("/api/emergency-real").then(() => {
+ window.alertIntervalCounter = 15;
+ document.getElementById("next-notification").innerText = "15 seconds";
+ })
+ }
+ }
+ }
+
+ function enableAlert() {
+ sendNotification();
+ document.getElementById("btn-on").style.display = "none";
+ document.getElementById("btn-off").style.display = "block";
+ document.getElementById("test-mode").disabled = true;
+ document.getElementById("fake-requests").disabled = true;
+
+ window.alertInterval = setInterval(() => {
+ window.alertIntervalCounter--;
+
+ if (window.alertIntervalCounter === 0) {
+ sendNotification();
+ } else if (window.alertIntervalCounter > -1) {
+ document.getElementById("next-notification").innerText = window.alertIntervalCounter + " second" + (window.alertIntervalCounter > 1 ? "s" : "");
+ }
+ }, 1000);
+ }
+
+ function disableAlert() {
+ clearInterval(window.alertInterval);
+ window.alertIntervalCounter = 15;
+ document.getElementById("next-notification").innerText = "never";
+ document.getElementById("btn-on").style.display = "block";
+ document.getElementById("btn-off").style.display = "none";
+ document.getElementById("test-mode").disabled = false;
+ document.getElementById("fake-requests").disabled = false;
+ }
+</script>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/fronting.php b/pages/fronting.php
new file mode 100644
index 0000000..359deb7
--- /dev/null
+++ b/pages/fronting.php
@@ -0,0 +1,879 @@
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $isLoggedIn; if (!$isLoggedIn) header("Location: /login") and die(); $title = "Front Planner"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php';
+
+$cloudburst = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-planner.json"), true);
+$raindrops = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-planner.json"), true);
+
+?>
+
+<br>
+<div class="container">
+ <div>
+ <h2>Front Planner</h2>
+ <table id="planner">
+ <tbody>
+ <tr class="planner-day">
+ <td colspan="4" id="planner-header-0">Today</td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d')]) $cloudburst[date('Y-m-d')] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d')];
+ if (!$raindrops[date('Y-m-d')]) $raindrops[date('Y-m-d')] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d')];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d') ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 0);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d') ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 0);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day" id="planner-header-1">
+ <td colspan="4">Tomorrow</td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + 86400)]) $cloudburst[date('Y-m-d', time() + 86400)] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + 86400)];
+ if (!$raindrops[date('Y-m-d', time() + 86400)]) $raindrops[date('Y-m-d', time() + 86400)] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + 86400)];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + 86400) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 1);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + 86400) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 1);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day" id="planner-header-2">
+ <td colspan="4"><?= date('l', time() + (86400 * 2)) ?></td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + (86400 * 2))]) $cloudburst[date('Y-m-d', time() + (86400 * 2))] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + (86400 * 2))];
+ if (!$raindrops[date('Y-m-d', time() + (86400 * 2))]) $raindrops[date('Y-m-d', time() + (86400 * 2))] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + (86400 * 2))];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 2)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 2);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 2)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 2);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day">
+ <td colspan="4" id="planner-header-3"><?= date('l', time() + (86400 * 3)) ?></td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + (86400 * 3))]) $cloudburst[date('Y-m-d', time() + (86400 * 3))] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + (86400 * 3))];
+ if (!$raindrops[date('Y-m-d', time() + (86400 * 3))]) $raindrops[date('Y-m-d', time() + (86400 * 3))] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + (86400 * 3))];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 3)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 3);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 3)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 3);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day">
+ <td colspan="4" id="planner-header-4"><?= date('l', time() + (86400 * 4)) ?></td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + (86400 * 4))]) $cloudburst[date('Y-m-d', time() + (86400 * 4))] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + (86400 * 4))];
+ if (!$raindrops[date('Y-m-d', time() + (86400 * 4))]) $raindrops[date('Y-m-d', time() + (86400 * 4))] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + (86400 * 4))];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 4)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 4);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 4)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 4);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day">
+ <td colspan="4" id="planner-header-5"><?= date('l', time() + (86400 * 5)) ?></td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + (86400 * 5))]) $cloudburst[date('Y-m-d', time() + (86400 * 5))] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + (86400 * 5))];
+ if (!$raindrops[date('Y-m-d', time() + (86400 * 5))]) $raindrops[date('Y-m-d', time() + (86400 * 5))] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + (86400 * 5))];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 5)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 5);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 5)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 5);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+
+ <tr class="planner-day">
+ <td colspan="4" id="planner-header-6"><?= date('l', time() + (86400 * 6)) ?></td>
+ <?php
+
+ if (!$cloudburst[date('Y-m-d', time() + (86400 * 6))]) $cloudburst[date('Y-m-d', time() + (86400 * 6))] = [];
+ $dayCloudburst = $cloudburst[date('Y-m-d', time() + (86400 * 6))];
+ if (!$raindrops[date('Y-m-d', time() + (86400 * 6))]) $raindrops[date('Y-m-d', time() + (86400 * 6))] = [];
+ $dayRaindrops = $raindrops[date('Y-m-d', time() + (86400 * 6))];
+
+ $index = 0;
+ $lengthCloudburst = count($dayCloudburst);
+ $lengthRaindrops = count($dayRaindrops);
+ $biggest = max($lengthCloudburst, $lengthRaindrops);
+
+ ?>
+ </tr>
+ <tr class="planner-header">
+ <td colspan="2">Cloudburst System</td>
+ <td colspan="2">Raindrops System</td>
+ </tr>
+ <?php for ($i = 0; $i <= $biggest; $i++): ?>
+ <tr class="planner-member">
+ <?php if (isset($dayCloudburst[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <td class="planner-link">
+ <?php $member = getSystemMember("ynmuc", $dayCloudburst[$index]); ?>
+ <a class="member-link" onclick="openEditFronter('cloudburst', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 6)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayCloudburst)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('cloudburst', 6);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ <?php if (isset($dayRaindrops[$index])): ?>
+ <td class="planner-member-id">
+ <?= $index + 1 ?>
+ </td>
+ <?php $member = getSystemMember("gdapd", $dayRaindrops[$index]); ?>
+ <td class="planner-link">
+ <a class="member-link" onclick="openEditFronter('raindrops', <?= $index ?>, '<?= date('Y-m-d', time() + (86400 * 6)) ?>')"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ </td>
+ <?php elseif ($index === count($dayRaindrops)): ?>
+ <td class="planner-add-inner planner-link" colspan="2">
+ <a href="#" onclick="addFronter('raindrops', 6);" class="planner-add-link">
+ <img src="/assets/icons/add.svg" alt="" class="planner-add-icon">
+ <span class="planner-add-text">Add new fronter</span>
+ </a>
+ </td>
+ <?php else: ?>
+ <td colspan="2" class="planner-empty"></td>
+ <?php endif; ?>
+ </tr>
+ <?php $index++; endfor; ?>
+ <tr class="planner-day planner-end-of-day">
+ <td colspan="4">
+ <?php if (count($dayCloudburst) > 0 && count($dayRaindrops) > 0): ?>
+ <?= getMiniName(getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["display_name"] ?? getSystemMember("ynmuc", $dayCloudburst[count($dayCloudburst) - 1])["name"]) ?> will sleep with <?= getMiniName(getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["display_name"] ?? getSystemMember("gdapd", $dayRaindrops[count($dayRaindrops) - 1])["name"]) ?>
+ <?php else: ?>
+ Unable to calculate who will sleep with who
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr class="planner-separator"></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <style>
+ #planner {
+ margin-top: 10px;
+ border-collapse: collapse;
+ width: 100%;
+ }
+
+ .planner-header {
+ font-weight: bold;
+ text-align: center;
+ }
+
+ .planner-header td {
+ width: 50%;
+ }
+
+ td {
+ border: 1px solid rgba(255, 255, 255, .25);
+ padding: 5px 10px;
+ }
+
+ .planner-day {
+ text-align: center;
+ color: rgba(255, 255, 255, .5);
+ font-weight: bold;
+ }
+
+ .planner-end-of-day {
+ font-weight: normal;
+ }
+
+ .planner-end-of-day td {
+ border-bottom-left-radius: 10px;
+ }
+
+ .planner-separator {
+ height: 20px;
+ }
+
+ .planner-member-id {
+ width: 10%;
+ text-align: right;
+ }
+
+ .planner-link {
+ padding: 0;
+ }
+
+ .planner-link a {
+ padding: 5px 10px;
+ display: block;
+ }
+
+ .planner-add-link {
+ color: rgba(255, 255, 255, .75);
+ text-decoration: none;
+ }
+
+ .planner-add-link:hover {
+ color: rgba(255, 255, 255, .75);
+ }
+
+ .planner-link:hover {
+ background-color: rgba(255, 255, 255, .125);
+ }
+
+ .planner-link:active {
+ background-color: rgba(255, 255, 255, .25);
+ }
+
+ .planner-add-icon {
+ filter: invert(1);
+ width: 24px;
+ vertical-align: middle;
+ opacity: .75;
+ }
+
+ .planner-add-text {
+ vertical-align: middle;
+ }
+
+ .modal-header {
+ border-bottom: 1px solid #353738;
+ }
+
+ .modal-content {
+ border: 1px solid rgba(255, 255, 255, .2);
+ background-color: #111;
+ }
+
+ .btn-close {
+ filter: invert(1);
+ }
+
+ .list-group-item {
+ color: #fff;
+ background-color: #222;
+ border: 1px solid rgba(255, 255, 255, .125);
+ }
+
+ .list-group-item.disabled {
+ color: #fff;
+ background-color: #222;
+ border-color: rgba(255, 255, 255, .125);
+ opacity: .75;
+ }
+
+ .list-group-item:hover {
+ background-color: #252525;
+ color: #ddd;
+ }
+
+ .list-group-item:active, .list-group-item:focus {
+ background-color: #272727;
+ color: #bbb;
+ }
+
+ .member-link, .list-group-item-action {
+ cursor: pointer !important;
+ }
+
+ </style>
+</div>
+
+<!--suppress JSUnresolvedVariable, JSUnresolvedFunction -->
+<script>
+ window.currentWorkingDate;
+ window.fronting = JSON.parse(window.atob(`<?= base64_encode(json_encode([
+ "raindrops" => $raindrops,
+ "cloudburst" => $cloudburst
+ ])) ?>`));
+ window.names = JSON.parse(window.atob(`<?php
+
+ $names = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ $names[$member['id']] = $member['display_name'] ?? $member['name'];
+ }
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ $names[$member['id']] = $member['display_name'] ?? $member['name'];
+ }
+
+ echo(base64_encode(json_encode($names))) ?>`));
+
+ function ordinal(n) {
+ let s = ["th", "st", "nd", "rd"];
+ let v = n % 100;
+ return n + (s[(v - 20) % 10] || s[v] || s[0]);
+ }
+
+ function openEditFronter(system, id, date) {
+ let display;
+
+ switch (date) {
+ case "<?= date('Y-m-d') ?>":
+ display = "today";
+ break;
+
+ case "<?= date('Y-m-d', time() + 86400) ?>":
+ display = "tomorrow";
+ break;
+
+ case "<?= date('Y-m-d', time() + (86400 * 2)) ?>":
+ display = "on <?= date('l', time() + (86400 * 2)) ?>";
+ break;
+
+ case "<?= date('Y-m-d', time() + (86400 * 3)) ?>":
+ display = "on <?= date('l', time() + (86400 * 3)) ?>";
+ break;
+
+ case "<?= date('Y-m-d', time() + (86400 * 4)) ?>":
+ display = "on <?= date('l', time() + (86400 * 4)) ?>";
+ break;
+
+ case "<?= date('Y-m-d', time() + (86400 * 5)) ?>":
+ display = "on <?= date('l', time() + (86400 * 5)) ?>";
+ break;
+
+ case "<?= date('Y-m-d', time() + (86400 * 6)) ?>":
+ display = "on <?= date('l', time() + (86400 * 6)) ?>";
+ break;
+ }
+
+ window.selectedFronting = {
+ system: system === "cloudburst" ? "ynmuc" : "gdapd",
+ date: date,
+ index: id
+ }
+
+ document.getElementById("edit-fronter-name").innerText = names[fronting[system][date][id]] ?? fronting[system][date][id];
+ document.getElementById("edit-fronter-date").innerText = display;
+ document.getElementById("edit-fronter-pos").innerText = ordinal(id + 1);
+ document.getElementById("edit-fronter-system").innerText = system === "cloudburst" ? "Cloudburst System" : "Raindrops System";
+
+ let modal = new bootstrap.Modal(document.getElementById('edit-fronter'));
+ modal.show();
+ }
+
+ function addFronter(system, offset) {
+ let date;
+ let display;
+
+ switch (offset) {
+ case 0:
+ date = "<?= date('Y-m-d') ?>";
+ display = "today";
+ break;
+
+ case 1:
+ date = "<?= date('Y-m-d', time() + 86400) ?>";
+ display = "tomorrow";
+ break;
+
+ case 2:
+ date = "<?= date('Y-m-d', time() + (86400 * 2)) ?>";
+ display = "on <?= date('l', time() + (86400 * 2)) ?>";
+ break;
+
+ case 3:
+ date = "<?= date('Y-m-d', time() + (86400 * 3)) ?>";
+ display = "on <?= date('l', time() + (86400 * 3)) ?>";
+ break;
+
+ case 4:
+ date = "<?= date('Y-m-d', time() + (86400 * 4)) ?>";
+ display = "on <?= date('l', time() + (86400 * 4)) ?>";
+ break;
+
+ case 5:
+ date = "<?= date('Y-m-d', time() + (86400 * 5)) ?>";
+ display = "on <?= date('l', time() + (86400 * 5)) ?>";
+ break;
+
+ case 6:
+ date = "<?= date('Y-m-d', time() + (86400 * 6)) ?>";
+ display = "on <?= date('l', time() + (86400 * 6)) ?>";
+ break;
+ }
+
+ window.currentWorkingDate = date;
+ document.getElementById("new-fronter-date").innerText = display;
+ document.getElementById("new-fronter-system").innerText = system === "cloudburst" ? "Cloudburst System" : "Raindrops System";
+ document.getElementById("list-" + system).style.display = "";
+ document.getElementById("list-" + (system === "cloudburst" ? "raindrops" : "cloudburst")).style.display = "none";
+
+ let modal = new bootstrap.Modal(document.getElementById('new-fronter'));
+ modal.show();
+ }
+
+ function confirmFronterAdd(system, id) {
+ Array.from(document.getElementsByClassName("new-fronter-link")).forEach((i) => {
+ i.classList.add("disabled");
+ });
+
+ document.getElementById("new-fronter-close").classList.add("disabled");
+
+ window.fetch("/api/fronter?t=add&d=" + window.currentWorkingDate + "&m=" + id + "&s=" + system).then(() => {
+ location.reload();
+ });
+ }
+
+ function deleteFronter() {
+ Array.from(document.getElementsByClassName("edit-fronter-link")).forEach((i) => {
+ i.classList.add("disabled");
+ });
+
+ document.getElementById("edit-fronter-close").classList.add("disabled");
+
+ window.fetch("/api/fronter?t=delete&d=" + window.selectedFronting["date"] + "&i=" + window.selectedFronting["index"] + "&s=" + window.selectedFronting["system"]).then(() => {
+ location.reload();
+ });
+ }
+
+ function moveFronterDown() {
+ Array.from(document.getElementsByClassName("edit-fronter-link")).forEach((i) => {
+ i.classList.add("disabled");
+ });
+
+ document.getElementById("edit-fronter-close").classList.add("disabled");
+
+ window.fetch("/api/fronter?t=down&d=" + window.selectedFronting["date"] + "&i=" + window.selectedFronting["index"] + "&s=" + window.selectedFronting["system"]).then(() => {
+ location.reload();
+ });
+ }
+
+ function moveFronterUp() {
+ Array.from(document.getElementsByClassName("edit-fronter-link")).forEach((i) => {
+ i.classList.add("disabled");
+ });
+
+ document.getElementById("edit-fronter-close").classList.add("disabled");
+
+ window.fetch("/api/fronter?t=up&d=" + window.selectedFronting["date"] + "&i=" + window.selectedFronting["index"] + "&s=" + window.selectedFronting["system"]).then(() => {
+ location.reload();
+ });
+ }
+</script>
+
+<div class="modal fade" id="new-fronter" data-bs-backdrop="static" data-bs-keyboard="false">
+ <div class="modal-dialog">
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <h4 class="modal-title">Add new fronter <span id="new-fronter-date">n/a</span></h4>
+ <button id="new-fronter-close" type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+
+ <div class="modal-body">
+ <p class="text-muted">Adding for the <span id="new-fronter-system">n/a</span></p>
+
+ <div class="list-group" id="list-raindrops">
+ <?php foreach (scoreOrder(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true), "gdapd") as $member): ?>
+ <a onclick="confirmFronterAdd('gdapd', '<?= $member['id'] ?>');" class="new-fronter-link member-link list-group-item list-group-item-action" href="#"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ <?php endforeach; ?>
+ </div>
+
+ <div class="list-group" id="list-cloudburst">
+ <?php foreach (scoreOrder(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true), "ynmuc") as $member): ?>
+ <a onclick="confirmFronterAdd('ynmuc', '<?= $member['id'] ?>');" class="new-fronter-link member-link list-group-item list-group-item-action" href="#"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($member["display_name"] ?? $member["name"]) ?></a>
+ <?php endforeach; ?>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
+
+<div class="modal fade" id="edit-fronter" data-bs-backdrop="static" data-bs-keyboard="false">
+ <div class="modal-dialog">
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <h4 class="modal-title">Edit <span id="edit-fronter-name">n/a</span> fronting in <span id="edit-fronter-pos">n/a</span> <span id="edit-fronter-date">n/a</span></h4>
+ <button id="edit-fronter-close" type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+
+ <div class="modal-body">
+ <p class="text-muted">Editing for the <span id="edit-fronter-system">n/a</span></p>
+
+ <div class="list-group" id="list-cloudburst">
+ <a class="list-group-item list-group-item-action edit-fronter-link" onclick="deleteFronter();">
+ <img src="/assets/icons/delete.svg" style="width:24px;filter:invert(1);vertical-align: middle;">
+ <span style="vertical-align: middle;">Delete</span>
+ </a>
+ <a class="list-group-item list-group-item-action edit-fronter-link" onclick="moveFronterUp();">
+ <img src="/assets/icons/up.svg" style="width:24px;filter:invert(1);vertical-align: middle;">
+ <span style="vertical-align: middle;">Move up</span>
+ </a>
+ <a class="list-group-item list-group-item-action edit-fronter-link" onclick="moveFronterDown();">
+ <img src="/assets/icons/down.svg" style="width:24px;filter:invert(1);vertical-align: middle;">
+ <span style="vertical-align: middle;">Move down</span>
+ </a>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
+
+<?php
+
+file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-planner.json", json_encode($cloudburst));
+file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-planner.json", json_encode($raindrops));
+
+require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php';
+
+?>
diff --git a/pages/home.php b/pages/home.php
new file mode 100644
index 0000000..4e853a6
--- /dev/null
+++ b/pages/home.php
@@ -0,0 +1,48 @@
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <?php if (isset($_GET['error'])): ?>
+ <div class="alert alert-danger alert-dismissible">
+ <button onclick='window.history.pushState({"html":null,"pageTitle":document.title},"", "/");' type="button" class="btn-close" data-bs-dismiss="alert"></button>
+ <b>Error: </b><?= strip_tags($_GET['error']) ?>
+ </div>
+ <?php endif; ?>
+
+ <div style="background:rgba(255, 255, 255, .1);max-width:100%;width:max-content;display:grid;grid-template-columns:128px 1fr;border-radius:10px;margin-left:auto;margin-right:auto;color:white;">
+
+ <!-- Logo -->
+ <img src="/assets/uploads/logo.jpg" alt="" style="width:128px;border-top-left-radius:10px;border-bottom-left-radius:10px;">
+
+ <!-- Banner text -->
+ <div style="padding:20px;display:flex;align-items:center;justify-content:center;">
+ <div>
+
+ <!-- Main title -->
+ <span style="font-weight:bold;font-size:24px;">Cuties and Plurality</span><br>
+
+ <!-- Tagline -->
+ <span style="font-weight:normal;font-size:16px;">Just a small safe place for two plural systems</span>
+
+ </div>
+ </div>
+
+ </div>
+
+ <?php global $isLoggedIn; global $_PROFILE; if ($isLoggedIn && ((int)date('H') >= 20 || (int)date('H') < 6)): ?>
+ <a href="/emergency" style="text-decoration: none;margin-top:15px;display:block;font-size:24px;">
+ <div class="alert alert-danger">
+ <b>Are you in need of help?</b> If you need immediate help from a loved one, you may want to enable the emergency alert by clicking here, even if that will wake up the <?= $_PROFILE['name'] === "Raindrops System" ? "Cloudburst System" : "Raindrops System" ?>. Use it as you need.
+ </div>
+ </a>
+ <?php endif; ?>
+
+ <div id="homepage-desktop" style="margin-top:10px;">
+
+ <?php cloudburst(false); ?>
+ <?php raindrops(false); ?>
+
+ </div>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?> \ No newline at end of file
diff --git a/pages/login.php b/pages/login.php
new file mode 100644
index 0000000..a6f075f
--- /dev/null
+++ b/pages/login.php
@@ -0,0 +1,2 @@
+<?php
+header("Location: /Authentication/Start") and die(); \ No newline at end of file
diff --git a/pages/logout.php b/pages/logout.php
new file mode 100644
index 0000000..ea1bfce
--- /dev/null
+++ b/pages/logout.php
@@ -0,0 +1,16 @@
+<?php
+
+if (isset($_COOKIE['PEH2_SESSION_TOKEN'])) {
+ if (str_contains($_COOKIE['PEH2_SESSION_TOKEN'], ".") || str_contains($_COOKIE['PEH2_SESSION_TOKEN'], "/")) {
+ header("Location: /") and die();
+ }
+
+ if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])))) {
+ unlink($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])));
+ header("Location: /") and die();
+ } else {
+ header("Location: /") and die();
+ }
+} else {
+ header("Location: /") and die();
+} \ No newline at end of file
diff --git a/pages/page.php b/pages/page.php
new file mode 100644
index 0000000..58f40eb
--- /dev/null
+++ b/pages/page.php
@@ -0,0 +1,40 @@
+<?php
+
+if (!isset($_GET['_']) || trim($_GET['_']) === "") header("Location: /?error=Invalid request") and die();
+
+$parts = explode("/", $_GET['_']);
+$system = $parts[0];
+$member = ($parts[1] ?? null) === "" ? null : $parts[1];
+
+if ($system !== "cloudburst" && $system !== "raindrops") header("Location: /?error=Invalid system ID") and die();
+$systemCommonName = $system === "cloudburst" ? "Cloudburst System" : "Raindrops System";
+$systemID = $system === "cloudburst" ? "ynmuc" : "gdapd";
+
+if ($member === null) {
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/system.php';
+} else if ($member === "-" && isset($parts[2])) {
+ if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/includes/system/' . $parts[2] . '.php')) {
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/system/' . $parts[2] . '.php';
+ } else {
+ header("Location: /?error=Page not found") and die();
+ }
+} else {
+ $members = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/" . $systemID . "-members.json"), true);
+ $memberData = null;
+ $memberCommonName = null;
+ $memberID = null;
+
+ foreach ($members as $m) {
+ if ($m['name'] === $member) {
+ $memberData = $m;
+ $memberCommonName = $m['display_name'] ?? $m['name'];
+ $memberID = $m['id'];
+ }
+ }
+
+ if ($memberData === null) header("Location: /?error=System member not found") and die();
+
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/member.php';
+}
+
+exit; \ No newline at end of file
diff --git a/pages/parser.php b/pages/parser.php
new file mode 100644
index 0000000..a35f594
--- /dev/null
+++ b/pages/parser.php
@@ -0,0 +1,247 @@
+<?php $title = "Message Parser"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <h2>Message Parser</h2>
+ <p>Enter a message here, and we will tell you which system member this message came from.</p>
+
+ <div style="display:grid;grid-template-columns:1fr 2fr;grid-gap:10px;">
+ <select id="system" title="Existing prefixes from..." class="tooltip-nohelp form-select" style='color:white;background-color:#111;border-color:#222;background-image:url("data:image/svg+xml,%3csvg xmlns=&apos;http://www.w3.org/2000/svg&apos; viewBox=&apos;0 0 16 16&apos;%3e%3cpath fill=&apos;none&apos; stroke=&apos;%23ffffff&apos; stroke-linecap=&apos;round&apos; stroke-linejoin=&apos;round&apos; stroke-width=&apos;2&apos; d=&apos;M2 5l6 6 6-6&apos;/%3e%3c/svg%3e");' onchange="update();">
+ <option value="all">(all systems)</option>
+ <option value="cloudburst">Cloudburst System</option>
+ <option value="raindrops">Raindrops System</option>
+ </select>
+ <span contenteditable="true" title="Message" class="tooltip-nohelp form-control" id="message" style="word-break: break-all;color:white;background:#111;border-color:#222;" onchange="update();" onkeydown="update();" onkeyup="update();"><span></span></span>
+ <script>
+ const input = document.getElementById('message');
+
+ input.addEventListener('keypress', (e) => {
+ if (e.code === "Enter") e.preventDefault();
+ });
+ </script>
+ </div>
+
+ <br>
+
+ <div id="result-cloudburst-outer" style="width: max-content;padding: 10px;background: #151515;border-radius: 30px;text-align: center;">
+ <span style="display:block;margin-bottom:7px;font-weight: bold;">Cloudburst System</span>
+ <div id="result-cloudburst" style="background: #222;width: max-content;border-radius: 999px;display: grid;padding: 10px 20px 10px 10px;grid-template-columns: 36px 1fr;grid-gap: 10px;">
+ <div style="align-items: center;justify-content: center;display: flex;">
+ <img src="" alt="" style="width: 36px;height: 36px;vertical-align: middle;border-radius: 999px;background: #333;" id="result-cloudburst-avatar">
+ </div>
+ <div style="display: flex;align-items: center;justify-content: center;">
+ <div>
+ <span style="font-weight: bold;" id="result-cloudburst-name">Name</span>
+ <span style="padding-left: 2px;">(<code id="result-cloudburst-prefix">Prefix</code>)</span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div id="result-raindrops-outer" style="margin-top:10px;width: max-content;padding: 10px;background: #151515;border-radius: 30px;text-align: center;">
+ <span style="display:block;margin-bottom:7px;font-weight: bold;">Raindrops System</span>
+ <div id="result-raindrops" style="background: #222;width: max-content;border-radius: 999px;display: grid;padding: 10px 20px 10px 10px;grid-template-columns: 36px 1fr;grid-gap: 10px;">
+ <div style="align-items: center;justify-content: center;display: flex;">
+ <img src="" alt="" style="width: 36px;height: 36px;vertical-align: middle;border-radius: 999px;background: #333;" id="result-raindrops-avatar">
+ </div>
+ <div style="display: flex;align-items: center;justify-content: center;">
+ <div>
+ <span style="font-weight: bold;" id="result-raindrops-name">Name</span>
+ <span style="padding-left: 2px;">(<code id="result-raindrops-prefix">Prefix</code>)</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <br>
+ <div id="host-alert" class="alert alert-secondary">
+ The entered message does not contain a prefix/suffix corresponding to a member of the selected system(s); therefore, the host was selected as a fallback. We assume that the host is talking when there is no prefix/suffix in the current message.
+ </div>
+
+ <script>
+ function setCursor(pos) {
+ let el = document.getElementById("message");
+ let selection = window.getSelection();
+ let range = document.createRange();
+
+ selection.removeAllRanges();
+ range.selectNodeContents(el);
+ range.collapse(false);
+ selection.addRange(range);
+ el.focus();
+ }
+
+ let existing = <?php
+
+ $existing1 = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true);
+ $existing2 = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true);
+
+ echo(json_encode([
+ "cloudburst" => $existing1,
+ "raindrops" => $existing2
+ ]));
+
+ ?>;
+
+ let host = {
+ raindrops: "<?php
+
+ $members = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true);
+ foreach ($members as $member) {
+ $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-$member[id]-metadata.json"), true);
+ if ($data["host"]) {
+ echo $member['id'];
+ }
+ }
+
+ ?>",
+ cloudburst: "<?php
+
+ $members = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true);
+ foreach ($members as $member) {
+ $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-$member[id]-metadata.json"), true);
+ if ($data["host"]) {
+ echo $member['id'];
+ }
+ }
+
+ ?>",
+ }
+
+ function update() {
+ let data;
+ let member;
+ let system = document.getElementById("system").value;
+ let text = document.getElementById("message").innerText;
+
+ switch (system) {
+ case "all":
+ document.getElementById("result-raindrops-outer").style.display = "";
+ document.getElementById("result-cloudburst-outer").style.display = "";
+ document.getElementById("result-raindrops-outer").style.marginTop = "10px";
+ break;
+
+ case "raindrops":
+ document.getElementById("result-raindrops-outer").style.display = "";
+ document.getElementById("result-cloudburst-outer").style.display = "none";
+ document.getElementById("result-raindrops-outer").style.marginTop = "0";
+ data = existing['raindrops'];
+ break;
+
+ case "cloudburst":
+ document.getElementById("result-raindrops-outer").style.display = "none";
+ document.getElementById("result-cloudburst-outer").style.display = "";
+ document.getElementById("result-raindrops-outer").style.marginTop = "0";
+ data = existing['cloudburst'];
+ break;
+ }
+
+ if (system === "all") {
+ updateParsed(text, "raindrops", existing["raindrops"])
+ updateParsed(text, "cloudburst", existing["cloudburst"])
+ } else {
+ updateParsed(text, system, existing[system])
+ }
+ }
+
+ function updateParsed(text, system, data) {
+ let textHTML = "<span>" + text + "</span>";
+ let member;
+ let prefix = null;
+ let suffix = null;
+ let matched = false;
+
+ for (member of data) {
+ for (let proxy of member['proxy_tags']) {
+ if (proxy.prefix !== null && text.startsWith(proxy.prefix)) {
+ if (proxy.suffix !== null) {
+ if (text.endsWith(proxy.suffix)) {
+ matched = true;
+ prefix = proxy.prefix;
+ suffix = proxy.suffix;
+ text = text.substring(proxy.prefix.length, text.length - proxy.suffix.length);
+ break;
+ }
+ } else {
+ matched = true;
+ prefix = proxy.prefix;
+ suffix = null;
+ text = text.substring(proxy.prefix.length, text.length);
+ break;
+ }
+ } else if (proxy.suffix !== null && text.endsWith(proxy.suffix)) {
+ if (proxy.prefix !== null) {
+ if (text.startsWith(proxy.prefix)) {
+ matched = true;
+ prefix = proxy.prefix;
+ suffix = proxy.suffix;
+ text = text.substring(proxy.prefix.length, text.length - proxy.suffix.length);
+ break;
+ }
+ } else {
+ matched = true;
+ prefix = null;
+ suffix = proxy.suffix;
+ text = text.substring(0, text.length - proxy.suffix.length);
+ break;
+ }
+ }
+ }
+
+ if (matched) break;
+ }
+
+ if (!matched) {
+ document.getElementById("host-alert").style.display = "block";
+ member = data.filter((i) => i['id'] === host[system])[0];
+ } else {
+ document.getElementById("host-alert").style.display = "none";
+ }
+
+ document.getElementById("result-" + system + "-avatar").src = member['avatar_url'];
+ document.getElementById("result-" + system + "-name").innerText = member['display_name'] ?? member['name'];
+ document.getElementById("result-" + system + "-prefix").innerText = member['proxy_tags'][0]['prefix'] + (member['proxy_tags'][0]['suffix'] !== null ? "..." + member['proxy_tags'][0]['suffix'] : "");
+
+
+ if (prefix !== null) {
+ if (suffix !== null) {
+ textHTML = "<span><span class='prefix'>" + prefix + "</span>" + text + "<span class='suffix'>" + suffix + "</span></span>";
+ } else {
+ textHTML = "<span><span class='prefix'>" + prefix + "</span>" + text + "</span>";
+ }
+ } else if (suffix !== null) {
+ textHTML = "<span>" + text + "<span class='suffix'>" + suffix + "</span></span>";
+ }
+
+ document.getElementById("message").innerHTML = textHTML;
+ try { setCursor(document.getElementById("message").innerHTML.length); } catch (e) {
+ console.error(e);
+ }
+ }
+
+ update();
+ </script>
+ <style>
+ .tooltip-inner {
+ text-align: left !important;
+ }
+
+ .text-peh-nowrap {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .prefix {
+ color: #88de70;
+ }
+
+ .suffix {
+ color: #de7070;
+ }
+ </style>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/prefix.php b/pages/prefix.php
new file mode 100644
index 0000000..721baa5
--- /dev/null
+++ b/pages/prefix.php
@@ -0,0 +1,444 @@
+<?php $title = "Prefix Generator"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <h2>Prefix Generator</h2>
+ <p>This prefix generator will take into account the prefixes from the existing members to try to generate new original prefixes for a potential new member.</p>
+
+ <div style="display:grid;grid-template-columns:1fr 1fr 1fr;grid-gap:10px;">
+ <select id="system" title="Existing prefixes from..." class="tooltip-nohelp form-select" style='color:white;background-color:#111;border-color:#222;background-image:url("data:image/svg+xml,%3csvg xmlns=&apos;http://www.w3.org/2000/svg&apos; viewBox=&apos;0 0 16 16&apos;%3e%3cpath fill=&apos;none&apos; stroke=&apos;%23ffffff&apos; stroke-linecap=&apos;round&apos; stroke-linejoin=&apos;round&apos; stroke-width=&apos;2&apos; d=&apos;M2 5l6 6 6-6&apos;/%3e%3c/svg%3e");' onchange="update();">
+ <optgroup label="General Options">
+ <option value="all">All systems</option>
+ <option value="none">Ignore existing prefixes</option>
+ </optgroup>
+ <optgroup label="Individual Systems">
+ <option value="cloudburst">Cloudburst System</option>
+ <option value="raindrops">Raindrops System</option>
+ </optgroup>
+ </select>
+ <input title="First Name" type="text" class="tooltip-nohelp form-control" id="first-name" placeholder="First Name" style="color:white;background:#111;border-color:#222;" onchange="update();" onkeydown="update();" onkeyup="update();">
+ <input title="Last Name" type="text" class="tooltip-nohelp form-control" id="last-name" placeholder="Last Name (optional)" style="color:white;background:#111;border-color:#222;" onchange="update();" onkeydown="update();" onkeyup="update();">
+ </div>
+
+ <br>
+ <div id="already" class="alert alert-primary" style="display:none;">
+ There is already a member named <b id="already-name">Name</b> in one of the systems, their primary prefix is currently <code id="already-prefix">???</code>
+ </div>
+ <div id="results-singular" style="display:none;">
+ <h4>Generated Prefix</h4>
+ <p>Below is a generated prefix for a member who goes by the entered name. We managed to generate only a single prefix for this name.</p>
+ </div>
+ <div id="results-none">
+ <h4>Generated Prefix</h4>
+ <p>We couldn't generate a prefix for a member who goes by this name, try tuning your settings.</p>
+ </div>
+ <div id="results-plural" style="display:none;">
+ <h4>Generated Prefixes</h4>
+ <p>Below is a list of generated prefixes for a member who goes by the entered name. The prefixes are ordered by relevance, the first prefix being the most relevant one. Hover over a prefix to see what makes it revelent or not</p>
+ </div>
+ <ol id="generated">
+ <li><code>{...}</code></li>
+ </ol>
+ <p id="hidden-message" style="display:none;"><span id="hidden-count">0</span> <span id="hidden-plural">entries have been hidden because they are existing prefixes </span><span id="hidden-singular">entry has been hidden because it is an existing prefix </span>in the selected system<span id="hidden-sys-plural">s</span>.</p>
+ </div>
+
+ <script>
+ let existing = <?php
+
+ $existing1 = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ foreach ($member['proxy_tags'] as $tag) {
+ if (!$tag["prefix"]) {
+ $existing1[] = "..." . $tag["suffix"];
+ } else if (!$tag["suffix"]) {
+ $existing1[] = $tag["prefix"];
+ } else {
+ $existing1[] = $tag["prefix"] . "..." . $tag["suffix"];
+ }
+ }
+ }
+ }
+
+
+ $existing2 = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ foreach ($member['proxy_tags'] as $tag) {
+ if (!$tag["prefix"]) {
+ $existing2[] = "..." . $tag["suffix"];
+ } else if (!$tag["suffix"]) {
+ $existing2[] = $tag["prefix"];
+ } else {
+ $existing2[] = $tag["prefix"] . "..." . $tag["suffix"];
+ }
+ }
+ }
+ }
+
+ echo(json_encode([
+ "cloudburst" => $existing1,
+ "raindrops" => $existing2
+ ]));
+
+ ?>;
+
+ let prefixesUsedBy = <?php
+
+ $existing1 = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ foreach ($member['proxy_tags'] as $tag) {
+ if (!$tag["prefix"]) {
+ $existing1["..." . $tag["suffix"]] = $member["display_name"] ?? $member["name"];
+ } else if (!$tag["suffix"]) {
+ $existing1[$tag["prefix"]] = $member["display_name"] ?? $member["name"];
+ } else {
+ $existing1[$tag["prefix"] . "..." . $tag["suffix"]] = $member["display_name"] ?? $member["name"];
+ }
+ }
+ }
+ }
+
+
+ $existing2 = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ foreach ($member['proxy_tags'] as $tag) {
+ if (!$tag["prefix"]) {
+ $existing2["..." . $tag["suffix"]] = $member["display_name"] ?? $member["name"];
+ } else if (!$tag["suffix"]) {
+ $existing2[$tag["prefix"]] = $member["display_name"] ?? $member["name"];
+ } else {
+ $existing2[$tag["prefix"] . "..." . $tag["suffix"]] = $member["display_name"] ?? $member["name"];
+ }
+ }
+ }
+ }
+
+ echo(json_encode([
+ "cloudburst" => $existing1,
+ "raindrops" => $existing2
+ ]));
+
+ ?>;
+
+ let o;
+ let membersByPrefixCloudburst = {};
+ let membersByPrefixRaindrops = {};
+
+ o = prefixesUsedBy["cloudburst"];
+ Object.keys(o).map((i) => { if (!membersByPrefixCloudburst[o[i]]) membersByPrefixCloudburst[o[i]] = []; membersByPrefixCloudburst[o[i]].push(i); });
+
+ o = prefixesUsedBy["raindrops"];
+ Object.keys(o).map((i) => { if (!membersByPrefixRaindrops[o[i]]) membersByPrefixRaindrops[o[i]] = []; membersByPrefixRaindrops[o[i]].push(i); });
+
+ function update() {
+ let generated = [];
+ let toIgnore = [];
+
+ let system = document.getElementById("system").value;
+ let firstName = document.getElementById("first-name").value.toLowerCase().trim().replace(/[^a-z]/gm, "");
+ let lastName = document.getElementById("last-name").value.toLowerCase().trim().replace(/[^a-z]/gm, "");
+
+ document.getElementById("already").style.display = "none";
+ if (Object.keys(membersByPrefixRaindrops).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).includes((firstName + " " + lastName).trim())) {
+ let data = {
+ name: Object.keys(membersByPrefixRaindrops)[Object.keys(membersByPrefixRaindrops).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).indexOf((firstName + " " + lastName).trim())],
+ prefix: membersByPrefixRaindrops[Object.keys(membersByPrefixRaindrops)[Object.keys(membersByPrefixRaindrops).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).indexOf((firstName + " " + lastName).trim())]][0]
+ };
+ console.log(data);
+
+ document.getElementById("already-name").innerText = data.name;
+ document.getElementById("already-prefix").innerText = data.prefix;
+ document.getElementById("already").style.display = "";
+ }
+ if (Object.keys(membersByPrefixCloudburst).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).includes((firstName + " " + lastName).trim())) {
+ let data = {
+ name: Object.keys(membersByPrefixCloudburst)[Object.keys(membersByPrefixCloudburst).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).indexOf((firstName + " " + lastName).trim())],
+ prefix: membersByPrefixCloudburst[Object.keys(membersByPrefixCloudburst)[Object.keys(membersByPrefixCloudburst).map(i => i.toLowerCase().trim().replace(/[^a-z ]/gm, "")).indexOf((firstName + " " + lastName).trim())]][0]
+ };
+ console.log(data);
+
+ document.getElementById("already-name").innerText = data.name;
+ document.getElementById("already-prefix").innerText = data.prefix;
+ document.getElementById("already").style.display = "";
+ }
+
+ switch (system) {
+ case "all":
+ toIgnore = [...existing["cloudburst"], ...existing["raindrops"]];
+ document.getElementById("hidden-sys-plural").style.display = "";
+ break;
+
+ case "raindrops":
+ toIgnore = existing["raindrops"];
+ document.getElementById("hidden-sys-plural").style.display = "none";
+ break;
+
+ case "cloudburst":
+ toIgnore = existing["cloudburst"];
+ document.getElementById("hidden-sys-plural").style.display = "none";
+ break;
+
+ case "none":
+ toIgnore = [];
+ document.getElementById("hidden-sys-plural").style.display = "";
+ break;
+ }
+
+ if (firstName.length > 0) {
+ generated.push({
+ prefix: firstName.substring(0, 1) + ".",
+ rules: ["<span class='text-warning'>firstNameFirstLetter</span>"]
+ });
+ }
+
+ if (lastName.length > 0) {
+ generated.push({
+ prefix: lastName.substring(0, 1) + ".",
+ rules: ["<span class='text-warning'>lastNameFirstLetter</span>"]
+ });
+ }
+
+ if (firstName.length > 1) {
+ generated.push({
+ prefix: firstName.substring(0, 2) + ".",
+ rules: ["<span class='text-warning'>firstNameFirstTwoLetters</span>"]
+ });
+ }
+
+ if (firstName.length > 0 && lastName.length > 0) {
+ generated.push({
+ prefix: firstName.substring(0, 1) + lastName.substring(0, 1) + ".",
+ rules: ["<span class='text-warning'>lastNameFirstTwoLetters</span>"]
+ });
+ }
+
+ if (firstName.length > 1) {
+ for (let i = 2; i < firstName.length + 1; i++) {
+ if (!(
+ firstName.substring(i - 1, i) === "a" ||
+ firstName.substring(i - 1, i) === "e" ||
+ firstName.substring(i - 1, i) === "i" ||
+ firstName.substring(i - 1, i) === "o" ||
+ firstName.substring(i - 1, i) === "u" ||
+ firstName.substring(i - 1, i) === "y"
+ )) {
+ generated.push({
+ prefix: firstName.substring(i - 1, i) + ".",
+ rules: ["<span class='text-warning'>firstNameLetterConsonant</span>"]
+ });
+ }
+ }
+ }
+
+ if (lastName.length > 1) {
+ for (let i = 2; i < lastName.length + 1; i++) {
+ if (!(
+ lastName.substring(i - 1, i) === "a" ||
+ lastName.substring(i - 1, i) === "e" ||
+ lastName.substring(i - 1, i) === "i" ||
+ lastName.substring(i - 1, i) === "o" ||
+ lastName.substring(i - 1, i) === "u" ||
+ lastName.substring(i - 1, i) === "y"
+ )) {
+ generated.push({
+ prefix: lastName.substring(i - 1, i) + ".",
+ rules: ["<span class='text-warning'>lastNameLetterConsonant</span>"]
+ });
+ }
+ }
+ }
+
+ if (firstName.length > 1) {
+ for (let i = 2; i < firstName.length + 1; i++) {
+ if (
+ firstName.substring(i - 1, i) === "a" ||
+ firstName.substring(i - 1, i) === "e" ||
+ firstName.substring(i - 1, i) === "i" ||
+ firstName.substring(i - 1, i) === "o" ||
+ firstName.substring(i - 1, i) === "u" ||
+ firstName.substring(i - 1, i) === "y"
+ ) {
+ generated.push({
+ prefix: firstName.substring(i - 1, i) + ".",
+ rules: ["<span class='text-warning'>firstNameLetterVowel</span>"]
+ });
+ }
+ }
+ }
+
+ if (lastName.length > 1) {
+ for (let i = 2; i < lastName.length; i++) {
+ if (
+ lastName.substring(i - 1, i) === "a" ||
+ lastName.substring(i - 1, i) === "e" ||
+ lastName.substring(i - 1, i) === "i" ||
+ lastName.substring(i - 1, i) === "o" ||
+ lastName.substring(i - 1, i) === "u" ||
+ lastName.substring(i - 1, i) === "y"
+ ) {
+ generated.push({
+ prefix: lastName.substring(i - 1, i + 1) + ".",
+ rules: ["<span class='text-warning'>lastNameTwoLettersVowel</span>"]
+ });
+ }
+ }
+ }
+
+ if (firstName.length > 2) {
+ for (let i = 2; i < firstName.length; i++) {
+ if (!(
+ firstName.substring(i - 1, i) === "a" ||
+ firstName.substring(i - 1, i) === "e" ||
+ firstName.substring(i - 1, i) === "i" ||
+ firstName.substring(i - 1, i) === "o" ||
+ firstName.substring(i - 1, i) === "u" ||
+ firstName.substring(i - 1, i) === "y"
+ )) {
+ generated.push({
+ prefix: firstName.substring(i - 1, i + 1) + ".",
+ rules: ["<span class='text-warning'>firstNameTwoLettersConsonant</span>"]
+ });
+ }
+ }
+ }
+
+ if (lastName.length > 2) {
+ for (let i = 2; i < lastName.length; i++) {
+ if (!(
+ lastName.substring(i - 1, i) === "a" ||
+ lastName.substring(i - 1, i) === "e" ||
+ lastName.substring(i - 1, i) === "i" ||
+ lastName.substring(i - 1, i) === "o" ||
+ lastName.substring(i - 1, i) === "u" ||
+ lastName.substring(i - 1, i) === "y"
+ )) {
+ generated.push({
+ prefix: lastName.substring(i - 1, i + 1) + ".",
+ rules: ["<span class='text-warning'>lastNameTwoLettersConsonant</span>"]
+ });
+ }
+ }
+ }
+
+ if (firstName.length > 2) {
+ for (let i = 2; i < firstName.length; i++) {
+ if (
+ firstName.substring(i - 1, i) === "a" ||
+ firstName.substring(i - 1, i) === "e" ||
+ firstName.substring(i - 1, i) === "i" ||
+ firstName.substring(i - 1, i) === "o" ||
+ firstName.substring(i - 1, i) === "u" ||
+ firstName.substring(i - 1, i) === "y"
+ ) {
+ generated.push({
+ prefix: firstName.substring(i - 1, i + 1) + ".",
+ rules: ["<span class='text-warning'>firstNameTwoLettersVowel</span>"]
+ });
+ }
+ }
+ }
+
+ if (lastName.length > 2) {
+ for (let i = 2; i < lastName.length; i++) {
+ if (
+ lastName.substring(i - 1, i) === "a" ||
+ lastName.substring(i - 1, i) === "e" ||
+ lastName.substring(i - 1, i) === "i" ||
+ lastName.substring(i - 1, i) === "o" ||
+ lastName.substring(i - 1, i) === "u" ||
+ lastName.substring(i - 1, i) === "y"
+ ) {
+ generated.push({
+ prefix: lastName.substring(i - 1, i + 1) + ".",
+ rules: ["<span class='text-warning'>lastNameTwoLettersVowel</span>"]
+ });
+ }
+ }
+ }
+
+ generated = generated.filter((c, index) => {
+ return generated.map((i) => { return i.prefix; }).indexOf(c.prefix) === index;
+ });
+
+ let generatedVowels = generated.filter((i) => {
+ return i.prefix.match(/[aeiouy]/);
+ }).map((i) => {
+ i.rules.push("<span class='text-danger'>containsVowels</span>");
+ return i;
+ });
+
+ let generatedNotVowels = generated.filter((i) => {
+ return !i.prefix.match(/[aeiouy]/);
+ }).map((i) => {
+ i.rules.push("<span class='text-success'>notContainsVowels</span>");
+ return i;
+ });
+
+ generated = [...generatedNotVowels, ... generatedVowels];
+
+ generated.sort((a, b) => {
+ return a.prefix.length - b.prefix.length;
+ });
+
+ let totalLength = generated.length;
+ generated = generated.filter((i) => {
+ return !toIgnore.includes(i.prefix);
+ });
+ let lengthAfterIgnore = generated.length;
+ let ignoredCount = totalLength - lengthAfterIgnore;
+
+ document.getElementById("hidden-count").innerText = ignoredCount.toString();
+ document.getElementById("hidden-plural").style.display = ignoredCount === 1 ? "none" : "inline";
+ document.getElementById("hidden-singular").style.display = ignoredCount === 1 ? "inline" : "none";
+ document.getElementById("hidden-message").style.display = ignoredCount === 0 ? "none" : "";
+
+ document.getElementById("results-none").style.display = "none";
+ document.getElementById("results-singular").style.display = "none";
+ document.getElementById("results-plural").style.display = "none";
+
+ if (generated.length === 0) {
+ document.getElementById("generated").innerHTML = "<li><code>{...}</code></li>";
+ document.getElementById("results-none").style.display = "";
+ } else {
+ let html = [];
+ let index = 1;
+
+ for (let prefix of generated) {
+ html.push(`<li><code data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="right" title="<b>Prefix:</b> <code>${prefix.prefix}</code><br><b>Score:</b> ${((1 - (index/generated.length))*100).toFixed(2)}%<hr><div class='text-peh-nowrap'>- ${prefix.rules.join("</div><div class='text-peh-nowrap'>- ")}</div><hr><div class='text-peh-nowrap'>- <span class='text-${existing["cloudburst"].includes(prefix.prefix) ? "danger" : "success"}'>Cloudburst</span> ${existing["cloudburst"].includes(prefix.prefix) ? ` (${prefixesUsedBy["cloudburst"][prefix.prefix]})` : ""}</div><div class='text-peh-nowrap'>- <span class='text-${existing["raindrops"].includes(prefix.prefix) ? "danger" : "success"}'>Raindrops</span> ${existing["raindrops"].includes(prefix.prefix) ? ` (${prefixesUsedBy["raindrops"][prefix.prefix]})` : ""}">${prefix.prefix}</code></li>`);
+
+ index++;
+ }
+
+ document.getElementById("generated").innerHTML = html.join("");
+
+ document.getElementById(generated.length > 1 ? "results-plural" : "results-singular").style.display = "";
+ }
+
+ let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
+ let tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
+ return new bootstrap.Tooltip(tooltipTriggerEl)
+ });
+
+ Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')).forEach((item) => {
+ item.style.cursor = "help";
+ })
+ }
+ </script>
+ <style>
+ .tooltip-inner {
+ text-align: left !important;
+ }
+
+ .text-peh-nowrap {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+ </style>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/relations.php b/pages/relations.php
new file mode 100644
index 0000000..54fc4ec
--- /dev/null
+++ b/pages/relations.php
@@ -0,0 +1,66 @@
+<?php $title = "Relations"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <h2>Relations</h2>
+ <?php foreach (scoreOrderGlobal() as $member): if (count($member["_metadata"]["marefriends"]) > 0 || count($member["_metadata"]["sisters"]) > 0): ?>
+ <div class="relation" style="background-color:rgba(255, 255, 255, .1);margin-bottom:10px;padding:10px;border-radius:10px;display:grid;grid-template-columns: 1fr 2fr 2fr;">
+ <a class="relation-intro" style="background-color:rgba(255, 255, 255, .05);border-right:1px solid rgba(255, 255, 255, .1);margin:-10px;padding:10px;border-top-left-radius:10px;border-bottom-left-radius:10px;color: white;text-decoration: none;" href="/<?= $member["_system"] === "gdapd" ? "raindrops" : "cloudburst" ?>/<?= $member["name"] ?>">
+ <img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $member['name'] . ".png") ? "-" . $member['name'] : "" ?>.png" style="width:24px;"> <?= $member["display_name"] ?? $member["name"] ?>
+ </a>
+
+ <div class="relation-item relation-item-marefriends" style="margin-left:10px;padding:0 20px;">
+ <b style="padding-right:5px;">Marefriends:</b><span class="list-separator-mobile"><br></span>
+ <?php if (count($member["_metadata"]["marefriends"]) === 0): ?>
+ <span class="text-muted">None</span>
+ <?php else: ?>
+ <?php $index = 0; foreach ($member["_metadata"]["marefriends"] as $id): $mfSystem = explode("/", $id)[0]; $marefriend = getSystemMember(explode("/", $id)[0], explode("/", $id)[1]); ?>
+ <a class="member-link" href="/<?= $mfSystem === "gdapd" ? "raindrops" : "cloudburst" ?>/<?= $marefriend["name"] ?>"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $marefriend['name'] . ".png") ? "-" . $marefriend['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($marefriend["display_name"] ?? $marefriend["name"]) ?></a><?php if ($index + 2 <= count($member["_metadata"]["marefriends"])) echo('<span class="list-separator-desktop">, </span><span class="list-separator-mobile"><br></span>'); $index++; ?>
+ <?php endforeach; ?>
+ <?php endif; ?>
+ </div>
+
+ <div class="relation-item relation-item-sisters" style="padding:0 20px;">
+ <b style="padding-right:5px;">Sisters:</b><span class="list-separator-mobile"><br></span>
+ <?php if (count($member["_metadata"]["sisters"]) === 0): ?>
+ <span class="text-muted">None</span>
+ <?php else: ?>
+ <?php $index = 0; foreach ($member["_metadata"]["sisters"] as $id): $mfSystem = explode("/", $id)[0]; $marefriend = getSystemMember(explode("/", $id)[0], explode("/", $id)[1]); ?>
+ <a class="member-link" href="/<?= $mfSystem === "gdapd" ? "raindrops" : "cloudburst" ?>/<?= $marefriend["name"] ?>"><img src="/assets/uploads/pt<?= file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/uploads/pt-" . $marefriend['name'] . ".png") ? "-" . $marefriend['name'] : "" ?>.png" style="width:24px;"> <?= getMiniName($marefriend["display_name"] ?? $marefriend["name"]) ?></a><?php if ($index + 2 <= count($member["_metadata"]["sisters"])) echo('<span class="list-separator-desktop">, </span><span class="list-separator-mobile"><br></span>'); $index++; ?>
+ <?php endforeach; ?>
+ <?php endif; ?>
+ </div>
+ </div>
+ <?php endif; endforeach; ?>
+ </div>
+
+ <style>
+ @media (max-width: 991px) {
+ .relation {
+ grid-template-columns: 1fr !important;
+ }
+
+ .relation-intro {
+ text-align: center;
+ border-bottom-left-radius: 0 !important;
+ border-top-right-radius: 10px;
+ border-right: none !important;
+ border-bottom: 1px solid rgba(255, 255, 255, .1);
+ }
+
+ .relation-item-marefriends {
+ margin-top: 20px !important;
+ }
+
+ .relation-item {
+ margin-top: 10px;
+ margin-left: 0 !important;
+ padding: 10px 0 !important;
+ text-align: center;
+ }
+ }
+ </style>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/score.php b/pages/score.php
new file mode 100644
index 0000000..841decc
--- /dev/null
+++ b/pages/score.php
@@ -0,0 +1,210 @@
+<?php
+
+require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $isLoggedIn;
+if (!$isLoggedIn) header("Location: /login") and die();
+
+$title = "Score System Testing"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php';
+
+?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <h2>Score System Testing</h2>
+
+ <h4>Raindrops System (<code><?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = $score["total"];
+ }
+ }
+
+ $total = array_reduce($scores, function($a, $b) {
+ return $a + $b;
+ });
+
+ echo round($total / (count(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true)) - 1));
+
+ ?></code>)</h4>
+ <ul>
+ <?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ $name = $member["display_name"] ?? $member["name"];
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = [
+ "name" => $name,
+ "page" => "/raindrops/" . $member["name"],
+ "score" => $score["total"],
+ "details" => $score
+ ];
+ }
+ }
+
+ uasort($scores, function($a, $b) {
+ return $b["score"] - $a["score"];
+ });
+
+ ?>
+
+ <?php foreach ($scores as $score): ?>
+ <li>
+ <details>
+ <summary><a href="<?= $score["page"] ?>"><?= $score["name"] ?></a> (<code><?= $score["score"] ?></code>)</summary>
+ <pre><?= json_encode($score["details"], JSON_PRETTY_PRINT) ?></pre>
+ </details>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+
+
+ <h4>Cloudburst System (<code><?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = $score["total"];
+ }
+ }
+
+ $total = array_reduce($scores, function($a, $b) {
+ return $a + $b;
+ });
+
+ echo round($total / (count(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true)) - 1));
+
+ ?></code>)</h4>
+ <ul>
+ <?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ $name = $member["display_name"] ?? $member["name"];
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = [
+ "name" => $name,
+ "page" => "/cloudburst/" . $member["name"],
+ "score" => $score["total"],
+ "details" => $score
+ ];
+ }
+ }
+
+ uasort($scores, function($a, $b) {
+ return $b["score"] - $a["score"];
+ });
+
+ ?>
+
+ <?php foreach ($scores as $score): ?>
+ <li>
+ <details>
+ <summary><a href="<?= $score["page"] ?>"><?= $score["name"] ?></a> (<code><?= $score["score"] ?></code>)</summary>
+ <pre><?= json_encode($score["details"], JSON_PRETTY_PRINT) ?></pre>
+ </details>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+
+ <h4>Global (<code><?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = $score["total"];
+ }
+ }
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = $score["total"];
+ }
+ }
+
+ $total = array_reduce($scores, function($a, $b) {
+ return $a + $b;
+ });
+
+ echo round($total / ((count(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true)) + count(json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true))) - 2));
+
+ ?></code>)</h4>
+ <ul>
+ <?php
+
+ $scores = [];
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ $name = $member["display_name"] ?? $member["name"];
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/gdapd-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = [
+ "name" => $name,
+ "page" => "/raindrops/" . $member["name"],
+ "score" => $score["total"],
+ "details" => $score
+ ];
+ }
+ }
+ foreach (json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-members.json"), true) as $member) {
+ if ($member["name"] !== "unknown") {
+ $name = $member["display_name"] ?? $member["name"];
+ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/score.php";
+ $metadata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/ynmuc-$member[id]-metadata.json"), true);
+ $score = calculateScore($metadata, $member["display_name"] ?? $member["name"]);
+
+ $scores[] = [
+ "name" => $name,
+ "page" => "/cloudburst/" . $member["name"],
+ "score" => $score["total"],
+ "details" => $score
+ ];
+ }
+ }
+
+ uasort($scores, function($a, $b) {
+ return $b["score"] - $a["score"];
+ });
+
+ ?>
+
+ <?php foreach ($scores as $score): ?>
+ <li>
+ <details>
+ <summary><a href="<?= $score["page"] ?>"><?= $score["name"] ?></a> (<code><?= $score["score"] ?></code>)</summary>
+ <pre><?= json_encode($score["details"], JSON_PRETTY_PRINT) ?></pre>
+ </details>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ </div>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?>
diff --git a/pages/terminology.php b/pages/terminology.php
new file mode 100644
index 0000000..f73d401
--- /dev/null
+++ b/pages/terminology.php
@@ -0,0 +1,10 @@
+<?php $title = "Terminology"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'; ?>
+
+<br>
+<div class="container">
+ <div id="page-content">
+ <?= file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/content/terminology.html") ?>
+ </div>
+</div>
+
+<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'; ?> \ No newline at end of file