Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

61 changed files with 1148 additions and 423 deletions

@ -1,7 +1,7 @@
# Adlerka.space
# Adlerka.Top
The code for https://adlerka.space
The code for https://adlerka.top
[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/)

@ -28,7 +28,7 @@
}
var r = function bold(t) {
const e = {1: "thin", 2: "regular", 3: "bold"};
var e = {1: "thin", 2: "regular", 3: "bold"};
return void 0 !== e[t] ? e[t] : "regular"
}, a = function shape(t) {
return "none" === t || "square" === t ? t : "circle"
@ -43,7 +43,7 @@
};
function queue(t) {
const e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
return setTimeout((function () {
t()
}), e)
@ -52,41 +52,36 @@
var p = [function breakpoint(t, e) {
if (t.getOption("breakpoint")) {
!function init() {
const n = t.getOption("columns"), o = t.getOption("breakpoint.columns"),
var n = t.getOption("columns"), o = t.getOption("breakpoint.columns"),
i = Number(e.getAttribute("data-columns")), r = function calculate(t, e) {
const n = window.innerWidth, o = Object.keys(t).filter((function (e) {
var n = window.innerWidth, o = Object.keys(t).filter((function (e) {
return n < t[e]
}));
return void 0 !== o[0] ? Number(o[0]) : e
}(o, n);
if (e.setAttribute("data-columns", n), void 0 !== r && i !== r) {
const a = t.getItems();
var a = t.getItems();
t.updateOption("columns", r), t.updateCurrentItems();
for (let s = 0; s < a.length; s += 1) t.go("columns", a[s]);
for (var s = 0; s < a.length; s += 1) t.go("columns", a[s]);
t.emit("breakpoint.changed")
}
}()
}
}, function transition(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0], a = t.getOption("duration");
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0], a = t.getOption("duration");
"stop" !== r ? (e.style.setProperty("transition-duration", "".concat(a, "ms")), t.on("destory", (function () {
e.style.removeProperty("transition-duration")
}))) : e.style.removeProperty("transition-duration")
}, function transform(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0];
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0];
e.style.setProperty("transform", "translateX(".concat(r, "px)")), t.on("destory", (function () {
e.style.removeProperty("transform")
}))
}, function autoplay(t) {
if (t.getOption("autoplay")) {
const e = t.getOption("autoplay.duration"),
n = "left" === t.getOption("autoplay.direction") ? "<" : ">",
var e = t.getOption("autoplay.duration"), n = "left" === t.getOption("autoplay.direction") ? "<" : ">",
o = function repeat(t) {
return setInterval((function () {
t()
@ -101,99 +96,86 @@
}))
}
}, function grouping(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0], a = o[1], s = t.getOption("grouping"), l = a + 1;
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0], a = o[1], s = t.getOption("grouping"), l = a + 1;
if (s) {
const u = t.getOption("columns"), c = Math.ceil((a + 1) / u);
var u = t.getOption("columns"), c = Math.ceil((a + 1) / u);
r.setAttribute("data-order", c)
} else r.setAttribute("data-order", l);
t.on("destory", (function () {
r.removeAttribute("data-order")
}))
}, function columns(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0], a = t.getOption("columns"), s = parseFloat((1 / a * 100).toFixed(2));
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0], a = t.getOption("columns"), s = parseFloat((1 / a * 100).toFixed(2));
r.style.setProperty("flex", "0 0 ".concat(s, "%")), t.on("destory", (function () {
r.style.removeProperty("flex")
}))
}, function preview(t, e) {
if (t.getOption("preview")) {
const n = t.getOption("preview.edge");
var n = t.getOption("preview.edge");
e.style.setProperty("padding", "0 ".concat(n, "px")), t.on("destory", (function () {
e.style.removeProperty("padding")
}))
}
}, function spacing(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0], a = Math.floor(t.getOption("spacing") / 2);
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0], a = Math.floor(t.getOption("spacing") / 2);
r.style.setProperty("padding", "0px ".concat(a, "px")), t.on("destory", (function () {
r.style.removeProperty("padding")
}))
}, function align(t, e) {
const n = t.getOption("align");
var n = t.getOption("align");
"center" === n ? e.style.setProperty("align-items", "center") : "bottom" === n && e.style.setProperty("align-items", "flex-end"), t.on("destory", (function () {
e.style.removeProperty("align-items")
}))
}, function touch(t, e) {
if (t.getOption("touch")) {
!function init() {
const n = t.getOption("touch.threshold"), o = t.getOption("touch.duration"), i = t.adaptEvent(e),
var n = t.getOption("touch.threshold"), o = t.getOption("touch.duration"), i = t.adaptEvent(e),
r = {x: 0, y: 0, time: 0};
i.on("touchstart", (function (t) {
t.preventDefault();
const e = t.changedTouches[0];
var e = t.changedTouches[0];
r.x = e.pageX, r.y = e.pageY, r.time = (new Date).getTime()
})), i.on("touchmove", (function (t) {
t.preventDefault()
})), i.on("touchend", (function (e) {
e.preventDefault();
const i = e.changedTouches[0], a = (new Date).getTime() - r.time, s = Math.abs(i.pageX - r.x);
var i = e.changedTouches[0], a = (new Date).getTime() - r.time, s = Math.abs(i.pageX - r.x);
if (!(a > o || s < n)) {
const l = i.pageX > r.x ? ">" : "<";
var l = i.pageX > r.x ? ">" : "<";
t.slideTo(l)
}
}))
}()
}
}, function clone(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let r = 2;
for (; r < n; r++) o[r - 2] = arguments[r];
const a = o[0], s = o[1], l = t.getOption("columns"), u = t.getOption("preview"), c = t.getOption("loop");
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), r = 2; r < n; r++) o[r - 2] = arguments[r];
var a = o[0], s = o[1], l = t.getOption("columns"), u = t.getOption("preview"), c = t.getOption("loop");
if (u || c) {
const p = t.getItemCount(), d = t.getItems(), f = l, h = a.cloneNode(!0);
let v = null, m = !1;
var p = t.getItemCount(), d = t.getItems(), f = l, h = a.cloneNode(!0), v = null, m = !1;
h.classList.add(i), s < f && (e.appendChild(h), m = !0), s >= p - f && (m ? ((v = a.cloneNode(!0)).classList.add(i), e.insertBefore(v, d[0])) : e.insertBefore(h, d[0])), t.on("destory", (function () {
h.remove(), v && v.remove()
}))
}
}, function slide(t, e) {
const n = arguments.length, o = new Array(n > 2 ? n - 2 : 0);
let i = 2;
for (; i < n; i++) o[i - 2] = arguments[i];
const r = o[0], a = o[1], s = t.getOption("grouping"), l = t.getOption("preview"),
for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), i = 2; i < n; i++) o[i - 2] = arguments[i];
var r = o[0], a = o[1], s = t.getOption("grouping"), l = t.getOption("preview"),
u = t.getOption("duration"), c = t.getOption("columns"), p = t.getOption("loop"),
d = t.getItems()[0].offsetWidth, f = t.getPage(), h = p || l, v = f.maximum();
let m = f.calculate(r, !1);
const g = m < 1 || m > v;
let y = 0;
d = t.getItems()[0].offsetWidth, f = t.getPage(), h = p || l, v = f.maximum(), m = f.calculate(r, !1),
g = m < 1 || m > v, y = 0;
!p && g || (y = s ? d * (0 - (h ? 0 : -1) - m) * c : d * (1 - (h ? c : 0) - m), t.emit("slide.start"), t.go("transition", a), t.go("transform", y), t.updatePosition(m), g ? queue((function () {
m = f.calculate(r, g), y = s ? d * (0 - m) * c : d * (1 - c - m), t.go("transition", "stop"), t.go("transform", y), t.updatePosition(m), t.emit("slide.end")
}), u + 10) : t.emit("slide.end"))
}, function loop(t, e) {
const n = t.getOption("loop"), o = t.getOption("grouping");
var n = t.getOption("loop"), o = t.getOption("grouping");
if (n && o) {
const i = t.getItems(), r = t.getOption("columns"), a = t.getItemCount(), s = i[i.length - 1],
var i = t.getItems(), r = t.getOption("columns"), a = t.getItemCount(), s = i[i.length - 1],
l = r - a % r, u = [];
if (l !== r && 1 !== r) {
for (let c = 1; c <= l; c += 1) {
const p = s.cloneNode(!0);
for (var c = 1; c <= l; c += 1) {
var p = s.cloneNode(!0);
p.classList.add("sliderm__slide--empty"), p.innerHTML = "", e.appendChild(p), u.push(p)
}
t.updateCurrentItems(), t.on("destory", (function () {
@ -204,35 +186,32 @@
}
}
}, function init(e) {
const n = e.getOption("duration"), o = e.getRoot();
var n = e.getOption("duration"), o = e.getRoot();
o.classList.add(t), o.classList.remove("".concat(t, "--initialized")), o.classList.add("".concat(t, "--initialize")), e.on("initialized", (function () {
queue((function () {
o.classList.remove("".concat(t, "--initialize")), o.classList.add("".concat(t, "--initialized"))
}), n + 50)
}))
}], d = [function pagination(t) {
let e, i, r;
const a = function click(e) {
var e, i, r, a = function click(e) {
if (o === e.target.className) {
const n = Array.prototype.indexOf.call(i.childNodes, e.target) + 1;
var n = Array.prototype.indexOf.call(i.childNodes, e.target) + 1;
t.slideTo(n)
}
};
let s = function mark() {
const e = t.getPosition(), o = findDom(t.getRoot(), ".".concat(n)).children;
}, s = function mark() {
var e = t.getPosition(), o = findDom(t.getRoot(), ".".concat(n)).children;
Array.from(o).forEach((function (t, n) {
const o = n + 1;
var o = n + 1;
t.removeAttribute("data-active"), o === e && t.setAttribute("data-active", !0)
}))
};
const l = function destory() {
}, l = function destory() {
r.off("click", a), t.off("slide.end", s), i.remove()
}, u = function init() {
!function render() {
const a = setDom("div", n);
var a = setDom("div", n);
e = t.getPage().maximum();
for (let s = 0; s < e; s += 1) {
const l = setDom("div", o);
for (var s = 0; s < e; s += 1) {
var l = setDom("div", o);
0 === s && l.setAttribute("data-active", !0), a.append(l)
}
i = a, r = t.adaptEvent(i), t.getRoot().append(i)
@ -245,7 +224,7 @@
})), u()
}, function spinner(t) {
!function init() {
const e = t.getOption("spinner.color"), n = setDom("div", "sliderm__spinner");
var e = t.getOption("spinner.color"), n = setDom("div", "sliderm__spinner");
n.style.setProperty("color", e), t.getRoot().append(n), t.on("destory", (function () {
n.remove()
}))
@ -253,7 +232,7 @@
}, function arrow(t) {
!function init() {
for (var e = [s, r, a, u, l, c], n = setDom("div", "sliderm__button--previous"), o = setDom("div", "sliderm__button--next"), i = t.adaptEvent(n), p = t.adaptEvent(o), d = null, f = null, h = 0; h < e.length; h += 1) {
let v = e[h].name, m = e[h](t.getOption("arrow.".concat(v)));
var v = e[h].name, m = e[h](t.getOption("arrow.".concat(v)));
null !== m && ("bold" === v ? (d = setDom("span", "sliderm__icon-left--".concat(m)), f = setDom("span", "sliderm__icon-right--".concat(m))) : "shape" === v ? (n.classList.add("sliderm__button--".concat(m)), o.classList.add("sliderm__button--".concat(m))) : ("bgColor" === v ? v = "background-color" : "size" === v && (v = "font-size", m = "".concat(m, "px")), n.style.setProperty(v, m), o.style.setProperty(v, m)))
}
n.append(d), o.append(f), t.getRoot().append(n), t.getRoot().append(o), i.on("click", (function () {
@ -267,8 +246,8 @@
}];
function _defineProperties(t, e) {
for (let n = 0; n < e.length; n++) {
const o = e[n];
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
@ -288,7 +267,7 @@
}
}, {
key: "off", value: function off(t, e) {
const n = this;
var n = this;
void 0 === e ? delete this.events[t] : this.events[t].forEach((function (o, i) {
o === e && n.events[t].splice(i, 1)
}))
@ -308,8 +287,8 @@
}();
function event_adapter_defineProperties(t, e) {
for (let n = 0; n < e.length; n++) {
const o = e[n];
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
@ -337,9 +316,7 @@
}
}, {
key: "destory", value: function destory() {
const t = Object.keys(this.events);
let e = 0;
for (; e < t.length; e += 1) this.off(t[e]);
for (var t = Object.keys(this.events), e = 0; e < t.length; e += 1) this.off(t[e]);
delete this.events
}
}, {
@ -377,8 +354,8 @@
};
function page_defineProperties(t, e) {
for (let n = 0; n < e.length; n++) {
const o = e[n];
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
@ -394,22 +371,19 @@
return e && page_defineProperties(t.prototype, e), n && page_defineProperties(t, n), Object.defineProperty(t, "prototype", {writable: !1}), t
}(Page, [{
key: "calculate", value: function calculate() {
const t = arguments.length, e = new Array(t);
let n = 0;
for (; n < t; n++) e[n] = arguments[n];
const o = e[0], i = e[1], r = this.sliderm.getOption("columns"),
for (var t = arguments.length, e = new Array(t), n = 0; n < t; n++) e[n] = arguments[n];
var o = e[0], i = e[1], r = this.sliderm.getOption("columns"),
a = this.sliderm.getOption("grouping"), s = this.sliderm.getItemCount(),
l = this.sliderm.getGroupCount(), u = this.sliderm.getPosition(), c = a ? l : s;
let p = u, d = 0;
l = this.sliderm.getGroupCount(), u = this.sliderm.getPosition(), c = a ? l : s, p = u, d = 0;
if (a) {
const f = Math.ceil(u * r / r);
var f = Math.ceil(u * r / r);
p = f
}
return "number" == typeof o ? d = o : ">" === o ? (d = p + 1) > c && i && (d = 1) : "<" === o && (d = p - 1) <= 0 && i && (d = c), d
}
}, {
key: "maximum", value: function maximum() {
const t = this.sliderm.getOption("loop"), e = this.sliderm.getOption("preview"),
var t = this.sliderm.getOption("loop"), e = this.sliderm.getOption("preview"),
n = this.sliderm.getOption("grouping"), o = this.sliderm.getOption("columns"), i = t || e;
return n ? this.sliderm.getGroupCount() : i ? this.sliderm.getItemCount() : this.sliderm.getItemCount() - o + 1
}
@ -430,11 +404,9 @@
return function _arrayWithHoles(t) {
if (Array.isArray(t)) return t
}(t) || function _iterableToArrayLimit(t, e) {
let n = null == t ? null : "undefined" != typeof Symbol && t[Symbol.iterator] || t["@@iterator"];
var n = null == t ? null : "undefined" != typeof Symbol && t[Symbol.iterator] || t["@@iterator"];
if (null == n) return;
let o, i;
const r = [];
let a = !0, s = !1;
var o, i, r = [], a = !0, s = !1;
try {
for (n = n.call(t); !(a = (o = n.next()).done) && (r.push(o.value), !e || r.length !== e); a = !0) ;
} catch (t) {
@ -455,7 +427,7 @@
function _unsupportedIterableToArray(t, e) {
if (t) {
if ("string" == typeof t) return _arrayLikeToArray(t, e);
let n = Object.prototype.toString.call(t).slice(8, -1);
var n = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === n && t.constructor && (n = t.constructor.name), "Map" === n || "Set" === n ? Array.from(t) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? _arrayLikeToArray(t, e) : void 0
}
}
@ -467,8 +439,8 @@
}
function sliderm_defineProperties(t, e) {
for (let n = 0; n < e.length; n++) {
const o = e[n];
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
@ -489,7 +461,7 @@
!function sliderm_classCallCheck(t, e) {
if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
}(this, Sliderm), _classPrivateMethodInitSpec(this, P), _classPrivateMethodInitSpec(this, b), _classPrivateMethodInitSpec(this, _), _classPrivateMethodInitSpec(this, y), _classPrivateMethodInitSpec(this, g);
const o = getDom(t);
var o = getDom(t);
o ? (this.options = Object.assign(v, n), this.event = new f, this.page = new m(this), this.root = o, this.initialized = !1, this.domEvents = [], this.itemCount = 0, this.position = 1, this.modules = {}, this.slider = findDom(this.root, ".".concat(e)), this.items = [], _classPrivateMethodGet(this, g, _initialize2).call(this)) : error('The DOM "'.concat(t, '" is invalid.'))
}
@ -497,7 +469,7 @@
return e && sliderm_defineProperties(t.prototype, e), n && sliderm_defineProperties(t, n), Object.defineProperty(t, "prototype", {writable: !1}), t
}(Sliderm, [{
key: "adaptEvent", value: function adaptEvent(t) {
const e = new h(t);
var e = new h(t);
return this.domEvents.push(e), e
}
}, {
@ -534,10 +506,10 @@
}
}, {
key: "getOption", value: function getOption(t) {
const e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null,
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null,
n = void 0 !== this.options[t] ? this.options[t] : e;
if (t.includes(".")) try {
const o = t.split("."), i = _slicedToArray(o, 2), r = i[0], a = i[1];
var o = t.split("."), i = _slicedToArray(o, 2), r = i[0], a = i[1];
return this.options["_".concat(r)][a]
} catch (t) {
return e
@ -547,7 +519,7 @@
}, {
key: "updateOption", value: function updateOption(t, e) {
if (t.includes(".")) try {
const n = _slicedToArray(t.split("."), 2), o = n[0], i = n[1];
var n = _slicedToArray(t.split("."), 2), o = n[0], i = n[1];
this.options["_".concat(o)][i] = e
} catch (t) {
} else this.options[t] = e
@ -558,7 +530,7 @@
}
}, {
key: "go", value: function go(t) {
let e;
var e;
if (void 0 !== this.modules[t]) {
for (var n = arguments.length, o = new Array(n > 1 ? n - 1 : 0), i = 1; i < n; i++) o[i - 1] = arguments[i];
(e = this.modules)[t].apply(e, [this, this.slider].concat(o))
@ -575,7 +547,7 @@
}, {
key: "emit", value: function emit(t) {
for (var e, n = arguments.length, o = new Array(n > 1 ? n - 1 : 0), i = 1; i < n; i++) o[i - 1] = arguments[i];
const r = [this].concat(o);
var r = [this].concat(o);
(e = this.event).emit.apply(e, [t].concat(_toConsumableArray(r)))
}
}, {
@ -588,15 +560,15 @@
}();
function _initialize2() {
const t = this;
var t = this;
this.emit("initialize"), _classPrivateMethodGet(this, _, _updateItems2).call(this), _classPrivateMethodGet(this, b, _updateGroupCount2).call(this), _classPrivateMethodGet(this, P, _beforeMountExtensions2).call(this), _classPrivateMethodGet(this, y, _mountExtensions2).call(this), this.go("init"), this.go("breakpoint"), this.go("loop"), this.go("align"), this.go("touch"), this.go("preview"), this.go("autoplay"), this.items.forEach((function (e, n) {
t.go("columns", e), t.go("spacing", e), t.go("grouping", e, n), t.go("clone", e, n)
})), this.slideTo(1), this.initialized = !0, this.emit("initialized")
}
function _mountExtensions2() {
for (let t = 0; t < p.length; t += 1) "function" == typeof p[t] && (this.modules[p[t].name] = p[t]);
for (let e = 0; e < d.length; e += 1) "function" == typeof d[e] && this.getOption(d[e].name) && d[e](this)
for (var t = 0; t < p.length; t += 1) "function" == typeof p[t] && (this.modules[p[t].name] = p[t]);
for (var e = 0; e < d.length; e += 1) "function" == typeof d[e] && this.getOption(d[e].name) && d[e](this)
}
function _updateItems2() {
@ -604,15 +576,15 @@
}
function _updateGroupCount2() {
const t = this.getOption("columns");
var t = this.getOption("columns");
this.groupCount = Math.ceil(this.itemCount / t)
}
function _beforeMountExtensions2() {
for (let t = 0; t < this.options.extensions.length; t += 1) {
const e = this.options.extensions[t].name;
for (var t = 0; t < this.options.extensions.length; t += 1) {
var e = this.options.extensions[t].name;
if ("" !== e) {
const n = this.options.extensions[t];
var n = this.options.extensions[t];
void 0 === this.options[e] ? p.push(n) : d.push(n)
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
assets/images/city.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1010 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/ye.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -51,7 +51,7 @@ async function handleResponse(data, successMessage, failureMessage) {
async function showDashboardGreeting() {
"use strict";
document.getElementById("welcomeMsg").innerText = `Hi, ${UserInfo.FirstName}.`;
document.getElementById("welcomeMsg").innerText = `Ahoj, ${UserInfo.FirstName}.`;
}
async function doAction(url, requestData, successMessage, failureMessage, silent) {
@ -220,6 +220,14 @@ async function togglearticlecreate() {
articleContainerElement.classList.toggle("hidden");
}
async function togglememecreate() {
"use strict";
let memeContainerElement = document.getElementById("memecreatecontainer");
await getMemeImages();
memeContainerElement.classList.toggle("hidden");
}
async function renderarticles() {
"use strict";
let template = document.querySelector('template[data-template-name="article"]').innerHTML;
@ -305,6 +313,9 @@ async function onPageLoad() {
if (currentSite === "account" && currentPage === "files") {
await listFiles();
}
if (currentSite === "memes" && currentPage === "index") {
await getMemeImages();
}
await doSlicks();
}
@ -435,12 +446,14 @@ async function updateUserProfile() {
const firstName = document.getElementById("updateFirstName").value;
const lastName = document.getElementById("updateLastName").value;
const nickname = document.getElementById("updateNickname").value;
const minecraftNick = document.getElementById("updateMinecraftNick").value;
const data = {
action: "update_user_profile",
first_name: firstName,
last_name: lastName,
nickname: nickname,
minecraft_nick: minecraftNick,
};
await doAction('/account', data, "Profile update Successful!", "Profile update failed.", false);
@ -465,6 +478,7 @@ async function populateUserInfoFields(userData) {
document.getElementById("updateFirstName").value = userData.FirstName || "";
document.getElementById("updateLastName").value = userData.LastName || "";
document.getElementById("updateNickname").value = userData.Nickname || "";
document.getElementById("updateMinecraftNick").value = userData.MinecraftNick || "";
document.getElementById("updateNewEmail").value = userData.Email || "";
}
@ -612,6 +626,142 @@ async function listFiles() {
await displayList(fileList, "filelist", deleteFile);
}
}
async function addMeme() {
let memeTitleElement = document.getElementById("meme_title_input");
let memeTextElement = document.getElementById("meme_text_input");
let memeImageElement = document.getElementById("meme_image_input");
await doAction("/meme", {
action: "addMeme",
meme_title: memeTitleElement.value,
meme_text: memeTextElement.value,
meme_image_id: memeImageElement.value
}, "Meme bol zmazaný", "Nastala chyba pri mazaní meme-u", false);
memeTitleElement.value = "";
memeTextElement.value = "";
memeImageElement.selectedIndex = 0;
await togglememecreate();
}
async function deleteMeme(memeId) {
await doAction("/meme", {
action: "deleteMeme",
meme_id: memeId
}, "Meme bol zmazaný", "Nastala chyba pri mazaní meme-u", false);
await softReload();
}
async function getMemeImages() {
let memeImageSelector = document.getElementById("meme_image_input");
let fileList = await getFileList();
fileList.forEach((item) => {
let option = document.createElement("option");
option.value = item.ID;
let splitPath = item.Path.split("/");
option.text = `${splitPath[splitPath.length - 1]} - ID: (${item.ID}) Autor: [${item.UploadedBy} (${item.UploadedByID})]`;
memeImageSelector.appendChild(option);
});
}
async function reloadMemeVotes(memeID) {
let memeVoteCounterElement = document.getElementById(`meme_votes_counter_${memeID}`);
let memeVoteUpvoteElement = document.getElementById(`meme_votes_upvote_${memeID}`);
let memeVoteDownvoteElement = document.getElementById(`meme_votes_downvote_${memeID}`);
let memeVoteUpvoteButtonElement = document.getElementById(`meme_votes_upvote_button_${memeID}`);
let memeVoteDownvoteButtonElement = document.getElementById(`meme_votes_downvote_button_${memeID}`);
let memeVoteResponse = await doAction('/meme', {
action: "getMemeVotes",
meme_id: memeID
}, "Počet hlasov k meme-u bol stiahnutý", "Nastala chyba pri sťahovaní počtu hlasov k meme-u", true);
let memeVotes = memeVoteResponse.NetVotes;
let userVote = memeVoteResponse.UserVote;
memeVoteCounterElement.innerText = memeVotes;
memeVoteCounterElement.classList.remove("positive", "negative", "neutral");
if (0 < memeVotes) {
memeVoteCounterElement.classList.add("positive");
} else if (0 > memeVotes) {
memeVoteCounterElement.classList.add("negative");
} else {
memeVoteCounterElement.classList.add("neutral");
}
memeVoteUpvoteButtonElement.classList.remove('visual_hover');
memeVoteDownvoteButtonElement.classList.remove('visual_hover');
let memeUpvoteVariant = "line";
let memeDownvoteVariant = "line";
if (0 < userVote) {
memeUpvoteVariant = "fill";
memeVoteUpvoteButtonElement.classList.add('visual_hover');
} else if (0 > userVote) {
memeDownvoteVariant = "fill";
memeVoteDownvoteButtonElement.classList.add('visual_hover');
}
await setElementClasses(memeVoteUpvoteElement, [`ri-arrow-up-circle-${memeUpvoteVariant}`]);
await setElementClasses(memeVoteDownvoteElement, [`ri-arrow-down-circle-${memeDownvoteVariant}`])
}
async function voteMeme(memeID, isUpvote) {
let memeVoteUpvoteElement = document.getElementById(`meme_votes_upvote_${memeID}`);
let memeVoteDownvoteElement = document.getElementById(`meme_votes_downvote_${memeID}`);
let memeVoteDelete = false;
if (isUpvote) {
if (memeVoteUpvoteElement.classList.contains("ri-arrow-up-circle-fill")) {
await deleteVoteMeme(memeID);
memeVoteDelete = true;
}
} else {
if (memeVoteDownvoteElement.classList.contains("ri-arrow-down-circle-fill")) {
await deleteVoteMeme(memeID);
memeVoteDelete = true;
}
}
if (!memeVoteDelete) {
await doAction("/meme", {
action: "voteMeme",
meme_id: memeID,
is_upvote: isUpvote
}, "Meme bol votovaný", "Nastala chyba pri votovaný", true);
}
await reloadMemeVotes(memeID);
}
async function deleteVoteMeme(memeId) {
await doAction("/meme", {
action: "deleteVoteMeme",
meme_id: memeId
}, "Hlas na meme bol zmazaný", "Nastala chyba pri mazaní hlasu na meme", true);
await reloadMemeVotes(memeId);
}
async function surveySubmit() {
const satisfaction = document.querySelector('input[name="satisfaction"]:checked');
const functionality = document.querySelector('input[name="functionality"]:checked');
const content = document.querySelector('input[name="content"]:checked');
const comment = document.querySelector('textarea[name="comment"]');
if (satisfaction && functionality && content && comment.value) {
await doAction("/survey", {
action: "surveySubmit",
satisfaction: satisfaction.value,
functionality: functionality.value,
content: content.value,
comment: comment.value
}, "Zaznamenané",
"Nastala chyba");
satisfaction.checked = false;
functionality.checked = false;
content.checked = false;
comment.value = "";
}
}
async function toggleRegister() {
let loginForm = document.getElementById("sign_in_form");
let registerForm = document.getElementById("sign_up_form");

@ -288,7 +288,13 @@ textarea{
width: 175px;
}
#articlecreate {
span#ye-span:hover + body{
background: url('/assets/images/ye.jpg') repeat !important;
background-size: 20% !important;
}
#articlecreate, #memecreate {
border: 5px solid var(--pico-primary);
z-index: 5;
margin: auto;
@ -305,7 +311,7 @@ textarea{
display: none;
}
#articlecreatecontainer{
#articlecreatecontainer, #memecreatecontainer{
display: flex;
align-items: center;
justify-content: center;
@ -347,6 +353,33 @@ div#articleslist>article{
flex-direction: column;
}
.meme_image {
max-width: 500px;
max-height: 300px;
width: auto;
height: auto;
}
.meme_link {
width: fit-content;
height: fit-content;
}
.meme_info, .meme_topbar {
display: flex;
flex-direction: row;
height: fit-content;
width: 100%;
justify-content: right;
}
.meme, .meme_body {
display: flex;
flex-direction: column;
padding: 0;
margin: 0;
}
.positive {
color: #008000;
}
@ -359,64 +392,6 @@ div#articleslist>article{
color: var(--pico-color);
}
div.citation {
display: flex;
flex-direction: column;
align-items: center;
justify-content: left;
padding: 10px;
background-color: var(--pico-box-shadow);
border-radius: 5px;
}
p.citationAuthor {
font-weight: lighter;
}
div.teamPerson, div.sponsor {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
div.teamDiv, div.sponsors {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
width: 100%;
}
div.sponsors {
justify-content: space-between;
}
div.logoText {
display: flex;
flex-direction: row;
gap: 3.25rem;
text-align: center;
align-content: center;
align-items: center;
}
p.logoP {
display: inline;
height: fit-content;
margin: 0;
}
p.teamPersonName, p.sponsorName {
font-weight: bolder;
}
img.teamPersonImage {
width: 200px;
height: 200px;
}
.visual_hover {
--pico-background-color: var(--pico-primary-hover-background);
--pico-border-color: var(--pico-primary-hover-border);
@ -424,8 +399,30 @@ img.teamPersonImage {
--pico-color: var(--pico-primary-inverse);
}
.visual_hover.meme_upvote {
--pico-background-color: #008000;
--pico-border-color: unset;
}
.visual_hover.meme_downvote {
--pico-background-color: #ff0000;
--pico-border-color: unset;
}
#meme_gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));
grid-auto-rows: 1fr;
gap: 20px
}
@media (max-width: 1050px) {
table .rozvrh {
overflow: auto;
}
.navsite_item .navpage_list {
max-height: unset !important;
}
@ -465,6 +462,7 @@ img.teamPersonImage {
display: flex !important;
max-height: 200px !important;
width: inherit;
box-sizing: content-box;
transition-delay: .1s;
position: unset !important;
}
@ -495,6 +493,11 @@ img.teamPersonImage {
flex-direction: column;
}
.meme_image {
max-width: 200px;
max-height: 200px;
}
.navsite_link {
width: 100%;
}

@ -26,6 +26,7 @@ function endpoint($endpoint_data): array
$endpoint_data["first_name"],
$endpoint_data["last_name"],
$endpoint_data["nickname"],
$endpoint_data["minecraft_nick"]
),
"update_user_email" => updateUserEmail(
$endpoint_data["email"]

17
endpoints/meme.php Normal file

@ -0,0 +1,17 @@
<?php
require_once "lib/meme.php";
function endpoint($endpoint_data): array
{
return match ($endpoint_data["action"]) {
"addMeme" => addMeme($endpoint_data['meme_title'], $endpoint_data['meme_text'], $endpoint_data['meme_image_id']),
"getMemes" => getMemeGallery($endpoint_data['offset'], $endpoint_data['meme_author'], $endpoint_data['meme_id'], $endpoint_data['meme_keyword']),
"deleteMeme" => deleteMeme($endpoint_data['meme_id']),
"getMemeVotes" => getMemeVotes($endpoint_data['meme_id']),
"deleteVoteMeme" => deleteVoteMeme($endpoint_data['meme_id']),
"voteMeme" => voteMeme($endpoint_data['meme_id'], $endpoint_data['is_upvote']),
default => ["Status" => "Fail", "Message" => "Invalid action"],
};
}

11
endpoints/survey.php Normal file

@ -0,0 +1,11 @@
<?php
require_once "lib/survey.php";
function endpoint($endpoint_data): array
{
return match ($endpoint_data["action"]) {
"surveySubmit" => submitSurvey($endpoint_data["satisfaction"], $endpoint_data["functionality"], $endpoint_data["content"], $endpoint_data["comment"]),
default => ["Status" => "Fail", "message" => "Invalid action"],
};
}

@ -1,7 +1,6 @@
<?php
use Random\RandomException;
/**
* Checks if the current session represents a logged-in user.
*
@ -117,6 +116,7 @@ function setDefaultSessionData(): void
$_SESSION["last_name"] = "";
$_SESSION["nickname"] = "";
$_SESSION["email"] = "";
$_SESSION["minecraft_nickname"] = "";
$_SESSION["privilege_level"] = $routerConfig["permissions"]["logged_out"];
}
/**
@ -149,7 +149,7 @@ function verifyPassword(int $userID, string $password): bool
function UpdateSession(): void
{
global $mysqli;
$stmt = $mysqli->prepare("SELECT FirstName, LastName, Nickname, Email, PrivilegeLevel, LastLoginAt, LoginCount, ClassID, FavoriteColor FROM Users WHERE ID = ? AND isActivated = 1");
$stmt = $mysqli->prepare("SELECT FirstName, LastName, Nickname, Email, MinecraftNick, PrivilegeLevel, LastLoginAt, LoginCount, ClassID, FavoriteColor FROM Users WHERE ID = ? AND isActivated = 1");
$stmt->bind_param("i", $_SESSION["ID"]);
$stmt->execute();
@ -157,18 +157,20 @@ function UpdateSession(): void
$last_name = "";
$nickname = "";
$email = "";
$minecraft_nickname = "";
$privilege_level = 0;
$class_id = 0;
$favorite_color = 0;
$lastLoginAt = null;
$loginCount = 0;
$stmt->bind_result($first_name, $last_name, $nickname, $email, $privilege_level, $lastLoginAt, $loginCount, $class_id, $favorite_color);
$stmt->bind_result($first_name, $last_name, $nickname, $email, $minecraft_nickname, $privilege_level, $lastLoginAt, $loginCount, $class_id, $favorite_color);
$stmt->fetch();
$stmt->close();
$_SESSION["first_name"] = $first_name;
$_SESSION["last_name"] = $last_name;
$_SESSION["nickname"] = $nickname;
$_SESSION["email"] = $email;
$_SESSION["minecraft_nickname"] = $minecraft_nickname;
$_SESSION["privilege_level"] = $privilege_level;
$_SESSION["lastLoginAt"] = $lastLoginAt;
$_SESSION["loginCount"] = $loginCount;
@ -300,26 +302,27 @@ function changePassword(string $oldPassword, string $newPassword): array
* @param string $firstName The new first name.
* @param string $lastName The new last name.
* @param string $nickname The new nickname.
* @param string $minecraft_nickname The new Minecraft nickname.
* @return array Status of the profile update ('Success' or 'Fail').
*@global mysqli $mysqli Global database connection object.
*/
function updateUserProfile(string $firstName, string $lastName, string $nickname): array
function updateUserProfile(string $firstName, string $lastName, string $nickname, string $minecraft_nickname): array
{
global $mysqli;
$status = ["Status" => "Fail"];
if (isLoggedIn() && !empty($firstName) && !empty($lastName) && !empty($nickname)) {
if (isLoggedIn() && !empty($firstName) && !empty($lastName) && !empty($nickname) && !empty($minecraft_nickname)) {
$stmt = $mysqli->prepare("UPDATE Users SET FirstName = ?, LastName = ?, Nickname = ? WHERE ID = ?");
$stmt = $mysqli->prepare("UPDATE Users SET FirstName = ?, LastName = ?, Nickname = ?, MinecraftNick = ? WHERE ID = ?");
/** @noinspection SpellCheckingInspection */
$stmt->bind_param("ssssi", $firstName, $lastName, $nickname, $_SESSION["ID"]);
$stmt->bind_param("ssssi", $firstName, $lastName, $nickname, $minecraft_nickname, $_SESSION["ID"]);
$stmt->execute();
if ($stmt->affected_rows > 0) {
$status["Status"] = "Success";
}
else {
$status["Status"] = "$firstName $lastName $nickname";
$status["Status"] = "$firstName $lastName $nickname $minecraft_nickname";
}
$stmt->close();
@ -389,7 +392,7 @@ function getUserInfo(): array
if(isLoggedIn()) {
global $mysqli;
$userID = $_SESSION["ID"];
$stmt = $mysqli->prepare("SELECT FirstName, LastName, Nickname, Email FROM Users WHERE ID = ?");
$stmt = $mysqli->prepare("SELECT FirstName, LastName, Nickname, Email, MinecraftNick FROM Users WHERE ID = ?");
$stmt->bind_param("i", $userID);
$stmt->execute();
@ -397,8 +400,9 @@ function getUserInfo(): array
$lastName = "";
$nickname = "";
$email = "";
$minecraft_nickname = "";
$stmt->bind_result($firstName, $lastName, $nickname, $email);
$stmt->bind_result($firstName, $lastName, $nickname, $email, $minecraft_nickname);
$stmt->fetch();
$stmt->close();
UpdateSession();
@ -409,7 +413,8 @@ function getUserInfo(): array
"FirstName" => $firstName,
"LastName" => $lastName,
"Nickname" => $nickname,
"Email" => $email
"Email" => $email,
"MinecraftNick" => $minecraft_nickname
];
}
@ -430,7 +435,7 @@ function addActivationCodes(int $count): array
$output = ["Status" => "Fail"]; // Default Status is "Fail"
if ($count > 0 && isUserAdmin() && isLoggedIn()) {
if (is_numeric($count) && $count > 0 && isUserAdmin() && isLoggedIn()) {
$stmt = $mysqli->prepare("INSERT INTO Users (ActivationToken, CreatedAt, CreatedBy) VALUES (?, NOW(), ?)");
for ($i = 0; $i < $count; $i++) {
@ -467,7 +472,7 @@ function listUsers(): array
if (isUserAdmin()) {
$users = [];
$result = $mysqli->query("SELECT ID, FirstName, LastName, Nickname, Email, PrivilegeLevel, CreatedAt, RegisteredAt, LastLoginAt, LoginCount, CreatedBy FROM Users WHERE isActivated = 1");
$result = $mysqli->query("SELECT ID, FirstName, LastName, Nickname, Email, MinecraftNick, PrivilegeLevel, CreatedAt, RegisteredAt, LastLoginAt, LoginCount, CreatedBy FROM Users WHERE isActivated = 1");
// Check if the query executed Successfully
if ($result) {

@ -29,7 +29,7 @@ function loadRouterConfig(): array
return [
'inlining' => false,
'domain' => 'adlerka',
'tld' => 'space',
'tld' => 'top',
'default_page' => 'index',
'default_site' => 'home',
'template_dir' => 'templates/',
@ -58,9 +58,9 @@ function loadRouterConfig(): array
'per_page' => 10
],
'seo' => [
'author' => 'Tím Adlerka space',
'description' => 'Toto je oficiálna stránka pre Adlerácky vesmírny program, kde môžete nájsť plno zaujímavostí o ňom.',
'keywords' => 'adlerka, alderka, studenti, vesmir, space, project, projekt, web, dev, webdev, web dev, skola, zabava',
'author' => 'Tím AdlerkaTop',
'description' => 'Toto je neoficiánla študentská stránka pre Adlerku, kde môžete nájsť plno zaujímavostí.',
'keywords' => 'adlerka, alderka, studenti, studentska stranka, web, dev, webdev, web dev, skola, zabava',
'generator' => 'TurboRoute',
'robots' => 'follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large'
]

316
lib/meme.php Normal file

@ -0,0 +1,316 @@
<?php
require_once "lib/upload.php";
require_once "lib/account.php";
/**
* Adds a meme to the database with associated image and text content.
*
* @param string $title The title of the meme.
* @param string $memeText The text content of the meme.
* @param int $imageID The ID of the image associated with the meme.
* @return array Returns an associative array with the operation status and a message.
* @global mysqli $mysqli The database connection object.
*/
function addMeme(string $title, string $memeText, int $imageID): array
{
global $mysqli;
$output = ["Status" => "Fail"];
if (isLoggedIn() && fileExists($imageID, false) && !empty($title) && !empty($memeText) && !empty($imageID) && $imageID > 0) {
$stmtMemeAdd = $mysqli->prepare('INSERT INTO Memes (AuthorID, Title, TextContent, FileID) VALUES (?, ?, ?, ?)');
$stmtMemeAdd->bind_param('issi', $_SESSION['ID'], htmlspecialchars($title), htmlspecialchars($memeText), $imageID);
if ($stmtMemeAdd->execute() && $stmtMemeAdd->affected_rows > 0) {
$output["Status"] = "Success";
$output["Meme"] = "Funny";
}
}
return $output;
}
function executeAndRenderMemes(mysqli_stmt $stmt): string {
global $routerConfig;
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($memeID, $title, $textContent, $createdAt, $authorID, $filePath, $imageWidth, $imageHeight, $userNickname);
$memes_out = '';
$meme_template = file_get_contents($routerConfig['template_dir'] . "meme.html");
$meme_gallery_template = file_get_contents($routerConfig['template_dir'] . 'meme_gallery.html');
while ($stmt->fetch()) {
$memes_out .= renderMeme($memeID, $authorID, $title, $textContent, $createdAt, $filePath, $imageWidth, $imageHeight, $userNickname, $meme_template);
}
$meme_add = isLoggedIn() ? file_get_contents($routerConfig['template_dir'] . 'meme_add.html') : '';
$meme_gallery_out = str_replace('__TEMPLATE_MEMES_HERE__', $memes_out, $meme_gallery_template);
$meme_gallery_out = str_replace('__TEMPLATE_MEME_ADD__', $meme_add, $meme_gallery_out);
$stmt->close();
return $meme_gallery_out;
}
/**
* Renders a meme into HTML based on provided data and a template.
*
* @param int $id The ID of the meme.
* @param int $authorId The author's user ID.
* @param string $title The title of the meme.
* @param string $textContent The text content of the meme.
* @param string $createdAt The creation timestamp of the meme.
* @param string $filePath The file path of the associated image.
* @param int $imageWidth The width of the image.
* @param int $imageHeight The height of the image.
* @param string $userNickname The nickname of the meme's author.
* @param string $meme_template The HTML template for a meme. (used to not read the template over and over when rendering more memes)
* @return string Returns the rendered HTML of the meme.
*/
function renderMeme(int $id, int $authorId, string $title, string $textContent, string $createdAt, string $filePath, int $imageWidth, int $imageHeight, string $userNickname, string $meme_template): string
{
$meme_out = str_replace('__TEMPLATE_MEME_TITLE__', htmlspecialchars($title), $meme_template);
$meme_out = str_replace('__TEMPLATE_MEME_AUTHOR__', htmlspecialchars($userNickname), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_DATE__', htmlspecialchars($createdAt), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_IMAGE__', '/' . htmlspecialchars($filePath), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_IMAGE_WIDTH__', strval($imageWidth), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_IMAGE_HEIGHT__', strval($imageHeight), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_DELETE_BUTTON__', (isModerator() || $_SESSION['ID'] == $authorId) ? "<button onclick=\"deleteMeme($id);\"><i class='ri-delete-bin-line'></i></button>" : '', $meme_out);
$meme_votes = calculateNetVotes($id);
$meme_net_votes = $meme_votes['NetVotes'];
if ($meme_votes['UserVote'] > 0) {
$meme_upvote_active = 'fill';
$meme_downvote_active = 'line';
$meme_vote_counter_class = 'positive';
$meme_upvote_button_class = ' visual_hover';
$meme_downvote_button_class = '';
} elseif (($meme_votes['UserVote'] < 0)) {
$meme_upvote_active = 'line';
$meme_downvote_active = 'fill';
$meme_vote_counter_class = 'negative';
$meme_upvote_button_class = '';
$meme_downvote_button_class = ' visual_hover';
} else {
$meme_downvote_active = 'line';
$meme_upvote_active = 'line';
$meme_vote_counter_class = 'neutral';
$meme_upvote_button_class = '';
$meme_downvote_button_class = '';
}
$meme_upvote = isLoggedIn() ? "<button id='meme_votes_upvote_button_$id' class='meme_upvote$meme_upvote_button_class' onclick=\"voteMeme($id, 1);\"> <i id='meme_votes_upvote_$id' class=\"ri-arrow-up-circle-$meme_upvote_active\"></i></button>" : '';
$meme_downvote = isLoggedIn() ? "<button id='meme_votes_downvote_button_$id' class='meme_downvote$meme_downvote_button_class' onclick=\"voteMeme($id, 0);\"> <i id='meme_votes_downvote_$id' class=\"ri-arrow-down-circle-$meme_downvote_active\"></i></button>" : '';
$meme_out = str_replace('__TEMPLATE_MEME_VOTES_NUMBER__', strval($meme_net_votes), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_UPVOTE__', $meme_upvote, $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_DOWNVOTE__', $meme_downvote, $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_ID__', strval($id), $meme_out);
$meme_out = str_replace('__TEMPLATE_MEME_VOTE_COUNTER_CLASS__', $meme_vote_counter_class, $meme_out);
return str_replace('__TEMPLATE_MEME_TEXT__', htmlspecialchars($textContent), $meme_out);
}
/**
* Renders a gallery of memes, optionally filtered by author ID, meme ID, or a keyword.
*
* This function retrieves memes from the database and returns an HTML string representation.
* It supports filtering by author ID, meme ID, or a keyword that is searched in titles and text content.
* It also supports pagination through an offset parameter.
*
* @param int|null $offset Pagination offset, used to calculate the starting point for records to return.
* @param int|null $authorId Optional author ID for filtering memes by a specific author.
* @param int|null $memeId Optional meme ID for rendering a single meme.
* @param string|null $keyword Optional keyword for full-text search in meme titles and content.
* @return string Returns the complete HTML content of the meme gallery, optionally filtered.
*/
function getMemeGallery(?int $offset = null, ?int $authorId = null, ?int $memeId = null, ?string $keyword = null): array {
return [
"Status" => "Success",
"Output" => renderMemeGallery($offset, $authorId, $memeId, $keyword)
];
}
function renderMemeGallery(?int $offset = null, ?int $authorId = null, ?int $memeId = null, ?string $keyword = null): string {
global $mysqli, $routerConfig;
// Start building the SQL query
$query = 'SELECT Memes.ID, Memes.Title, Memes.TextContent, Memes.CreatedAt, Memes.AuthorID,
Files.Path, Files.Width, Files.Height, Users.Nickname
FROM Memes
INNER JOIN Users ON Memes.AuthorID = Users.ID
INNER JOIN Files ON Memes.FileID = Files.ID';
$conditions = [];
$params = [];
$types = '';
// Add conditions based on provided parameters
if ($authorId !== null) {
$conditions[] = 'Memes.AuthorID = ?';
$params[] = $authorId;
$types .= 'i';
}
if ($memeId !== null) {
$conditions[] = 'Memes.ID = ?';
$params[] = $memeId;
$types .= 'i';
}
if ($keyword !== null) {
$conditions[] = '(Memes.Title LIKE CONCAT("%", ?, "%") OR Memes.TextContent LIKE CONCAT("%", ?, "%"))';
$params[] = $keyword;
$params[] = $keyword;
$types .= 'ss';
}
// Append conditions to the query
if (!empty($conditions)) {
$query .= ' WHERE ' . join(' AND ', $conditions);
}
if($offset == null) {
$offset = 0;
}
// Add pagination and limit
$query .= ' LIMIT ? OFFSET ?';
$params[] = $routerConfig['meme']['per_page'];
$params[] = $routerConfig['meme']['per_page'] * $offset;
$types .= 'ii';
$stmt = $mysqli->prepare($query);
$stmt->bind_param($types, ...$params);
return executeAndRenderMemes($stmt);
}
/**
* Deletes a meme from the database if the current user has the right permissions.
*
* @param int $memeID The ID of the meme to delete.
* @return array Returns an associative array with the status of the operation.
* @global mysqli $mysqli The database connection object.
*/
function deleteMeme(int $memeID): array
{
global $mysqli;
$out = ["Status" => "Fail"];
if (isLoggedIn()) {
$query = !isModerator() ? 'DELETE FROM Memes WHERE ID = ? AND AuthorID = ?' : 'DELETE FROM Memes WHERE ID = ?';
$stmtDelete = $mysqli->prepare($query);
if (!isModerator()) {
$stmtDelete->bind_param('ii', $memeID, $_SESSION['ID']);
} else {
$stmtDelete->bind_param('i', $memeID);
}
$stmtDelete->execute();
if ($stmtDelete->affected_rows > 0) {
$out['Status'] = 'Success';
}
$stmtDelete->close();
}
return $out;
}
/**
* Records or updates a vote on a meme by the current user.
*
* @param int $memeID The ID of the meme to be voted on.
* @param int $isUpvote Indicates whether the vote is an upvote (1) or downvote (0).
* @return array Returns an associative array with the status of the vote operation.
* @global mysqli $mysqli The database connection object.
*/
function voteMeme(int $memeID, int $isUpvote): array
{
global $mysqli;
$out = ["Status" => "Fail"];
if ($isUpvote != 1) {
$isUpvote = 0;
}
$memeVoteConn = $mysqli->prepare('INSERT INTO MemeVotes (MemeID, UserID, isUpvote) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE isUpvote = VALUES(isUpvote)');
$memeVoteConn->bind_param('iii', $memeID, $_SESSION['ID'], $isUpvote);
$memeVoteConn->execute();
if ($memeVoteConn->affected_rows > 0) {
$out['Status'] = 'Success';
}
$memeVoteConn->close();
return $out;
}
/**
* Deletes a vote previously made by the current user on a meme.
*
* @param int $memeID The ID of the meme whose vote is to be deleted.
* @return array Returns an associative array with the status of the deletion.
* @global mysqli $mysqli The database connection object.
*/
function deleteVoteMeme(int $memeID): array
{
global $mysqli;
$out = ["Status" => "Fail"];
$memeVoteConn = $mysqli->prepare('DELETE FROM MemeVotes WHERE MemeID = ? AND UserID = ?');
$memeVoteConn->bind_param('ii', $memeID, $_SESSION['ID']);
$memeVoteConn->execute();
if ($memeVoteConn->affected_rows > 0) {
$out['Status'] = 'Success';
}
$memeVoteConn->close();
return $out;
}
/**
* Calculates the net votes for a meme and determines if the current user has voted on it.
* The array has both the net votes and the user vote(0 when the user hasn't voted)
*
* @param int $memeID The ID of the meme for which votes are being calculated.
* @return array Returns an array with net votes and the user's vote status.
* @global mysqli $mysqli The database connection object.
*/
function calculateNetVotes(int $memeID): array
{
global $mysqli;
// Adjusted query to calculate net votes and get the user's vote in one go
$query = "
SELECT
SUM(CASE WHEN isUpvote = 1 THEN 1 ELSE -1 END) AS NetVotes,
(
SELECT CASE WHEN isUpvote = 1 THEN 1 ELSE -1 END
FROM MemeVotes
WHERE MemeID = ? AND UserID = ?
) AS UserVote
FROM MemeVotes
WHERE MemeID = ?";
$stmt = $mysqli->prepare($query);
$userID = $_SESSION['ID'];
$stmt->bind_param('iii', $memeID, $userID, $memeID);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_assoc();
$netVotes = $data['NetVotes'] ?? 0; // Null coalescing operator in case no votes are found
$userVote = $data['UserVote'] ?? 0; // Default to 0 if the user hasn't voted
$stmt->close();
return [
"NetVotes" => $netVotes,
"UserVote" => $userVote
];
}
/**
* Fetches the net votes and user's vote status for a specific meme.
* Essentially just a wrapper of getMemeVotes for an API call
*
* @param int $memeID The ID of the meme to fetch votes for.
* @return array Returns an array with the net votes and the user's vote status, along with operation status.
*/
function getMemeVotes(int $memeID): array
{
$voteData = calculateNetVotes($memeID);
return [
"Status" => "Success",
"NetVotes" => $voteData['NetVotes'],
"UserVote" => $voteData['UserVote']
];
}

@ -204,6 +204,7 @@ function getPage(string $site_name_in = null, string $page_name_in = null): stri
"UserInfo_LastName" => $_SESSION["last_name"],
"UserInfo_Nickname" => $_SESSION["nickname"],
"UserInfo_Email" => $_SESSION["email"],
"UserInfo_MinecraftNick" => $_SESSION["minecraft_nickname"],
];
}
$dynamic_script = generateScriptData($dynamic_script_data);

@ -11,7 +11,7 @@
*/
function generateScriptData(array $phpArray):string {
// Check if the array is associative and single-level
if (count($phpArray) > 0 && count(array_filter(array_keys($phpArray), 'is_string')) === count($phpArray)) {
if (is_array($phpArray) && count($phpArray) > 0 && count(array_filter(array_keys($phpArray), 'is_string')) === count($phpArray)) {
// Generate JavaScript code to save each array element to local storage
$out = "<script>";
foreach ($phpArray as $key => $value) {

21
lib/survey.php Normal file

@ -0,0 +1,21 @@
<?php
require_once "lib/account.php";
function submitSurvey(int $satisfaction, int $functionality, int $content, string $comment): array
{
global $mysqli;
$output = ["Status" => "Fail", "Opinion" => "Ignored unsuccessfully!"];
if (isLoggedIn()
&& $satisfaction >= 1 && $satisfaction <= 5
&& $functionality >= 1 && $functionality <= 5
&& $content >= 1 && $content <= 5
&& !empty($comment)) {
$stmtMemeAdd = $mysqli->prepare('INSERT INTO Survey (AuthorID, Satisfaction, Functionality, Content, Comment) VALUES (?, ?, ?, ?, ?)');
$stmtMemeAdd->bind_param('iiiis', $_SESSION['ID'], $satisfaction, $functionality, $content, htmlspecialchars($comment));
if ($stmtMemeAdd->execute() && $stmtMemeAdd->affected_rows > 0) {
$output["Status"] = "Success";
$output["Opinion"] = "Ignored successfully!";
}
}
return $output;
}

@ -1,11 +0,0 @@
<page minimal_permission_level="1" page_title="CanSat" secret="no"></page>
<h1>About CanSat</h1>
<p>
The CanSat project is an educational endeavor that combines the fields of aerospace engineering and technology. It
involves designing and building a small satellite, no larger than a soda can, which is then launched into the
atmosphere to collect data and perform various tasks.
This hands-on project allows students to gain practical experience in areas such as programming, electronics, and
data analysis. By working together in teams, students learn valuable skills in problem-solving, communication, and
teamwork.
</p>

@ -1,75 +0,0 @@
<page minimal_permission_level="1" page_title="FAQ" secret="no"></page>
<div class="faq">
<h1>Frequently Asked Questions</h1>
<div class="faq-question">
<div class="question">
<p>What is CanSat?</p>
<div class="answer">
<p>CanSat is a European Space Agency program that challenges teams of students to build a satellite-like
device, called a CanSat, to perform specific missions. It provides an opportunity for students to
gain hands-on experience in space-related projects.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>How will your CanSat identify fires?</p>
<div class="answer">
<p>We will equip our CanSat with a thermal imaging camera and a regular imaging camera. By combining the
data from these cameras with satellite position information, we can accurately locate and identify
the scale of potential fires.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>What other capabilities does your CanSat have?</p>
<div class="answer">
<p>Our CanSat also includes on-board sensors to measure temperature and humidity. This data will provide
valuable insights into fire behavior and the environmental conditions surrounding the fires.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>What is the significance of your mission?</p>
<div class="answer">
<p>Wildfires have devastating effects on communities, ecosystems, and the global climate. By developing
a CanSat that can detect fires and provide accurate information, we aim to minimize the damage
caused by these disasters and support the efforts of firefighters and environmental experts.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>What challenges do you anticipate?</p>
<div class="answer">
<p>Building and launching a CanSat comes with various challenges, such as ensuring the reliability of
the sensors, achieving accurate data transmission, and designing a robust structure to withstand the
launch and descent. However, we are prepared to overcome these challenges through careful planning
and testing.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>How can we stay updated on your progress?</p>
<div class="answer">
<p>You can follow our journey and stay updated on our progress through our website and social media
platforms, where we will share exciting updates, milestones, and insights into our project.</p>
</div>
</div>
</div>
<div class="faq-question">
<div class="question">
<p>Can we support your team in any way?</p>
<div class="answer">
<p>Absolutely! Your support means a lot to us. If you are interested in collaborating, providing
resources, or offering any form of assistance, please reach out to us through our contact
information provided on our website.</p>
</div>
</div>
</div>
</div>

@ -1,51 +0,0 @@
<page minimal_permission_level="1" page_title="Team" secret="no"></page>
<p>
We are a team of high school electrical engineering students, aged 17 to 18, proudly representing Slovakia in the
2024 edition of the CanSat project. With a genuine passion for science and technology, we are excited to embark on
our first-ever project in the field of space exploration. Coming together, we aim to contribute to the mission of
the CanSat program and make a meaningful impact on the world.
</p>
<hr>
<div class="teamDiv">
<div class="teamPerson">
<img alt="Simon" class="teamPersonImage" src="/assets/images/people/simon.png">
<p class="teamPersonName">Šimon</p>
<p class="teamPersonRole">Embedded systems</p>
</div>
<div class="teamPerson">
<img alt="Tibor" class="teamPersonImage" height="1000" src="/assets/images/people/tibor.png" width="1000">
<p class="teamPersonName">Tibor</p>
<p class="teamPersonRole">3D Design, Parachute design</p>
</div>
<div class="teamPerson">
<img alt="Michal" class="teamPersonImage" height="1000" src="/assets/images/people/michal.png" width="1000">
<p class="teamPersonName">Michal</p>
<p class="teamPersonRole">Programmer, Team Leader</p>
</div>
<div class="teamPerson">
<img alt="Samuel" class="teamPersonImage" height="1000" src="/assets/images/people/samuel.png" width="1000">
<p class="teamPersonName">Samuel</p>
<p class="teamPersonRole">Electronics, Circuit design</p>
</div>
<div class="teamPerson">
<img alt="Adam" class="teamPersonImage" height="1000" src="/assets/images/people/adam.png" width="1000">
<p class="teamPersonName">Adam</p>
<p class="teamPersonRole">Radio technics</p>
</div>
<div class="teamPerson">
<img alt="Tomáš" class="teamPersonImage" height="1000" src="/assets/images/people/tomas.png" width="1000">
<p class="teamPersonName">Tomáš</p>
<p class="teamPersonRole">Sponzoring</p>
</div>
<div class="teamPerson">
<img alt="Sebastián" class="teamPersonImage" height="1000" src="/assets/images/people/sebastian.png" width="1000">
<p class="teamPersonName">Sebastián</p>
<p class="teamPersonRole">Sponzoring</p>
</div>
<div class="teamPerson">
<img alt="Bruno" class="teamPersonImage" height="1000" src="/assets/images/people/bruno.png" width="1000">
<p class="teamPersonName">Bruno</p>
<p class="teamPersonRole">Embedded development</p>
</div>
</div>

@ -1,26 +0,0 @@
<page minimal_permission_level="1" page_title="Mission" secret="no"></page>
<h1>Our mission</h1>
<p>
In the vast realm of space exploration, we have chosen a mission that holds immense significance for both human
safety and environmental preservation. Our goal is to develop a CanSat that can effectively identify and classify
potential forest fires, aiding firefighters and environmental professionals in their crucial work. Additionally, we
aim to report any illegal fireplaces we come across, promoting the protection of our natural surroundings.
</p>
<hr>
<h1>Achieving the mission</h1>
<p>
Detecting potential or existing forest fires is no easy task for a machine. To make this possible, we make use of a
thermal imaging sensor combined with a visible light sensor (also called a camera) to gather information about
whats happening on the ground. We then process this information and add location data to see where the fire is
exactly. Additionally, we make use of the onboard temperature and humidity sensors to calculate the potential risk
of fire even before it happens.
</p>
<hr>
<h1>The impact</h1>
<p>
While we may not detect any fires at the day of the competition (we hope we wont), we aim to develop a technology
that will allow for inexpensive surveillance and data gathering across wide regions of forests. When not inside of a
CanSat but mounted on a drone for example, data used from the satellite could be used for identifying and locating
anything from illegal fireplaces to large-scale forest fires. We believe that our technology can be used all around
the world to aid firefighters in the mission of protecting our environment from the dangers of fire.
</p>

@ -1,5 +1,5 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="2" page_title="Files" secret="yes"></page>
<page minimal_permission_level="2" secret="yes" page_title="Súbory"></page>
<div id="filelist"></div>
<form id="uploadForm" enctype="multipart/form-data" method="POST">
<label for="fileInput">Send this file: </label>

@ -17,6 +17,6 @@ return [
[
"minimal_permission_level" => 1,
"secret" => "no",
"page_title" => "Account"
"page_title" => "Účet"
]
];

@ -16,6 +16,6 @@ return [
[
"minimal_permission_level" => 2,
"secret" => "no",
"page_title" => "Settings"
"page_title" => "Nastavenia"
]
];

47
pages/account/survey.html Normal file

@ -0,0 +1,47 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="2" secret="yes" page_title="Prieskum"></page>
<form id="surveyForm">
<h3>Spokojnosť so stránkou:</h3>
<input type="radio" name="satisfaction" value="5" id="spokojnost_super">
<label for="spokojnost_super">Super</label>
<input type="radio" name="satisfaction" value="4" id="spokojnost_dobre">
<label for="spokojnost_dobre">Dobre</label>
<input type="radio" name="satisfaction" value="3" id="spokojnost_da_sa">
<label for="spokojnost_da_sa">Dá sa</label>
<input type="radio" name="satisfaction" value="2" id="spokojnost_zle">
<label for="spokojnost_zle">Zle</label>
<input type="radio" name="satisfaction" value="1" id="spokojnost_nanic">
<label for="spokojnost_nanic">Nanič</label>
<br>
<br>
<h3>Funkčnosť stránky:</h3>
<input type="radio" name="functionality" value="5" id="funkcnost_super">
<label for="funkcnost_super">Super</label>
<input type="radio" name="functionality" value="4" id="funkcnost_dobre">
<label for="funkcnost_dobre">Dobre</label>
<input type="radio" name="functionality" value="3" id="funkcnost_da_sa">
<label for="funkcnost_da_sa">Dá sa</label>
<input type="radio" name="functionality" value="2" id="funkcnost_zle">
<label for="funkcnost_zle">Zle</label>
<input type="radio" name="functionality" value="1" id="funkcnost_nanic">
<label for="funkcnost_nanic">Nanič</label>
<br>
<br>
<h3>Obsah stránky:</h3>
<input type="radio" name="content" value="5" id="content_super">
<label for="content_super">Super</label>
<input type="radio" name="content" value="4" id="content_dobre">
<label for="content_dobre">Dobre</label>
<input type="radio" name="content" value="3" id="content_da_sa">
<label for="content_da_sa">Dá sa</label>
<input type="radio" name="content" value="2" id="content_zle">
<label for="content_zle">Zle</label>
<input type="radio" name="content" value="1" id="content_nanic">
<label for="content_nanic">Nanič</label>
<br>
<br>
<textarea name="comment" placeholder="Komentár" cols="80" rows="10" required></textarea>
<br>
<br>
<button type="button" onclick="surveySubmit()">Odoslať</button>
</form>

@ -1,12 +0,0 @@
<page minimal_permission_level="2" page_title="Testing" secret="no"></page>
<div class="sliderm" id="exampe-slider">
<div class="sliderm__slider">
<div class="sliderm__slides">
<div class="sliderm__slide">1</div>
<div class="sliderm__slide">2</div>
<div class="sliderm__slide">3</div>
<div class="sliderm__slide">4</div>
<div class="sliderm__slide">5</div>
</div>
</div>
</div>

@ -1,19 +1,20 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="1" page_title="Homepage" secret="no"></page>
<page minimal_permission_level="1" secret="no" page_title="Domov"></page>
<header>
<h1 class="title">Who are we?</h1>
<p>We are a team of talented and ambitious high school students from Adlerka electrical engineering school,
representing Slovakia in the European Space Agencys CanSat project. With an admiration for space technology, we
challenge our skills in electronics, programming, and mechanical design to build our own CanSat.
Our shared values of education, curiosity, and perseverance drive us to push the boundaries of innovation. With
the opportunity provided by ESA, we are committed to our mission and hope to inspire others to dream big while
learning the wonders of space exploration.</p>
<h1 class="title">Vitaj, na tejto úžasnej stránke</h1>
<p>Neoficiálna študentská stránka pre Adlerku</p>
</header>
<hr>
<div class="citation">
<p class="citationText">
“The only limit to our realization of tomorrow will be our doubts of today.”
</p>
<p class="citationAuthor"> Franklin D. Roosevelt</p>
<div class="sliderm" id="exampe-slider">
<div class="sliderm__slider">
<div class="sliderm__slides">
<div class="sliderm__slide">1</div>
<div class="sliderm__slide">2</div>
<div class="sliderm__slide">3</div>
<div class="sliderm__slide">4</div>
<div class="sliderm__slide">5</div>
</div>
</div>
</div>

18
pages/memes/index.php Normal file

@ -0,0 +1,18 @@
<?php
require_once "lib/router.php";
require_once "lib/meme.php";
global $routerConfig;
$output = renderMemeGallery();
return [
"output" => $output,
"parameters" =>
[
"minimal_permission_level" => 1,
"secret" => "no",
"page_title" => "Galéria"
]
];

@ -23,12 +23,12 @@ foreach ($articles as $article){
//$articleWrittenBy = $article["WrittenBy"];
$articleWrittenAt = htmlspecialchars($article["WrittenAt"]);
$articleWrittenByName = htmlspecialchars($article["WrittenByName"]);
$articleTemplateTemp = str_replace("__TEMPLATE_ARTICLE_TITLE__", $articleTitle, $articleTemplate);
$articleTemplateTemp = str_replace("__TEMPLATE_ARTICLE_AUTHOR__", $articleWrittenByName, $articleTemplateTemp);
$articleTemplateTemp = str_replace("__TEMPLATE_ARTICLE_DATE__", $articleWrittenAt, $articleTemplateTemp);
$articleTemplateTemp = str_replace("__TEMPLATE_ARTICLE_BODY__", $articleBody, $articleTemplateTemp);
$articleTemplate = str_replace("__TEMPLATE_ARTICLE_TITLE__", $articleTitle, $articleTemplate);
$articleTemplate = str_replace("__TEMPLATE_ARTICLE_AUTHOR__", $articleWrittenByName, $articleTemplate);
$articleTemplate = str_replace("__TEMPLATE_ARTICLE_DATE__", $articleWrittenAt, $articleTemplate);
$articleTemplate = str_replace("__TEMPLATE_ARTICLE_BODY__", $articleBody, $articleTemplate);
$articles_out .= $articleTemplateTemp;
$articles_out .= $articleTemplate;
}
$output = str_replace("__TEMPLATE__ARTICLES_HERE__", $articles_out, $output);
@ -39,6 +39,6 @@ return [
[
"minimal_permission_level" => 1,
"secret" => "no",
"page_title" => "Articles"
"page_title" => "Novinky"
]
];

8
pages/notes/index.html Normal file

@ -0,0 +1,8 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="2" secret="no" page_title="Zošit"></page>
<header>
<h1 class="title">Adlerka Zošit</h1>
</header>
<hr>
<h2>Čoskoro bude v prevádzke</h2>
<h3>Nájdete(a pridáte) tu poznámky a úlohy zo školy</h3>

5
pages/rozvrh/index.html Normal file

@ -0,0 +1,5 @@
<page minimal_permission_level="2" secret="no" page_title="INFO"></page>
<header>
<h1>Toto sú rozvrhy niektorých Adlerákov</h1>
<h2>Zatiaľ hardcoded, potom dorobíme funkcionalitu zbierania dát z Edupage</h2>
</header>

@ -0,0 +1,62 @@
<page minimal_permission_level="2" secret="no" page_title="1.C 2.skupina"></page>
<header>
<h1>Rozvrh 1.C 2.Skupina</h1>
</header>
<main>
<table class="rozvrh">
<tbody>
<tr>
<th>0 (7:10 - 7:55)</th>
<th>1 (8:00 - 8:45)</th>
<th>2 (8:50 - 9:35)</th>
<th>3 (9:45 - 10:30)</th>
<th>4 (10:50 - 11:35)</th>
<th>5 (11:45 - 12:30)</th>
<th>6 (12:40 - 13:25)</th>
<th>7 (13:30 - 14:15)</th>
</tr>
<tr>
<td></td>
<td>MAT</td>
<td>ELK</td>
<td>SJL</td>
<td colspan="2">ZER</td>
<td>ANJ</td>
<td>MAT</td>
</tr>
<tr>
<td colspan="3">PRX</td>
<td>SJL</td>
<td colspan="2">INF</td>
<td>ELK</td>
</tr>
<tr>
<td></td>
<td>PRO</td>
<td>SJL</td>
<td>FYZ</td>
<td>ANJ</td>
<td>MAT</td>
<td>ELK</td>
<td>TSV</td>
</tr>
<tr>
<td colspan="2"></td>
<td colspan="2">PRO</td>
<td>ANJ</td>
<td>TDK</td>
<td>MAT</td>
<td>ETV</td>
</tr>
<tr>
<td></td>
<td>TDK</td>
<td>OBN</td>
<td>TSV</td>
<td>FYZ</td>
<td>PRO</td>
<td>DEJ</td>
</tr>
</tbody>
</table>
</main>

@ -0,0 +1,62 @@
<page minimal_permission_level="2" secret="no" page_title="1.C 1.skupina"></page>
<header>
<h1>Rozvrh 1.C 1.Skupina</h1>
</header>
<main>
<table class="rozvrh">
<tbody>
<tr>
<th>0 (7:10 - 7:55)</th>
<th>1 (8:00 - 8:45)</th>
<th>2 (8:50 - 9:35)</th>
<th>3 (9:45 - 10:30)</th>
<th>4 (10:50 - 11:35)</th>
<th>5 (11:45 - 12:30)</th>
<th>6 (12:40 - 13:25)</th>
<th>7 (13:30 - 14:15)</th>
</tr>
<tr>
<td></td>
<td>MAT</td>
<td>ELK</td>
<td>SJL</td>
<td colspan="2">ZER</td>
<td>MAT</td>
<td>ANJ</td>
</tr>
<tr>
<td colspan="3">PRX</td>
<td>SJL</td>
<td colspan="2">INF</td>
<td>ELK</td>
</tr>
<tr>
<td></td>
<td>PRO</td>
<td>SJL</td>
<td>TSV</td>
<td>FYZ</td>
<td>ANJ</td>
<td>MAT</td>
<td>ELK</td>
</tr>
<tr>
<td colspan="2"></td>
<td colspan="2">PRO</td>
<td>TDK</td>
<td>TSV</td>
<td>MAT</td>
<td>ETV</td>
</tr>
<tr>
<td></td>
<td>ANJ</td>
<td>OBN</td>
<td>TDK</td>
<td>FYZ</td>
<td>PRO</td>
<td>DEJ</td>
</tr>
</tbody>
</table>
</main>

@ -0,0 +1,64 @@
<page minimal_permission_level="2" secret="no" page_title="1.D 1.skupina"></page>
<header>
<h1>Rozvrh 1.D 1.Skupina</h1>
</header>
<main>
<table class="rozvrh">
<tbody>
<tr>
<th>0 (7:10 - 7:55)</th>
<th>1 (8:00 - 8:45)</th>
<th>2 (8:50 - 9:35)</th>
<th>3 (9:45 - 10:30)</th>
<th>4 (10:50 - 11:35)</th>
<th>5 (11:45 - 12:30)</th>
<th>6 (12:40 - 13:25)</th>
<th>7 (13:30 - 14:15)</th>
</tr>
<tr>
<td></td>
<td>TSV</td>
<td colspan="2">PRO</td>
<td>MAT</td>
<td>TDK</td>
<td>PRO</td>
<td>SJL</td>
</tr>
<tr>
<td></td>
<td>FYZ</td>
<td>TDK</td>
<td>MAT</td>
<td>ELK</td>
<td>OBN</td>
<td>ANJ</td>
<td>ETV</td>
</tr>
<tr>
<td></td>
<td>ELK</td>
<td>MAT</td>
<td>SJL</td>
<td>ANJ</td>
<td>ELK</td>
<td colspan="2">INF</td>
</tr>
<tr>
<td colspan="2"></td>
<td colspan="2">ZER</td>
<td>MAT</td>
<td>FYZ</td>
<td>DEJ</td>
<td>TSV</td>
</tr>
<tr>
<td></td>
<td>SJL</td>
<td>ANJ</td>
<td>PRO</td>
<td colspan="3">PRX</td>
</tr>
</tbody>
</table>
</main>

33
pages/smp/index.html Normal file

@ -0,0 +1,33 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="1" secret="no" page_title="Domov"></page>
<header>
<h1 class="title">Vitaj, na oficiálnej AdlerkaSMP stránke</h1>
<p>Najlepší <a href="https://minecraft.net" style="text-decoration: underline; color: #fff;" target="_blank">Minecraft®™</a>
server na Adlerke</p>
</header>
<hr>
<main>
<div class="wrapper feature-list">
<h2>Čo môžeš očakávať od AdlerkaSMP:</h2>
<ul class="feature-list-ul">
<li>Módovaný gameplay bez nutnosti sťahovať módy (niektoré módy však vylepšia zážitok)</li>
<li>Jednoduché pripojenie, hostname je <strong>adlerka.top</strong></li>
<li>
<strong>Super admini:</strong>
<ul>
<li>Starajú sa o server</li>
<li>Udržiavajú ho bezpečným miestom</li>
<li>
<strong>Zoznam adminov:</strong>
<ul>
<li>BRNSystems</li>
<li>YeahAkis_</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</main>

61
pages/smp/mods.html Normal file

@ -0,0 +1,61 @@
<!--suppress HtmlUnknownTag, HtmlUnknownTag -->
<page minimal_permission_level="1" secret="no" page_title="Modlist"></page>
<main>
<h2>Launcher:</h2>
<a href="https://prismlauncher.org/download/">Prism Launcher <b>(ODPORÚČANÝ)</b></a><br>
<h2>Módy pre klienta:</h2>
<a href="/assets/adlerka_client.mrpack">Komplet ako MrPack <b>(ODPORÚČANÉ)</b></a><br>
<h3>Vizuálne:</h3>
<ol>
<li><a href="https://cdn.modrinth.com/data/zV5r3pPn/versions/kJmEO0xO/skinlayers3d-fabric-1.6.2-mc1.20.4.jar">3D Skin Layers</a></li>
<li><a href="https://cdn.modrinth.com/data/wdLuzzEP/versions/rNWb9ncY/Gamma-Utils-1.7.19-mc1.20.4.jar">Gamma Utils</a></li>
<li><a href="https://cdn.modrinth.com/data/w7ThoJFB/versions/BalILUb7/Zoomify-2.13.2.jar">Zoomify</a></li>
<li><a href="https://cdn.modrinth.com/data/M08ruV16/versions/jGGumR4a/bobby-5.1.0%2Bmc1.20.4.jar">Bobby</a></li>
<li><a href="https://cdn.modrinth.com/data/1IjD5062/versions/JXhQlDZl/continuity-3.0.0-beta.4%2B1.20.2.jar">Continuity</a></li>
<li><a href="https://cdn.modrinth.com/data/ZcR9weSm/versions/UrOG4IKT/dynamiccrosshair-7.7%2B1.20.4-fabric.jar">Dynamic Crosshair</a></li>
<li><a href="https://cdn.modrinth.com/data/rUgZvGzi/versions/AqXSvu6M/eating-animation-1.20%2B1.9.61.jar">Eating Animation</a></li>
<li><a href="https://cdn.modrinth.com/data/WhbRG4iK/versions/PNG0Dp43/fallingleaves-1.15.5%2B1.20.1.jar">Falling Leaves</a></li>
<li><a href="https://cdn.modrinth.com/data/YL57xq9U/versions/kGdJ11Rt/iris-mc1.20.4-1.6.17.jar">Iris</a></li>
<li><a href="https://cdn.modrinth.com/data/yBW8D80W/versions/mrQ8ZiyU/lambdynamiclights-2.3.4%2B1.20.4.jar">Lambdynamiclights</a></li>
<li><a href="https://cdn.modrinth.com/data/MPCX6s5C/versions/ZLjUeuU8/notenoughanimations-fabric-1.7.1-mc1.20.4.jar">Not Enough Animations</a></li>
</ol>
<h3>Performance:</h3>
<ol>
<li><a href="https://cdn.modrinth.com/data/NNAgCjsB/versions/7JR5qJ8f/entityculling-fabric-1.6.4-mc1.20.4.jar">Entity Culling</a></li>
<li><a href="https://cdn.modrinth.com/data/uXXizFIs/versions/pguEMpy9/ferritecore-6.0.3-fabric.jar">FerriteCore</a></li>
<li><a href="https://cdn.modrinth.com/data/Orvt0mRa/versions/Aouse6P7/indium-1.0.30%2Bmc1.20.4.jar">Indium</a></li>
<li><a href="https://cdn.modrinth.com/data/fQEb0iXm/versions/bRcuOnao/krypton-0.2.6.jar">Krypton</a></li>
<li><a href="https://cdn.modrinth.com/data/gvQqBUqZ/versions/nMhjKWVE/lithium-fabric-mc1.20.4-0.12.1.jar">Lithium</a></li>
<li><a href="https://cdn.modrinth.com/data/Bh37bMuy/versions/fkLiGoHs/reeses_sodium_options-1.7.2%2Bmc1.20.4-build.102.jar">Reese's Sodium Options</a></li>
<li><a href="https://cdn.modrinth.com/data/AANobbMI/versions/4GyXKCLd/sodium-fabric-0.5.8%2Bmc1.20.4.jar">Sodium</a></li>
<li><a href="https://cdn.modrinth.com/data/PtjYWJkn/versions/M0ndiav7/sodium-extra-0.5.4%2Bmc1.20.4-build.116.jar">Sodium-extra</a></li>
</ol>
<h3>Utility:</h3>
<ol>
<li><a href="https://cdn.modrinth.com/data/DFqQfIBR/versions/rGQZ2yBQ/CraftPresence-2.3.5%2B1.20.4.jar">CraftPresence</a></li>
<li><a href="https://cdn.modrinth.com/data/8shC1gFX/versions/AkivIlyi/BetterF3-9.0.2-Fabric-1.20.4.jar">BetterF3</a></li>
<li><a href="https://cdn.modrinth.com/data/nvQzSEkH/versions/fNHCa6bl/Jade-1.20.4-fabric-13.3.1.jar">Jade</a></li>
<li><a href="https://cdn.modrinth.com/data/aC3cM3Vq/versions/m0Dd8Cjy/MouseTweaks-fabric-mc1.20-2.25.jar">Mouse Tweaks</a></li>
<li><a href="https://cdn.modrinth.com/data/qQyHxfxd/versions/tfv6A4l5/NoChatReports-FABRIC-1.20.4-v2.5.0.jar">No Chat Reports</a></li>
<li><a href="https://cdn.modrinth.com/data/nfn13YXA/versions/Jhw0fDTs/RoughlyEnoughItems-14.0.688-fabric.jar">Roughly Enough Items</a></li>
<li><a href="https://cdn.modrinth.com/data/V8XJ8f5f/versions/q9eTEsvC/RoughlyEnoughProfessions-fabric-1.20.4-2.2.0.jar">Roughly Enough Professions</a></li>
<li><a href="https://cdn.modrinth.com/data/NcUtCpym/versions/2lbtkEPK/XaerosWorldMap_1.38.1_Fabric_1.20.4.jar">Xaero's WorldMap</a></li>
<li><a href="https://cdn.modrinth.com/data/1bokaNcj/versions/N5jBKzC0/Xaeros_Minimap_24.0.3_Fabric_1.20.4.jar">Xaero's_Minimap</a></li>
<li><a href="https://cdn.modrinth.com/data/EsAfCjCV/versions/pmFyu3Sz/appleskin-fabric-mc1.20.3-2.5.1.jar">Appleskin</a></li>
<li><a href="https://cdn.modrinth.com/data/mOgUt4GM/versions/sjtVVlsA/modmenu-9.0.0.jar">Modmenu</a></li>
<li><a href="https://cdn.modrinth.com/data/Nv2fQJo5/versions/TGJXKoTQ/replaymod-1.20.4-2.6.15.jar">Replaymod</a></li>
<li><a href="https://cdn.modrinth.com/data/njGhQ4fN/versions/4tIwORrJ/roughly-searchable-2.6.1%2B1.20.4.jar">Roughly Searchable</a></li>
<li><a href="https://cdn.modrinth.com/data/9eGKb6K1/versions/r7e564VW/voicechat-fabric-1.20.4-2.5.11.jar">Simple Voice Chat</a></li>
</ol>
<h3>Dependecies:</h3>
<ol>
<li><a href="https://cdn.modrinth.com/data/lhGA9TYQ/versions/kVjQWX0l/architectury-11.1.17-fabric.jar">Architectury</a></li>
<li><a href="https://cdn.modrinth.com/data/gu7yAYhd/versions/augSR8tA/cc-tweaked-1.20.4-fabric-1.110.0.jar">CC Tweaked</a></li>
<li><a href="https://cdn.modrinth.com/data/9s6osm5g/versions/eBZiZ9NS/cloth-config-13.0.121-fabric.jar">Cloth Config</a></li>
<li><a href="https://cdn.modrinth.com/data/P7dR8mSH/versions/htRy7kbI/fabric-api-0.96.11%2B1.20.4.jar">Fabric Api</a></li>
<li><a href="https://cdn.modrinth.com/data/Ha28R6CL/versions/ZMokinzs/fabric-language-kotlin-1.10.19%2Bkotlin.1.9.23.jar">Fabric Language Kotlin</a></li>
<li><a href="https://cdn.modrinth.com/data/hvFnDODi/versions/0.1.3/lazydfu-0.1.3.jar">Lazydfu</a></li>
<li><a href="https://cdn.modrinth.com/data/xGdtZczs/versions/Kk7rWLSf/polymer-bundled-0.7.7%2B1.20.4.jar">Polymer</a></li>
<li><a href="https://cdn.modrinth.com/data/1eAoo2KR/versions/StXMrAsz/yet-another-config-lib-fabric-3.3.2%2B1.20.4.jar">Yet Another Config Lib</a></li>
</ol>
</main>

@ -1,7 +1,7 @@
<div class="wrapper-403 wrapper-40x">
<h2>FORBIDDEN</h2>
<h2>TY KÁR KAM TO DEŠ</h2>
<h1 class="error-code">403</h1>
<h3><i class="ri-error-warning-line"></i> You are not authorized to view this page: <span class="error">__TEMPLATE_PAGE_TITLE__</span>. <i class="ri-error-warning-line"></i></h3>
<h3><i class="ri-error-warning-line"></i> Našli sme stránku ktorú hľadáš, ale nemáš práva na ňu pristupovať: <span class="error">__TEMPLATE_PAGE_TITLE__</span>. <i class="ri-error-warning-line"></i></h3>
<!--suppress HtmlUnknownTarget -->
<a class="back" href="__DEFAULT_LINK__" role="button"><i class="ri-arrow-left-line"></i> BACK HOME</a>
<a href="__DEFAULT_LINK__" role="button" class="back"><i class="ri-arrow-left-line"></i> SPÄŤ DOMOV</a>
</div>

@ -1,7 +1,7 @@
<div class="wrapper-404 wrapper-40x">
<h2>NOT FOUND</h2>
<h2>TY KÁR KAM TO DEŠ</h2>
<h1 class="error-code">404</h1>
<h3><i class="ri-error-warning-line"></i> This page was not found: <span class="error">__TEMPLATE_PAGE_TITLE__</span>. <i class="ri-error-warning-line"></i></h3>
<h3><i class="ri-error-warning-line"></i> Nenašli sme stránku ktorú hľadáš: <span class="error">__TEMPLATE_PAGE_TITLE__</span>. <i class="ri-error-warning-line"></i></h3>
<!--suppress HtmlUnknownTarget -->
<a class="back" href="__DEFAULT_LINK__" role="button"><i class="ri-arrow-left-line"></i> BACK HOME</a>
<a href="__DEFAULT_LINK__" role="button" class="back"><i class="ri-arrow-left-line"></i> SPÄŤ DOMOV</a>
</div>

@ -1,7 +1,7 @@
<div class="wrapper-500">
<h2>Someone messed up</h2>
<h2>Niekto to pobabral</h2>
<h1 class="error-code">500</h1>
<h3><i class="ri-error-warning-line"></i> Some incompetent developer messed up. <i class="ri-error-warning-line"></i></h3>
<h3><i class="ri-error-warning-line"></i> Nejaký neschopný vývojár nevedel robiť túto stránku. <i class="ri-error-warning-line"></i></h3>
<!--suppress HtmlUnknownTarget -->
<a class="back" href="__DEFAULT_LINK__" role="button"><i class="ri-arrow-left-line"></i> BACK HOME</a>
<a href="__DEFAULT_LINK__" role="button" class="back"><i class="ri-arrow-left-line"></i> SPÄŤ DOMOV</a>
</div>

@ -1,17 +1 @@
<p>Sponsors</p>
<div class="sponsors">
<div class="sponsor">
<img alt="Needronix" class="sponsorLogo" height="200" src="/assets/images/sponsors/needronix.png" width="200" />
<p class="sponsorName">Needronix</p>
</div>
<!-- <div class="sponsor">-->
<!-- <img alt="Sensoneo" class="sponsorLogo" height="200" src="/assets/images/sponsors/sensoneo.png" width="200">-->
<!-- <p class="sponsorName">Sensoneo</p>-->
<!-- </div>-->
<!-- <div class="sponsor">-->
<!-- <img alt="ZF" class="sponsorLogo" height="200" src="/assets/images/sponsors/zf.png" width="200">-->
<!-- <p class="sponsorName">ZF</p>-->
<!-- </div>-->
</div>
<a href="https://www.adlerka.sk">Adlerka school</a>
<a href="https://cansat.esa.int">CanSat</a>
<p>Toto nie je oficiálna stránka <span id="ye-span">Adlerky</span>, jedná sa o neoficiálnu študentskú stránku</p>

27
templates/meme.html Normal file

@ -0,0 +1,27 @@
<article class="meme" id="meme___TEMPLATE_MEME_ID__">
<div class="meme_header" id="meme_header___TEMPLATE_MEME_ID__">
<h2 class='meme_title' id="meme_title___TEMPLATE_MEME_ID__">__TEMPLATE_MEME_TITLE__</h2>
<div class="meme_topbar" id="meme_info___TEMPLATE_MEME_ID__">
<div class="meme_voting" id="meme_voting___TEMPLATE_MEME_ID__">
__TEMPLATE_MEME_UPVOTE__
<p class="votes_counter __TEMPLATE_MEME_VOTE_COUNTER_CLASS__"
id="meme_votes_counter___TEMPLATE_MEME_ID__">__TEMPLATE_MEME_VOTES_NUMBER__</p>
__TEMPLATE_MEME_DOWNVOTE__
</div>
<div class="meme_info">
<p class='meme_author' id="meme_author___TEMPLATE_MEME_ID__"><i class="ri-user-line"></i>__TEMPLATE_MEME_AUTHOR__
</p>
<p class='meme_date' id="meme_date___TEMPLATE_MEME_ID__"><i class="ri-calendar-line"></i>__TEMPLATE_MEME_DATE__
</p>
__TEMPLATE_MEME_DELETE_BUTTON__
</div>
</div>
</div>
<div class="meme_body" id="meme_body___TEMPLATE_MEME_ID__">
<a class="meme_link" href="__TEMPLATE_MEME_IMAGE__" download>
<img id="meme_image___TEMPLATE_MEME_ID__" src="__TEMPLATE_MEME_IMAGE__" width="__TEMPLATE_MEME_IMAGE_WIDTH__"
height="__TEMPLATE_MEME_IMAGE_HEIGHT__" alt="meme image"
class="meme_image"></a>
<p class="meme_text" id="meme_text___TEMPLATE_MEME_ID__">__TEMPLATE_MEME_TEXT__</p>
</div>
</article>

15
templates/meme_add.html Normal file

@ -0,0 +1,15 @@
<div id="memecreatecontainer" class="hidden">
<div id="memecreate">
<label for="meme_title_input">Názov meme-u: </label>
<input type="text" id="meme_title_input" placeholder="Názov meme-u"/>
<label for="meme_text_input">Text meme-u: </label>
<input type="text" id="meme_text_input" placeholder="Text meme-u"/>
<label for="meme_image_input">Obrázok meme-u</label>
<select id="meme_image_input"></select>
<button id="memecreatebutton" onclick="addMeme()"><i class="ri-add-circle-line"></i></button>
<button id="memecreateclose" onclick="togglememecreate()"><i class="ri-close-line"></i></button>
</div>
</div>

@ -0,0 +1,12 @@
<header>
<h1 class="title">Adlerka Memes</h1>
<p>Skoro, ako <a href="https://reddit.com/r/adlerka" target="_blank">r/adlerka</a>, ale lepšie.</p>
<button id="memecreateopen" onclick="togglememecreate()"><i class="ri-add-circle-line"></i></button>
<hr>
</header>
<main>
<div id="meme_gallery">
__TEMPLATE_MEMES_HERE__
</div>
__TEMPLATE_MEME_ADD__
</main>

@ -1,12 +1,12 @@
<div class="logoText">
<div class="logo">
<div class="logo">
<a href="/home/index">
<img alt="Adlerka logo" height="150" src="/assets/images/favicon.png" style="width:auto;" width="150">
<picture id="standard-logo">
<source media="(min-width:4200px)" srcset="/assets/images/adlerka_256.png">
<source media="(min-width:2100px)" srcset="/assets/images/adlerka_128.png">
<img src="/assets/images/adlerka_64.png" alt="Adlerka logo" style="width:auto;">
</picture>
</a>
</div>
<p class="logoP">Adlerka Space Program</p>
</div>
<i class="ri-menu-line" id="toggle_button"></i>
<ul id="navsite_list">
__NAV_PAGES__

@ -1,5 +1,6 @@
<header>
<h1 class="title">NEWS</h1>
<h1 class="title"></h1>
<p>Adlerka študentské news</p>
<button id="articlecreateopen" onclick="togglearticlecreate()"><i class="ri-add-circle-line"></i></button>
</header>
@ -15,7 +16,7 @@
<div id="articlecreate">
<input type="text" placeholder="Article Title" id="articletitleinput"><br>
<textarea id="articlebodyinput" placeholder="Article Body" rows="10" cols="80"></textarea><br>
<label for="articleprivilegeinput">Permission required:</label>
<label for="articleprivilegeinput">Oprávnenie na pozretie článku:</label>
<input type="number" id="articleprivilegeinput" min="1" value="1" step="1">
<button id="articlesubmit" onclick="submitarticle()"><i class="ri-add-circle-line"></i></button>
<button id="articlecreateclose" onclick="togglearticlecreate()"><i class="ri-close-line"></i></button>

@ -10,7 +10,7 @@
<link rel="icon" href="/assets/images/favicon.png" type="image/png">
__TEMPLATE__DYNAMIC__SCRIPT__
__TEMPLATE__DYNAMIC__STYLE__
<script async data-website-id="962431d7-e53a-48a8-b58d-7771df9de861" src="https://umami.brn.systems/script.js"></script>
<script async src="https://umami.brn.systems/script.js" data-website-id="95e93885-5c19-4cab-ba9b-2f746a316a2a"></script>
<script async src="/assets/script.js"></script>
<script async src="/assets/3rdparty/sliderm.js"></script>
<title>__TEMPLATE_PAGE_TITLE__</title>

@ -18,6 +18,9 @@
<label for="updateNickname">Nickname:</label>
<input type="text" id="updateNickname" name="updateNickname" required><br>
<label for="updateMinecraftNick">Minecraft Nick:</label>
<input type="text" id="updateMinecraftNick" name="updateMinecraftNick" required><br>
<button type="button" onclick="updateUserProfile()">Update Profile</button>
</div>
<br><br>