diff --git a/go.mod b/go.mod index aa74511..d06b101 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect + github.com/yuin/goldmark v1.7.12 // indirect golang.org/x/sys v0.28.0 // indirect lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b // indirect ) diff --git a/go.sum b/go.sum index 9049862..e3aad05 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1S github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= +github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= diff --git a/main.go b/main.go index 8397356..d93d254 100644 --- a/main.go +++ b/main.go @@ -1,48 +1,38 @@ package main import ( + "bytes" "fmt" + "html/template" "log" "net/http" "os" + "strings" "github.com/gofiber/fiber/v2" "github.com/gofiber/template/html/v2" + "github.com/yuin/goldmark" "lmika.dev/web/isknow/models" ) func main() { - questions := models.QuestionSet{ - Questions: []models.Question{ - { - ID: "1", - Text: "What is 1 + 1?", - Choices: []models.Choice{ - {Text: "1"}, - {Text: "2", IsRight: true}, - {Text: "3"}, - {Text: "4"}, - }, - Fact: "1 + 1 = 2", - }, - { - ID: "2", - Text: "What is 3 * 5?", - Choices: []models.Choice{ - {Text: "5"}, - {Text: "10"}, - {Text: "15", IsRight: true}, - {Text: "20"}, - }, - Fact: "I can't use the iPad for coding this", - }, - }, - } + questions := models.Game prefix, _ := os.LookupEnv("PATH_PREFIX") engine := html.New("./views", ".html") engine.AddFunc("prefix", func() string { return prefix }) + engine.AddFunc("markdown", func(s string) template.HTML { + if s == "" { + return "" + } + + var buf bytes.Buffer + if err := goldmark.Convert([]byte(strings.TrimSpace(s)), &buf); err != nil { + return "" + } + return template.HTML(buf.String()) + }) app := fiber.New(fiber.Config{ Views: engine, diff --git a/models/game.go b/models/game.go new file mode 100644 index 0000000..d4ada7c --- /dev/null +++ b/models/game.go @@ -0,0 +1,146 @@ +package models + +var Game = QuestionSet{ + Questions: []Question{ + { + ID: "1", + Text: "The ISO headquarters are located in which Swiss city?", + Choices: []Choice{ + {Text: "Geneva", IsRight: true}, + {Text: "Lucerne"}, + {Text: "Zürich"}, + {Text: "Basel"}, + }, + Fact: ` +Founded in 1947, and much like many other multilateral organisations, the +International Organization for Standardization is headquartered in Geneva, Switzerland. +[Wikipedia](https://en.wikipedia.org/wiki/International_Organization_for_Standardization) + `, + }, + { + ID: "2", + Text: "What does ISO 8859 attempt to standardise?", + Choices: []Choice{ + {Text: "Encoding of 8-bit characters", IsRight: true}, + {Text: "Format for date and times"}, + {Text: "Reference temperature of geometrical product specification"}, + {Text: "Information retrieval standards of weather metadata"}, + }, + Fact: ` +ISO 8859 is a series of standards for 8-bit character encodings. Probably the most well know of +these is ISO 8859-1, which will appear in the declaration of XML documents. [Wikipedia](https://en.wikipedia.org/wiki/ISO/IEC_8859). +The remaining choices are also ISO standards, including the reference temperature of geometrical product specification, +which is [ISO 1](https://en.wikipedia.org/wiki/ISO_1). + `, + }, + { + ID: "3", + Text: "Which one of these values satisfy ISO 3166-2?", + Choices: []Choice{ + {Text: "GB", IsRight: true}, + {Text: "USD"}, + {Text: "en-AU"}, + {Text: "2025-06-12T112:00:00Z"}, + }, + Fact: ` +ISO 3166-2 defines codes for identify the principal subdivisions of all countries defined in ISO 3166-1. It is used in part to encode +the top-level country codes for domains. [Wikipedia](https://en.wikipedia.org/wiki/ISO_3166-2) + `, + }, + { + ID: "4", + Text: "If I were to correctly format the date and time Monday, 16th June 2025 12:00:00 GMT using ISO 8601, the result will look like which of the following?", + Choices: []Choice{ + {Text: "2025-06-16T12:00:00Z", IsRight: true}, + {Text: "2025-06-16 12:00:00Z"}, + {Text: "16 Jun, 2025 12:00:00 GMT"}, + {Text: "06/16/2025 12:00:00 UTC"}, + }, + Fact: ` +Arguably, [the correct way](https://xkcd.com/1179/) to write numeric dates. + `, + }, + { + ID: "5", + Text: "The Date header in a HTTP 1.1 requests is defined by which standard?", + Choices: []Choice{ + {Text: "RFC 2616", IsRight: true}, + {Text: "RFC 822"}, + {Text: "RFC 1036"}, + {Text: "ISO 3166-2"}, + }, + Fact: ` +The standard [allows for 3 types of dates](https://www.rfc-editor.org/rfc/rfc2616#section-3.3): RFC 822 (updated in RFC 1123), +RFS 850 (updated in RFC 1036), and the ANSI C asctime() format. + `, + }, + { + ID: "6", + Text: "When someone says they have an \"ISO image\" of a CD or DVD, which ISO format are they referring to?", + Choices: []Choice{ + {Text: "ISO 9660", IsRight: true}, + {Text: "ISO 8859"}, + {Text: "ISO 3166"}, + {Text: "ISO 19110"}, + }, + Fact: ` +ISO 9660, also known as ECMA-119, is the standardised file system used for optical media. [Wikipedia](https://en.wikipedia.org/wiki/ISO_9660) + `, + }, + { + ID: "7", + Text: "Which format of a comercial word processing software package was submitted to be an ISO standard by its vendor?", + Choices: []Choice{ + {Text: "Microsoft's Office Office (.docx)", IsRight: true}, + {Text: "Microsoft's Word (.doc)"}, + {Text: "LibreOffice's Open Document (.odf)"}, + {Text: "Apple Pages (.pages)"}, + }, + Fact: ` +[Microsoft's Open Office XML](https://en.wikipedia.org/wiki/Office_Open_XML) file format received the standard number ISO 29500. + `, + }, + { + ID: "8", + Text: "What HTTP method was defined in RFC 2324?", + Choices: []Choice{ + {Text: "WHEN", IsRight: true}, + {Text: "POST"}, + {Text: "DELETE"}, + {Text: "OPTIONS"}, + }, + Fact: ` +[RFC 2324](https://www.rfc-editor.org/rfc/rfc2324) defines the Hyper Text Coffee Pot Control Protocol, the April Fools Day RFC +that also gave us the "418 I'm a teapot" error code. WHEN is used to instruct the HTTP server to stop pouring milk. + `, + }, + { + ID: "9", + Text: "Which layers of the OSI networking stack are missing from the TCP/IP networking stack?", + Choices: []Choice{ + {Text: "Presentation and Session", IsRight: true}, + {Text: "Presentation and Application"}, + {Text: "Session and Transport"}, + {Text: "Network and Data Link"}, + }, + Fact: ` +[Developed by the ISO](https://en.wikipedia.org/wiki/OSI_model) in the 1970s, the model lost out to the less prescriptive one +developed by the Internet Engineering Task Force. + `, + }, + { + ID: "10", + Text: "The only successful implementation of RFC 1149 involved the transmission of IP packages via which species of avian carrier?", + Choices: []Choice{ + {Text: "Pigeon", IsRight: true}, + {Text: "Eagle"}, + {Text: "Seagull"}, + {Text: "Magpie"}, + }, + Fact: ` +9 packets of data were transmitted, with a response time of up to 100 minutes and a packet loss of 55%. +[Wikipedia](https://en.wikipedia.org/wiki/IP_over_Avian_Carriers) + `, + }, + }, +} diff --git a/public/scripts/controllers/clearstate.js b/public/scripts/controllers/clearstate.js index 8fd2d27..4bd0692 100644 --- a/public/scripts/controllers/clearstate.js +++ b/public/scripts/controllers/clearstate.js @@ -3,7 +3,6 @@ import { gameState } from "./gamestate.js"; export default class extends Controller { startGame(ev) { - console.log("Start game"); gameState.clearChoices(); } } \ No newline at end of file diff --git a/public/scripts/controllers/gamestate.js b/public/scripts/controllers/gamestate.js index 10e18cb..1a5ed86 100644 --- a/public/scripts/controllers/gamestate.js +++ b/public/scripts/controllers/gamestate.js @@ -9,9 +9,9 @@ class GameState { return null; } - setQuestionChoice(qId, cId) { + setQuestionChoice(qId, cId, isRight) { let savedItem = this._readGameState(); - savedItem[qId] = cId; + savedItem[qId] = {cId: cId, isRight: isRight}; localStorage.setItem(GAME_STATE_KEY, JSON.stringify(savedItem)); } @@ -19,6 +19,20 @@ class GameState { localStorage.removeItem(GAME_STATE_KEY); } + getSummary() { + let savedItem = this._readGameState(); + let summary = { totalAnswered: 0, totalRight: 0 }; + + for (let k in savedItem) { + summary.totalAnswered++; + if (savedItem[k].isRight) { + summary.totalRight++; + } + } + + return summary; + } + _readGameState() { let savedItem = localStorage.getItem(GAME_STATE_KEY); if (savedItem === null) { diff --git a/public/scripts/controllers/picker.js b/public/scripts/controllers/picker.js index c3f70e5..c5d8a6a 100644 --- a/public/scripts/controllers/picker.js +++ b/public/scripts/controllers/picker.js @@ -14,7 +14,7 @@ export default class extends Controller { if (hasAnswer) { this._revealAnswer(); - let e = this.radioTargets.find((e) => e.value == hasAnswer); + let e = this.radioTargets.find((e) => e.value == hasAnswer.cId); if (e) { e.checked = true; } @@ -35,7 +35,7 @@ export default class extends Controller { return; } - gameState.setQuestionChoice(this.qidValue, e.value); + gameState.setQuestionChoice(this.qidValue, e.value, e.value === this.answerValue); this.element.classList.add("reveal"); window.setTimeout(() => { this._revealAnswer(); }); diff --git a/public/scripts/controllers/yourscore.js b/public/scripts/controllers/yourscore.js index dba36be..9f756b9 100644 --- a/public/scripts/controllers/yourscore.js +++ b/public/scripts/controllers/yourscore.js @@ -15,7 +15,7 @@ export default class extends Controller { } _startAnimating(t) { - this._finalScore = 10; + this._finalScore = gameState.getSummary().totalRight; this._startT = t; this._finalArcPostition = 360 * this._finalScore / MAX_QUESTIONS; diff --git a/views/question.html b/views/question.html index 4f6a928..3db784d 100644 --- a/views/question.html +++ b/views/question.html @@ -22,7 +22,7 @@