Commit f3635fa022e624a62b9941073656563a3ecec6e3

Authored by Miguel Barão
1 parent a0ab1672
Exists in master and in 1 other branch dev

minor reorganization

update BUGS
BUGS.md
  1 +# Perguntations
1 2  
2   -# BUGS
  3 +## BUGS
3 4  
4   -- correct devia poder ser corrido mais que uma vez (por exemplo para alterar cotacoes, corrigir perguntas)
5   -- guardar testes em JSON assim que sao atribuidos aos alunos (ou guardados inicialmente com um certo nome, e atribuidos posteriormente ao aluno).
6   -- cookies existe um perguntations_user e um user. De onde vem o user?
7   -- QuestionCode falta reportar nos comments os vários erros que podem ocorrer (timeout, etc)
8   -- algumas vezes a base de dados guarda o mesmo teste em duplicado. ver se dois submits dao origem a duas correcções.
9   -talvez a base de dados devesse ter como chave do teste um id que fosse único desse teste particular (não um auto counter, nem ref do teste)
10   -- em caso de timeout na submissão (e.g. JOBE ou script nao responde) a correcção não termina e o teste não é guardado.
11   -- grade gives internal server error??
  5 +- talvez a base de dados devesse ter como chave do teste um id que fosse único
  6 + desse teste particular (não um auto counter, nem ref do teste)
  7 +- em caso de timeout na submissão (e.g. JOBE ou script nao responde) a correcção
  8 + não termina e o teste não é guardado.
12 9 - reload do teste recomeça a contagem no inicio do tempo.
13   -- em admin, quando scale_max não é 20, as cores das barras continuam a reflectir a escala 0,20. a tabela teste na DB não tem a escala desse teste.
14   -- em grade.html as barras estao normalizadas para os limites scale_min e max do teste actual e nao dos testes realizados no passado (tabela test devia guardar a escala).
15   -- codigo `hello world` nao esta a preservar o whitespace. O renderer de markdown gera a tag <code> que não preserva whitespace. Necessario adicionar <pre>.
16   -- mensagems de erro do assembler aparecem na mesma linha na correcao e nao fazerm rendering do `$t`, ver se servidor faz parse do markdown dessas mensagens.
17   -- a revisao do teste não mostra as imagens.
18   -- Test.reset_answers() unused.
19   -- teste nao esta a mostrar imagens de vez em quando.???
20   -- show-ref nao esta a funcionar na correccao (pelo menos)
  10 +- em admin, quando scale_max não é 20, as cores das barras continuam a reflectir
  11 + a escala 0,20. a tabela teste na DB não tem a escala desse teste.
  12 +- mensagems de erro do assembler aparecem na mesma linha na correcao e nao
  13 + fazerm rendering do `$t`, ver se servidor faz parse do markdown dessas
  14 + mensagens.
  15 +- a revisao do teste não mostra as imagens que nao estejam ja em cache.
21 16  
22   -# TODO
  17 +## TODO
23 18  
24   -- JOBE correct async
25   -- esta a corrigir código JOBE mesmo que nao tenha respondido???
26   -- permitir remover alunos que estão online para poderem comecar de novo.
27   -- guardar nota final grade truncado em zero e sem ser truncado (quando é necessário fazer correcções à mão às perguntas, é necessário o valor não truncado)
28   -- stress tests. use https://locust.io
29   -- wait for admin to start test. (students can be allowed earlier)
30   -- impedir os eventos copy/paste. alunos usam isso para trazer codigo ja feito nos computadores. Obrigar a fazer reset? fazer um copy automaticamente?
31   -- na pagina admin, mostrar com cor vermelha as horas de entrada dos alunos que ja tenham excedido o tempo
32   -- retornar None quando nao ha alteracoes relativamente à última vez.
33   -ou usar push (websockets?)
  19 +- QuestionTextArea falta reportar nos comments os vários erros que podem ocorrer
  20 + (timeout, etc)
  21 +- pergunta com varias partes.
  22 +- /review incluir identificacao do aluno no jumbotron (para poder gerar pdf).
  23 +- corrir mais que uma vez (por ex. para alterar cotacoes, corrigir perguntas)
  24 +- guardar testes em JSON assim que sao atribuidos aos alunos.
  25 +- impedir os eventos copy/paste. alunos usam isso para trazer codigo ja feito
  26 + nos computadores. Obrigar a fazer reset? fazer um copy automaticamente?
  27 +- na pagina admin, mostrar com cor vermelha as horas de entrada dos alunos que
  28 + ja tenham excedido o tempo
  29 +- /admin long pooling.
34 30 - mudar ref do test para test_id (ref já é usado nas perguntas)
35 31 - servidor ntpd no x220 para configurar a data/hora dos portateis dell
36   -- sala de espera: autorização dada, mas teste não disponível até que seja dada ordem para começar.
37   -- alunos com necessidades especiais nao podem ter autosubmit. ter um autosubmit_exceptions: ['123', '456']
38   -- submissao fazer um post ajax?
39   -- adicionar opcao para eliminar um teste em curso.
  32 +- sala de espera: autorização dada, mas teste não disponível até que seja dada
  33 + ordem para começar.
  34 +- alunos com necessidades especiais nao podem ter autosubmit. ter um
  35 + autosubmit_exceptions: ['123', '456']
40 36 - enviar resposta de cada pergunta individualmente.
41   -- experimentar gerador de svg que inclua no markdown da pergunta e ver se funciona.
42   -- quando ha varias perguntas para escolher, escolher sucessivamente em vez de aleatoriamente.
43   -- como refrescar a tabela de admin sem fazer reload da pagina?
44   -- botao "testar resposta" que valida codigo relativamente a syntax, mas nao classifica. perguntas devem ter opcao validate: script.py. Aluno pressiona botao e codigo é enviado para servidor para validação, feedback é mostrado na pagina de teste.
45   -- test: botao submeter valida se esta online com um post willing_to_submit, se estiver online, mostra mensagem de confirmacao, caso contrario avisa que nao esta online.
  37 +- experimentar gerador de svg que inclua no markdown da pergunta.
  38 +- botao "testar resposta" que valida syntax mas nao classifica.
  39 + perguntas devem ter opcao validate: script.py.
  40 + Aluno pressiona botao e codigo é enviado para servidor para validação,
  41 +- test: botao submeter valida se esta online com um post willing_to_submit,
  42 + se estiver online, mostra mensagem de confirmacao, caso contrario avisa que
  43 + nao esta online.
46 44 - test: Cada pergunta respondida é logo submetida.
47   -- test: calculadora javascript.
48 45 - admin: histograma das notas.
49 46 - admin: mostrar as horas a que o teste terminou para os testes terminados.
50 47 - admin: histograma das notas.
51 48 - admin: mostrar teste gerado para aluno (tipo review).
52   -- fazer renderer para formulas com mathjax serverside (mathjax-node) ou usar katex.
53   -- fazer renderer para imagens, com links /file?ref=xpto;name=zzz.jpg
54   -- fazer renderer para linguagem assembly mips?
55   -- cancelar teste no menu admin. Dado o numero de aluno remove teste e faz logout do aluno.
  49 +- admin: Cancelar teste e fazer logout do aluno (e.g. fraude)
56 50 - mathjax-node:
57 51 sudo pkg install node npm
58 52 npm install mathjax-node mathjax-node-cli # pacotes em ~/node_modules
59 53 node_modules/mathjax-node-cli/bin/tex2svg '\sqrt{x}'
60   - usar isto para gerar svg que passa a fazer parte do texto da pergunta (markdown suporta tags svg?)
  54 + usar isto para gerar svg que passa a fazer parte do texto da pergunta
  55 + (markdown suporta tags svg?)
61 56 fazer funçao tex() que recebe formula e converte para svg. exemplo:
62 57 fr'''A formula é {tex("\sqrt{x]}")}'''
63   -- Gerar pdf's com todos os testes no final (pdfkit).
64   -- manter registo dos unfocus durante o teste e de qual a pergunta visivel nesse momento
  58 +- Gerar pdf's com todos os testes no final (pdfkit, firefox marionette).
  59 +- registos unfocus durante o teste e qual a pergunta visivel nesse momento
65 60 - permitir varios testes, aluno escolhe qual o teste que quer fazer.
66 61 - se ocorrer um erro na correcçao avisar aluno para contactar o professor.
67   -- abrir o teste numa janela maximizada e que nao permite que o aluno a redimensione/mova?
68   -- detectar scroll e enviar posição para servidor (analise de scroll para detectar copianço? ou simplesmente para analisar como os alunos percorrem o teste)
69   -- aviso na pagina principal para quem usa browser incompativel ou settings esquisitos... Apos login pode ser enviado e submetido um exemplo de teste para verificar se browser consegue submeter? ha alunos com javascript bloqueado?
70   -- criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput
71   -- perguntas para professor corrigir mais tarde. permitir que review possa alterar as notas
72   -- fazer uma calculadora javascript e por no menu. surge como modal
73   -
74   -# FIXED
75   -
76   -- testar as perguntas todas no início do teste como o aprendizations.
77   -- adicionar identificacao do aluno no jumbotron inicial do teste, para que ao imprimir para pdf a identificacao do aluno venha escrita no documento.
78   -- internal server error quando em --review, download csv detalhado.
79   -- perguntas repetidas (mesma ref) dao asneira, porque a referencia é usada como chave em varios sitios e as chaves nao podem ser dupplicadas.
80   - da asneira pelo menos na funcao get_questions_csv. na base de dados tem de estar registado tb o numero da pergunta, caso contrario é impossível saber a qual corresponde.
81   -- mostrar unfocus e window area em /admin
82   -- CRITICAL se answer for `i<n` a revisão de provas mostra apenas i (interpreta `<` como tag?)
83   -- botao de autorizar desliga-se, fazer debounce.
84   -- link na pagina com a nota para voltar ao principio.
85   -- default logger config mostrar horas com segundos
86   -- test: mostrar duração do teste com progressbar no navbar.
87   -- lidar com eventos unfocus.
88   -- servidor nao esta a lidar com eventos resize.
89   -- sock.bind(sockaddr) OSError: [Errno 48] Address already in use
90   -- dizer quanto desconta em cada pergunta de escolha multipla
91   -- se houver erros a abrir ficheiros .yaml de perguntas, depois dos testes diz "No errors found".
92   -- se faltarem files na especificação do teste, o check não detecta e factory não gera para essas perguntas.
93   -- nao esta a usar points das perguntas
94   -- quando se clica no texto de uma opcao, salta para outro lado na pagina.
95   -- suportar cotacao to teste diferente de 20 (e.g. para juntar perguntas em papel). opcao "points: 18" que normaliza total para 18 em vez de 20.
96   -- fazer package para instalar perguntations com pip.
97   -- pymips: nao pode executar syscalls do spim.
98   -- exception sqlalchemy relacionada com threads.
99   -- acrescentar logger.conf que sirva de base.
100   -- questions.py textarea has a abspath which does not make sense! why is it there? not working for perguntations, but seems to work for aprendizations
101   -- textarea foi modificado em aprendizations para receber cmd line args. corrigir aqui tb.
102   -- usar npm para instalar javascript
103   -- se aluno entrar com l12345 rebenta. numa funcao get_... ver imagem no ipad
104   -- no test3 está contar 1.0 valores numa pergunta do tipo info? acontece para type: info, e não para type: information
105   -- default correct in checkbox must be 1.0, so that the pairs (right,wrong) still work with `correct` left undefined.
106   -- textarea com codemirror
107   -- decorador para user 0, evita o "if uid==0" em muitas funcoes.
108   -- numeric interval deve converter respostas que usam virgulas para pontos decimais
109   -- self.testapp.get_json_filename_of_test(test_id) retorna None quando test_id nao existe.
110   -- o eventloop está a bloquear. correção do teste é blocking. usar threadpoolexecutor?
111   -- substituir get_event_loop por get_runnint_loop (ver https://docs.python.org/3/library/asyncio-eventloop.html)
112   -- review nao esta a funcionar
113   -- servir imagens das perguntas não funciona. Necessario passar a ref da pergunta no link para poder ajustar o path no FileHandler.
114   -- a primeira coluna da tabela admin deveria estar sempre ordenada.
115   -- abortar depois de testar todas as perguntas, caso haja algum erro.
116   -- imagens jpg/png nas perguntas.
117   -- initdb está a inicializar com passwords iguais aos numeros. deveria ser vazio para alunos definirem.
118   -- upgrade popper e fazer link.
119   -- mover scripts js para head, com defer. ver todos os templates.
120   -- update fontawesome to 5.
121   -- mostrar comments e solution na revisao de prova.
122   -- upgrade para tornado 5.0.
123   -- ctrl-c should ask for confirmation before exiting.
124   -- md_to_html() nao usa o segundo argumento q. pode retirar-se dos templates?
125   -- config/logger.yaml ainda é do cherrypy...
126   -- uniformizar question.py com a de aprendizations...
127   -- qual a diferenca entre md_to_html e md_to_html_review, parece desnecessario haver dois.
128   -- converter markdown para mistune.
129   -- como alterar configuracao para mostrar logs de debug?
130   -- espaco no final das tabelas.
131   -- total do teste aparece negativo.
132   -- reset password nao funciona no admin
133   -- reload a intervalos não funciona.
134   -- allow/deny nao funciona no /admin.
135   -- Review de um teste que foi apagado rebenta.
136   -- numeracao das perguntas do teste esta a contar com paineis informativos...
137   -- markdown no teste nao funciona
138   -- review de um teste nao funciona (hardcoded...)
139   -- testar SSL
140   -- text-numeric não está a gerar a pergunta. faltam templates?
141   -- testar perguntas warning/warn
142   -- qd user 0 faz logout rebenta.
143   -- Quando grava JSON do teste deve usar 'path' tal como definido na configuração e não expandido. Isto porque em OSX /home é /Users e quando se muda de um sistema para outro não encontra os testes. Assim, usando ~ na configuração deveria funcionar sempre.
144   -- configuração do teste não joga bem com o do aprendizations. Em particular os scripts não ficam com o mesmo path!!!
145   -- configurar pf em freebsd, port forward 80 -> 8080. documentacao
146   -- barras com notas em grade estão desalinhadas.
147   -- erros nos generators devem ser ERROR e não WARNING.
148   -- se directorio "logs" não existir no directorio actual aborta com mensagem de erro.
149   -- se um teste tiver a mesma pergunta repetida (ref igual), rebenta na correcçao. As respostas são agregadas numa lista para cada ref. Ex: {'ref1': 'resposta1', 'ref2': ['resposta2a', 'resposta2b']}
150   -- usar http://fontawesome.io/examples/ em vez dos do bootstrap3
151   -- se pergunta tiver 'type:' errado, rebenta.
152   -- se submeter um teste so com information, da divisao por zero.
153   -- se save_answers nao existir, da warning que nao serao gravados, mas sao sempre gravados! pagina de administracao diz --not being saved--
154   -- first login é INFO e não WARNING
155   -- /review não mostra imagens porque precisa que teste esteja a decorrer...
156   -- visualizar um teste ja realizado na página de administração
157   -- Depois da correcção, mostra testes realizados que não foram realizados pelo próprio
158   -- detectar se janela perde focus e alertar o prof (http://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active)
159   -- server nao esta a receber eventos focus/blur dos utilizadores diferentes de '0', estranho...
160   -- permitir adicionar imagens nas perguntas.
161   -- detect_unfocus.js so funciona se estiver inline no html. porquê???
162   -- inserir novo aluno /admin não fecha.
163   -- se aluno desistir, ainda fica marcado como online
164   -- give dá None em vez de 0.0
165   -- debug mode: log levels not working
166   -- Se aluno fizer logout, o teste não é gravado e ficamos sem registo do teste que o aluno viu.
167   -- criar sqlalchemy sessions dentro de app de modo a estarem associadas a requests. ver se é facil usar with db:(...) para criar e fechar sessão.
168   -- sqlalchemy queixa-se de threads.
169   -- SQLAlchemy em vez da classe database.
170   -- replace sys.exit calls
171   -- if does not find questions, aborts silently
172   -- argumentos da linha de comando a funcionar.
173   -- configuracao dos logs cherrypy para se darem bem com os outros
174   -- browser e ip usados gravado no test.
175   -- botões allow all/deny all.
176   -- mostrar botão de reset apenas no final da pagina, com edit para escrever o número.
177   -- aluno faz login, mas fecha browser, ficando no estado (online,deny). Ao tentar login com outro browser está deny e o prof não consegue pô-lo em allow pois já não está na lista. => solucao é manter todos os alunos numa tabela.
178   -- pagina de login nao esta a apresentar bem. parece que precisa de autorizacao para aceder a /static...
179   -- Não mostrar Professor nos activos em /admin
180   -- /admin mostrar actualizações automaticamente?
181   -- se no teste uma das "ref" nao existir nos ficheiros de perguntas, rebenta.
182   -- alunos podem estar online, mas browser perder sessao => nao conseguem mais entrar porque a App pensa que estão online. Permitir login e dar o mesmo teste.
183   -- pagina de management dos alunos.
184   - mostrar online ordenados por hora de login, offline por número.
185   - permitir reset da pw e allow/disallow
186   -- script de correcção pode enviar dicionario yaml com grade e comentarios. ex:
187   - grade: 0.5
188   - comments: Falhou na função xpto.
189   - os comentários são guardados no teste (ficheiro) ou enviados para o browser no modo practice.
190   -- testar regex na definicao das perguntas. como se faz rawstring em yaml?
191   - singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. Solução (http://stackoverflow.com/questions/10771163/python-interpreting-a-regex-from-a-yaml-config-file) é fazer
192   - correct: !regex '^(yes|no)'
  62 +- abrir o teste numa janela maximizada e que nao permite que o aluno a
  63 + redimensione/mova? modo kiosk?
  64 +- detectar scroll e enviar posição para servidor (analise de scroll para detectar copianço?)
  65 +- criar perguntas de outros tipos, e.g. associação, ordenação.
  66 +- stress tests. use https://locust.io
... ...
demo/demo.yaml
... ... @@ -47,7 +47,7 @@ scale: [0, 20]
47 47 # ----------------------------------------------------------------------------
48 48 # Files to import. Each file contains a list of questions in yaml format.
49 49 files:
50   - - questions/questions-tutorial.yaml
  50 + - questions/tutorial.yaml
51 51  
52 52 # This is the list of questions that will make up the test.
53 53 # The order is preserved.
... ...
demo/questions/correct-question.py 0 → 100755
... ... @@ -0,0 +1,27 @@
  1 +#!/usr/bin/env python3
  2 +
  3 +'''
  4 +Demonstação de um script de correcção
  5 +'''
  6 +
  7 +import re
  8 +import sys
  9 +
  10 +s = sys.stdin.read()
  11 +
  12 +ans = set(re.findall(r'[\w]+', s.lower())) # get words in lowercase
  13 +rgb = set(['red', 'green', 'blue']) # the correct answer
  14 +
  15 +# a nota é o número de cores certas menos o número de erradas
  16 +grade = max(0,
  17 + len(rgb.intersection(ans)) - len(ans.difference(rgb))) / 3
  18 +
  19 +if ans == rgb:
  20 + print('---\n'
  21 + 'grade: 1.0\n'
  22 + 'comments: Muito bem!')
  23 +
  24 +else:
  25 + print('---\n'
  26 + f'grade: {grade}\n'
  27 + 'comments: A resposta correcta é "red green blue".')
... ...
demo/questions/correct-timeout.py 0 → 100755
... ... @@ -0,0 +1,12 @@
  1 +#!/usr/bin/env python3
  2 +
  3 +import sys
  4 +import time
  5 +
  6 +s = sys.stdin.read()
  7 +
  8 +# sleep a lot of time to generate timeout during correction
  9 +time.sleep(100)
  10 +
  11 +# probably this result will not be seen because the script will be interrupted
  12 +print(0.5)
... ...
demo/questions/correct/correct-question.py
... ... @@ -1,27 +0,0 @@
1   -#!/usr/bin/env python3
2   -
3   -'''
4   -Demonstação de um script de correcção
5   -'''
6   -
7   -import re
8   -import sys
9   -
10   -s = sys.stdin.read()
11   -
12   -ans = set(re.findall(r'[\w]+', s.lower())) # get words in lowercase
13   -rgb = set(['red', 'green', 'blue']) # the correct answer
14   -
15   -# a nota é o número de cores certas menos o número de erradas
16   -grade = max(0,
17   - len(rgb.intersection(ans)) - len(ans.difference(rgb))) / 3
18   -
19   -if ans == rgb:
20   - print('---\n'
21   - 'grade: 1.0\n'
22   - 'comments: Muito bem!')
23   -
24   -else:
25   - print('---\n'
26   - f'grade: {grade}\n'
27   - 'comments: A resposta correcta é "red green blue".')
demo/questions/correct/correct-timeout.py
... ... @@ -1,12 +0,0 @@
1   -#!/usr/bin/env python3
2   -
3   -import sys
4   -import time
5   -
6   -s = sys.stdin.read()
7   -
8   -# sleep a lot of time to generate timeout during correction
9   -time.sleep(100)
10   -
11   -# probably this result will not be seen because the script will be interrupted
12   -print(0.5)
demo/questions/questions-tutorial.yaml
... ... @@ -1,658 +0,0 @@
1   ----
2   -# ----------------------------------------------------------------------------
3   -- type: information
4   - ref: tut-test
5   - title: Configuração do teste
6   - text: |
7   - O teste é configurado num ficheiro `yaml`
8   - (ver especificação [aqui](https://yaml.org)).
9   - A configuração contém a identificação do teste, base de dados dos alunos,
10   - ficheiros de perguntas a importar e uma selecção de perguntas e respectivas
11   - cotações.
12   -
13   - Exemplo:
14   -
15   - ```yaml
16   - ---
17   - # --------------------------------------------------------------------------
18   - ref: tutorial # referência, pode ser reusada em vários turnos
19   - title: Demonstração # título da prova
20   - database: students.db # base de dados previamente criada com initdb
21   - answers_dir: ans # directório onde ficam os testes dos alunos
22   -
23   - # opcionais
24   - duration: 60 # duração da prova em minutos (default: inf)
25   - autosubmit: true # submissão automática (default: false)
26   - show_points: true # mostra cotação das perguntas (default: true)
27   - scale: [0, 20] # normaliza cotações para o intervalo indicado.
28   - # não normaliza por defeito (default: None)
29   -
30   - # --------------------------------------------------------------------------
31   - # Ficheiros de perguntas a importar (relativamente a `questions_dir`)
32   - files:
33   - - tabelas.yaml
34   - - topic1/questions.yaml
35   - - topic2/part1/questions.yaml
36   - - topic2/part2/questions.yaml
37   -
38   - # --------------------------------------------------------------------------
39   - # Especificação das perguntas do teste e respectivas cotações.
40   - # O teste é uma lista de perguntas, onde cada pergunta é especificada num
41   - # dicionário com a referência da pergunta e a respectiva cotação.
42   - questions:
43   - - ref: pergunta1
44   - points: 3.5
45   -
46   - - ref: pergunta2
47   - points: 2.0
48   -
49   - # por defeinto, a cotação da pergunta é 1.0 valor
50   - - ref: pergunta3
51   -
52   - # escolhe aleatoriamente uma das variantes da pergunta
53   - - ref: [pergunta3a, pergunta3b]
54   - points: 0.5
55   -
56   - # --------------------------------------------------------------------------
57   - ```
58   -
59   - A ordem das perguntas é mantida quando apresentada no teste.
60   -
61   - O mesmo teste pode ser realizado várias vezes em turnos diferentes, não é
62   - necessário alterar nada.
63   -
64   -# ----------------------------------------------------------------------------
65   -- type: information
66   - ref: tut-questions
67   - title: Especificação das perguntas
68   - text: |
69   - As perguntas estão definidas num ou mais ficheiros `yaml` como uma lista de
70   - perguntas, onde cada pergunta é um dicionário.
71   -
72   - Por exemplo, um ficheiro com o conteúdo abaixo contém duas perguntas, uma
73   - de escolha múltipla e outra apenas informativa:
74   -
75   - ```yaml
76   - ---
77   - #---------------------------------------------------------------------------
78   - - type: radio
79   - ref: chave-unica-1
80   - text: Quanto é $1+1$?
81   - options:
82   - - 1
83   - - 2
84   - - 3
85   -
86   - #---------------------------------------------------------------------------
87   - - type: information
88   - ref: chave-unica-2
89   - text: |
90   - Quando o texto da pergunta tem várias linhas, dá jeito usar o símbolo
91   - `|` de pipe, para indicar que tudo o que estiver indentado faz parte do
92   - texto. É o caso desta pergunta.
93   -
94   - O texto das perguntas é escrito em `markdown` e suporta fórmulas em
95   - LaTeX.
96   -
97   - #---------------------------------------------------------------------------
98   - ```
99   -
100   - As chaves são usadas para construir o teste e não se podem repetir, mesmo
101   - em ficheiros diferentes.
102   - De seguida mostram-se exemplos dos vários tipos de perguntas.
103   -
104   -# ----------------------------------------------------------------------------
105   -- type: radio
106   - ref: tut-radio
107   - title: Escolha simples, uma opção correcta.
108   - text: |
109   - As perguntas de escolha simples, permitem fazer uma pergunta e apresentar
110   - várias opções de resposta em que apenas uma delas está certa.
111   - A utilização mais simples é a seguinte:
112   -
113   - ```yaml
114   - - type: radio
115   - ref: pergunta-1
116   - title: Escolha simples, uma opção correcta.
117   - text: |
118   - Bla bla bla.
119   - options:
120   - - Opção 0
121   - - Opção 1
122   - - Opção 2
123   - - Opção 3
124   - - Opção 4
125   - ```
126   -
127   - Sem outras configurações, assume-se que a primeira opção é a resposta
128   - correcta ("Opção 0" neste caso) e as 5 opções são apresentadas por ordem
129   - aleatória.
130   -
131   - Para evitar que os alunos memorizem os textos das opções, podem definir-se
132   - várias opções correctas com escrita ligeiramente diferente, sendo escolhida
133   - apenas uma delas para apresentação.
134   - Por exemplo, se as 2 primeiras opções estiverem correctas e as restantes
135   - erradas, e quisermos apresentar ao aluno 3 opções no total, acrescenta-se:
136   -
137   - ```yaml
138   - correct: [1, 1, 0, 0, 0]
139   - choose: 3
140   - ```
141   -
142   - Neste caso, será escolhida uma opção certa e duas erradas.
143   - Os valores em `correct` representam o grau de correcção no intervalo [0, 1]
144   - onde 1 representa 100% certo e 0 representa 0%. Podem ser usados valores
145   - entre 0 e 1, sendo atribuída a respectiva cotação, mas só o valor 1
146   - representa uma opção certa.
147   -
148   - Por defeito, as opções são apresentadas por ordem aleatória, mas é possível
149   - usar a ordem predefinida. Por exemplo, para manter a ordem e indicar que a
150   - resposta correcta é a do meio define-se:
151   -
152   - ```yaml
153   - correct: [0, 0, 1, 0, 0]
154   - shuffle: false
155   - ```
156   -
157   - As respostas erradas descontam, tendo uma cotação de $-1/(n-1)$ do valor da
158   - pergunta, onde $n$ é o número de opções apresentadas ao aluno (a ideia é o
159   - valor esperado ser zero quando as respostas são aleatórias e uniformemente
160   - distribuídas). Para não descontar acrescenta-se:
161   -
162   - ```yaml
163   - discount: false
164   - ```
165   - options:
166   - - Opção 0 (certa)
167   - - Opção 1 (certa)
168   - - Opção 2
169   - - Opção 3
170   - - Opção 4
171   - correct: [1, 1, 0, 0, 0]
172   - choose: 3
173   - solution: |
174   - A solução correcta é a **Opção 0** ou a **Opção 1**.
175   -
176   -# ----------------------------------------------------------------------------
177   -- type: checkbox
178   - ref: tut-checkbox
179   - title: Escolha múltipla, várias opções correctas
180   - text: |
181   - As perguntas de escolha múltipla permitem apresentar um conjunto de opções
182   - podendo ser seleccionadas várias em simultâneo.
183   - Funcionam como múltiplas perguntas independentes de resposta sim/não.
184   -
185   - As respostas que devem ou não ser seleccionadas são indicadas com `1` e `0`
186   - ou com booleanos `true` e `false`.
187   - Cada resposta errada desconta um valor que é o simétrico da resposta certa.
188   - Se acertar uma opção ganha `+1`, se errar obtém `-1`.
189   -
190   - ```yaml
191   - - type: checkbox
192   - ref: tut-checkbox
193   - title: Escolha múltipla, várias opções correctas
194   - text: |
195   - Bla bla bla.
196   - options:
197   - - Opção 0 (certa)
198   - - Opção 1
199   - - Opção 2
200   - - Opção 3 (certa)
201   - - Opção 4
202   - correct: [1, 0, 0, 1, 0]
203   - ```
204   -
205   - Neste exemplo, seleccionando as opções 0 e 3 obtém-se cotação `+1` em cada
206   - uma, enquanto que seleccionando erradamente as opções 1, 2 e 4 obtém-se
207   - cotação `-1`.
208   - Do mesmo modo, não seleccionando as opções certas 0 e 3 obtém-se a cotação
209   - `-1` em cada uma, e não seleccionando (correctamente) as 1, 2 e 4 obtém-se
210   - `+1` em cada.
211   -
212   - *(Neste tipo de perguntas não há forma de responder a apenas algumas delas,
213   - são sempre todas corrigidas. Se um aluno só sabe a resposta a algumas das
214   - opções, deve ter cuidado porque as restantes também serão classificadas e
215   - arrisca-se a ter cotação negativa)*
216   -
217   - Cada opção pode opcionalmente ser escrita como uma afirmação e o seu
218   - contrário, de maneira a aumentar a variabilidade dos textos.
219   - Por exemplo:
220   -
221   - ```yaml
222   - options:
223   - - ['O céu é azul', 'O céu não é azul']
224   - - ['Um triangulo tem 3 lados', 'Um triangulo tem 2 lados']
225   - - O nosso planeta tem um satélite natural
226   - correct: [1, 1, 1]
227   - ```
228   -
229   - Assume-se que a primeira alternativa de cada opção tem a cotação indicada
230   - em `correct`, enquanto a segunda alternativa tem a cotação contrária.
231   -
232   - Tal como nas perguntas do tipo `radio`, podem ser usadas as configurações
233   - `shuffle` e `discount` com valor `false` para as desactivar.
234   - Se `discount` é `false` então as respostas erradas têm cotação 0 em vez do
235   - simétrico.
236   - options:
237   - - ['Opção 0 (sim)', 'Opção 0 (não)']
238   - - ['Opção 1 (não)', 'Opção 1 (sim)']
239   - - Opção 2 (não)
240   - - Opção 3 (sim)
241   - correct: [1, 0, 0, 1]
242   - shuffle: false
243   -
244   -# ----------------------------------------------------------------------------
245   -- type: text
246   - ref: tut-text
247   - title: Resposta de texto em linha
248   - text: |
249   - Este tipo de perguntas permite uma resposta numa linha de texto. A resposta
250   - está correcta se coincidir exactamente com alguma das respostas admissíveis.
251   -
252   - ```yaml
253   - - type: text
254   - ref: tut-text
255   - title: Resposta de texto em linha
256   - text: |
257   - De que cor é o céu?
258   -
259   - Escreva a resposta em português.
260   - correct: ['azul', 'Azul', 'AZUL']
261   - ```
262   -
263   - Neste caso, as respostas aceites são `azul`, `Azul` ou `AZUL`.
264   -
265   - Em alguns casos pode ser conveniente transformar a resposta antes de a
266   - comparar, por exemplo para remover espaços ou converter para minúsculas.
267   - A opção `transform` permite dar uma sequência de transformações a aplicar à
268   - resposta do aluno, por exemplo:
269   -
270   - ```yaml
271   - transform: ['trim', 'lower']
272   - correct: ['azul']
273   - ```
274   -
275   - Estão disponíveis as seguintes transformações:
276   -
277   - * `trim` remove os espaços do início e fim da resposta, os espaços do meio
278   - mantêm-se inalterados.
279   - * `remove_space` remove todos os espaços (início, meio e fim).
280   - * `normalize_space` remove espaços do início e fim (trim), e substitui
281   - múltiplos espaços por um único espaço (no meio).
282   - * `lower` e `upper` convertem respectivamente para minúsculas e maiúsculas.
283   - transform: ['trim', 'lower']
284   - correct: ['azul']
285   - solution: |
286   - O céu é `azul`, pelo menos durante o dia e se estiver bom tempo...
287   -
288   -# ---------------------------------------------------------------------------
289   -- type: text-regex
290   - ref: tut-text-regex
291   - title: Resposta de texto em linha, expressão regular
292   - text: |
293   - Este tipo de pergunta é semelhante à linha de texto da pergunta anterior.
294   - A única diferença é que esta é validada por uma expressão regular.
295   -
296   - ```yaml
297   - - type: text-regex
298   - ref: tut-text-regex
299   - title: Resposta de texto em linha
300   - text: |
301   - Bla bla bla
302   - correct: '(VERDE|[Vv]erde)'
303   - ```
304   -
305   - Neste exemplo a expressão regular é `(VERDE|[Vv]erde)`.
306   -
307   - Também se pode dar uma lista de expressões regulares. Nesse caso a resposta
308   - é considerada correcta se fizer match com alguma delas.
309   - No exemplo acima, poder-se-ia ter usado uma lista
310   -
311   - ```yaml
312   - correct:
313   - - 'VERDE'
314   - - '[Vv]erde'
315   - ```
316   -
317   - ---
318   -
319   - **Atenção:** A expressão regular deve seguir as convenções da suportadas em
320   - python (ver
321   - [Regular expression operations](https://docs.python.org/3/library/re.html)).
322   - Em particular, a expressão regular acima também aceita a resposta
323   - `verde, azul`.
324   - Deve marcar-se o início e final `^(VERDE|[Vv]erde)$` para evitar estas
325   - situações.
326   -
327   - correct: '(VERDE|[Vv]erde)'
328   - solution: |
329   - Deveria ter escrito `VERDE` ou `Verde` ou `verde`.
330   -
331   -# ---------------------------------------------------------------------------
332   -- type: numeric-interval
333   - ref: tut-numeric-interval
334   - title: Resposta numérica em linha de texto
335   - text: |
336   - Este tipo de perguntas esperam uma resposta numérica (vírgula flutuante).
337   - O resultado é considerado correcto se estiver dentro do intervalo fechado
338   - indicado.
339   -
340   - ```yaml
341   - - type: numeric-interval
342   - ref: tut-numeric-interval
343   - title: Resposta numérica em linha de texto
344   - text: |
345   - Escreva o número $\pi$ com pelo menos duas casa decimais.
346   - correct: [3.14, 3.15]
347   - ```
348   -
349   - Neste exemplo o intervalo de respostas correctas é o intervalo fechado
350   - [3.14, 3.15].
351   -
352   - Se em vez de dar um intervalo, apenas for indicado um valor numérico $n$,
353   - este é automaticamente convertido para para um intervalo $[n,n]$.
354   -
355   - **Atenção:** as respostas têm de usar o ponto como separador decimal.
356   - Em geral são aceites números inteiros, como `123`,
357   - ou em vírgula flutuante, como em `0.23`, `1e-3`.
358   - correct: [3.14, 3.15]
359   - solution: |
360   - Sabemos que $\pi\approx 3.14159265359$.
361   - Portanto, um exemplo de uma resposta correcta é `3.1416`.
362   -
363   -# ---------------------------------------------------------------------------
364   -- type: textarea
365   - ref: tut-textarea
366   - title: Resposta em múltiplas linhas de texto
367   - text: |
368   - Este tipo de perguntas permitem respostas em múltiplas linhas de texto e
369   - são as mais flexíveis.
370   -
371   - A resposta é enviada para um programa externo para ser avaliada.
372   - O programa externo é um programa que tem de ser executável pelo pelo
373   - sistema operativo (pode ser um binário ou script desde que o respectivo
374   - interpretador instalado).
375   - Este programa externo recebe a resposta submetida pelo aluno via `stdin` e
376   - devolve a classificação via `stdout`.
377   - Exemplo:
378   -
379   - ```yaml
380   - - type: textarea
381   - ref: tut-textarea
382   - title: Resposta em múltiplas linhas de texto
383   - text: |
384   - Bla bla bla
385   - correct: correct/correct-question.py # programa a executar
386   - timeout: 5
387   - ```
388   -
389   - Neste exemplo, o programa de avaliação é um script python que verifica se a
390   - resposta contém as três palavras red, green e blue, e calcula uma nota no
391   - intervalo 0.0 a 1.0.
392   - O programa externo é executado num processo separado e a interacção faz-se
393   - via stdin/stdout.
394   -
395   - Se o programa externo exceder o `timeout` indicado (em segundos),
396   - este é automaticamente terminado e é atribuída a classificação de 0.0
397   - valores na pergunta.
398   -
399   - Após terminar a correcção, o programa externo deve enviar a classificação
400   - para o stdout.
401   - Pode simplesmente fazer `print` da classificação como um número em vírgula
402   - flutuante, por exemplo
403   -
404   - ```yaml
405   - 0.75
406   - ```
407   -
408   - ou opcionalmente escrever em formato json ou yaml, eventualmente com um
409   - comentário que será arquivado com o teste.
410   - Exemplo:
411   -
412   - ```yaml
413   - grade: 0.5
414   - comments: |
415   - Esqueceu-se de algumas cores.
416   - A resposta correcta era `red green blue`.
417   - ```
418   -
419   - O comentário é mostrado na revisão de prova.
420   - answer: |
421   - Aqui o aluno escreve a resposta.
422   - Esta caixa aumenta de tamanho automaticamente e
423   - pode estar previamente preenchida como neste caso (use `answer: texto`).
424   - correct: correct/correct-question.py
425   - timeout: 5
426   - tests_right:
427   - - 'red green blue'
428   - # tests_wrong:
429   - # - 'blue gray yellow'
430   -
431   -# ---------------------------------------------------------------------------
432   -- type: information
433   - ref: tut-information
434   - title: Texto informativo
435   - text: |
436   - As perguntas deste tipo não contam para avaliação. O objectivo é fornecer
437   - instruções para os alunos, por exemplo tabelas para consulta, fórmulas, etc.
438   - Nesta, tal como em todos os tipos de perguntas podem escrever-se fórmulas
439   - em LaTeX. Exemplo:
440   -
441   - A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
442   - definida pela função densidade de probabilidade
443   -
444   - $$
445   - p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
446   - \exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
447   - $$
448   -
449   - ---
450   -
451   - ```yaml
452   - - type: information
453   - ref: tut-information
454   - title: Texto informativo
455   - text: |
456   - A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
457   - definida pela função densidade de probabilidade
458   -
459   - $$
460   - p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
461   - \exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
462   - $$
463   - ```
464   -
465   -# ---------------------------------------------------------------------------
466   -- type: success
467   - ref: tut-success
468   - title: Texto informativo (sucesso)
469   - text: |
470   - Não conta para avaliação. É apenas o aspecto gráfico que muda.
471   -
472   - Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com uma
473   - fonte e cor diferente.
474   - Também se podem escrever troços de código coloridos conforme a linguagem:
475   -
476   - ```C
477   - int main() {
478   - printf("Hello world!");
479   - return 0; // comentario
480   - }
481   - ```
482   -
483   - ---
484   -
485   - ```yaml
486   - - type: success
487   - ref: tut-success
488   - title: Texto informativo (sucesso)
489   - text: |
490   - Não conta para avaliação. É apenas o aspecto gráfico que muda.
491   -
492   - Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com
493   - uma fonte e cor diferente.
494   - Também se podem escrever troços de código coloridos conforme a
495   - linguagem:
496   -
497   - ```C
498   - int main() {
499   - printf("Hello world!");
500   - return 0; // comentario
501   - }
502   - ```
503   -
504   - ```
505   -
506   -# ---------------------------------------------------------------------------
507   -- type: warning
508   - ref: tut-warning
509   - title: Texto informativo (aviso)
510   - text: |
511   - Não conta para avaliação.
512   -
513   - Neste exemplo mostramos como se pode construir uma tabela como a seguinte:
514   -
515   - Left | Center | Right
516   - -----------------|:----------------:|----------:
517   - *hello* | $\sin(x^2)$ | $1600.00
518   - **world** | $\frac{1}{2\pi}$ | $12.50
519   - `code` | $\sqrt{\pi}$ | $1.99
520   -
521   - As tabelas podem conter Markdown e LaTeX e permitem alinhamento das colunas,
522   - mas o markdown é muito simples e não permite mais funcionalidades.
523   -
524   - ---
525   -
526   - ```yaml
527   - - type: warning
528   - ref: tut-warning
529   - title: Texto informativo (aviso)
530   - text: |
531   - Bla bla bla
532   -
533   - Left | Center | Right
534   - -----------------|:----------------:|----------:
535   - *hello* | $\sin(x^2)$ | $1600.00
536   - **world** | $\frac{1}{2\pi}$ | $12.50
537   - `code` | $\sqrt{\pi}$ | $1.99
538   - ```
539   -
540   -# ----------------------------------------------------------------------------
541   -- type: alert
542   - ref: tut-alert1
543   - title: Texto informativo (perigo) - versão 1
544   - text: |
545   - Não conta para avaliação. Texto importante.
546   -
547   - ![planetas](planets.png "Planetas do Sistema Solar")
548   -
549   - As imagens podem ser adicionadas usando a notação standard em markdown. Há
550   - duas possibilidads:
551   -
552   - - Imagens inline: não têm título definido e podem ser incluídas no meio de
553   - uma linha de texto usando`![alt text](image.jpg)`.
554   - - Imagens centradas com título: `![alt text](image.jpg "Título da imagem")`.
555   - O título é colocado por baixo da imagem. Pode ser uma string vazia.
556   -
557   -- type: alert
558   - ref: tut-alert2
559   - title: Texto informativo (perigo) - versão 2
560   - text: |
561   - Não conta para avaliação. Texto importante.
562   -
563   - ![planetas](planets.png "Planetas do Sistema Solar")
564   -
565   - As imagens podem ser adicionadas usando a notação standard em markdown. Há
566   - duas possibilidads:
567   -
568   - - Imagens inline: não têm título definido e podem ser incluídas no meio de
569   - uma linha de texto usando `![alt text](image.jpg)`.
570   - - Imagens centradas com título: `![alt text](image.jpg "Título da imagem")`.
571   - O título é colocado por baixo da imagem. Pode ser uma string vazia.
572   -
573   -# ----------------------------------------------------------------------------
574   -- type: information
575   - text: |
576   - This question is not included in the test and will not show up.
577   - It also lacks a "ref" and is automatically named
578   - `questions/questions-tutorial.yaml:0013`.
579   - A warning is shown on the console about this.
580   - The number at the end is the index position of this question.
581   - Indices start at 0.
582   -
583   -# ----------------------------------------------------------------------------
584   -- type: generator
585   - ref: tut-generator
586   - script: generate-question.py
587   - args: [1, 100]
588   -
589   -# ----------------------------------------------------------------------------
590   -- type: information
591   - ref: tut-yamllint
592   - title: Sugestões para validar yaml
593   - text: |
594   - Como os testes e perguntas são ficheiros `yaml`, é conveniente validar se
595   - estão correctamente definitos. Um *linter* recomendado é o `yamllint`. Pode
596   - ser instalado com `pip install yamllint` e usado do seguinte modo:
597   -
598   - ```sh
599   - yamllint test.yaml
600   - yamllint questions.yaml
601   - ```
602   -
603   - No caso de programas geradores de perguntas e programas de correcção de
604   - respostas pode usar-se um *pipe*:
605   -
606   - ```sh
607   - generate-question | yamllint -
608   - correct-answer | yamllint -
609   - ```
610   -
611   -# ----------------------------------------------------------------------------
612   -# - type: code
613   -# ref: tut-code
614   -# title: Submissão de código (JOBE)
615   -# text: |
616   -# É possível enviar código para ser compilado e executado por um servidor
617   -# JOBE instalado separadamente, ver [JOBE](https://github.com/trampgeek/jobe).
618   -
619   -# ```yaml
620   -# - type: code
621   -# ref: tut-code
622   -# title: Submissão de código (JOBE)
623   -# text: |
624   -# Escreva um programa em C que recebe uma string no standard input e
625   -# mostra a mensagem `hello ` seguida da string.
626   -# Por exemplo, se o input for `Maria`, o output deverá ser `hello Maria`.
627   -# language: c
628   -# correct:
629   -# - stdin: 'Maria'
630   -# stdout: 'hello Maria'
631   -# - stdin: 'xyz'
632   -# stdout: 'hello xyz'
633   -# ```
634   -
635   -# Existem várias linguagens suportadas pelo servidor JOBE (C, C++, Java,
636   -# Python2, Python3, Octave, Pascal, PHP).
637   -# O campo `correct` deverá ser uma lista de casos a testar.
638   -# Se um caso incluir `stdin`, este será enviado para o programa e o `stdout`
639   -# obtido será comparado com o declarado. A pergunta é considerada correcta se
640   -# todos os outputs coincidirem.
641   -
642   -# Por defeito é o usado o servidor JOBE declarado no teste. Para usar outro
643   -# diferente nesta pergunta usa-se a opção `server: 127.0.0.1` com o endereço
644   -# apropriado.
645   -# answer: |
646   -# #include <stdio.h>
647   -# int main() {
648   -# char name[20];
649   -# scanf("%s", name);
650   -# printf("hello %s", name);
651   -# }
652   -# # server: 192.168.1.85
653   -# language: c
654   -# correct:
655   -# - stdin: 'Maria'
656   -# stdout: 'hello Maria'
657   -# - stdin: 'xyz'
658   -# stdout: 'hello xyz'
demo/questions/tutorial.yaml 0 → 100644
... ... @@ -0,0 +1,609 @@
  1 +---
  2 +# ----------------------------------------------------------------------------
  3 +- type: information
  4 + ref: tut-test
  5 + title: Configuração do teste
  6 + text: |
  7 + O teste é configurado num ficheiro `yaml`
  8 + (ver especificação [aqui](https://yaml.org)).
  9 + A configuração contém a identificação do teste, base de dados dos alunos,
  10 + ficheiros de perguntas a importar e uma selecção de perguntas e respectivas
  11 + cotações.
  12 +
  13 + Exemplo:
  14 +
  15 + ```yaml
  16 + ---
  17 + # --------------------------------------------------------------------------
  18 + ref: tutorial # referência, pode ser reusada em vários turnos
  19 + title: Demonstração # título da prova
  20 + database: students.db # base de dados previamente criada com initdb
  21 + answers_dir: ans # directório onde ficam os testes dos alunos
  22 +
  23 + # opcionais
  24 + duration: 60 # duração da prova em minutos (default: inf)
  25 + autosubmit: true # submissão automática (default: false)
  26 + show_points: true # mostra cotação das perguntas (default: true)
  27 + scale: [0, 20] # normaliza cotações para o intervalo indicado.
  28 + # não normaliza por defeito (default: None)
  29 +
  30 + # --------------------------------------------------------------------------
  31 + # Ficheiros de perguntas a importar (relativamente a `questions_dir`)
  32 + files:
  33 + - tabelas.yaml
  34 + - topic1/questions.yaml
  35 + - topic2/part1/questions.yaml
  36 + - topic2/part2/questions.yaml
  37 +
  38 + # --------------------------------------------------------------------------
  39 + # Especificação das perguntas do teste e respectivas cotações.
  40 + # O teste é uma lista de perguntas, onde cada pergunta é especificada num
  41 + # dicionário com a referência da pergunta e a respectiva cotação.
  42 + questions:
  43 + - ref: pergunta1
  44 + points: 3.5
  45 +
  46 + - ref: pergunta2
  47 + points: 2.0
  48 +
  49 + # por defeinto, a cotação da pergunta é 1.0 valor
  50 + - ref: pergunta3
  51 +
  52 + # escolhe aleatoriamente uma das variantes da pergunta
  53 + - ref: [pergunta3a, pergunta3b]
  54 + points: 0.5
  55 +
  56 + # --------------------------------------------------------------------------
  57 + ```
  58 +
  59 + A ordem das perguntas é mantida quando apresentada no teste.
  60 +
  61 + O mesmo teste pode ser realizado várias vezes em turnos diferentes, não é
  62 + necessário alterar nada.
  63 +
  64 +# ----------------------------------------------------------------------------
  65 +- type: information
  66 + ref: tut-questions
  67 + title: Especificação das perguntas
  68 + text: |
  69 + As perguntas estão definidas num ou mais ficheiros `yaml` como uma lista de
  70 + perguntas, onde cada pergunta é um dicionário.
  71 +
  72 + Por exemplo, um ficheiro com o conteúdo abaixo contém duas perguntas, uma
  73 + de escolha múltipla e outra apenas informativa:
  74 +
  75 + ```yaml
  76 + ---
  77 + #---------------------------------------------------------------------------
  78 + - type: radio
  79 + ref: chave-unica-1
  80 + text: Quanto é $1+1$?
  81 + options:
  82 + - 1
  83 + - 2
  84 + - 3
  85 +
  86 + #---------------------------------------------------------------------------
  87 + - type: information
  88 + ref: chave-unica-2
  89 + text: |
  90 + Quando o texto da pergunta tem várias linhas, dá jeito usar o símbolo
  91 + `|` de pipe, para indicar que tudo o que estiver indentado faz parte do
  92 + texto. É o caso desta pergunta.
  93 +
  94 + O texto das perguntas é escrito em `markdown` e suporta fórmulas em
  95 + LaTeX.
  96 +
  97 + #---------------------------------------------------------------------------
  98 + ```
  99 +
  100 + As chaves são usadas para construir o teste e não se podem repetir, mesmo
  101 + em ficheiros diferentes.
  102 + De seguida mostram-se exemplos dos vários tipos de perguntas.
  103 +
  104 +# ----------------------------------------------------------------------------
  105 +- type: radio
  106 + ref: tut-radio
  107 + title: Escolha simples, uma opção correcta.
  108 + text: |
  109 + As perguntas de escolha simples, permitem fazer uma pergunta e apresentar
  110 + várias opções de resposta em que apenas uma delas está certa.
  111 + A utilização mais simples é a seguinte:
  112 +
  113 + ```yaml
  114 + - type: radio
  115 + ref: pergunta-1
  116 + title: Escolha simples, uma opção correcta.
  117 + text: |
  118 + Bla bla bla.
  119 + options:
  120 + - Opção 0
  121 + - Opção 1
  122 + - Opção 2
  123 + - Opção 3
  124 + - Opção 4
  125 + ```
  126 +
  127 + Sem outras configurações, assume-se que a primeira opção é a resposta
  128 + correcta ("Opção 0" neste caso) e as 5 opções são apresentadas por ordem
  129 + aleatória.
  130 +
  131 + Para evitar que os alunos memorizem os textos das opções, podem definir-se
  132 + várias opções correctas com escrita ligeiramente diferente, sendo escolhida
  133 + apenas uma delas para apresentação.
  134 + Por exemplo, se as 2 primeiras opções estiverem correctas e as restantes
  135 + erradas, e quisermos apresentar ao aluno 3 opções no total, acrescenta-se:
  136 +
  137 + ```yaml
  138 + correct: [1, 1, 0, 0, 0]
  139 + choose: 3
  140 + ```
  141 +
  142 + Neste caso, será escolhida uma opção certa e duas erradas.
  143 + Os valores em `correct` representam o grau de correcção no intervalo [0, 1]
  144 + onde 1 representa 100% certo e 0 representa 0%. Podem ser usados valores
  145 + entre 0 e 1, sendo atribuída a respectiva cotação, mas só o valor 1
  146 + representa uma opção certa.
  147 +
  148 + Por defeito, as opções são apresentadas por ordem aleatória, mas é possível
  149 + usar a ordem predefinida. Por exemplo, para manter a ordem e indicar que a
  150 + resposta correcta é a do meio define-se:
  151 +
  152 + ```yaml
  153 + correct: [0, 0, 1, 0, 0]
  154 + shuffle: false
  155 + ```
  156 +
  157 + As respostas erradas descontam, tendo uma cotação de $-1/(n-1)$ do valor da
  158 + pergunta, onde $n$ é o número de opções apresentadas ao aluno (a ideia é o
  159 + valor esperado ser zero quando as respostas são aleatórias e uniformemente
  160 + distribuídas). Para não descontar acrescenta-se:
  161 +
  162 + ```yaml
  163 + discount: false
  164 + ```
  165 + options:
  166 + - Opção 0 (certa)
  167 + - Opção 1 (certa)
  168 + - Opção 2
  169 + - Opção 3
  170 + - Opção 4
  171 + correct: [1, 1, 0, 0, 0]
  172 + choose: 3
  173 + solution: |
  174 + A solução correcta é a **Opção 0** ou a **Opção 1**.
  175 +
  176 +# ----------------------------------------------------------------------------
  177 +- type: checkbox
  178 + ref: tut-checkbox
  179 + title: Escolha múltipla, várias opções correctas
  180 + text: |
  181 + As perguntas de escolha múltipla permitem apresentar um conjunto de opções
  182 + podendo ser seleccionadas várias em simultâneo.
  183 + Funcionam como múltiplas perguntas independentes de resposta sim/não.
  184 +
  185 + As respostas que devem ou não ser seleccionadas são indicadas com `1` e `0`
  186 + ou com booleanos `true` e `false`.
  187 + Cada resposta errada desconta um valor que é o simétrico da resposta certa.
  188 + Se acertar uma opção ganha `+1`, se errar obtém `-1`.
  189 +
  190 + ```yaml
  191 + - type: checkbox
  192 + ref: tut-checkbox
  193 + title: Escolha múltipla, várias opções correctas
  194 + text: |
  195 + Bla bla bla.
  196 + options:
  197 + - Opção 0 (certa)
  198 + - Opção 1
  199 + - Opção 2
  200 + - Opção 3 (certa)
  201 + - Opção 4
  202 + correct: [1, 0, 0, 1, 0]
  203 + ```
  204 +
  205 + Neste exemplo, seleccionando as opções 0 e 3 obtém-se cotação `+1` em cada
  206 + uma, enquanto que seleccionando erradamente as opções 1, 2 e 4 obtém-se
  207 + cotação `-1`.
  208 + Do mesmo modo, não seleccionando as opções certas 0 e 3 obtém-se a cotação
  209 + `-1` em cada uma, e não seleccionando (correctamente) as 1, 2 e 4 obtém-se
  210 + `+1` em cada.
  211 +
  212 + *(Neste tipo de perguntas não há forma de responder a apenas algumas delas,
  213 + são sempre todas corrigidas. Se um aluno só sabe a resposta a algumas das
  214 + opções, deve ter cuidado porque as restantes também serão classificadas e
  215 + arrisca-se a ter cotação negativa)*
  216 +
  217 + Cada opção pode opcionalmente ser escrita como uma afirmação e o seu
  218 + contrário, de maneira a aumentar a variabilidade dos textos.
  219 + Por exemplo:
  220 +
  221 + ```yaml
  222 + options:
  223 + - ['O céu é azul', 'O céu não é azul']
  224 + - ['Um triangulo tem 3 lados', 'Um triangulo tem 2 lados']
  225 + - O nosso planeta tem um satélite natural
  226 + correct: [1, 1, 1]
  227 + ```
  228 +
  229 + Assume-se que a primeira alternativa de cada opção tem a cotação indicada
  230 + em `correct`, enquanto a segunda alternativa tem a cotação contrária.
  231 +
  232 + Tal como nas perguntas do tipo `radio`, podem ser usadas as configurações
  233 + `shuffle` e `discount` com valor `false` para as desactivar.
  234 + Se `discount` é `false` então as respostas erradas têm cotação 0 em vez do
  235 + simétrico.
  236 + options:
  237 + - ['Opção 0 (sim)', 'Opção 0 (não)']
  238 + - ['Opção 1 (não)', 'Opção 1 (sim)']
  239 + - Opção 2 (não)
  240 + - Opção 3 (sim)
  241 + correct: [1, 0, 0, 1]
  242 + shuffle: false
  243 +
  244 +# ----------------------------------------------------------------------------
  245 +- type: text
  246 + ref: tut-text
  247 + title: Resposta de texto em linha
  248 + text: |
  249 + Este tipo de perguntas permite uma resposta numa linha de texto. A resposta
  250 + está correcta se coincidir exactamente com alguma das respostas admissíveis.
  251 +
  252 + ```yaml
  253 + - type: text
  254 + ref: tut-text
  255 + title: Resposta de texto em linha
  256 + text: |
  257 + De que cor é o céu?
  258 +
  259 + Escreva a resposta em português.
  260 + correct: ['azul', 'Azul', 'AZUL']
  261 + ```
  262 +
  263 + Neste caso, as respostas aceites são `azul`, `Azul` ou `AZUL`.
  264 +
  265 + Em alguns casos pode ser conveniente transformar a resposta antes de a
  266 + comparar, por exemplo para remover espaços ou converter para minúsculas.
  267 + A opção `transform` permite dar uma sequência de transformações a aplicar à
  268 + resposta do aluno, por exemplo:
  269 +
  270 + ```yaml
  271 + transform: ['trim', 'lower']
  272 + correct: ['azul']
  273 + ```
  274 +
  275 + Estão disponíveis as seguintes transformações:
  276 +
  277 + * `trim` remove os espaços do início e fim da resposta, os espaços do meio
  278 + mantêm-se inalterados.
  279 + * `remove_space` remove todos os espaços (início, meio e fim).
  280 + * `normalize_space` remove espaços do início e fim (trim), e substitui
  281 + múltiplos espaços por um único espaço (no meio).
  282 + * `lower` e `upper` convertem respectivamente para minúsculas e maiúsculas.
  283 + transform: ['trim', 'lower']
  284 + correct: ['azul']
  285 + solution: |
  286 + O céu é `azul`, pelo menos durante o dia e se estiver bom tempo...
  287 +
  288 +# ---------------------------------------------------------------------------
  289 +- type: text-regex
  290 + ref: tut-text-regex
  291 + title: Resposta de texto em linha, expressão regular
  292 + text: |
  293 + Este tipo de pergunta é semelhante à linha de texto da pergunta anterior.
  294 + A única diferença é que esta é validada por uma expressão regular.
  295 +
  296 + ```yaml
  297 + - type: text-regex
  298 + ref: tut-text-regex
  299 + title: Resposta de texto em linha
  300 + text: |
  301 + Bla bla bla
  302 + correct: '(VERDE|[Vv]erde)'
  303 + ```
  304 +
  305 + Neste exemplo a expressão regular é `(VERDE|[Vv]erde)`.
  306 +
  307 + Também se pode dar uma lista de expressões regulares. Nesse caso a resposta
  308 + é considerada correcta se fizer match com alguma delas.
  309 + No exemplo acima, poder-se-ia ter usado uma lista
  310 +
  311 + ```yaml
  312 + correct:
  313 + - 'VERDE'
  314 + - '[Vv]erde'
  315 + ```
  316 +
  317 + ---
  318 +
  319 + **Atenção:** A expressão regular deve seguir as convenções da suportadas em
  320 + python (ver
  321 + [Regular expression operations](https://docs.python.org/3/library/re.html)).
  322 + Em particular, a expressão regular acima também aceita a resposta
  323 + `verde, azul`.
  324 + Deve marcar-se o início e final `^(VERDE|[Vv]erde)$` para evitar estas
  325 + situações.
  326 +
  327 + correct: '(VERDE|[Vv]erde)'
  328 + solution: |
  329 + Deveria ter escrito `VERDE` ou `Verde` ou `verde`.
  330 +
  331 +# ---------------------------------------------------------------------------
  332 +- type: numeric-interval
  333 + ref: tut-numeric-interval
  334 + title: Resposta numérica em linha de texto
  335 + text: |
  336 + Este tipo de perguntas esperam uma resposta numérica (vírgula flutuante).
  337 + O resultado é considerado correcto se estiver dentro do intervalo fechado
  338 + indicado.
  339 +
  340 + ```yaml
  341 + - type: numeric-interval
  342 + ref: tut-numeric-interval
  343 + title: Resposta numérica em linha de texto
  344 + text: |
  345 + Escreva o número $\pi$ com pelo menos duas casa decimais.
  346 + correct: [3.14, 3.15]
  347 + ```
  348 +
  349 + Neste exemplo o intervalo de respostas correctas é o intervalo fechado
  350 + [3.14, 3.15].
  351 +
  352 + Se em vez de dar um intervalo, apenas for indicado um valor numérico $n$,
  353 + este é automaticamente convertido para para um intervalo $[n,n]$.
  354 +
  355 + **Atenção:** as respostas têm de usar o ponto como separador decimal.
  356 + Em geral são aceites números inteiros, como `123`,
  357 + ou em vírgula flutuante, como em `0.23`, `1e-3`.
  358 + correct: [3.14, 3.15]
  359 + solution: |
  360 + Sabemos que $\pi\approx 3.14159265359$.
  361 + Portanto, um exemplo de uma resposta correcta é `3.1416`.
  362 +
  363 +# ---------------------------------------------------------------------------
  364 +- type: textarea
  365 + ref: tut-textarea
  366 + title: Resposta em múltiplas linhas de texto
  367 + text: |
  368 + Este tipo de perguntas permitem respostas em múltiplas linhas de texto e
  369 + são as mais flexíveis.
  370 +
  371 + A resposta é enviada para um programa externo para ser avaliada.
  372 + O programa externo é um programa que tem de ser executável pelo pelo
  373 + sistema operativo (pode ser um binário ou script desde que o respectivo
  374 + interpretador instalado).
  375 + Este programa externo recebe a resposta submetida pelo aluno via `stdin` e
  376 + devolve a classificação via `stdout`.
  377 + Exemplo:
  378 +
  379 + ```yaml
  380 + - type: textarea
  381 + ref: tut-textarea
  382 + title: Resposta em múltiplas linhas de texto
  383 + text: |
  384 + Bla bla bla
  385 + correct: correct-question.py # programa a executar
  386 + timeout: 5
  387 + ```
  388 +
  389 + Neste exemplo, o programa de avaliação é um script python que verifica se a
  390 + resposta contém as três palavras red, green e blue, e calcula uma nota no
  391 + intervalo 0.0 a 1.0.
  392 + O programa externo é executado num processo separado e a interacção faz-se
  393 + via stdin/stdout.
  394 +
  395 + Se o programa externo exceder o `timeout` indicado (em segundos),
  396 + este é automaticamente terminado e é atribuída a classificação de 0.0
  397 + valores na pergunta.
  398 +
  399 + Após terminar a correcção, o programa externo deve enviar a classificação
  400 + para o stdout.
  401 + Pode simplesmente fazer `print` da classificação como um número em vírgula
  402 + flutuante, por exemplo
  403 +
  404 + ```yaml
  405 + 0.75
  406 + ```
  407 +
  408 + ou opcionalmente escrever em formato json ou yaml, eventualmente com um
  409 + comentário que será arquivado com o teste.
  410 + Exemplo:
  411 +
  412 + ```yaml
  413 + grade: 0.5
  414 + comments: |
  415 + Esqueceu-se de algumas cores.
  416 + A resposta correcta era `red green blue`.
  417 + ```
  418 +
  419 + O comentário é mostrado na revisão de prova.
  420 + answer: |
  421 + Aqui o aluno escreve a resposta.
  422 + Esta caixa aumenta de tamanho automaticamente e
  423 + pode estar previamente preenchida como neste caso (use `answer: texto`).
  424 + correct: correct-question.py
  425 + timeout: 5
  426 + tests_right:
  427 + - 'red green blue'
  428 + # tests_wrong:
  429 + # - 'blue gray yellow'
  430 +
  431 +# ---------------------------------------------------------------------------
  432 +- type: information
  433 + ref: tut-information
  434 + title: Texto informativo
  435 + text: |
  436 + As perguntas deste tipo não contam para avaliação. O objectivo é fornecer
  437 + instruções para os alunos, por exemplo tabelas para consulta, fórmulas, etc.
  438 + Nesta, tal como em todos os tipos de perguntas podem escrever-se fórmulas
  439 + em LaTeX. Exemplo:
  440 +
  441 + A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
  442 + definida pela função densidade de probabilidade
  443 +
  444 + $$
  445 + p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
  446 + \exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
  447 + $$
  448 +
  449 + ---
  450 +
  451 + ```yaml
  452 + - type: information
  453 + ref: tut-information
  454 + title: Texto informativo
  455 + text: |
  456 + A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
  457 + definida pela função densidade de probabilidade
  458 +
  459 + $$
  460 + p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
  461 + \exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
  462 + $$
  463 + ```
  464 +
  465 +# ---------------------------------------------------------------------------
  466 +- type: success
  467 + ref: tut-success
  468 + title: Texto informativo (sucesso)
  469 + text: |
  470 + Não conta para avaliação. É apenas o aspecto gráfico que muda.
  471 +
  472 + Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com uma
  473 + fonte e cor diferente.
  474 + Também se podem escrever troços de código coloridos conforme a linguagem:
  475 +
  476 + ```C
  477 + int main() {
  478 + printf("Hello world!");
  479 + return 0; // comentario
  480 + }
  481 + ```
  482 +
  483 + ---
  484 +
  485 + ```yaml
  486 + - type: success
  487 + ref: tut-success
  488 + title: Texto informativo (sucesso)
  489 + text: |
  490 + Não conta para avaliação. É apenas o aspecto gráfico que muda.
  491 +
  492 + Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com
  493 + uma fonte e cor diferente.
  494 + Também se podem escrever troços de código coloridos conforme a
  495 + linguagem:
  496 +
  497 + ```C
  498 + int main() {
  499 + printf("Hello world!");
  500 + return 0; // comentario
  501 + }
  502 + ```
  503 +
  504 + ```
  505 +
  506 +# ---------------------------------------------------------------------------
  507 +- type: warning
  508 + ref: tut-warning
  509 + title: Texto informativo (aviso)
  510 + text: |
  511 + Não conta para avaliação.
  512 +
  513 + Neste exemplo mostramos como se pode construir uma tabela como a seguinte:
  514 +
  515 + Left | Center | Right
  516 + -----------------|:----------------:|----------:
  517 + *hello* | $\sin(x^2)$ | $1600.00
  518 + **world** | $\frac{1}{2\pi}$ | $12.50
  519 + `code` | $\sqrt{\pi}$ | $1.99
  520 +
  521 + As tabelas podem conter Markdown e LaTeX e permitem alinhamento das colunas,
  522 + mas o markdown é muito simples e não permite mais funcionalidades.
  523 +
  524 + ---
  525 +
  526 + ```yaml
  527 + - type: warning
  528 + ref: tut-warning
  529 + title: Texto informativo (aviso)
  530 + text: |
  531 + Bla bla bla
  532 +
  533 + Left | Center | Right
  534 + -----------------|:----------------:|----------:
  535 + *hello* | $\sin(x^2)$ | $1600.00
  536 + **world** | $\frac{1}{2\pi}$ | $12.50
  537 + `code` | $\sqrt{\pi}$ | $1.99
  538 + ```
  539 +
  540 +# ----------------------------------------------------------------------------
  541 +- type: alert
  542 + ref: tut-alert1
  543 + title: Texto informativo (perigo) - versão 1
  544 + text: |
  545 + Não conta para avaliação. Texto importante.
  546 +
  547 + ![planetas](planets.png "Planetas do Sistema Solar")
  548 +
  549 + As imagens podem ser adicionadas usando a notação standard em markdown. Há
  550 + duas possibilidads:
  551 +
  552 + - Imagens inline: não têm título definido e podem ser incluídas no meio de
  553 + uma linha de texto usando`![alt text](image.jpg)`.
  554 + - Imagens centradas com título: `![alt text](image.jpg "Título da imagem")`.
  555 + O título é colocado por baixo da imagem. Pode ser uma string vazia.
  556 +
  557 +- type: alert
  558 + ref: tut-alert2
  559 + title: Texto informativo (perigo) - versão 2
  560 + text: |
  561 + Não conta para avaliação. Texto importante.
  562 +
  563 + ![planetas](planets.png "Planetas do Sistema Solar")
  564 +
  565 + As imagens podem ser adicionadas usando a notação standard em markdown. Há
  566 + duas possibilidads:
  567 +
  568 + - Imagens inline: não têm título definido e podem ser incluídas no meio de
  569 + uma linha de texto usando `![alt text](image.jpg)`.
  570 + - Imagens centradas com título: `![alt text](image.jpg "Título da imagem")`.
  571 + O título é colocado por baixo da imagem. Pode ser uma string vazia.
  572 +
  573 +# ----------------------------------------------------------------------------
  574 +- type: information
  575 + text: |
  576 + This question is not included in the test and will not show up.
  577 + It also lacks a "ref" and is automatically named
  578 + `questions/questions-tutorial.yaml:0013`.
  579 + A warning is shown on the console about this.
  580 + The number at the end is the index position of this question.
  581 + Indices start at 0.
  582 +
  583 +# ----------------------------------------------------------------------------
  584 +- type: generator
  585 + ref: tut-generator
  586 + script: generate-question.py
  587 + args: [1, 100]
  588 +
  589 +# ----------------------------------------------------------------------------
  590 +- type: information
  591 + ref: tut-yamllint
  592 + title: Sugestões para validar yaml
  593 + text: |
  594 + Como os testes e perguntas são ficheiros `yaml`, é conveniente validar se
  595 + estão correctamente definitos. Um *linter* recomendado é o `yamllint`. Pode
  596 + ser instalado com `pip install yamllint` e usado do seguinte modo:
  597 +
  598 + ```sh
  599 + yamllint test.yaml
  600 + yamllint questions.yaml
  601 + ```
  602 +
  603 + No caso de programas geradores de perguntas e programas de correcção de
  604 + respostas pode usar-se um *pipe*:
  605 +
  606 + ```sh
  607 + generate-question | yamllint -
  608 + correct-answer | yamllint -
  609 + ```
... ...