diff --git a/devel-server.py b/devel-server.py
index 9f5284e..410e109 100755
--- a/devel-server.py
+++ b/devel-server.py
@@ -5,6 +5,7 @@ import http.server
import mistune
import os
import pathlib
+import puzzles
import socketserver
HTTPStatus = http.server.HTTPStatus
@@ -17,7 +18,7 @@ def page(title, body):
-
+
{}
@@ -72,24 +73,37 @@ you are a fool.
def serve_puzzles(self):
body = []
- parts = self.path.split("/")
+ path = self.path.rstrip('/')
+ parts = path.split("/")
if len(parts) < 3:
# List all categories
body.append("# Puzzle Categories")
for i in glob.glob(os.path.join("puzzles", "*", "")):
body.append("* [{}](/{})".format(i, i))
- elif len(parts) == 4:
+ elif len(parts) == 3:
# List all point values in a category
body.append("# Puzzles in category `{}`".format(parts[2]))
- puzzles = []
- for i in glob.glob(os.path.join("puzzles", parts[2], "*", "")):
- pparts = os.path.split(i[:-1])
- points = int(pparts[-1])
- puzzles.append(points)
- for puzzle in sorted(puzzles):
+ puzz = []
+ for i in glob.glob(os.path.join("puzzles", parts[2], "*.moth")):
+ base = os.path.basename(i)
+ root, _ = os.path.splitext(base)
+ points = int(root)
+ puzz.append(points)
+ for puzzle in sorted(puzz):
body.append("* [puzzles/{cat}/{points}](/puzzles/{cat}/{points}/)".format(cat=parts[2], points=puzzle))
- elif len(parts) == 5:
+ elif len(parts) == 4:
body.append("# {} puzzle {}".format(parts[2], parts[3]))
+ with open("puzzles/{}/{}.moth".format(parts[2], parts[3])) as f:
+ p = puzzles.Puzzle(f)
+ body.append("* Author: `{}`".format(p.fields.get("author")))
+ body.append("* Summary: `{}`".format(p.fields.get("summary")))
+ body.append('')
+ body.append("## Body")
+ body.append(p.body)
+ body.append("## Answers:")
+ for a in p.answers:
+ body.append("* `{}`".format(a))
+ body.append("")
else:
body.append("# Not Implemented Yet")
self.serve_md('\n'.join(body))
diff --git a/puzzles.py b/puzzles.py
new file mode 100644
index 0000000..e2c79f5
--- /dev/null
+++ b/puzzles.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python3
+
+import hmac
+import base64
+import argparse
+import glob
+import json
+import os
+import mistune
+import random
+
+messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+def djb2hash(buf):
+ h = 5381
+ for c in buf:
+ h = ((h * 33) + c) & 0xffffffff
+ return h
+
+class Puzzle:
+ def __init__(self, stream):
+ self.message = bytes(random.choice(messageChars) for i in range(20))
+ self.fields = {}
+ self.answers = []
+ self.hashes = []
+
+ body = []
+ header = True
+ for line in stream:
+ if header:
+ line = line.strip()
+ if not line.strip():
+ header = False
+ continue
+ key, val = line.split(':', 1)
+ key = key.lower()
+ val = val.strip()
+ self._add_field(key, val)
+ else:
+ body.append(line)
+ self.body = ''.join(body)
+
+ def _add_field(self, key, val):
+ if key == 'answer':
+ h = djb2hash(val.encode('utf8'))
+ self.answers.append(val)
+ self.hashes.append(h)
+ else:
+ self.fields[key] = val
+
+ def htmlify(self):
+ return mistune.markdown(self.body)
+
+ def publish(self):
+ obj = {
+ 'author': self.fields['author'],
+ 'hashes': self.hashes,
+ 'body': self.htmlify(),
+ }
+ return obj
+
+ def secrets(self):
+ obj = {
+ 'answers': self.answers,
+ 'summary': self.fields['summary'],
+ }
+ return obj
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Build a puzzle category')
+ parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source')
+ args = parser.parse_args()
+
+ for puzzledir in args.puzzledir:
+ puzzles = {}
+ secrets = {}
+ for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")):
+ filename = os.path.basename(puzzlePath)
+ points, ext = os.path.splitext(filename)
+ points = int(points)
+ puzzle = Puzzle(open(puzzlePath))
+ puzzles[points] = puzzle
+
+ for points in sorted(puzzles):
+ puzzle = puzzles[points]
+ print(puzzle.secrets())
+
diff --git a/www/res/style.css b/www/res/style.css
index 404d707..f6802c1 100644
--- a/www/res/style.css
+++ b/www/res/style.css
@@ -55,7 +55,9 @@ pre, tt {
padding: 0.25em 0.5em;
}
-#body {
+#preview {
+ background-image: url(preview.png);
+ background-size: contain;
max-width: 40em;
display: block;
margin: 1% auto;