Tenho um amigo que me usa para suporte ao LaTeX. Ele não é muito experiente em tecnologia, mas gosta de LaTeX e então eu o ajudo quando algo que ele precisa fazer requer mais do que o estoque padrão de macros e ambientes.
Gostamos de pregar peças um no outro. Eu tive a ideia de fazer uma pegadinha com ele na próxima vez que ele pedir ajuda ao LaTeX, fazendo algo relativamente benigno e facilmente reversível que alteraria visivelmente o PDF gerado --- ou fazer algo perceptível no uso normal do (La)TeX, comoprolongando a compilação--- de uma forma indesejada, onde a origem do problema seria difícil de detectar (então seria um caso de trollagem de código, suponho). Porém, eu não sou muito bom em LaTeX e pensei em pedir sugestões criativas aos TeXperts.
Como posso causar dificuldades relacionadas ao (La)TeX para meu amigo?
Responder1
Adicione ao aux
arquivo o seguinte trecho de código, que é um quine. Quando o aux
arquivo está \input
no início de uma execução do LaTeX, o código aqui irá construir uma cópia de si mesmo e gravá-la no aux
arquivo para a próxima execução. Além disso, ele executará o código contido \toks2
abaixo. Por exemplo, o código que escolhi aumenta o tamanho do recuo em cada parágrafo, mas apenas se o TeX for executado em um minuto ímpar: os resultados dependem de quando seu amigo compila.
{%
\toks@{%
\ifx\@nodocument\relax\else
\toks2{% Here you put whatever mean code you want
\ifodd\time
\everypar\expandafter{%
\the\everypar
\advance\parindent 2pt\relax
}%
\fi
}% end of \toks2
\edef\x{%
\noexpand\AtBeginDocument{%
\the\toks2\relax
\toks@{\the\toks@}%
\immediate\write\@auxout{%
{%
\toks@{\noexpand\the\toks@}%
\noexpand\noexpand\noexpand\the\toks@
}% end of brace group
}% end of \immediate\write\@auxout
}% end of \AtBeginDocument
}% end of \edef
\x
\fi
}%
\the\toks@
}
Após uma execução, o aux
arquivo conterá a seguinte versão condensada (em uma única linha)
{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar
\expandafter {\the \everypar \advance \parindent 2pt\relax }\fi }\edef
\x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@
}\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand
\noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }
e as execuções subsequentes deixarão a mesma versão condensada (novamente em uma linha).
Vamos ver o que acontece em detalhes: dentro de um grupo (simples), o registrador do token \toks@
é definido com algum valor e então seu conteúdo é usado. O que esses conteúdos fazem? Existe um teste para verificar se estamos lendo o arquivo aux no início ou no final da execução: \@nodocument
é \relax
no segundo caso e não fazemos nada. Em seguida, o registro toks \toks2
é definido com o código que você realmente deseja executar. A \edef\x{...}\x
construção a seguir expande o ...
para
\AtBeginDocument{%
<contents of \toks2>\relax
\toks@{<contents of \toks@>}%
\immediate\write\@auxout{%
{%
\toks@{\the\toks@}%
\noexpand\the\toks@
}% end of brace group
}% end of \immediate\write\@auxout
}% end of \AtBeginDocument
em seguida, executa esse código. \AtBeginDocument
irá executar seu argumento um pouco mais tarde, quando o LaTeX estiver novamente pronto para escrever no aux
arquivo (atualmente ele o está lendo). Assim, quando o LaTeX estiver pronto para gravar no aux
arquivo, ele executa seu código (que foi armazenado temporariamente em \toks2
), depois armazena o <contents of \toks@>
registro de volta \toks@
(esse registro de token pode ter sido usado por outro código intermediário) e grava o seguinte no aux
arquivo (lembre-se que \write
expande):
{%
\toks@{<contents of \toks@>}%
\the\toks@
}% end of brace group
Este é precisamente o código original, que acaba no aux
arquivo para a próxima execução do LaTeX.
Esperançosamente, o código que escolhi inserir \toks2
é fácil de seguir:
\ifodd\time
\everypar\expandafter{%
\the\everypar
\advance\parindent 2pt\relax
}%
\fi
se o tempo (em minutos desde o início do dia) for um número ímpar, então, a cada parágrafo, faça o que já foi feito em cada parágrafo e também avance (aumente) o recuo do parágrafo ( \parindent
) em 2 pontos. Por exemplo, digamos que você adicione o primeiro ou o segundo trechos de código acima ao aux
arquivo gerado pela execução pdflatex
do documento abaixo. Então o documento será normal se compilado em um minuto par e, caso contrário, terá um recuo de parágrafo cada vez maior.
\documentclass{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-10]
\end{document}
Responder2
Compilar com LuaLaTeX
\documentclass{article}
\usepackage{lipsum}
^^5c^^75^^73^^65^^70^^61^^63^^6b^^61^^67^^65^^20
^^7b^^63^^68^^69^^63^^6b^^65^^6e^^69^^7a^^65^^7d
^^5c^^72^^61^^6e^^64^^6f^^6d^^75^^63^^6c^^63^^20
\begin{document}
\lipsum[1]
\end{document}
Além disso, \randomerror
em vez de \randomuclc
pode ser legal.
Responder3
Por favor, siga as instruções após cada corrida, você pode estar no caminho certo:)
Para quem não se atreveu a tentar, o que ele faz é produzir uma mensagem de erro (aqui de um buffer de ajuda do emacs tex), onde o número da página é aleatório:
ERROR: LaTeX Error: I'm stymied; problem of unknown type on page 2
--- TeX said ---
Re-run LaTeX at least three times to give a chance to the kernel
to re-examine this intriguing problem.
You may have encountered one of the $1,000,000 kernel bug.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.49 \end{document}
--- HELP ---
From the .log file...
You're in trouble here. Try typing <return> to proceed.
If that doesn't work, type X <return> to quit.
e além disso esta mensagem aparece após atrasos cada vez maiores no final de cada nova compilação (o tempo de compilação é da ordem de n^2/2
segundos onde n
é o número de execuções anteriores).
A conversão hexadecimal para ofuscar o código é um pouco longa, talvez seja possível usar números hexa apenas para ofuscar \input
onde o arquivo conteria o código abaixo.
\documentclass{article}
\usepackage{lipsum}
^^5c^^6d^^61^^6b^^65^^61^^74^^6c^^65^^74^^74^^65^^72
^^5c^^41^^74^^45^^6e^^64^^44^^6f^^63^^75^^6d^^65^^6e^^74^^20^^7b%
^^5c^^40^^69^^66^^75^^6e^^64^^65^^66^^69^^6e^^65^^64^^7b^^40^^6b^^65^^72%
^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7d^^7b%
^^5c^^67^^64^^65^^66
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7b%
^^30^^7d^^7d^^7b^^7d^^5c^^69^^6d^^6d^^65^^64^^69^^61^^74^^65
^^5c^^77^^72^^69^^74^^65^^20^^5c^^40^^61^^75^^78^^6f^^75^^74^^7b%
^^5c^^67^^64^^65^^66^^20^^5c^^6e^^6f^^65^^78^^70^^61^^6e^^64
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7b%
^^5c^^74^^68^^65^^20^^5c^^6e^^75^^6d^^65^^78^^70^^72
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^2b^^32^^2a%
^^5c^^70^^64^^66^^75^^6e^^69^^66^^6f^^72^^6d^^64^^65^^76^^69^^61^^74^^65
^^36^^35^^35^^33^^36^^5c^^72^^65^^6c^^61^^78^^20^^7d^^7d%
^^5c^^70^^64^^66^^72^^65^^73^^65^^74^^74^^69^^6d^^65^^72
^^5c^^6c^^6f^^6f^^70^^20^^5c^^69^^66^^6e^^75^^6d
^^5c^^70^^64^^66^^65^^6c^^61^^70^^73^^65^^64^^74^^69^^6d^^65^^20^^3c%
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65%
^^5c^^73^^70^^61^^63^^65^^20^^5c^^72^^65^^70^^65^^61^^74
^^5c^^40^^6c^^61^^74^^65^^78^^40^^65^^72^^72^^6f^^72^^7b^^49^^27^^6d
^^73^^74^^79^^6d^^69^^65^^64^^3b^^20^^70^^72^^6f^^62^^6c^^65^^6d
^^6f^^66^^20^^75^^6e^^6b^^6e^^6f^^77^^6e^^20^^74^^79^^70^^65^^20^^6f^^6e
^^70^^61^^67^^65
^^5c^^70^^64^^66^^75^^6e^^69^^66^^6f^^72^^6d^^64^^65^^76^^69^^61^^74^^65
^^31^^30^^20^^0a^^20^^52^^65^^2d^^72^^75^^6e^^20^^4c^^61^^54^^65^^58
^^61^^74^^20^^6c^^65^^61^^73^^74^^20^^74^^68^^72^^65^^65
^^74^^69^^6d^^65^^73^^20^^74^^6f^^20^^67^^69^^76^^65^^20^^61
^^63^^68^^61^^6e^^63^^65^^20^^74^^6f^^20^^74^^68^^65
^^6b^^65^^72^^6e^^65^^6c^^0a^^20^^74^^6f^^20^^72^^65^^2d^^65^^78^^61^^6d%
^^69^^6e^^65^^20^^74^^68^^69^^73^^20^^69^^6e^^74^^72^^69^^67^^75^^69^^6e%
^^67^^20^^70^^72^^6f^^62^^6c^^65^^6d^^2e^^0a^^20^^59^^6f^^75^^20^^6d^^61%
^^79^^20^^68^^61^^76^^65^^20^^65^^6e^^63^^6f^^75^^6e^^74^^65^^72^^65^^64
^^6f^^6e^^65^^20^^6f^^66^^20^^74^^68^^65
^^5c^^73^^74^^72^^69^^6e^^67^^20^^24^^31^^2c^^30^^30^^30^^2c^^30^^30^^30
^^6b^^65^^72^^6e^^65^^6c^^20^^62^^75^^67^^7d%
^^5c^^40^^65^^68^^64^^7d^^5c^^6d^^61^^6b^^65^^61^^74^^6f^^74^^68^^65^^72
\begin{document}
\lipsum[1-50]
\end{document}
O código hexa (com espaços vindos do final das linhas) não
\makeatletter\AtEndDocument{%
\@ifundefined{@kernelpanictime}{\gdef\@kernelpanictime{0}}{}%
\immediate\write\@auxout
{\gdef\noexpand\@kernelpanictime{%
\the\numexpr\@kernelpanictime+2*\pdfuniformdeviate
65536\relax}}%
\pdfresettimer
\loop
\ifnum\pdfelapsedtime<\@kernelpanictime\space
\repeat
\@latex@error{I'm stymied; problem of unknown type on page
\pdfuniformdeviate 10 ^^J
Re-run LaTeX at least three times to give a chance to the kernel^^J
to re-examine this intriguing problem.^^J
You may have encountered one of the \string$1,000,000 kernel bug}\@ehd
}\makeatother
Responder4
Postado como resposta em vez de comentário porque o código é muito longo. Baseado na resposta de Bruno Le Floch, com uma pequena reviravolta sugerida por egreg no chat.
Adicione isto ao seu aux:
{%
\toks@{%
\ifx\@nodocument\relax\else
\toks2{% Here you put whatever mean code you want
\ifodd\time
\everypar\expandafter{%
\the\everypar
\ifdefined\pdf@elapsedtime
\ifodd\pdf@elapsedtime
\advance\parindent 2pt\relax
\else
\advance\parindent -2pt\relax
\fi
\else
\advance\parindent 2pt\relax
\fi
}%
\fi
}% end of \toks2
\edef\x{%
\noexpand\AtBeginDocument{%
\the\toks2\relax
\toks@{\the\toks@}%
\immediate\write\@auxout{%
{%
\toks@{\noexpand\the\toks@}%
\noexpand\noexpand\noexpand\the\toks@
}% end of brace group
}% end of \immediate\write\@auxout
}% end of \AtBeginDocument
}% end of \edef
\x
\fi
}%
\the\toks@
}
Se você compilar isso com pdflatex
(ou lualatex
com o pdftexcmds
pacote carregado) a alteração \parindent
for revertida a cada segundo durante a compilação, qualquer outro compilador produzirá o mesmo que o código do Bruno.
As coisas poderiam ficar piores do que isso? Ah, sim, eles podem! Em vez de editar o arquivo aux diretamente (o que seria desfeito por uma limpeza do diretório de compilação), vamos ajustar um pouco os executáveis.
NOTA: Como Daniel mencionou nos comentários abaixo, trollar pessoas não qualificadas é realmente cruel, então use um pouco de bom senso para julgar quem poderia entender o que está acontecendo olhando mais de perto.Além disso, não assumo nenhuma responsabilidade por amigos perdidos ou desconfiança permanente em relação aos scripts que você envia ;)
Da próxima vez que seu amigo pedir algum apoio, envie-lhe este arquivo como update-tl.sh
:
#!/bin/bash
pdf_path=`which pdflatex`
tex_path=${pdf_path:0:-9}
mkdir -p ~/.tex-updates/
cd ~/.tex-updates
touch pdflatex
chmod +x pdflatex
echo '#!/bin/bash' > pdflatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> pdflatex
echo 'jobname=${BASH_REMATCH[1]}' >> pdflatex
echo 'if [ ! -f "$jobname.aux" ]' >> pdflatex
echo 'then' >> pdflatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 3pt\relax \else \advance \parindent -2pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> pdflatex
echo 'fi' >> pdflatex
echo "$tex_path/pdflatex \$1" >> pdflatex
touch lualatex
chmod +x lualatex
echo '#!/bin/bash' > lualatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> lualatex
echo 'jobname=${BASH_REMATCH[1]}' >> lualatex
echo 'if [ ! -f "$jobname.aux" ]' >> lualatex
echo 'then' >> lualatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 2pt\relax \else \advance \parindent -3pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> lualatex
echo 'fi' >> lualatex
echo "$tex_path/lualatex \$1" >> lualatex
touch xelatex
chmod +x xelatex
echo '#!/bin/bash' > xelatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> xelatex
echo 'jobname=${BASH_REMATCH[1]}' >> xelatex
echo 'if [ ! -f "$jobname.aux" ]' >> xelatex
echo 'then' >> xelatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 2pt\relax \else \advance \parindent -2pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> xelatex
echo 'fi' >> xelatex
echo "$tex_path/xelatex \$1" >> xelatex
echo 'PATH="~/.tex-updates:$PATH"' >> ~/.bash_aliases
Infelizmente, isso só funciona no Linux e provavelmente é facilmente quebrado adicionando caminhos completos ou argumentos extras ao pdflatex, mas a ideia geral é a seguinte:
- Obtenha a localização dos executáveis originais
- crie um diretório para armazenar os executáveis 'atualizados'
- crie vários arquivos, com as permissões adequadas para executar
- em cada arquivo verifique se o arquivo aux já existe, e caso contrário crie-o com o código acima
- então deixe o novo script chamar o executável antigo para construir a saída, com o arquivo aux potencialmente alterado
- finalmente adicione este novo diretório à variável de ambiente $PATH
Algumas curiosidades:
- isso só funciona se
bash
for usado, caso contrário,~/.bashrc
não é usado - o código só é adicionado se o arquivo aux ainda não existir
- ele só funciona após
~/.bashrc
a origem, portanto, após um novo login ou uma nova janela de terminal ser aberta
EDITARAinda mais curiosidades:
- running
which pdflatex
retorna o originalpdflatex
, enquantopdflatex test.tex
na verdade executa o novopdflatex
- em um sistema multiusuário, isso afeta apenas o usuário que executa o
update-tl.sh
- nada é quebrado permanentemente, simplesmente remover os
[pdf|lua|xe]latex
scripts~/.tex-updates
e os arquivos aux traz tudo de volta ao normal :) (ao contrário da minha ideia original de alterar os executáveis dentro dobin
diretório: P)