From ce532ec982cf8fcb3315b43a793a4aa06e869ba2 Mon Sep 17 00:00:00 2001 From: Yacov Dlougach Date: Sun, 23 Oct 2022 14:09:42 +0100 Subject: [PATCH] 1) Fix inconsitencies between automatic and human messages in the exported commentary feed. 2) Allow 4-byte Unicode characters in team names 3) Implement basic commentary messages for submission during the freeze --- config.yaml.template | 6 +++ create_icat_instance.sql | 12 ++--- .../main/java/katalyzeapp/ConfigReader.java | 1 + katalyze/src/main/java/model/Analyzer.java | 6 +-- .../main/java/model/ContestProperties.java | 2 +- .../src/main/java/model/LoggableEvent.java | 5 +-- katalyze/src/main/java/model/Problem.java | 5 +++ katalyze/src/main/java/model/Team.java | 7 +++ .../java/rules/SubmissionAfterFreeze.java | 44 +++++++++++++++++++ www/region.php | 6 ++- 10 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 katalyze/src/main/java/rules/SubmissionAfterFreeze.java diff --git a/config.yaml.template b/config.yaml.template index 58392c3..4215645 100644 --- a/config.yaml.template +++ b/config.yaml.template @@ -109,6 +109,12 @@ katalyzer: ranks: 10 # exec: "./capture.sh {teamId} {time} {currentRank} {potentialRank}" + # SubmissionAfterFreeze - simple notification for submissions during freeze time. + # Filters according to team's pre-freeze rank + submissionAfterFreeze: + enable: true + ranks: 25 + codeActivity: scoreboardFreezeMinutes: 240 defaultGranularityMinutes: 5 diff --git a/create_icat_instance.sql b/create_icat_instance.sql index f8ac3e0..acb40f1 100644 --- a/create_icat_instance.sql +++ b/create_icat_instance.sql @@ -251,7 +251,7 @@ CREATE TABLE IF NOT EXISTS `teams` ( `id` int(11) NOT NULL AUTO_INCREMENT, `reservation_id` int(11) DEFAULT NULL, `team_id` int(11) NOT NULL, - `team_name` varchar(150) NOT NULL, + `team_name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `institution_id` int(11) DEFAULT NULL, `site_id` int(11) DEFAULT NULL, `school_name` varchar(150) DEFAULT NULL, @@ -269,12 +269,12 @@ CREATE TABLE IF NOT EXISTS `teams` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; -DROP TABLE IF EXISTS 'teammembers'; +DROP TABLE IF EXISTS `teammembers`; CREATE TABLE teammembers( - id int(11) NOT NULL, - team_id int(11) NOT NULL, - full_name varchar(50) DEFAULT NULL, - role varchar(30) DEFAULT NULL, + `id` int(11) NOT NULL, + `team_id` int(11) NOT NULL, + `full_name` varchar(50) DEFAULT NULL, + `role` varchar(30) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; diff --git a/katalyze/src/main/java/katalyzeapp/ConfigReader.java b/katalyze/src/main/java/katalyzeapp/ConfigReader.java index 0268a7e..dbcf8ab 100644 --- a/katalyze/src/main/java/katalyzeapp/ConfigReader.java +++ b/katalyze/src/main/java/katalyzeapp/ConfigReader.java @@ -140,6 +140,7 @@ private void setupRules(Analyzer analyzer) { addRuleIfEnabled(analyzer, "newLeader", new NewLeader(config.getInt("katalyzer.rule.newLeader.breakingRanks",4), config.getInt("katalyzer.rule.newLeader.ranks", 10))); addRuleIfEnabled(analyzer, "rejectedSubmission", new RejectedSubmission(config.getInt("katalyzer.rule.RejectedSubmission.ranks", 10))); addRuleIfEnabled(analyzer, "rankPredictor", new RankPredictor(config.getInt("katalyzer.rule.rankPredictor.ranks", 10))); + addRuleIfEnabled(analyzer, "submissionAfterFreeze", new SubmissionAfterFreeze(config.getInt("katalyzer.rule.submissionAfterFreeze.ranks", 25))); addRuleIfEnabled(analyzer, "allProblemsSolved", new CriterionRule(new AllProblemsSolved())); addRuleIfEnabled(analyzer, "allTeamsSolvedOneProblem", new CriterionRule(new AllTeamsSolvedOneProblem())); } diff --git a/katalyze/src/main/java/model/Analyzer.java b/katalyze/src/main/java/model/Analyzer.java index 3fd7c95..91c7de7 100644 --- a/katalyze/src/main/java/model/Analyzer.java +++ b/katalyze/src/main/java/model/Analyzer.java @@ -50,7 +50,7 @@ private LoggableEvent buildEventFromAnalystMsg(AnalystMessage msg) { if (firstTeam == null) { firstTeam = team; } - message = message.replace(teamTag, team.getName()); + message = message.replace(teamTag, team.stringForCommentary()); } } @@ -58,7 +58,7 @@ private LoggableEvent buildEventFromAnalystMsg(AnalystMessage msg) { for (String problemTag : problemsInMessage) { Problem problem = hashtagFinder.getProblem(contest, problemTag); if (problem != null) { - message = message.replace(problemTag, problem.getNameAndLabel()); + message = message.replace(problemTag, problem.stringForCommentary()); } } @@ -273,4 +273,4 @@ public boolean isStopped() { } } - \ No newline at end of file + diff --git a/katalyze/src/main/java/model/ContestProperties.java b/katalyze/src/main/java/model/ContestProperties.java index b2c13ad..f384860 100644 --- a/katalyze/src/main/java/model/ContestProperties.java +++ b/katalyze/src/main/java/model/ContestProperties.java @@ -21,7 +21,7 @@ public static ContestProperties fromJSON(JSONObject src) { ContestProperties target = new ContestProperties(); target.id = src.getString("id"); target.name = src.getString("name"); - target.formalName = src.getString("formal_name"); + target.formalName = src.optString("formal_name", null); String startTime = src.optString("start_time", null); if (startTime != null && !startTime.equals("null")) { diff --git a/katalyze/src/main/java/model/LoggableEvent.java b/katalyze/src/main/java/model/LoggableEvent.java index ac5c440..5cb800d 100644 --- a/katalyze/src/main/java/model/LoggableEvent.java +++ b/katalyze/src/main/java/model/LoggableEvent.java @@ -5,7 +5,6 @@ public class LoggableEvent { private static int nextEventId = 0; - private static final TeamNameAsOrganization teamNameExtractor = new TeamNameAsOrganization(); public final Contest contest; @@ -61,10 +60,10 @@ private static String replaceMarkup(String source, String tag, String replacemen private String getCleartextMessage(String message) { if (problem != null) { - message = replaceMarkup(message, "problem", problem.getNameAndLabel()); + message = replaceMarkup(message, "problem", problem.stringForCommentary()); } if (team != null) { - message = replaceMarkup(message, "team", teamNameExtractor.apply(team)); + message = replaceMarkup(message, "team", team.stringForCommentary()); } return message; } diff --git a/katalyze/src/main/java/model/Problem.java b/katalyze/src/main/java/model/Problem.java index 4b7f00c..7f4773b 100644 --- a/katalyze/src/main/java/model/Problem.java +++ b/katalyze/src/main/java/model/Problem.java @@ -67,4 +67,9 @@ public boolean equals(Object o) { return id.equals(other.id); } + public String stringForCommentary() { + // This will at some point change into "{problems:}". + return getNameAndLabel(); + } + } diff --git a/katalyze/src/main/java/model/Team.java b/katalyze/src/main/java/model/Team.java index e3e4f7b..9a6c636 100644 --- a/katalyze/src/main/java/model/Team.java +++ b/katalyze/src/main/java/model/Team.java @@ -110,4 +110,11 @@ public String getShortName() { public Organization getOrganization() { return organization == null ? Organization.NullObject : this.organization; } + + public String stringForCommentary() { + // This is same as "TeamNameAsOrganization.apply" at the moment, + // but might change as we adopt 2022-07 notation ("{teams:}") + Organization org = getOrganization(); + return Organization.isNull(org) ? getName() : org.getDisplayName(); + } } diff --git a/katalyze/src/main/java/rules/SubmissionAfterFreeze.java b/katalyze/src/main/java/rules/SubmissionAfterFreeze.java new file mode 100644 index 0000000..e02bd46 --- /dev/null +++ b/katalyze/src/main/java/rules/SubmissionAfterFreeze.java @@ -0,0 +1,44 @@ +package rules; + +import model.*; + +public class SubmissionAfterFreeze extends StateComparingRuleBase implements SolutionSubmittedEvent { + + // Only submissions of teams with rank <= threshold will result in a notification. + final private int rankThreshold; + + public SubmissionAfterFreeze(int rankThreshold) { + this.rankThreshold = rankThreshold; + } + + public void onSolutionSubmitted(StandingsAtSubmission standingsAtSubmission) { + Standings standingsBefore = standingsAtSubmission.before; + Contest contest = standingsBefore.getContest(); + InitialSubmission submission = standingsAtSubmission.submission; + + if (!contest.isFrozen(submission.contestTimeMilliseconds)) { + return; + } + + Team team = submission.team; + Score teamScore = standingsBefore.scoreOf(team); + + if (standingsBefore.rankOf(team) > rankThreshold) { + return; + } + + if (teamScore.isSolved(submission.getProblem())) { + // Skip notifications for problems already solved. + return; + } + + String message = "{team} submitted a solution for {problem}."; + LoggableEvent event = new LoggableEvent(contest, submission.contestTimeMilliseconds, message, EventImportance.Whatever, standingsAtSubmission.submission, null); + notify(event); + } + + public String toString() { + return String.format("Submissions after freeze (rank <= %d)", rankThreshold); + } +} + diff --git a/www/region.php b/www/region.php index 3d6da88..994e79b 100644 --- a/www/region.php +++ b/www/region.php @@ -12,7 +12,11 @@ $db = init_db(); // get the region/super region names -$result = mysqli_query($db, "select * from team_regions where $query"); +if ($query == "") { + $result = mysqli_query($db, "select * from team_regions"); +} else { + $result = mysqli_query($db, "select * from team_regions where $query"); +} $team_ids = array(); $name = "(unknown)";