groff で書かれた中編小説

プログラマーが groff で 2 つの中編小説を書き、1 つは 50 ページ、1 つは 120 ページ。使った小さなマクロパッケージ、ページトラップ、ハイフネーション、Vim の設定について語る。

日本語
コピー
三本编程书并排摆在一起的照片:The C Programming Language、The UNIX Programming Environment、UNIX Network Programming

最近、自分の2作目の中編小説を書き終えた。

「pdfinfo」と「wc」の出力のスクリーンショット:1つ目の文書は約50ページ/1.5万語、2つ目は約120ページ/4万語。

やめておけ。公開するつもりはないし、個人的に送ることもない。それは公開するのと何も変わらない。

1作目はA5でおよそ50ページ(約1万5千語)、2作目は約120ページ(約4万語)。(「中編小説」の定義に照らすと、どちらもぎりぎり該当する。1作目は少し短く、2作目は少し長い。)

これをやり遂げたこと自体が、荒唐無稽で現実味がない。学生時代、「書く」ことに関わるものはすべて純粋な苦痛だった。数学や物理、その他の「技術」系の話題を除いては。それが今、こうして書いている。

どれくらいかかったか。1作目は7か月あまり。2作目、長いほうは? 10日だ。

昨年のいつごろか、7月あたりから、アパートに何十年も置きっぱなしだった本を読み始めた。思っていたよりずっと楽しかった。理由はわからない。これまで本を読んだことがないわけではない。ただ、読書はいつもどこか退屈で、やたら時間がかかった。技術書を除けば、の話だが。ここで言っているのはフィクションのことだ。多くても年に1冊。それが昨年はなぜか夢中になって、2025年7月から今までに小説をおよそ30冊読んだ。数日で読み終えるものもあれば、3か月かかるものもあった。

だから自分でやってみるのも、それほど遠い話ではない。

このブログは基本的に技術寄りなので、使ったソフトウェアの話をしよう。

groff

この2冊の「本」(本当の本と呼べるものではないが、面倒なのでそう呼ぶ)はどちらもgroffで組んだ。Linuxのターミナルでman pageをレンダリングするときによく使われる、あれだ。ただしgroff/troffは組版システム一式で、本物の本を作ることもできる。以前のブログ記事でも何度か触れた。

3冊のプログラミング書の写真:『Cプログラミング言語』『UNIXプログラミング環境』『UNIXネットワークプログラミング』。
『Cプログラミング言語』の1ページ。
『UNIXネットワークプログラミング』の1ページで、いくつかの図表が示されている。

groff の魅力は、その小ささと速さにあると思う。それでいて高品質な組版が得られる。13年半使っている PC で、50ページの文書なら700ミリ秒ほど、120ページなら1.6秒で生成できた。これには後述する前処理も含まれている。最近のソフトの大半が泥の中を歩いているような遅さなのに比べると、この速さは心地いい。

面白そうだったので、小さなマクロパッケージを自分で書いてみた。実際、中身はごくわずかだ。簡単な小説や中編を書くのに大げさなものは要らない。目次も、相互参照も、図表も、コードブロックも、リストもいらない。文章がすらすら流れて、ときどき単語が強調されればそれで十分だ。

注意しておくと、以下のテキストには TODO がいくつか残っている。groff は本格的な組版システムで、こうした話は複雑だ。そのすべてを把握するには、まだまだ程遠い。

基本の書式

マクロは3つだけ。

.\" Section header / chapter title
.de SH
.   sp 1v
.   ps +5p
.   ce
\f[HR]\\$1\fP
.   ps
.   sp 4v
..
.\" Normal paragraph with hanging indent.
.de PP
.   br
.   ti +2m
..
.\" "Long" paragraph, longer empty space.
.de LP
.   sp 2v
..

(SH という名前は man page から引き継いだものだ。man page をかなり書いてきたせいで、いつの間にかこの名前が定着してしまった。CH(「章見出し」)や CT(「章題」)のほうが適切かもしれない。あるいは、そう、.CHAPTER でもいい。)

マクロの定義は .de で始まり、.. までの内容がそのマクロに属する。

  • .SH:1 vee 下げ、 フォントサイズを大きくし、中央揃えを要求し、HR フォント(Helvetica)でマクロの第1引数を出力し、元のフォントサイズに戻してから vee 4つ分の間隔を空ける。
  • .PP:現在の行を改行するだけで、次の行の出力に一時的なインデントを要求する。これでぶら下げインデントになり、ドイツの書籍ではこれが慣例だ。
  • .LP:段落の間に少し空白を入れるだけ。章の中の時間の飛躍などに使う。

各コマンドは man 7 groff で調べられる。

ここまでできれば、それなりに本らしい文書を出力するには十分だ。

上の断片を macros.groff という名前のファイルに入れる。章ごとに1ファイルだ。たとえば chapter01.groff。 そうしたら、こんなコマンドで PDF を生成できる。

groff -Tpdf -dpaper=a5 -P-pa5 macros.groff chapter01.groff >book.pdf

A5 はおおよそ「普通の本」のページサイズに相当する。

フッターとページ番号

デフォルトではページ番号が付かないことに気づくだろう。デジタル版の PDF だけが欲しいなら、ページ番号はまったく不要と言っていい。印刷するときには役に立つが、正直なところ、ファイルの中に必要かというとそうでもない。

ただし、この仕組みはページの区切りで判断を誤る。上の例で PDF を生成すればわかるはずだ:

PDFビューアのスクリーンショット:最後の行のテキストがページの外にはみ出している。

最後の行の出力のベースラインが、ちょうどページの外に落ちているように見える。何が起きているのか分からない。これはページサイズを A5 にしたことと関係がある。つまり、またしても設定すべき場所をもう一箇所見落としているのだろう。以下の変更でついでに直るはずだ。

ページ番号まわりは3つの部品からできている。まず、フッター(ページ番号が入る領域)の高さはいくつか。これをレジスタに定義した(必須ではない。こう書いたほうが「コード」として読みやすいと感じただけ)。名前は適当だ:

.nr _FooterSize 5v

次に、ページ下端にトラップを仕込む:

.wh -\n[_FooterSize]u _FooterTrap

\n[_FooterSize] は _FooterSize という名前のレジスタの値を「取り出す」。先頭にマイナス記号が付いているので負の値で、ページ下端からの相対位置になる。ドキュメントにはこうある:

汎用レジスタ(nr リクエストで作成または更新するもの)は暗黙のうちに無次元であり、測定の文脈で解釈する場合は基本単位で数えられる。

なぜ u が必要なのかはよく分かっていない。マニュアルをまだ全部読み通していないのだ。言うまでもなく、これを付けないと動かない。

ともあれ、トラップはページ終端の 5v 手前に設置され、_FooterTrap マクロを呼び出す。こんな形だ:

.de _FooterTrap
.\" Push current environment on stack and switch to `_FooterEnv`.
.\" Parent env will keep partially collected lines.
.   ev _FooterEnv
.\" Copy settings from default environment.
.   evc 0
.\" Don't do this for pages 1 and 2, they're title pages in my actual
.\" "book".
.   if \\n[%]>2 \{\
.\" Set vertical position, explained in the text below.
.       sp |\\n[.p]u-2v
.\" Print % register centered.
.       ce
\fR\\n[%]\fP
\}
.\" Go back to previous environment.
.   ev
.\" Request page break.
'   bp
..

インラインコメントを外すとぐっと読みやすくなる:

.de _FooterTrap
.   ev _FooterEnv
.   evc 0
.   if \\n[%]>2 \{\
.       sp |\\n[.p]u-2v
.       ce
\fR\\n[%]\fP
\}
.   ev
'   bp
..

なぜ 'bp ではなく .bp なのか。これは後で触れる。

自信がないのは、垂直位置を |\\n[.p]u-2v にした点だ。これはページ上端からの相対位置で、ページの長さから vee 2つ分を引いた値になる。|-2v-1v(ドキュメントにある「vee 1つ分を引く」を考慮に入れても)でも動くはずだと思っていたが、そうすると無限ループに陥る(おそらく同じトラップが繰り返し発火している)。なぜか。

ヘッダー

対称性のために、ページ上端にも余白を入れたい:

.nr _HeaderSize 5v
.de _HeaderTrap
'   sp |\\n[_HeaderSize]u
..
.wh 0v _HeaderTrap

TODO がもう1つ。これは完全には対称になっていない。ヘッダーの長さがフッターより少し大きい。これもページサイズの問題か。

トラップを詳しく見る

トラップを詳しく見ていこう。これは百パーセント確信があるわけではない。以下は現時点での理解だ。

いや、まずは上の例から離れよう。次のものから始める:

This is a little excerpt from Mary Shelly's Frankenstein.

These visions faded when I perused, for the first time, those poets
whose effusions entranced my soul and lifted it to heaven. I also became
a poet and for one year lived in a paradise of my own creation; I
imagined that I also might obtain a niche in the temple where the names
of Homer and Shakespeare are consecrated. You are well acquainted with
my failure and how heavily I bore the disappointment. But just at that
time I inherited the fortune of my cousin, and my thoughts were turned
into the channel of their earlier bent.

Six years have passed since I resolved on my present undertaking. I can,
even now, remember the hour from which I dedicated myself to this great
enterprise. I commenced by inuring my body to hardship. I accompanied
the whale-fishers on several expeditions to the North Sea; I voluntarily
endured cold, famine, thirst, and want of sleep; I often worked harder
than the common sailors during the day and devoted my nights to the
study of mathematics, the theory of medicine, and those branches of
physical science from which a naval adventurer might derive the greatest
practical advantage. Twice I actually hired myself as an under-mate in a
Greenland whaler, and acquitted myself to admiration. I must own I felt
a little proud when my captain offered me the second dignity in the
vessel and entreated me to remain with the greatest earnestness, so
valuable did he consider my services.

これを test.groff として保存し、PDF を生成する:

groff -Tpdf test.groff >book.pdf

結果はこうなる:

3段落の本文とフッターのページ番号を含むPDFページ。

10v の位置にトラップを仕掛ける。今は空で、何もしない。次の一節をファイルの先頭に挿し込む:

.de MyTrap
..
.wh 10v MyTrap
.\"

PDF は変わらないように見える。

では、trap マクロをこう変えたらどうなるか?

.de MyTrap
FOO
..

結果はこうなる:

最後の段落の途中、fishers という単語の直後に FOO が挿入された PDF ページ。

「fishers」という単語を出力したところで、トラップが発動した。PDF では「FOO」が「fishers」の後ろに来ている。「fishers」がトラップを発動し、そのあと「FOO」が挿入されたわけだ。話はこれだけのことだ。そうだろう?

「FOO」を行頭に置き、その行にはこの単語以外何も置かないようにしたいとする。「fishers」は次の行に回す。

僕の理解が正しければ、鍵は環境の切り替えにある。環境は現在収集している行(およびその他多くのもの)を保持している。新しい環境に切り替えれば、まっさらなバッファ/行が手に入る。この時点ではまだ空だ。そこでこの行をフラッシュ/切断して PDF に送り込み、元の環境に戻せばよい:

.de MyTrap
.   ev MyTrapEnv
FOO
.   br
.   ev
..

こんな感じだ:

PDFページで FOO が単独で1行を占め、最後の段落を分断している。

ここまでは問題ない。次は「FOO」の前後に空行を1行ずつ入れたい:

.de MyTrap
.   ev MyTrapEnv
.   sp
FOO
.   sp
.   ev
..

新しい環境で .sp を実行する。これは改行して余白を挿入する。まだ何も収集していないので、この時点の改行では何も印字されない。続いて FOO。これは直接印字されず、収集されるだけだ。次の .sp で再び改行し(ここで「FOO」が印字される)、さらに余白を挿入する。

FOO の行の上下に空白がある PDF ページ。

よし。ここで、trap の中では「FOO」を上下1行ずつ空けて表示したいだけだとしよう。その後、本文はページ上の絶対位置、たとえば 17v から続けたい。

そこで、こうするのはどうだろう。以前の環境に戻り、絶対位置指定のリクエストを出す:

.de MyTrap
.   ev MyTrapEnv
.   sp
FOO
.   sp
.   ev
.   sp |17v
..

まずい:

FOO と fishers という単語だけが表示され、その後に大きな空白が続く PDF ページ。

.sp |17v は、すでに集め終えた行(「fishers」だけの行)を改行してから、そのあとで 空白を挿入する。この改行は不要だ。(「fishers」が trap で止めたのと同じ位置にあることにも注目。)

. の代わりに ' を使えば、この問題は避けられる:

'   The neutral apostrophe is the no-break control character, rec‐
    ognized where the control character  is.   It  suppresses  the
    (first) break implied by the bp, ce, cf, fi, fl, "in", nf, rj,
    sp,  ti,  and trf requests.  The requested operation takes ef‐
    fect at the next break.

こうする:

.de MyTrap
.   ev MyTrapEnv
.   sp
FOO
.   sp
.   ev
'   sp |17v
..

結果:

PDFページで FOO が単独の行になり、段落は大きな間隔の後に続いている。

ドキュメントの例では環境を切り替えていない。ただ、環境を切り替えたほうが何が起きているか見やすいと思う。(間違っていなければいいのだが。)

最後にひとつ。環境は設定を引き継ぐ。.ev foo は前の環境をクローンするのではなく、まっさらな環境を開く(同名の環境がすでに存在する場合を除く)。だから僕のマクロパッケージでも .evc 0 をしている。

小さな練習問題をひとつ。'sp |12v、'sp |11.5v、'sp |11v、最後は 'sp |9v まで試して、何が起きるか見てほしい。

文間のスペース

この記事を書くまで、ドキュメント(Basics)にこんな一文があるのに気づいていなかった:

新しい行で文を始めないなら、前の文のあとにスペースを2つ入れる。GNU troff はそれで文末の句読点を認識し、それに応じて文間のスペースを挿入する。

僕はこれをやっていない。ドイツ語では一般的ではないからだ。だが今、気づいた。PDF ではこうなっていることがある:

Foo. Bar.

こうなって、隙間が少し広がることもある:

Foo.  Bar.

僕の知る限り、ドイツ語の書籍では普通こうしない。次のリクエストで切った。「最小単語間隔」はデフォルトの12のまま、「追加の文間スペース」を0にしている:

.ss 12 0

これはマクロパッケージには入れていない。「index」ファイル(book.groff、下のデモパッケージを参照)の先頭に置いてある。

ドイツ語のハイフネーション

どうやら、これだけらしい:

.hla den
.hpf hyphen.den

den は「de(utsch) new」、つまり2006年の新ドイツ語正書法の規則だ。

Markdown とその他の前処理

実のところ、2つの物語はどちらも純粋な groff で書いた。上で説明したマクロを使って。

Markdownの大きな利点は「見た目が楽」なことだ。おおむね人向けのテキストのように読める。groff はそうではない。いや、それほどひどくはない。書くのが苦痛なら groff で170ページ以上も書いたりしない。悪くはない。他のいくつかの場所でも groff を使っている。それでも Markdown のほうが少しだけ楽で、執筆そのものに集中しやすくなる気がする。

あとになって、2つ目の物語を「Markdown」に変換した。1つ目はやる気が起きなかった。引用符付きなのは、使っている要素がごくわずかで、完全な Markdown ではないからだ:

  • ファイル先頭の # Chapter title。
  • 段落の間は空行1つ、--- は「長い空行」。
  • *foo* は強調テキスト。

これだけ。変換は確かに楽だった。

全部を素の Markdown で書いて、HTML ファイルを生成すればよかったのかもしれない。ツールは前から持っている。このブログがそうだ。ついでに PDF も出力できるかもしれない。だがそれではいろいろ足りない。そのひとつが、テキストを本当に両端揃えにするエンジンだ。HTML で両端揃えの文字を見ると目が痛くなる。あれは惨事だ。groff や TeX が組むもののほうがはるかに、比べものにならないほどいい。

どうせ手を入れるなら、基本的な文字の置換もついでにできる。僕のキーボードにはドイツ語の組版用引用符 U+201E と U+201C が直接あるが、本では ギュメのほうがよく使われる。

最初は Python でやろうと思ったが、短い Perl スクリプトに変えた。ファイル全体を読み込んで複数行の正規表現をかけやすいからだ。だいたいこんな感じ:

perl -0pe '
# Guillemets are preferred in books.
s/... German typographic quotes, see demo package .../... Guillemets .../g;

# Markdown "h1" into ".SH".
s/^# ([^\n]+)\n/.SH "\1"\n/smg;

# Markdown "hr" into ".LP".
s/\n---\n/.LP/smg;

# Markdown paragraphs into ".PP".
s/\n\n/\n.PP\n/smg;

# Markdown emphasize into groff font selection:
s/\*([^*]+)\*/\\fI\1\\fP/smg;
'

出力は相変わらず、あの小さなマクロパッケージ用の groff だ。ただし今はこう書ける:

# Kapitel 42: Die Antwort

Da war sie also. Die Antwort auf *alle* Fragen.

Und dann ging es weiter:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum
hendrerit blandit suscipit. Maecenas sed nisi nec ante mattis
vulputate. Pellentesque maximus leo id purus vestibulum dictum.
Donec tincidunt mollis viverra. Curabitur at ligula in turpis
pellentesque vehicula.

Duis hendrerit commodo mauris, non posuere leo vulputate ut. Nulla
finibus urna eget vehicula auctor. Mauris in posuere nibh. Vivamus
ut metus vel nisi gravida molestie vitae et tellus. Integer mi odio,
vestibulum eget laoreet vel, auctor nec ligula. Quisque eu placerat
quam, eu tincidunt mauris. Nam vestibulum lectus non leo dignissim,
non sagittis dolor venenatis.

こちらのほうがずっと読みやすく、Vim ではシンタックスハイライトも効く。まあ、ハイライトされるのは *emphasized* の部分だけだが。残りはどうでもいい:

Vim が Markdown を標準のハイライトで表示している。強調テキストにはターミナルの「standout」属性が使われている。

Vim の話に戻ろう……

Vim

Goyo

そのために、とても重要な Vim プラグインがある。

https://github.com/junegunn/goyo.vim

UI 要素をほぼすべて隠してくれる。

さらに、ターミナルウィンドウを全画面にしてデスクトップも隠す。

それだけだ。「邪魔の入らない執筆」はその名のとおり。音楽を流すことはあっても、それ以外は何もない。ブラウザも、時計も、何もかも。あるのはタイプライターと、よく効くアンドゥだけだ。

Markdown ハイライト、Goyo 有効、ターミナルが全画面モードの Vim の写真。

フォントは UW ttyp0 の 11x22 版を使っている。

テキストのリフロー

プレーンテキストファイルには、よく使われる組版のやり方がひとつある:

This is one sentence.
This is another one.
And so on and so on.
One sentence per line, that's it.
Sentences can be short.
Or they can be pretty long, sometimes even exceeding the available width on your screen, thus requiring you to either scroll or have your editor soft-wrap it for you when displaying it.

上で見た groff のドキュメントにあるとおり、この書き方には groff にとって実用的な意味がある(文の終わりを正しく認識できる)。バージョン管理での diff のノイズも減らせる。

もうひとつよくあるのは、1段落を1行に収めるやり方だ。段落の後ろに「物理的な」改行をひとつ置くだけで、どう表示するかはエディタに任せる:

This is one sentence. This is another one. And so on and so on. One sentence per line, that's it. Sentences can be short. Or they can be pretty long, sometimes even exceeding the available width on your screen, thus requiring you to either scroll or have your editor soft-wrap it for you when displaying it.

90年代末から2000年代初頭にかけて、僕はこの2番目の方式を何年も使っていた。が、結局ハード改行に戻した。こんなふうに:

This is one sentence. This is another one. And so on and so on. One
sentence per line, that's it. Sentences can be short. Or they can be
pretty long, sometimes even exceeding the available width on your
screen, thus requiring you to either scroll or have your editor
soft-wrap it for you when displaying it.

単純にこちらのほうが読みやすく、スクロールもしやすいと感じるからだ。それにDOSの「輝かしい」昔を思い出す。あの頃は T エディタを多用していて、ファイルは全部こんな状態だった(もちろん手作業で整えた)。欠点は確かにある。他人と共同作業するときはあまりよくない。まあ、僕の場合は問題ない。

もうひとつの欠点は、編集のついでに段落を組み直さなければならないこと。ありがたいことに、Vim ならこれは簡単だ:

" In ~/.vimrc:
set nojs
map Q gq}

あとはカーソルを段落の先頭に置いて:

[T]his is one sentence.
This is another one.
And so on and so on.
One sentence per line, that's it.
Sentences can be short.

Q を押せば、こうなる:

This is one sentence. This is another one. And so on and so on. One
sentence per line, that's it. Sentences can be short.
[_]

カーソルはこの段落の後ろに止まる。文書全体を組み直したいなら、ファイルの末尾まで Q を押し続ければいい。

追記::set formatoptions+=a を使えば、編集しながら段落を自動で組み直すこともできる。僕はふだんそうしたくない。リフローは明示的な操作であってほしい。ただ、散文を書くときにはたぶん便利だろう。

nojs というオプション(名前がちょっと面白いだろう?)は最近知った。正式名は nojoinspaces で、これが防ぐのは、まさに僕がすべきこと(ただしドイツ語では習慣になっていない)だ。つまり、ピリオドの後に空白を2つ入れるのをやめさせる。付けずに、つまり set js のままだと、こうなる:

This is one sentence.  This is another one.  And so on and so on.
One sentence per line, that's it.  Sentences can be short.

好みが分かれるところだが、僕は好きじゃない。

Git

ほとんどすべてのものと同じく、これも Git で管理している。

が、それだけだ。現在の状態は頻繁にコミットするが、それ以外のことはほとんど気にしていない。まともなコミットメッセージも何もない。「バックアップ」代わりに、ノートPCとデスクトップの間でデータを同期するための道具にすぎない。

demo-book.tar.gz:すべてを組み上げる

言ったとおり、本当の「本」は公開しない。代わりに「足場」のデモを置いておく:

demo-book.tar.gz

(これは更新しない。現時点のスナップショットにすぎない。)

執筆プロセスそのもの

これについてはあまり語らない。僕は完全に初心者だ。

途中で何度か方向を変えた。どちらの話でも、本文を書き始める前に全体を下書きしてみたが、あまり役には立たなかった。最初の話はもともと出来がよくなかった。設定は面白かったが、当時の僕はノッていなかった。だからあんなに時間がかかった。2つ目の話の基本アイデアはもっと地味で、それが実際どれほど面白いかに気づいたのは後になってからだ。ひねりが多くて、そこが気に入っている。

事実関係を整理するのは思ったよりずっと難しかった。特に途中で方向を変えた後は。どの登場人物が、いつ、なぜ、何を知っているのか? 動機は? すべて整合が取れていて、説得力があるか? ひたすらすべてを疑い続ける。彼女は本当にここでそうしなければならないのか、それとも別のもっと筋の通った道があるのか? 100ページ前に彼女が言ったことは、最後の大どんでん返しの後でも成り立つのか? そんなことの繰り返しだ。この点はもっと腕を上げないといけない。次は「登場人物一覧」を作って、各人物のプロフィールを用意するつもりだ。

独自のルールや歴史を持つ世界を組み立てるのは、結果としてとても魅力的だった。人物を形づくるのも同じだ。

話の長さのせいで、校正はばかげているほど大変だった。120ページを数分で読み通すことなんてできない。昨日、2つ目の話を最後まで通して読んだのだが、かかった時間は……記録を見る……3時間。はあ。

これからどこへ?

昨日あの120ページをもう一度読んだわけだが……実のところ、かなり気に入っている。結果には満足している。学ぶべきことは明らかに山ほどある。この分野全体が僕にとってはまったく新しい。物語がうまく運べていない箇所はたくさん見つかった。テンポが悪い、話が進みすぎる。(今のところ、一気に読んだときにしか気づけない。はあ。)言葉選びがよくない箇所もある。細部が足りない。などなど。それでも、話そのものは自分で読みたいと思えるものだ。

groff をもっと深く掘ることも TODO に入れてある。理由は明らかだろう。

本当に気に入っているのは、このプロセスに完全に没頭できたことだ。あの120ページを書くのに10日かかった。そのうち1日はキーボードを一切叩いていない。その日は国を横断している最中で、暇な時間がたっぷりあり、ノートPCは持っていなかったが、少なくとも1章はほぼ「書き上げ」、そして(大部分は)暗記した。あれこれ考え、新しいアイデアが浮かぶ。完全な没頭。

もっとそういう状態がほしい。:-)

もしかしたら、いつかこういうものを公開するかもしれない(つまり、このサイトに置くかもしれない)。今ではない。これは自分のためにやっている。自分の作品を無遠慮な批評家にずたずたにされることには、これっぽっちも興味がない。放っておいてくれ。:-)

LLM を使えと提案しようと考えているなら:おめでとう、君は完全に的外れだ。「Setzen, 6.」

出典: movq.de← ホームへ戻る