大量のメールを処理できるNeomutt
仕事ツールの中でも意外と重要なメーラーについて考えます。 一般的にメールクライアントは機能で比べることが多いと思いますが、 私がメーラーを選ぶ上で重要視していることは速度です。 ほとんどのオープンソースはGitHubかメーリングリストを使って開発されているので参加すると大量のメールでGmailがあふれることになります。 いちいちリポジトリをブラウザで見に行っていられないのでたくさんWatchしておいて何か起きたらメールで知ることになります。 そうなると数万〜数十万のメールがGmailにはいっていてもIMAPで快適に扱えないとこの用途では使い物になりません。
なぜIMAPにこだわるかといえば、数万〜数十万オーダーのメールをPOP3でとってきてDropboxに置いておくと初回のファイル同期が遅くなりすぎるからです。Dropboxの同期が数時間かかると気軽にクリーンインストールできません。クリーンインストールは最高のセキュリティ対策なので式年遷宮1のように定期的に行います。したがって、要件はメールの既読管理をしたいだけであるので何も管理しなくていいIMAPが最適なのです。2 そしてこのような厳しい要求に耐えうるのはneomutt以外にはないでしょう。
Neomutt(mutt)
neomuttは現存するメーラーでおそらく世界最速であろうと思います。 Cで実装されているターミナルで使うCUIのメーラーです。
ご覧のように、2018年にもなってCUIのメールクライアントを使うのは懐古趣味ではないかと言われそうではありますが、 neomuttの速さを見ていただければ納得してもらえるのではないかと思っています。 このデタラメな速さが数万〜数十万オーダーで快適に作業するためには必要です。 GitHubに投稿するときはメールにある該当issueやプルリクエストのリンクをクリックするとChromiumが開くようになっています。
さて、あまりにも早すぎて何をやっているかわからないと思うので少し説明をします。 まず l を押して、見せても問題のないGitHubでの公開のやり取りのメールだけをフィルタした状態でgifアニメーションは始まります。 GitHubのやり取りは初期状態として未読状態にしてあります。 青色のメールは未読状態のメールであるということになります。 ざっとメールを下に確認していって一番上に戻ってきます。
次に未読メールが自分と関係ないとわかっている場合を想定して未読メールを既読状態にしていきます。 しかし、この操作を取り消したいのでいったん1のメールに戻り 既読状態にしたメールを未読状態に戻していきます。 このようなすさまじい速度での作業に対応できるメールクライアントはneomuttしかありません。 2018年にもなって使う価値があるCUIソフトウェアであることがわかっていただけたかと思います。 neomuttの設定は最後に書いておきます。詳しくは私のGitHubをどうぞ。
Sylpheed
GUIのメーラーも使っています。 GUIのメールクライアントではSylpheedが一番軽快で速いのではないかと思います。 もちろん速さはneomuttには及びませんが、とても使いやすいツールです。 私は大量のメールが来るGmailはneomuttで処理して、solist.workドメインなどに来るメールをSylpheedで処理するようにしています。3 Sylpheedはsolist.workドメインのメールを扱うのでデータの保護を重要視していて、POP3で受信するとすぐにDropboxにデータがバックアップされるようになっています。 SylpheedはEmacsキーバインドでメールの作業が一通りできるのでオススメです。
~/.sylpheed-2.0/folderlist.xml
<?xml version="1.0" encoding="UTF-8"?>
<folderlist>
<folder type="mh" name="メール箱" path="/home/masa/Dropbox/sylpheed/Mail">
<folderitem type="outbox" name="sent" path="sent" threaded="1" mtime="0" new="0" unread="0" total="32" />
<folderitem type="inbox" name="inbox" path="inbox" threaded="1" sort_key="date" sort_type="descending" mtime="1541688903" new="0" unread="0" total="246">
<folderitem type="normal" name="support" path="inbox/support" threaded="1" mtime="0" new="0" unread="0" total="2" />
</folderitem>
<folderitem type="junk" name="junk" path="junk" threaded="1" mtime="0" new="0" unread="0" total="0" />
<folderitem type="trash" name="trash" path="trash" threaded="1" mtime="0" new="0" unread="0" total="2" />
<folderitem type="queue" name="queue" path="queue" threaded="1" mtime="0" new="0" unread="0" total="0" />
<folderitem type="draft" name="draft" path="draft" threaded="1" mtime="0" new="0" unread="0" total="1" />
</folder>
</folderlist>
folderlist.xmlの中の
path="/home/masa/Dropbox/sylpheed/Mail"
でDropbox内にメールデータを置くことができます。 これでSylpheedで受信したメールはすぐにDropboxに同期されるのでバックアップ不要となります。バックアップしなくていいクリーンインストールを気軽にできる環境になれるともう以前のような環境には戻れません。
Sylpheedの設定が終わったら${HOME}/.sylpheed-2.0をDropboxに同期しましょう。
Makefile
sylpheed: ## Init sylpheed
sudo pacman -S sylpheed
test -L ${HOME}/.sylpheed-2.0 || rm -rf ${HOME}/.sylpheed-2.0
ln -vsfn ${HOME}/Dropbox/sylpheed/.sylpheed-2.0 ${HOME}/.sylpheed-2.0
allinstall: ttf-cica install init initdropbox pipinstall goinstall aur mozc neomutt docker mariadb redis rbenv rustinstall nodeinstall screenkey dnsmasq desktop chromium jekyll sxiv zeal zoom toggle sylpheed
このようなMakefileを用意すると次回からはmake sylpheedでこの処理が適応されます。 さらにmake allinstallするとmake sylpheedも実行されるのでクリーンインストール時はmake allinstallするだけでよいことになります。 詳しくはこちらの記事を参考にしてください。
ダークモードについて
普段使っている環境の背景が黒いのは格好いいからそうしているのではなく長時間見ていても目が悪くならないようにするためです。 Emacs Terminal Email Chromiumは基本的にダークモードで使用します。4 資料を作るとき人に見せる時だけChromiumは通常の状態に戻してよそ行きの状態にします。 これは目の負担はディスプレイの面積×明るさであると一般的に知られていて、 普段はダークモードで目の負担を下げたいからです。 ですから私は大きなディスプレイも使わないようにしています。 ソフトウェアエンジニアは長年液晶ディスプレイを見続けるわけですから目は大切にしなければいけません。
ChromiumのダークモードはDark ReaderとStylusを使って実現しています。 Stylusのスタイルを適応するサイトではDark Readerをそのドメインだけオフにします。 基本的にはDark Readerでダークモードを実現し、Dark Readerで見にくいサイトだけStylusで対応するという感じです。私がStylusでダークモードを実現しているサイトはGoogle、Googleドライブ、Googleカレンダー、GitLab、Feedly、Trelloです。RedditやTwitterやGmailのように夜間モードが実装されているサイトでは夜間モードを使用しています。Hacker Newsは見にくいのでEmacsのhackernews.elで見ています。RedditはRTVで見るのもお勧めです。
誰だったかは忘れましたが昔ビリヤードのプレイヤーで視力を落とさないようにするために 新聞や雑誌をお付きの人に読ませているというエピソードがありました。 これは目をいたわる別の視点とアイデアを提供してくれます。 視力を落とさないようにするために人を使ってもよいし、 また、それは人である必要もないのです。 現代のソフトウェアエンジニア的にはコンピュータに読ませるかポットキャストをソースにするという方法がよいと思います。 人を雇うのはコストが高すぎると思うので。
ポットキャストのような音を情報源として利用すると、もう一つのメリットが得られます。 それは、存在しなかった時間を作りだせることです。 ポットキャストを聞きながらジョギングや散歩や通勤をすると今まで有効利用されていない 時間についでに情報をインプットすることが可能になります。5 最近有益なポットキャストが増えてきたのはこういう事情もあるのかなと思っています。 はしょって読まれるブログより、運動しながら聞かれるのだとしても早送りされることがないポットキャストのほうが メディアとしての価値がありそうな気がします。 まぁはしょって読めないような濃密な記事を書けばよいと思いますが…。
neomuttの設定
必要なものをインストールします。
sudo pacman -S neomutt
yay -S goobook-git
goobook authenticate
Gmail側でIMAPの設定はすませてある前提です。
.muttrc
set send_charset="iso-2022-jp:utf-8"
source ~/Dropbox/mutt/password.rc
set folder = "imaps://imap.gmail.com:993"
set spoolfile = "+INBOX"
set imap_check_subscribed
set hostname = gmail.com
set mail_check = 120
set timeout = 300
set imap_keepalive = 300
set postponed = "+[GMail]/Drafts"
set record = "+[GMail]/Sent Mail"
set header_cache=~/.mutt/cache/headers
set message_cachedir=~/.mutt/cache/bodies
set certificate_file=~/.mutt/certificates
set signature =~/.mutt/signature
set move = no
set include
set sort = 'threads'
set sort_aux = 'reverse-last-date-received'
set auto_tag = yes
ignore "Authentication-Results:"
ignore "DomainKey-Signature:"
ignore "DKIM-Signature:"
hdr_order Date From To Cc
set pager_index_lines=8
bind editor ^T complete
bind editor <space> noop
# mailcap
alternative_order text/plain text/html *
set mailcap_path = ~/.mutt/mailcap
auto_view text/html
# emacs
#set editor="emacsclient -a \"\" -t"
# vim
set editor="vim"
# notify-send
set new_mail_command="notify-send --icon=mail-message-new 'New Email' '%n new messages, %u unread.' &"
# alias
set alias_file = "~/.mutt/aliases"
set sort_alias = alias
set reverse_alias = yes
source $alias_file
## GooBook
set query_command="goobook query '%s'"
macro index,pager a "<pipe-message>goobook add<return>" "add sender to google contacts"
bind editor <Tab> complete-query
# pager
set pager_context = 3
unset markers
# make sure that you are using mutt linked against slang, not ncurses, or
# suffer the consequences of weird color issues. use "mutt -v" to check this.
# custom body highlights -----------------------------------------------
# highlight my name and other personally relevant strings
#color body color136 color234 "(ethan|schoonover)"
# custom index highlights ----------------------------------------------
# messages which mention my name in the body
#color index color136 color234 "~b \"phil(_g|\!| gregory| gold)|pgregory\" !~N !~T !~F !~p !~P"
#color index J_cream color230 "~b \"phil(_g|\!| gregory| gold)|pgregory\" ~N !~T !~F !~p !~P"
#color index color136 color37 "~b \"phil(_g|\!| gregory| gold)|pgregory\" ~T !~F !~p !~P"
#color index color136 J_magent "~b \"phil(_g|\!| gregory| gold)|pgregory\" ~F !~p !~P"
## messages which are in reference to my mails
#color index J_magent color234 "~x \"(mithrandir|aragorn)\\.aperiodic\\.net|thorin\\.hillmgt\\.com\" !~N !~T !~F !~p !~P"
#color index J_magent color230 "~x \"(mithrandir|aragorn)\\.aperiodic\\.net|thorin\\.hillmgt\\.com\" ~N !~T !~F !~p !~P"
#color index J_magent color37 "~x \"(mithrandir|aragorn)\\.aperiodic\\.net|thorin\\.hillmgt\\.com\" ~T !~F !~p !~P"
#color index J_magent color160 "~x \"(mithrandir|aragorn)\\.aperiodic\\.net|thorin\\.hillmgt\\.com\" ~F !~p !~P"
# for background in 16 color terminal, valid background colors include:
# base03, bg, black, any of the non brights
# basic colors ---------------------------------------------------------
color normal color241 color234
color error color160 color234
color tilde color235 color234
color message color37 color234
color markers color160 color254
color attachment color254 color234
color search color61 color234
#color status J_black J_status
color status color241 color235
color indicator color255 color13
color tree color13 color255 # arrow in thread
# basic monocolor screen
mono bold bold
mono underline underline
mono indicator reverse
mono error bold
# index ----------------------------------------------------------------
#color index color160 color234 "~D(!~p|~p)" # deleted
#color index color235 color234 ~F # flagged
#color index color166 color234 ~= # duplicate messages
#color index color240 color234 "~A!~N!~T!~p!~Q!~F!~D!~P" # the rest
#color index J_base color234 "~A~N!~T!~p!~Q!~F!~D" # the rest, new
color index color160 color234 "~A" # all messages
color index color166 color234 "~E" # expired messages
color index color33 color234 "~N" # new messages
color index color33 color234 "~O" # old messages
color index color61 color234 "~Q" # messages that have been replied to
color index color240 color234 "~R" # read messages
color index color33 color234 "~U" # unread messages
color index color33 color234 "~U~$" # unread, unreferenced messages
color index color241 color234 "~v" # messages part of a collapsed thread
color index color241 color234 "~P" # messages from me
color index color37 color234 "~p!~F" # messages to me
color index color37 color234 "~N~p!~F" # new messages to me
color index color37 color234 "~U~p!~F" # unread messages to me
color index color240 color234 "~R~p!~F" # messages to me
color index color160 color234 "~F" # flagged messages
color index color160 color234 "~F~p" # flagged messages to me
color index color160 color234 "~N~F" # new flagged messages
color index color160 color234 "~N~F~p" # new flagged messages to me
color index color160 color234 "~U~F~p" # new flagged messages to me
color index color235 color160 "~D" # deleted messages
color index color245 color234 "~v~(!~N)" # collapsed thread with no unread
color index color136 color234 "~v~(~N)" # collapsed thread with some unread
color index color64 color234 "~N~v~(~N)" # collapsed thread with unread parent
# statusbg used to indicated flagged when foreground color shows other status
# for collapsed thread
color index color160 color235 "~v~(~F)!~N" # collapsed thread with flagged, no unread
color index color136 color235 "~v~(~F~N)" # collapsed thread with some unread & flagged
color index color64 color235 "~N~v~(~F~N)" # collapsed thread with unread parent & flagged
color index color64 color235 "~N~v~(~F)" # collapsed thread with unread parent, no unread inside, but some flagged
color index color37 color235 "~v~(~p)" # collapsed thread with unread parent, no unread inside, some to me directly
color index color136 color160 "~v~(~D)" # thread with deleted (doesn't differentiate between all or partial)
#color index color136 color234 "~(~N)" # messages in threads with some unread
#color index color64 color234 "~S" # superseded messages
#color index color160 color234 "~T" # tagged messages
#color index color166 color160 "~=" # duplicated messages
# message headers ------------------------------------------------------
#color header color240 color234 "^"
color hdrdefault color240 color234
color header color241 color234 "^(From)"
color header color33 color234 "^(Subject)"
# body -----------------------------------------------------------------
color quoted color33 color234
color quoted1 color37 color234
color quoted2 color136 color234
color quoted3 color160 color234
color quoted4 color166 color234
color signature color240 color234
color bold color235 color234
color underline color235 color234
color normal color255 color234
#
color body color245 color234 "[;:][-o][)/(|]" # emoticons
color body color245 color234 "[;:][)(|]" # emoticons
color body color245 color234 "[*]?((N)?ACK|CU|LOL|SCNR|BRB|BTW|CWYL|\
|FWIW|vbg|GD&R|HTH|HTHBE|IMHO|IMNSHO|\
|IRL|RTFM|ROTFL|ROFL|YMMV)[*]?"
color body color245 color234 "[ ][*][^*]*[*][ ]?" # more emoticon?
color body color245 color234 "[ ]?[*][^*]*[*][ ]" # more emoticon?
## pgp
color body color160 color234 "(BAD signature)"
color body color37 color234 "(Good signature)"
color body color234 color234 "^gpg: Good signature .*"
color body color241 color234 "^gpg: "
color body color241 color160 "^gpg: BAD signature from.*"
mono body bold "^gpg: Good signature"
mono body bold "^gpg: BAD signature from.*"
# yes, an insance URL regex
color body color160 color234 "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]"
# and a heavy handed email regex
#color body J_magent color234 "((@(([0-9a-z-]+\\.)*[0-9a-z-]+\\.?|#[0-9]+|\\[[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\]),)*@(([0-9a-z-]+\\.)*[0-9a-z-]+\\.?|#[0-9]+|\\[[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\.[0-9]?[0-9]?[0-9]\\]):)?[0-9a-z_.+%$-]+@(([0-9a-z-]+\\.)*[0-9a-z-]+\\.?|#[0-9]+|\\[[0-2]?[0-9]?[0-9]\\.[0-2]?[0-9]?[0-9]\\.[0-2]?[0-9]?[0-9]\\.[0-2]?[0-9]?[0-9]\\])"
# Various smilies and the like
#color body color230 color234 "<[Gg]>" # <g>
#color body color230 color234 "<[Bb][Gg]>" # <bg>
#color body color136 color234 " [;:]-*[})>{(<|]" # :-) etc...
# *bold*
#color body color33 color234 "(^|[[:space:][:punct:]])\\*[^*]+\\*([[:space:][:punct:]]|$)"
#mono body bold "(^|[[:space:][:punct:]])\\*[^*]+\\*([[:space:][:punct:]]|$)"
# _underline_
#color body color33 color234 "(^|[[:space:][:punct:]])_[^_]+_([[:space:][:punct:]]|$)"
#mono body underline "(^|[[:space:][:punct:]])_[^_]+_([[:space:][:punct:]]|$)"
# /italic/ (Sometimes gets directory names)
#color body color33 color234 "(^|[[:space:][:punct:]])/[^/]+/([[:space:][:punct:]]|$)"
#mono body underline "(^|[[:space:][:punct:]])/[^/]+/([[:space:][:punct:]]|$)"
# Border lines.
#color body color33 color234 "( *[-+=#*~_]){6,}"
#folder-hook . "color status J_black J_status "
#folder-hook gmail/inbox "color status J_black color136 "
#folder-hook gmail/important "color status J_black color136 "
.mutt/mailcap
text/html; w3m -I %{charset} -T text/html; copiousoutput;
text/markdown; w3m -I %{charset} -T text/markdown; copiousoutput;
image/jpg; eog %s
image/jpeg; eog %s
image/png; eog %s
image/gif; eog %s
application/pdf; evince %s
application/x-pdf; evince %s
application/zip; file-roller %s
application/gzip; file-roller %s
application/x-rar-compressed; file-roller %s
application/x-msexcel; xdg-open %s
application/ms-exc; xdg-open %s
application/excel; xdg-open %s
application/msexcel; xdg-open %s
application/vnd.ms-exc; xdg-open %s
application/vnd.ms-excel; xdg-open %s
application/msword; xdg-open %s
application/vnd.openxmlformats-officedocument.wordprocessingml.document; xdg-open %s
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; xdg-open %s
パスワードはGitHubで共有しないようにしておきます。 もし間違ってGitHubにコミットしてしまったらすぐにパスワードは変更しましょう。
~/Dropbox/mutt/password.rc
set imap_user = "youraddress@gmail.com"
set imap_pass = "yourpassword"
set smtp_url = "smtp://youraddress@smtp.gmail.com:587/"
set smtp_pass = "yourpassword"
set from = "youraddress@gmail.com"
set realname = "Your Name"
~/Dropbox/mutt/.goobookrc
# "#" or ";" at the start of a line makes it a comment.
[DEFAULT]
# The following are optional, defaults are shown
# This file is written by the oauth library, and should be kept secure,
# it's like a password to your google contacts.
;oauth_db_filename: ~/.goobook_auth.json
# The client secret file is not really secret.
;client_secret_filename: ~/.goobook_client_secret.json
;cache_filename: ~/.goobook_cache
;cache_expiry_hours: 24
;filter_groupless_contacts: yes
# New contacts will be added to this group in addition to "My Contacts"
# Note that the group has to already exist on google or an error will occur.
# One use for this is to add new contacts to an "Unsorted" group, which can
# be sorted easier than all of "My Contacts".
;default_group:
email: youraddress@gmail.com
password: yourpassword
~/Dropbox/mutt/signature
Your Name
~/Dropbox/mutt/aliases
alias piko Piko Taro <pikotaro@example.com>
alias kosaka Kosaka Daimaou <kosaka.daimaou@example.com>
こうしておくと新規メールを出すときに
To: piko
で Piko Taro pikotaro@example.com にメールすることができます。
neomuttのMakefile
この設定が気に入ったのでMakefileに登録しておきましょう。くわしくはこちらの記事に書いてあるので参考にしてください。今回の例ではこうなります。
neomutt: ## Init neomutt mail client
sudo pacman -S neomutt
mkdir -p ${HOME}/.mutt
ln -vsf ${PWD}/.muttrc ${HOME}/.muttrc
ln -vsf ${PWD}/.mutt/mailcap ${HOME}/.mutt/mailcap
ln -vsf ${PWD}/.mutt/certificates ${HOME}/.mutt/certificates
ln -vsf ${HOME}/Dropbox/mutt/aliases ${HOME}/.mutt/aliases
ln -vsf ${HOME}/Dropbox/mutt/signature ${HOME}/.mutt/signature
ln -vsf ${HOME}/Dropbox/mutt/.goobookrc ${HOME}/.goobookrc
yay -S goobook-git
goobook authenticate
allinstall: ttf-cica install pipinstall goinstall aur mozc neomutt docker mariadb redis rbenv rustinstall nodeinstall screenkey dnsmasq desktop chromium jekyll sxiv zeal zoom toggle
これで
make neomutt
を実行するだけで次回のラップトップ再インストール時にこの設定が適応されます。
make allinstall
を実行するとmake neomuttも実行されるようになるのでさらに楽です。
-
20年に一度ではセキュリティ対策にはならないでしょう。 ↩︎
-
オフラインのためにPOP3でローカルにメールデータを持つのはこのオーダーでは面倒です。Dropboxのサーバーはアメリカにあるので太平洋ケーブルを渡りますし初回の同期が遅いのは仕方ないでしょう。年に数日くらいある移動中のオフラインの時間は電子書籍を読むことにしているのでオフラインは諦めています。面倒かつリターンが少ないものは諦めるのも正しい戦略だと思います。最近はオフラインになる場所も少なくなってきているので実はそんなに困っていないような…. ↩︎
-
実際のところほとんど全てのアプリケーションがダークモードです。私のつかっているGTKテーマはAdapta-gtk-themeです。Arch Linuxならsudo pacman -S adapta-gtk-theme だけでインストールできます。 ↩︎
-
ヘッドホンで両耳を塞ぐと危ないので片耳だけで聞くのがオススメです。最近は耳を塞がないAfterShokzがおすすめです。 ↩︎
ブログ記事を投稿したらTwitterでお知らせいたします。ブログを気に入っていただけた方はお気軽にフォローしてください。
— Solist Work (@SolistWork) 2018年11月27日
関連記事
最新記事
タグ一覧
-
ansible (2)
application (8)
chrome (1)
command (14)
django (1)
docker (3)
document (1)
emacs (14)
git (2)
google (1)
hugo (1)
kubernetes (1)
linux (20)
makefile (6)
mariadb (2)
melpa (1)
postgresql (2)
python (1)
security (2)
terminal (11)
thinkpad (2)
work (6)
zsh (10)