Commit f912ea67 authored by Henrik Tramberend's avatar Henrik Tramberend
Browse files

Working on the exam generator and some CSS fixes

parent 57924457
...@@ -42,9 +42,6 @@ main = do ...@@ -42,9 +42,6 @@ main = do
let metaA = globA "**/*-meta.yaml" let metaA = globA "**/*-meta.yaml"
-- Read meta data.
-- metaData <- readMetaDataIO meta
-- Calculate targets -- Calculate targets
let decksA = deckSourcesA >>= calcTargets ".md" ".html" let decksA = deckSourcesA >>= calcTargets ".md" ".html"
let decksPdfA = deckSourcesA >>= calcTargets ".md" ".pdf" let decksPdfA = deckSourcesA >>= calcTargets ".md" ".pdf"
......
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad () import Control.Monad ()
import Control.Exception import Control.Exception
import Data.Maybe () import Data.Maybe ()
...@@ -27,115 +29,153 @@ import Test ...@@ -27,115 +29,153 @@ import Test
import Embed import Embed
main :: IO () main :: IO ()
main = main = do
do -- Calculate some directories
-- Calculate some directories projectDir <- calcProjectDirectory
projectDir <- calcProjectDirectory let privateDir = projectDir </> "private"
let privateDir = projectDir </> "private" -- Find questions
-- Find sources questionFiles <- glob "**/*-quest.yaml"
testFiles <- glob "**/*-quest.yaml" -- Find exams
-- Meta data examFiles <- glob "**/*-exam.yaml"
metaFiles <- glob "**/*-meta.yaml" -- Meta data
-- Calculate targets metaFiles <- glob "**/*-meta.yaml"
let catalog = privateDir </> "complete-quest-catalog.pdf" -- Calculate targets
-- Prepare Mustache templates let catalog = privateDir </> "complete-quest-catalog.pdf"
let templates = compileTesterTemplates -- Prepare Mustache templates
--- let templates = compileTesterTemplates
shakeArgs shakeOptions $ ---
do want ["catalog"] shakeArgs
-- shakeOptions $
catalog %> do want ["catalog"]
\out -> --
do need testFiles catalog %>
allQuestions <- readTests testFiles \out ->
renderCatalog projectDir templates allQuestions out do need questionFiles
-- allQuestions <- readTests questionFiles
phony "catalog" $ renderCatalog projectDir templates allQuestions out
do need [catalog] --
-- phony
phony "new-mc" $ "catalog" $
do let string = Y.encodePretty Y.defConfig multipleChoiceStationary do need [catalog]
liftIO $ B.writeFile "new-mc-quest.yaml" string --
-- phony
phony "new-ft" $ "new-exam" $
do let string = Y.encodePretty Y.defConfig fillTextStationary do let string = Y.encodePretty Y.defConfig examStationary
liftIO $ B.writeFile "new-ft-quest.yaml" string liftIO $ B.writeFile "new-exam.yaml" string
-- --
phony "new-f" $ phony
do let string = Y.encodePretty Y.defConfig freeStationary "new-mc" $
liftIO $ B.writeFile "new-f-quest.yaml" string do let string = Y.encodePretty Y.defConfig multipleChoiceStationary
-- liftIO $ B.writeFile "new-mc-quest.yaml" string
phony "clean" $ --
do removeFilesAfter "." ["private"] phony
"new-ft" $
do let string = Y.encodePretty Y.defConfig fillTextStationary
liftIO $ B.writeFile "new-ft-quest.yaml" string
--
phony
"new-f" $
do let string = Y.encodePretty Y.defConfig freeStationary
liftIO $ B.writeFile "new-f-quest.yaml" string
--
phony
"clean" $
do removeFilesAfter "." ["private"]
-- Reads all the questions and returns them along with the base directory of -- Reads all the questions and returns them along with the base directory of
-- each. -- each.
readTests :: [FilePath] -> Action [(Question, FilePath)] readTests
:: [FilePath] -> Action [(Question, FilePath)]
readTests files = mapM readTest files readTests files = mapM readTest files
where readTest :: FilePath -> Action (Question, FilePath) where
readTest file = readTest :: FilePath -> Action (Question, FilePath)
do absolutePath <- liftIO $ makeAbsolute file readTest file = do
string <- liftIO $ B.readFile absolutePath absolutePath <- liftIO $ makeAbsolute file
let question = string <- liftIO $ B.readFile absolutePath
case Y.decodeEither' string of let question =
Right yaml -> yaml case Y.decodeEither' string of
Left exception -> Right yaml -> yaml
throw $ Left exception ->
YamlException $ throw $
"Error parsing YAML file: " ++ YamlException $
file ++ ", " ++ (show exception) "Error parsing YAML file: " ++ file ++ ", " ++ (show exception)
return (question, takeDirectory absolutePath) return (question, takeDirectory absolutePath)
renderCatalog :: FilePath -> Templates -> [(Question, FilePath)] -> FilePath -> Action() -- Renders a catalog of all questions (TODO sorted by LectureId and TopicId).
renderCatalog projectDir templates questions out = renderCatalog
do let markdown = map (\(q,b) -> (renderMarkdown q,b)) questions :: FilePath -> Templates -> [(Question, FilePath)] -> FilePath -> Action ()
let pandoc = map parseMarkdown markdown renderCatalog projectDir templates questions out = do
need $ concatMap extractLocalImagePathes pandoc let markdown =
let catalog = map
Pandoc nullMeta $ concatMap (\(Pandoc _ blocks) -> blocks) pandoc (\(q,b) ->
let options = (renderMarkdown q, b))
def {writerStandalone = True questions
,writerTemplate = B.unpack testLatexTemplate let pandoc = map parseMarkdown markdown
,writerHighlight = True need $ concatMap extractLocalImagePathes pandoc
,writerHighlightStyle = pygments let catalog =
,writerCiteMethod = Citeproc} Pandoc nullMeta $
putNormal $ "# pandoc (for " ++ out ++ ")" concatMap
pandocMakePdf options catalog out (\(Pandoc _ blocks) ->
where parseMarkdown (markdown,base) = blocks)
case readMarkdown def markdown of pandoc
let options =
def
{ writerStandalone = True
, writerTemplate = B.unpack testLatexTemplate
, writerHighlight = True
, writerHighlightStyle = pygments
, writerCiteMethod = Citeproc
}
putNormal $ "# pandoc (for " ++ out ++ ")"
pandocMakePdf options catalog out
where
parseMarkdown (markdown,base) =
case readMarkdown def markdown of
Left err -> throw $ PandocException (show err) Left err -> throw $ PandocException (show err)
Right pandoc -> walk (adjustImageUrls base) pandoc Right pandoc -> walk (adjustImageUrls base) pandoc
adjustImageUrls base (Image attr inlines (url,title)) = adjustImageUrls base (Image attr inlines (url,title)) =
(Image attr inlines (adjustLocalUrl projectDir base url,title)) (Image attr inlines (adjustLocalUrl projectDir base url, title))
adjustImageUrls _ inline = inline adjustImageUrls _ inline = inline
renderMarkdown question = renderMarkdown question =
T.unpack $ T.unpack $ M.substitute (selectTemplate templates question) (MT.mFromJSON question)
M.substitute (selectTemplate templates question)
(MT.mFromJSON question)
-- TODO Make this work -- TODO Make this work
newOrder :: Int -> IO [Int] newOrder
newOrder n = :: Int -> IO [Int]
do gen <- getStdGen newOrder n = do
return $ shuffle' [0..(n-1)] n gen gen <- getStdGen
return $ shuffle' [0 .. (n - 1)] n gen
-- TODO Make this work -- TODO Make this work
shuffleAnswers :: Question -> Action Question shuffleAnswers
shuffleAnswers q = :: Question -> Action Question
case qstAnswer q of shuffleAnswers q =
MultipleChoice choices correct -> case qstAnswer q of
do let n = length choices MultipleChoice choices correct -> do
order <- liftIO $ newOrder n let n = length choices
return q {qstAnswer = order <- liftIO $ newOrder n
MultipleChoice (shuffle choices order) return
(shuffle correct order)} q
otherwise -> return q { qstAnswer = MultipleChoice (shuffle choices order) (shuffle correct order)
}
otherwise -> return q
examStationary :: Exam
examStationary =
Exam
{ examStudentInfoFile = "PATH/TO/STUDENT/INFO"
, examDateTime = "DATE_TIME"
, examDurationInMinutes = "DURATION_IN_MINUTES"
, examTrack = 1
, examLectureIds = ["LECTURE_ID"]
, examExcludedTopicIds = ["EXCLUDED_TOPIC_ID"]
}
multipleChoiceStationary :: Question multipleChoiceStationary :: Question
multipleChoiceStationary = multipleChoiceStationary =
Question Question
{ qstId = "ID" { qstTopicId = "TOPIC_ID"
, qstLecture = 0 , qstLectureId = "LECTURE_ID"
, qstTitle = "MULTIPLE CHOICE" , qstTitle = "MULTIPLE CHOICE"
, qstPoints = 5 , qstPoints = 5
, qstQuestion = "THE QUESTION?" , qstQuestion = "THE QUESTION?"
...@@ -148,10 +188,10 @@ multipleChoiceStationary = ...@@ -148,10 +188,10 @@ multipleChoiceStationary =
} }
fillTextStationary :: Question fillTextStationary :: Question
fillTextStationary = fillTextStationary =
Question Question
{ qstId = "ID" { qstTopicId = "TOPIC_ID"
, qstLecture = 0 , qstLectureId = "LECTURE_ID"
, qstTitle = "FILL TEXT" , qstTitle = "FILL TEXT"
, qstPoints = 5 , qstPoints = 5
, qstQuestion = "THE QUESTION?" , qstQuestion = "THE QUESTION?"
...@@ -164,10 +204,10 @@ fillTextStationary = ...@@ -164,10 +204,10 @@ fillTextStationary =
} }
freeStationary :: Question freeStationary :: Question
freeStationary = freeStationary =
Question Question
{ qstId = "ID" { qstTopicId = "TOPIC_ID"
, qstLecture = 0 , qstLectureId = "LECTURE_ID"
, qstTitle = "FREE" , qstTitle = "FREE"
, qstPoints = 5 , qstPoints = 5
, qstQuestion = "THE QUESTION?" , qstQuestion = "THE QUESTION?"
...@@ -177,4 +217,4 @@ freeStationary = ...@@ -177,4 +217,4 @@ freeStationary =
} }
, qstDifficulty = Medium , qstDifficulty = Medium
, qstComment = "COMMENT" , qstComment = "COMMENT"
} }
\ No newline at end of file
Track: 1
LectureIds:
- LECTURE_ID
ExcludeTopicIds:
- EXCLUDED_TOPIC_ID
DurationInMinutes: DURATION_IN_MINUTES
StudentInfoFile: PATH/TO/STUDENT/INFO
DateTime: DATE_TIME
...@@ -20,8 +20,7 @@ transition: linear ...@@ -20,8 +20,7 @@ transition: linear
## Pandoc-Markdown ## Pandoc-Markdown
- Slides are basically [Pandoc-Markdown](http://pandoc.org) formatted - Slides are basically [Pandoc-Markdown](http://pandoc.org) formatted text
text
- Pandoc provides a Markdown variant with many extensions - Pandoc provides a Markdown variant with many extensions
## Some Pandoc extensions ## Some Pandoc extensions
...@@ -55,7 +54,7 @@ transition: linear ...@@ -55,7 +54,7 @@ transition: linear
The following text ist included from file `/resource/realtive.md`: The following text ist included from file `/resource/realtive.md`:
[#include](/resource/relative.md) [\#include](/resource/relative.md)
# Multicolumn slides # Multicolumn slides
...@@ -63,7 +62,7 @@ The following text ist included from file `/resource/realtive.md`: ...@@ -63,7 +62,7 @@ The following text ist included from file `/resource/realtive.md`:
![](img/htr-beuth.jpg) ![](img/htr-beuth.jpg)
### ###
## Slide source ## Slide source
...@@ -87,7 +86,7 @@ The following text ist included from file `/resource/realtive.md`: ...@@ -87,7 +86,7 @@ The following text ist included from file `/resource/realtive.md`:
## Relative path ## Relative path
![](img/06-metal.png){width=75%} ![](img/06-metal.png){width="75%"}
# LaTeX Math # LaTeX Math
...@@ -118,7 +117,7 @@ $$ ...@@ -118,7 +117,7 @@ $$
[:youtube](Wji-BZ0oCwg) [:youtube](Wji-BZ0oCwg)
``` ```
### ###
## Video ## Video
...@@ -167,7 +166,7 @@ $$ ...@@ -167,7 +166,7 @@ $$
- This block is marked `.alert` - This block is marked `.alert`
``` ```
### ###
## Block styles ## Block styles
...@@ -194,7 +193,7 @@ $e=mc^2$ ...@@ -194,7 +193,7 @@ $e=mc^2$
These are speaker notes. These are speaker notes.
``` ```
### ###
## Block level ## Block level
...@@ -209,9 +208,7 @@ $e=mc^2$ ...@@ -209,9 +208,7 @@ $e=mc^2$
# These are just notes {.notes} # These are just notes {.notes}
Slides with headers that are have the `.notes` class attribute are not Slides with headers that are have the `.notes` class attribute are not included in the presentation. They are only visible in the handout and probably are available as presenter notes during slide presentation.
included in the presentation. They are only visible in the handout and
probably are available as presenter notes during slide presentation.
# Cached Images # Cached Images
...@@ -219,17 +216,15 @@ probably are available as presenter notes during slide presentation. ...@@ -219,17 +216,15 @@ probably are available as presenter notes during slide presentation.
Remote images can be cached locally Remote images can be cached locally
Cache directory is named `img/cached` and is located in the directory of Cache directory is named `img/cached` and is located in the directory of the referencing document
the referencing document
`decker cache` scans for and downloads all images `decker cache` scans for and downloads all images
### ###
## Cached remote image ## Cached remote image
![Some piece of scene ![Some piece of scene graph](https://tramberend.beuth-hochschule.de/img/cg1-banner.png)
graph](https://tramberend.beuth-hochschule.de/img/cg1-banner.png)
# Meta Data # Meta Data
...@@ -298,8 +293,7 @@ Your total score is 42. ...@@ -298,8 +293,7 @@ Your total score is 42.
- `*-deck.html` a *reveal.js* based HTML slide deck - `*-deck.html` a *reveal.js* based HTML slide deck
- `*-deck.pdf` a PDF version of that deck - `*-deck.pdf` a PDF version of that deck
- `*-handout.html` a HTML document containing only the speaker notes - `*-handout.html` a HTML document containing only the speaker notes from the deck
from the deck
- `*-handout.pdf` a PDF version of that handout - `*-handout.pdf` a PDF version of that handout
## Generated from `*-page.md` ## Generated from `*-page.md`
...@@ -317,8 +311,7 @@ Your total score is 42. ...@@ -317,8 +311,7 @@ Your total score is 42.
## `decker` ## `decker`
- Recursively scans the current directory for Markdown files ending in - Recursively scans the current directory for Markdown files ending in `.md`
`.md`
## `decker clean` ## `decker clean`
......
Points: 5
LectureId: Some lecture id
Answer:
CorrectAnswer: THE ANSWER.
tag: FreeForm
HeightInMm: 20
TopicId: Some topic id
Title: FREE
Difficulty: Medium
Comment: COMMENT
Question: THE QUESTION?
Points: 5
LectureId: Some lecture id
Answer:
tag: FillText
CorrectWords:
- HOLES
- TEXT
FillText: FILL THE ___ IN THE ___.
TopicId: Some topic id
Title: FILL TEXT
Difficulty: Medium
Comment: COMMENT
Question: THE QUESTION?
Points: 5
LectureId: Some lecture id
Answer:
tag: MultipleChoice
Correct:
- ANSWER_1
- ANSWER_2
Incorrect:
- DISTRACTOR_1
- DISTRACTOR_2
TopicId: Some topic id
Title: MULTIPLE CHOICE
Difficulty: Medium
Comment: COMMENT
Question: THE QUESTION?
# Aufgabe N: {{Title}} # Aufgabe N: {{Title}}
| | | | | |
|---------------+-------------------| |---------------|----------------|
| Titel | **{{Title}}** | | Titel | **{{Title}}** |
| Id | {{Id}} | | Id | {{TopicId}} |
| Vorlesung | {{Lecture}} | | Vorlesung | {{LectureId}} |
| Schwierigkeit | {{Difficulty}} | | Schwierigkeit | {{Difficulty}} |
| Punkte | {{Points}} | | Punkte | {{Points}} |
| Kommentar | {{Comment}} | | Kommentar | {{Comment}} |
......
# Aufgabe N: {{Title}} # Aufgabe N: {{Title}}
| | | | | |
|---------------+-------------------| |---------------|----------------|
| Titel | **{{Title}}** | | Titel | **{{Title}}** |
| Id | {{Id}} | | Id | {{TopicId}} |
| Vorlesung | {{Lecture}} | | Vorlesung | {{LectureId}} |
| Schwierigkeit | {{Difficulty}} | | Schwierigkeit | {{Difficulty}} |
| Punkte | {{Points}} | | Punkte | {{Points}} |
| Kommentar | {{Comment}} | | Kommentar | {{Comment}} |
...@@ -13,4 +13,4 @@ ...@@ -13,4 +13,4 @@
{{Answer.FillText}} {{Answer.FillText}}
*Antwort:* {{#Answer.CorrectWords}}{{.}}, {{/Answer.CorrectWords}} *Antwort:* {{\#Answer.CorrectWords}}{{.}}, {{/Answer.CorrectWords}}
# decker
# decker
A markdown based tool for slide deck creation. A markdown based tool for slide deck creation.
## Usage ## Usage
*decker* behaves very much like a build tool. It works recursively on the *decker* behaves very much like a build tool. It works recursively on the current directory and all subdirectories. Markdown files ending on `.md` in those directories are processed and converted to either a reveal.js slide show, a HTML document, or a PDF document, depending on the file name.
current directory and all subdirectories. Markdown files ending on `.md` in
those directories are processed and converted to either a reveal.js slide show,
a HTML document, or a PDF document, depending on the file name.
`*-deck.md` `*-deck.md`
: Files with this ending are processed as silde decks. From one source file : Files with this ending are processed as silde decks. From one source file potentially four different targets can be generated:
potentially four different targets can be generated:
- `*-deck.html` A reveal.js based slide show - `*-deck.html` A reveal.js based slide show
- `*-handout.hmtl` A HTML document containing the speaker notes to the - `*-handout.hmtl` A HTML document containing the speaker notes to the slide show.
slide show.
- `*-deck.pdf` A PDF version of the slide show - `*-deck.pdf` A PDF version of the slide show
- `*-handout.pdf` A PDF version of the handout - `*-handout.pdf` A PDF version of the handout
`*.md` `*-page.md`
: General Markdown files are translated into corresponding HTML or
PDF documents. : Markdown files ending on `*-page.md` are translated into corresponding HTML or PDF documents.
## *decker* targets ## *decker* targets
...@@ -34,69 +28,51 @@ decker html ...@@ -34,69 +28,51 @@ decker html
: Builds HTML versions of all available documents. : Builds HTML versions of all available documents.