JSON points generator

This commit is contained in:
Neale Pickett 2015-04-08 17:28:18 -06:00
parent 64151ffa88
commit f8a906c3fe
6 changed files with 4999 additions and 1073 deletions

167
bin/install-category Executable file
View File

@ -0,0 +1,167 @@
#! /bin/sh -e
indir=$1; shift
if ! [ -d $indir ]; then
echo "Usage: $0 PUZZLEDIR"
exit 1
fi
die () {
echo "$@" 1>&2
exit 1
}
escape () {
sed 's/&/\&amp;/g;s/</\&lt;/g;s/>/\&gt;/g'
}
template () {
cat="$1"; shift
points="$1"; shift
author=$(echo $1 | escape); shift
cat <<EOF
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>$cat $points</title>
<link rel="stylesheet" href="/css/style.css" type="text/css">
</head>
<body>
<h1>$cat for $points points</h1>
EOF
echo "<section id=\"readme\">"
cat
echo "</section>"
if [ $# -gt 0 ]; then
echo "<section id=\"files\">"
echo "<h2>Associated files:</h2>"
echo "<ul>"
while [ $# -gt 0 ]; do
fn="$1"; shift
efn="$(echo $fn | escape)"
echo "<li><a href=\"$fn\">$efn</a></li>"
done
echo "</ul>"
echo "</section>"
fi
cat <<EOF
<section id="form">
<form id="puzzler" action="/puzzler.cgi" method="post" accept-charset="utf-8">
<input type="hidden" name="c" value="$cat">
<input type="hidden" name="p" value="$points">
Team hash:<input name="t" size="8">
Answer:<input name="a" size="20">
<input type="submit" value="submit">
</form>
</section>
<address>Puzzle by <span class="author" data-handle="$author">$author</span></address>
</body>
</html>
EOF
}
cat=$(basename $indir)
outdir=$(dirname $0)/puzzles/$cat
uanswers=$outdir/answers.unsorted
usummary=$outdir/summary.unsorted
umap=$outdir/map.unsorted
if ! [ -r $outdir/mkpuzzles.salt ]; then
dd if=/dev/urandom bs=1 count=16 2>/dev/null | md5sum | cut -d\ -f1 > $outdir/salt
fi
read salt < $outdir/salt
> $uanswers
rm -f $usummary
for dn in $indir/[0-9]*; do
[ -d $dn ] || continue
points=$(basename $dn)
echo $dn
odn=$(printf "%s/%s/%s" "$salt" "$cat" "$points" | md5sum | sed 's/\(....\)/\1./g' | cut -b 1-19)
tgt=$outdir/puzzles/$odn
mkdir -p $tgt
#touch $tgt/index.html
if [ -f $dn/Makefile ]; then
# If there's a Makefile, run make
make DESTDIR=$(pwd)/$tgt -C $dn || exit 1
files=$(ls -1 $tgt | grep -v index.html || true)
elif [ -f $dn/00manifest.txt ]; then
# If there's a manifest, use that
files=
while read fn; do
ln -f $dn/$fn $tgt/
case $fn in
,*)
;;
*)
files="$files $fn"
;;
esac
done < $dn/00manifest.txt
else
# Otherwise, look for special files and copy the rest
files=
for fn in $dn/*; do
case $(basename $fn) in
00*)
# Handle meta-information later
;;
*~|"#"*)
# Don't copy temporary or backup files
;;
,*)
# Copy but don't list
ln -f $fn $tgt/
;;
*)
#ext=$(echo $fn | sed -ne 's/.*\././p')
cfn=$(md5sum $fn | cut -b -8)$ext
ln -f $fn $tgt/$cfn
files="$files $cfn"
;;
esac
done
fi
# Append answers
if [ -f $dn/00answer.txt ]; then
awk -v P=$points '/./ { printf("%d %s\n", P, $0); }' < $dn/00answer.txt >> $uanswers
else
die "$dn/00answer.txt: No such file or directory"
fi
# Append summary
if [ -f $dn/00summary.txt ]; then
awk -v P=$points '/./ { printf("%d %s\n", P, $0); }' < $dn/00summary.txt >> $usummary
fi
# Read author
if [ -f $dn/00author.txt ]; then
author=$(cat $dn/00author.txt)
else
die "$dn/00author.txt does not exist."
fi
# Generate index now that we have a list of files
if [ -f $dn/00index.mdwn ]; then
markdown --html4tags $dn/00index.mdwn
fi | template $cat $points "$author" $files > $tgt/index.html
# Write to map
printf "%d %s\n" $points $odn >> $umap
done
sort -n $umap > $outdir/map.txt
sort -n $uanswers > $outdir/answers.txt
[ -f $usummary ] && sort -ns $usummary > $outdir/summary.txt
rm -f $uanswers $usummary $umap

58
bin/kothd Executable file
View File

@ -0,0 +1,58 @@
#! /bin/sh
echo "Figuring out web user..."
for www in www-data http _; do
id $www && break
done
if [ $www = _ ]; then
echo "Unable to determine httpd user on this system. Dying."
exit 1
fi
initialize () {
for i in points.new points.tmp teams; do
mkdir -p state/$i
setfacl -m ${www}:rwx state/$i
done
>> state/points.log
hd < /dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > state/teams/assigned.txt
}
once () {
if [ -f disabled ]; then
return
fi
if ! [ -d state ]; then
initialize $1
fi
# Collect new points
find state/points.new -type f | while read fn; do
cat $fn >> state/points.log
rm $fn
done
# Generate new puzzles.html
if $KOTH_BASE/puzzles.cgi > www/puzzles.new; then
mv www/puzzles.new www/puzzles.html
fi
# Generate new points.json
if $KOTH_BASE/points > www/points.new; then
mv www/points.new www/points.json
fi
}
cd $(basename $0)
KOTH_BASE=$(pwd)
while true; do
for dn in $KOTH_BASE/*; do
cd $dn
once
done
sleep 5
done

45
bin/points Executable file
View File

@ -0,0 +1,45 @@
#! /usr/bin/awk -f
BEGIN {
nteams = 0;
print "{";
print " \"points\": [";
}
{
ts = $1;
hash = $2;
cat = $3;
points = $4;
teamno = teams[hash];
if (! teamno) {
teamno = ++nteams;
teams[hash] = teamno;
getline teamnames[teamno] < ("state/teams/" hash)
}
if (NR > 1) {
# JSON sucks.
print ",";
}
printf("[%d, \"%d\", \"%s\", %d]", ts, teamno, cat, points);
}
END {
print "";
print " ],";
print " \"teams\": {";
for (i in teamnames) {
if (i > 1) {
print ",";
}
printf("\"%d\": \"%s\"", i, teamnames[i]);
}
print "";
print " }";
print "}";
}

View File

@ -63,7 +63,7 @@ pre {
font-family: "Ubuntu Mono", monospace; font-family: "Ubuntu Mono", monospace;
} }
tt, code, kbd, samp { code, kbd, samp {
font-family: "Ubuntu Mono", monospace; font-family: "Ubuntu Mono", monospace;
} }
@ -104,8 +104,26 @@ hr {
} }
/**** Section ****/
section, nav {
color: #35170c;
max-width: 35em;
border-radius: 0.6em;
margin: 1em auto;
padding: 0.2em;
}
section {
background: #e1c3b8;
}
/*** navigation bar ***/ /*** navigation bar ***/
nav {
background: #b9e0ef;
}
nav h2 { nav h2 {
display: none; display: none;
} }
@ -113,6 +131,7 @@ nav h2 {
nav ul { nav ul {
list-style: none; list-style: none;
text-align: center; text-align: center;
padding: 0;
} }
nav li { nav li {
@ -128,15 +147,6 @@ nav li + li:before {
content: " | "; content: " | ";
} }
section {
background: #e1c3b8;
background-size: 100% 100%;
color: #35170c;
max-width: 35em;
border-radius: 0.6em;
margin: 1em auto;
padding: 0.2em;
}
/**** Terminal ****/ /**** Terminal ****/

View File

@ -4,24 +4,44 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Welcome</title> <title>Welcome</title>
<link rel="stylesheet" href="css/style.css" type="text/css"> <link rel="stylesheet" href="css/style.css" type="text/css">
<script src="js/terminal.js" async></script>
<script>
function init() {
output("Hello world.");
output("This is the new Tracer FIRE terminal.")
output("This is going to be your primary interface to Tracer FIRE 6 and 7. All of your interactions with the system will go through this interface, which is sort of like the old school terminal we had previously, but not exactly? I guess it's like steampunk or weird western, but for the 1980s.")
output("I sincerely hope you like it. Personally, I am pretty psyched about how it looks. If I could go back and show it to myself when I was 13 I would have been bowled over.")
output(" - Neale Pickett")
}
window.addEventListener("load", init);
</script>
</head> </head>
<body> <body>
<h1>Tracer FIRE 6E</h1> <h1>Tracer FIRE 6E</h1>
<section> <section>
Here's some stuff. <p>
Here is what you need to do:
</p>
<ol>
<li>
<a href="register.html">Register</a> your team.
This only needs to happen once per team,
so if somebody else on your team has already done it,
you don't need to.
</li>
<li>
Get an <a href="puzzles.html">overview of puzzles</a>,
and start working on something.
The list of open puzzles changes over time,
you need to reload the page to get the current version!
</li>
<li>
Check the <a href="scoreboard.html">scoreboard</a>
in another tab,
to see how your team is doing.
</li>
</ol>
</section> </section>
<nav>
<ul>
<li><a href="register.html">Register</a></li>
<li><a href="puzzles.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load Diff