#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 }