Princípio: adicionar um modo = 1 gerador
(server/score/updatescore-<modo>.sh) + 1 renderizador
(web/contest/score/score-<modo>.js), ligados
pela mesma string de modo.
conf do contest define CONTEST_TYPE
(icpc | obi | treino |
heuristic | outro;
lista-publica/lista-privada →
treino; ausente → icpc).users/<login>/metrics.json (mantido
incremental pelo daemon a cada veredicto via
metrics_recompute): cada metrics carrega, por problema,
counted (tentativas até o 1º AC — quais verdicts contam
obedece o PENALTY_VERDICTS do conf; ver modo
icpc abaixo), first_ac_epoch,
pending, best_score (NNp), heur
(Score/Score Ajustado) e a visão frozen
(pré-FREEZE_TIME). Os geradores leem tudo numa passada só
(sc_cells em score-common.sh:
find users -name metrics.json | xargs jq) — rebuild
O(usuários), sem varrer history.server/score/build.sh <contest> recomputa os
metrics em massa se o conf mudou desde o último build
(var/.metrics-stamp — cobre edição de
FREEZE_TIME e o 1º build de um contest importado), despacha
para updatescore-<modo>.sh e grava
contests/<contest>/var/placar.txt (atômico;
var/placar-full.txt = sem freeze, p/ privilegiados). É
chamado pelo daemon após cada veredicto.GET /api/v1/contest/score?contest=<c>
serve esse TXT cru — com cache preguiçoso: se o
placar.txt está velho (var/.score-dirty —
tocado a cada escrita de history — ou conf mais novos) ou
nunca foi gerado, a rota chama build.sh na hora (sob
flock, sem estampida) e então serve. Assim contests
importados deixam de ficar com placar vazio.web/contest/score/) lê a 1ª linha =
modo e despacha para o renderizador.icpc ← linha 1: o modo (bare)
desc:asc:flag:username:univ short:team name:univ full:A:B:C:D:Total:Penalty:LastAC ← cabeçalho
BR:br-df-alfa:UNB:ALFA:Universidade de Brasília:1/30:2/40:1/55::3/68::4:213:68
:. O placar já vem
ordenado — o front só renderiza na ordem.desc/asc (campos de ordenação já aplicados):
o renderizador deve descartar TODAS as colunas iniciais cujo
valor seja desc ou asc.flag (ISO), username,
univ short, team name, univ full
(as de univ são opcionais), uma coluna por problema (na ordem dos short
names), Total; no modo icpc também
Penalty (soma das penalidades, coluna
VISÍVEL) e LastAC (minuto de prova do
último problema resolvido — coluna de SISTEMA: a UI usa p/ detectar
empate exato, não exibe).| Modo | Célula de problema | Ordenação | Cor |
|---|---|---|---|
icpc |
vazio=não tentou · tentativas/minuto=resolveu ·
tentativas/minuto*=first to solve (★ +
contorno; menor first_ac_epoch do problema entre os times
do placar, na mesma visão frozen/full) ·
tentativas/-=tentou |
1º acertos↓ · 2º penalidade↑
(penalidade=(tent−1)·PENALTY_MINUTES+minuto; default 20) ·
3º minuto do ÚLTIMO problema resolvido↑
(LastAC) |
pinta com a cor do balão |
Penalidade configurável (modo icpc) —
duas vars de conf, editáveis pelo /contest/admin/settings
(mudar em prova recomputa o placar no próximo GET):
PENALTY_MINUTES (default 20): minutos somados por
tentativa que conta antes do AC.PENALTY_VERDICTS (códigos
wa tle mle rte ce; default wa tle mle rte):
quais verdicts entram no counted do metrics. Judge
Error/No_Servers e provisórios nunca contam; strings legadas
fora do vocabulário canônico continuam contando (comportamento
histórico). Lista vazia (PENALTY_VERDICTS='') = nenhum
verdict penaliza (só o minuto do AC). | obi | pontos
(0–100) | Total↓ | — | | treino | resolvidos / tentativas |
resolvidos↓ | — | | heuristic | melhor Score | Score↓
(Score Ajustado como desempate) | — | | outro | colunas
100% personalizadas (cabeçalho traz os nomes reais) | já ordenado | se
houver coluna flag, mostra bandeira |xyz)server/score/updatescore-xyz.sh <contest> — emite
o TXT (1ª linha xyz + cabeçalho + linhas ordenadas).
Reaproveite server/score/score-common.sh.server/score/build.sh (case
xyz) updatescore-xyz.sh ;;).web/contest/score/score-xyz.js — recebe o TXT já
parseado e renderiza.web/contest/score/score.js.Geradores existentes (testados contra dados reais, batem com os
placares legados): updatescore-icpc.sh,
updatescore-obi.sh, updatescore-treino.sh,
updatescore-heuristic.sh,
updatescore-outro.sh.
flag (código de país ISO-2 ou estado BR-SP)
vira um SVG servido pelo próprio MOJ em /shared/flags/ (271
países + 27 estados) — nada de CDN externo. Ver
web/shared/flags.js./contest/teams (por-usuário, PRECEDE o
teams-meta): diretório dos times a partir do
.team{univ_short,univ_full,flag,region} do account.json
(aba 👥 Times do admin) + has_logo/has_photo.
O nome do time é o fullname (campo único;
a coluna team name do TXT sai de
.team.name // .fullname — .team.name é só
legado da migração). O placar mescla explícito
primeiro: bandeira/univ que faltarem no TXT, a
sede (t._region, filtro por nome), o
brasão (/contest/team-logo, vence o logo
por regra) e o link 📷 da foto
(/contest/team-photo, abre em nova aba).teams-meta
(contests/<id>/teams-meta.json, lido por
GET /contest/teams-meta): regras regex no login →
{country, school, school_full, logo?}.
Fallback: o placar preenche bandeira/universidade/logo
só no que o por-usuário e a coluna não trouxeram, e habilita
filtro por país/escola. O logo é um data-URL embutido
(offline). Editável na criação e no admin do contest.regions.json,
GET /contest/regions): árvore hierárquica; cada entrada
casa por nome (igualdade com a sede
.team.region do time) ou pelo
regex no login (clássico).SCORE_ANON=1 no conf, ou
toggle local): esconde o desempenho individual e mostra agregado —
participantes, quartis por nº de problemas resolvidos,
distribuição e resolvedores por problema. Forçado para não-admins quando
SCORE_ANON=1.balloons.json,
GET /contest/balloons): mapa letra→cor (default ICPC A–O).
Campo enableSonic ativa o modo secreto do
Sonic (GIFs locais em /shared/assets/sonic/)./contest/statistics/ (admin/judge/mon) e similaridade em
/contest/jplag/.