Files
2025-09-28 22:45:26 +02:00

91 lines
2.3 KiB
Typst

#let request = json(bytes(sys.inputs.at("request")))
#import "@preview/charged-ieee:0.1.4": ieee
#let parse-rfc3339-datetime(rfc3339-string) = {
// Split into date and time+offset
let (date-part, time-and-offset-part) = rfc3339-string.split("T")
// Parse date
let (year, month, day) = date-part.split("-").map(int)
// Handle UTC "Z" or offset (+/-hh:mm)
let time-part = time-and-offset-part
let offset = none
if time-part.ends-with("Z") {
time-part = time-part.slice(0, time-part.len() - 1)
offset = (0, 0) // UTC
} else if time-part.contains("+") {
let parts = time-part.split("+")
time-part = parts.first()
offset = parts.last().split(":").map(int)
offset = (offset.at(0), offset.at(1)) // (+hh, +mm)
} else if time-part.contains("-") {
let idx = time-part.rfind("-")
time-part = time-part.slice(0, idx)
let offstr = time-part.slice(idx+1)
offset = offstr.split(":").map(int)
offset = (-offset.at(0), -offset.at(1)) // (-hh, -mm)
}
// Split time, possibly with fractional seconds
let time-parts = time-part.split(":")
let hour = int(time-parts.at(0))
let minute = int(time-parts.at(1))
let second = 0
if time-parts.len() > 2 {
if time-parts.at(2).contains(".") {
let sec-parts = time-parts.at(2).split(".")
second = int(sec-parts.first())
// Fractions are ignored, but you could round if needed
} else {
second = int(time-parts.at(2))
}
}
return datetime(
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: second,
)
}
#let currentDateTime = parse-rfc3339-datetime(request.timestamp)
#let ua = request.headers.at("user-agent", default: "")
#let browser = if ua.contains("Firefox") {
"Firefox"
} else if ua.contains("Edg/") {
"Edge"
} else if ua.contains("Chrome/") {
"Chrome"
} else if ua.contains("Safari/6") or ua.contains("Safari/7") {
"Safari"
} else {
"Unknown"
}
#let platform = if ua.contains("Win64") {
"Windows"
} else if ua.contains("Android") {
"Android"
} else if ua.contains("iPhone OS") {
"iPhone"
} else {
"Unknown"
}
#let styling(it) = {
show link: this => {
underline(text(this, fill: rgb("#5555ff")))
}
it
}