!7 cmodule GazelleWebServer > DynPrintLogAndEnabled { transient MyHTTPD server; void start() ctex { super.start(); if (!enabled) ret; server = new MyHTTPD(80); server.serveFunction = func(S uri, SS parms) { serve(uri, parms) }; server.start(); print("HTTP server started on port " + server.getPort()); } void cleanMeUp { server.stop(); server = null; } O serve(S uri, SS parms) { new Matches m; if (swic(uri, "/rule/", m)) { S ruleID = assertGlobalID(m.rest()); PairS textAndComment = unnull(dm_textAndCommentForRule(ruleID)); L feedback = dm_gazelle_feedbackForRule(ruleID); S title = "Rule " + ruleID; ret hhtml_head_title_body(title + " | Gazelle", h2(htmlEncode2("Gazelle | " + title)) + h3("Rule") + hpre(textAndComment.a) + (nempty(textAndComment.b) ? h3("Comments") + hpre(textAndComment.b) : "") + h3("Feedback") + htmlTable2(map(feedback, func(O o) -> Map { litorderedmap( "Judgement" := getString judgement(o), "Mapping" := getString varMap(o), "Context" := getString context(o), "Comment" := getString comment(o), "Struct" := getString matchedRuleStruct(o)) }))); } if (!eq(uri, "/")) ret serve404(); final Map feedbackStats = dm_gazelle_feedbackStats(); ret hhtml_head_title_body("Gazelle!", hcenter( p("Hello! " + targetBlank("https://discordapp.com/invite/SEAjPqk", "Join my Discord server!") + " Here are my rules:") + htmlTable2(map(dm_allRulesFromRulesModuleWithCommentsAndIDs(), func(T3 t) -> SS { S ruleID = t.c; ret litorderedmap( "Rule ID" := htmlEncode2(ruleID), "Rule Text" := htmlEncode_nlToBr(t.a), "Comments" := htmlEncode_nlToBr(withoutLine("discord", t.b)), "Feedback" := ahref(rawSelfLink("rule/" + ruleID), toInt(feedbackStats.get(ruleID)))); }), htmlEncode := false, paramsByColName := litmap("Feedback" := litobjectarray(align := 'center))))); } } sS rawSelfLink(S uri) { ret addSlashPrefix(uri); }