<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>memo.yammer.jp</title>
    <link>https://memo.yammer.jp/posts/</link>
    <description>Recent content in Posts on memo.yammer.jp</description>
    <generator>memo.yammer.jp with Astro (https://github.com/yammerjp/memo.yammer.jp)</generator>
    <language>ja</language>
    <copyright>©2026 Keisuke Nakayama</copyright>
    <lastBuildDate>Tue, 02 Jun 2026 00:28:35 GMT</lastBuildDate>
    <atom:link href="https://memo.yammer.jp/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>トイカメラで、写真の荒さを楽しむ</title>
      <link>https://memo.yammer.jp/posts/20251215</link>
      <pubDate>Tue, 16 Dec 2025 00:10:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20251215</guid>
      <description>&lt;p&gt;2025年も残り2週間、いかがお過ごしでしょうか？&lt;/p&gt;
&lt;p&gt;最近私はトイカメラを買いました。&lt;/p&gt;
&lt;h2&gt;トイカメラを買った&lt;/h2&gt;
&lt;p&gt;トイカメラとは安価な素材で作られた簡素なカメラを指し、チープな見た目やうつり具合を楽しむもののようです。
スマホで高画質な写真が撮れる昨今、細かいところまで綺麗に映るのはありがたいものの、いいと感じる写真を撮るには素人にはどうも腕が足りず、イマイチだなあと感じてしまう機会も多くあります。
そこで、あえて逆張りで荒い解像度でトイカメラで撮るなら、細かいことを気にせず写真を楽しく撮れるのではないかと思い、、買って試してみることにしました。&lt;/p&gt;
&lt;p&gt;買ったのは&lt;a href=&quot;https://www.watch.impress.co.jp/docs/series/itsmo/2067229.html&quot;&gt;Impress Watchの記事&lt;/a&gt;でも紹介されているKODAK Charmeraというカメラです。&lt;/p&gt;
&lt;p&gt;手の中に収まる小さな筐体で、重さも軽く、まさにキーホルダーのようなサイズで、ポケットやバッグの隙間にするりと忍ばせることができるコンパクトさが特徴。&lt;/p&gt;
&lt;p&gt;充電と転送はUSB Type-Cで行えます。私はキーホルダーサイズの短いケーブルを買って、iPhoneから取り込んで使っています。&lt;/p&gt;
&lt;p&gt;届いて1週間ほど、それまでの間に取ってみたいくつかの写真とともに近況を紹介します。&lt;/p&gt;
&lt;h2&gt;近況&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://toycamera-assets.yammer.jp/posts/15443fa0-33bf-4b77-b85d-168fb1f19387/0e84eb7e-b88d-4ddb-9d17-4fa9107dea6f/PICT0006.jpg&quot; alt=&quot;charmeraの筐体&quot;&gt;&lt;/p&gt;
&lt;p&gt;筐体は小さく、そしてとても軽いので、ポケットに入っていてもあまり存在を感じないこともあるぐらいです。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://toycamera-assets.yammer.jp/posts/15443fa0-33bf-4b77-b85d-168fb1f19387/81d1174c-ca28-47bf-8770-f20040a97dca/PICT0007.jpg&quot; alt=&quot;観葉植物&quot;&gt;&lt;/p&gt;
&lt;p&gt;ふと観葉植物を買うことになり、家の中にフェイクグリーン以外の緑色が増えました。買ってみると結構見栄えが良いので、部屋の中を生い茂らせたくなってきます。
冬だからか水やりの頻度はずいぶん少ないらしく、まだまだ土が乾きません。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://toycamera-assets.yammer.jp/posts/15443fa0-33bf-4b77-b85d-168fb1f19387/e6333030-7af7-4bed-9e95-e3429321717e/PICT0038.jpg&quot; alt=&quot;田畑の広がる景色&quot;&gt;&lt;/p&gt;
&lt;p&gt;Charmeraにはいくつかのフィルター機能があるっぽく、ハイキングの帰りの農道ののどかなところをさらにのどかにしてみました。&lt;/p&gt;
&lt;p&gt;というように、日常のなんともない写真でも自分の中で楽しむ機会が増えた気がするので、購入してよかったです。
そのうち飽きそうな気もするが、まだ飽きていないのでしばらくは楽しむことにしましょう。&lt;/p&gt;
&lt;h2&gt;画像の投稿場所&lt;/h2&gt;
&lt;p&gt;さてさて、こういった画像を振り返られるようにどこかに上げておきたいのですが、このブログは画像をあげるのには少し億劫なところがあります。
画像はAmazon S3においているのですが、アップロードは手動でCLIかマネージドコンソールからあげるという温かみのある運用なのです。
というわけで、新たに投稿できる場所を用意しました。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://toycamera.yammer.jp/@yammer&quot;&gt;https://toycamera.yammer.jp/@yammer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;画像を投稿できる場所はSNSの他にも&lt;a href=&quot;https://awkblog.net/@yammerjp&quot;&gt;awkで作ったブログ&lt;/a&gt;だったり、OSSのmemosというアプリをホストしている&lt;a href=&quot;https://usememos.yammer.jp/&quot;&gt;マイクロブログ&lt;/a&gt;だったり、すでにいろいろあるわけだが、いくつ作っても捕まるわけではないので、もう一つぐらい良いでしょう。
DynamoDBに馴染みがなかったのだが自分の道具箱に入れておきたく、素振りもかねて、カメラが届くまでの間にAIにコードを書かせていました。&lt;/p&gt;
&lt;p&gt;どう作ったかと要素技術の感想を以下に少しメモしておきます。技術の話をスキップするには、次の節「締め」へ！&lt;/p&gt;
&lt;p&gt;S3とDynamoDBにつながるTypeScriptで書いたアプリをHonoで組み立て、Lambdaに上げて&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/urls-configuration.html&quot;&gt;Function URLs&lt;/a&gt; + CloudFrontで配信しています。
管理画面は&lt;a href=&quot;https://github.com/honojs/middleware/tree/main/packages/oidc-auth&quot;&gt;@hono/oidc-auth&lt;/a&gt;でGoogleアカウントで入れるようにしているので、私以外も使えるように広く公開できるのですが、OAuth 2.0アプリの公開が面倒で自分に閉じたままになっています。&lt;/p&gt;
&lt;p&gt;ちいさなCRUDの機能があるだけですが、入門としては大体こんな感じかというのを一通り試すことができました。
HonoのLambda向けのボイラープレートがよくできていて、そしてLambdaをNode.jsランタイムのまま使うとデプロイが超早くて体験が良かったです。
ただし、Function URLsとCloudFrontの組み合わせは、OACでPOST/PUTを受け付けるには、&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html&quot;&gt;ヘッダにsha256sumをつけなきゃいけない&lt;/a&gt;というのが結構謎で、完全なMPAにするわけには行かなそうで、ここは少し使いづらいと感じます。&lt;/p&gt;
&lt;p&gt;DynamoDBは、シングルテーブル、パーティションキーとソートキーの指定、GSIあたりの存在を知り、スキーマの検討の時に、どう引くかを想像しながらやっていくと良さそうな感触を得ました。
従量課金でスケールするということで小さな個人のアプリなら特に考えることはないのですが、商用環境でのトラフィックのスパイクは、RDBよりはよっぽど捌きやすいとはいえ、流石に何も考えなくていいなんてことは全然なさそうで、ある程度のキャパシティプランニングや、スパイク幅の考慮が必要そうというのも見えてきました。それはそう。&lt;/p&gt;
&lt;h2&gt;締め&lt;/h2&gt;
&lt;p&gt;本記事は、&lt;a href=&quot;https://adventar.org/calendars/11887&quot;&gt;GMOペパボ EC Advent Calendar 2025&lt;/a&gt;の5日目の記事でした！
遅くなってしまってすみません！&lt;/p&gt;
&lt;p&gt;前日(概念)のtichiseさんの&lt;a href=&quot;https://zenn.dev/pepabo/articles/2aaddc5d39e089&quot;&gt;Devinが得意なこと・苦手なこと - 7ヶ月の運用から学んだこと&lt;/a&gt;は、特に力を発揮するタスクの規模の要件や内容が具体的だったのが、再認識できて学びになる記事でした！
翌日(概念)のkarugaさんの&lt;a href=&quot;https://ikaruga.org/2025/12/05/sake/&quot;&gt;2025 アルコール カラーミーショップ 検索&lt;/a&gt;、URLがシンプル &lt;code&gt;sake&lt;/code&gt; で美しいですね！たくさんのショップ様に使っていただけるのはありがたく、身が引き締まる思い出もあります。&lt;/p&gt;
&lt;p&gt;そのほか&lt;a href=&quot;https://note.com/bqnq/n/nadb86065d2c3&quot;&gt;ばなさん&lt;/a&gt;や&lt;a href=&quot;https://note.com/pigyuna/n/n4d8215ff51df&quot;&gt;ちょりーさん&lt;/a&gt;、&lt;a href=&quot;https://note.com/omikitchen/n/n166f9b953b64&quot;&gt;おみきさんの記事&lt;/a&gt;を見ながら、私も一年を振り返らねばという気持ちになりました。
年末は時間に区切りをつけて振り返り、次の振る舞いを改める良い機会ですね。山のことを振り返ったり、仕事のことを振り返ったりもしたいのですが、なかなか収まらなそうなのでまた別の記事にすることとしましょう。&lt;/p&gt;
&lt;p&gt;それでは、良いお年を！&lt;/p&gt;</description>
    </item>
    <item>
      <title>メール送信者認証技術の整理</title>
      <link>https://memo.yammer.jp/posts/mail-sender-authentication</link>
      <pubDate>Fri, 04 Jul 2025 18:52:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/mail-sender-authentication</guid>
      <description>&lt;p&gt;SPF, DKIM, DMARCをはじめとするメール送信者認証技術のトピックが時々必要になるので、自分用のメモとして書き出しておきます。覚えていないところはRFCを見たりしていますが、記憶の中を書き出しているだけので、間違っているところがあったらご指摘ください。&lt;/p&gt;
&lt;h2&gt;メール送信者認証技術はなぜ必要なのか？&lt;/h2&gt;
&lt;h3&gt;SMTPで送信元を表すのは、IPアドレス、エンベロープFrom、ヘッダFrom&lt;/h3&gt;
&lt;p&gt;メールは、SMTPというプロトコル上でやり取りされます。この時、送信者側がどのホスト名からの接続か宣言されることとなっており、これがいわゆるエンベロープFromと呼ばれます。SMTPプロトコル上ではメールの内容(メールヘッダ+メールボディ)を合わせてテキストとして送信し、メールヘッダの中には送信者を表すFromのヘッダ(いわゆるヘッダFrom) が書かれています。&lt;/p&gt;
&lt;h3&gt;SMTP上でエンベロープFromとヘッダFromを検証する仕組みはない。どのメールを受け取るかは受信者が決める&lt;/h3&gt;
&lt;p&gt;SMTPのプロトコル上は、エンベロープFromとヘッダFromは特に縛りがなく、何を書いても規格上は問題ないメールとして取り扱われます。これが問題で、メールは送信者が好きに自分の身元を名乗りたい放題のプロトコル&lt;sup&gt;&lt;a href=&quot;#user-content-fn-smtp_supported_from&quot; id=&quot;user-content-fnref-smtp_supported_from&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;になっており、送信元のアドレス (=ドメイン) が本当にその人の所有しているものかを確認する術がありません。このような性質から、スパムメールと呼ばれる正当な送信元ではないメールも多数流通し、それに対応するために、インターネット上のメールというエコシステムでは、基本的に受信者が受信するかどうかを決めることでコントロールしている、というふうな構図となっています。&lt;/p&gt;
&lt;h3&gt;大手の受信者が公開しているポリシーに、送信側は実質的に従う必要がある&lt;sup&gt;&lt;a href=&quot;#user-content-fn-mail_provider_policy&quot; id=&quot;user-content-fnref-mail_provider_policy&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/h3&gt;
&lt;p&gt;特に影響力のある大手の受信者(GmailやMicrosoft(outlook.com)、iCloud等)に受信してもらえるよう、送信者側がその基準を満たすようなメールを送る必要性が、昨今高まっています。明確に方針として示されたのが、2024年から適用されている、いわゆる&lt;a href=&quot;https://support.google.com/a/answer/81126?hl=ja&quot;&gt;Gmailガイドライン&lt;/a&gt;です。Gmailに向けてメールを送る全ての送信者に一定の基準を設け、また大量送信者には、より厳しい基準を設け、満たさないメールは受信拒否すると宣言されました。後述する、メール送信者認証技術 (DMARC=pass) への準拠が求められるようになったことで、メールの送信者、特に大量送信者にはその対応が求められました。また、現在や今後も、大手受信者のポリシー変更があれば、追従する必要があります。&lt;/p&gt;
&lt;h2&gt;個々のメール送信者認証技術&lt;/h2&gt;
&lt;p&gt;メールの仕組みに話を戻しましょう。&lt;/p&gt;
&lt;p&gt;受信者側が、そのメールに書かれている送信元が正当かどうかを確認する等のための仕組みとして、メール送信者認証技術があります。これが SPF, DKIM, DMARC (そしてBIMI！) などの各種規格です。&lt;/p&gt;
&lt;h3&gt;DNSレコードに書かれていることは、ドメインの所有者の意思で書かれているはず&lt;/h3&gt;
&lt;p&gt;どのプロトコルも基本的に、DNSを信頼の元としています。ドメインの正当な所有者だけがDNSにレコードを登録でき、世界にその情報が正しいと伝えることができるはず、という点が起点となっています。DNSのTXTレコードに書いてあるを信頼し、受信したメールがそれと一致するかを、受信者側で検証することで、メール自体も信頼できるかを判断できるようになっています。&lt;/p&gt;
&lt;h3&gt;SPF (passならば、エンベロープFromのドメイン所有者が認めたIPアドレスのサーバから送られたとわかる)&lt;/h3&gt;
&lt;p&gt;SPFは、次のようなDNSレコードを公開するものです。ドメインの所有者が、メールを送出するサーバのIPアドレスをTXTレコードとして宣言することで、それ以外のメールサーバから送出された場合は不正であると判断できるようになります。SMTPはTCP/IP上で成立していますから、送信元のIPアドレスは通信時にわかるので、それと比較して問題ないかを確認できます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com. IN TXT &quot;v=spf1 ip4:192.0.2.100 ~all&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただし、ここで受信者が引くドメインは、エンベロープFromのドメインです。ヘッダFromに書かれた内容は検証されません。一般的なメールクライアントで送信元メールアドレスとして表示されているのはヘッダFromですが、全く違っていても検証されず、SPFはpassしたと判断されます。&lt;/p&gt;
&lt;h3&gt;DKIM (passならば、署名したドメインの所有者がそのメール内容を送信したとわかる)&lt;/h3&gt;
&lt;p&gt;DKIMは、次のようなDNSレコードを公開するものです。ドメインの所有者が、公開鍵を公開します。メール送出時にドメインの所有者(か権限を委譲された者。以下略します)しか知らない秘密鍵でメールの内容に署名することで、署名を検証すれば、ドメインの所有者の送出したメールの内容(ヘッダやボディ) が正しいことを検証できます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default._domainkey.example.com. IN TXT &quot;v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3JbLw...（公開鍵の文字列）...AQAB&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただし、ここで署名したドメインは、ヘッダFromやエンベロープFromでなくても良いことになっています。&lt;/p&gt;
&lt;h3&gt;DMARC&lt;/h3&gt;
&lt;p&gt;DMARCは、次のようなDNSレコードを公開するものです。メールの受信者に対して、受信したメールの取り扱い方法を宣言するものです。SPFやDKIMをどの程度厳格に検証すべきか、また検証失敗時にその旨をレポートする先を示しています。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_dmarc.example.com. IN TXT &quot;v=DMARC1; p=quarantine; rua=mailto:dmarc-report@example.com; ruf=mailto:dmarc-forensic@example.com; fo=1; adkim=r; aspf=r&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DMARCには、SPFやDKIMを組み合わせて、メール送信元の確からしさを判定する基準の一つである「アライメント」を定めています。また、DMARCの基準を満たしていない場合に、それをレポートする仕組みがあります。順に見ていきましょう。&lt;/p&gt;
&lt;h4&gt;アライメント&lt;/h4&gt;
&lt;p&gt;SPFアライメントはエンベロープFromとヘッダFromが一致している時に、満たしていることとなっています。SPFがpassしている状況下では、送信者として表示されるヘッダFromのドメイン所有者が、そのメールが送出されたメールサーバ(IP)を信頼しているので、その点で確からしいメールだと言えるでしょう。&lt;/p&gt;
&lt;iframe class=&quot;speakerdeck-iframe&quot; frameborder=&quot;0&quot; src=&quot;https://speakerdeck.com/player/e47be4bcb39e4c2abdc4ea0ad2588cf4?slide=49&quot; title=&quot;実録_マルチテナント環境でのGmailガイドライン対応&quot; allowfullscreen=&quot;true&quot; style=&quot;border: 0px; background: padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;&quot; data-ratio=&quot;1.7777777777777777&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;DKIMアライメントは署名ドメインとヘッダFromのドメインが一致している時に満たしていることとなっています。DKIMがpassしている状況下では、これを満たすメールは送信者として表示されるヘッダFromのドメイン所有者がメール本文に署名していることから、その点で確からしいメールだと言えるでしょう。&lt;/p&gt;
&lt;iframe class=&quot;speakerdeck-iframe&quot; frameborder=&quot;0&quot; src=&quot;https://speakerdeck.com/player/e47be4bcb39e4c2abdc4ea0ad2588cf4?slide=51&quot; title=&quot;実録_マルチテナント環境でのGmailガイドライン対応&quot; allowfullscreen=&quot;true&quot; style=&quot;border: 0px; background: padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;&quot; data-ratio=&quot;1.7777777777777777&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;なお、SPFまたはDKIMのいずれかにpassし、かつSPFアライメントもしくはDKIMアライメントのいずれかをpassしているとき、DMARCにpassしたと判定されます&lt;/p&gt;
&lt;h4&gt;ポリシー&lt;/h4&gt;
&lt;p&gt;DMARCにpassしていないメールがどれくらい流通しているかを、ドメインの所有者が知るために、ポリシーを宣言することとなっています。 &lt;code&gt;none&lt;/code&gt; , &lt;code&gt;quarantine&lt;/code&gt; , &lt;code&gt;reject&lt;/code&gt;  があり、各受信者に、そのポリシーに従ってメールを取り扱うことや、 DMARCをpassしないメールがあったときに、その内容をレポートするメールを送信してほしい旨を宣言します。&lt;/p&gt;
&lt;p&gt;送信者としてのポリシーであり、仕組み上受信者が従わなければならないような制約はないですが、成り立ちからして受信者の事情からできてきたものであるからこのようになっていると理解しています。&lt;/p&gt;
&lt;h3&gt;BIMI&lt;/h3&gt;
&lt;p&gt;BIMIは、次のようなDNSレコードを公開するものです。メールの受信者に対して、送信元のブランドロゴを宣言します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default._bimi.example.com. IN TXT &quot;v=BIMI1; l=https://example.com/logo.svg; a=https://example.com/bimi.pem&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BIMIは、DMARCのポリシーが &lt;code&gt;quarantine&lt;/code&gt; 以上であり、かつロゴが VMC (Verified Mark Certificate) と呼ばれる証明書で署名されている必要があります。VMCでの署名を受けるには、各国の機関による商標等の知的財産権の登録が必要となっています。&lt;/p&gt;
&lt;p&gt;BIMIがサポートされる環境で、確認されたメールには、送信元を表すロゴが、メールクライアントに表示されます。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;というわけで、メールを専門に取り扱わないWebアプリケーションエンジニアにとっては、HTTP以外のプロトコルのことを考える時間は珍しいでしょうし、SMTPとそれをもとに構成された多層のメールエコシステムに関する理解は、忘れてしまうと面倒そうなのでメモとして書き出しました。&lt;/p&gt;
&lt;h2&gt;メール技術のキャッチアップ&lt;/h2&gt;
&lt;p&gt;私が2024年や2025年にメールに関する学びを得た書籍とWebサイトを紹介して終わります&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.shoeisha.co.jp/book/detail/9784798183930&quot;&gt;実務で使える メール技術の教科書&lt;/a&gt; ... 2025年現在で、メールに関連する技術を、その分野に詳しくないソフトウェア開発者がゼロから知ろうと思った時に事前知識なく読み始められる丁寧な書籍&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/azumakuniyuki/feb-2024-no-auth-no-entry&quot;&gt;azumakuniyuki/feb-2024-no-auth-no-entry&lt;/a&gt; ... Gmailガイドラインをはじめとする、2024年以降の大手メール受信者プロバイダの公開するポリシーを時系列で記録したリポジトリ。過去に公開されていた内容との差分や、特定の事業者に閉じない大手メール受信プロバイダの動向に気づくことができる&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://speakerdeck.com/azumakuniyuki/gu-iji-shu-nituite-smtpxian-dai-shi-qing-tumamishi-i&quot;&gt;古い技術について SMTP現代事情つまみ食い&lt;/a&gt; ... SPF/DKIM/DMARCの関係性を説明してくれている&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://workaround.org&quot;&gt;ISPmail GUIDE&lt;/a&gt; ... Postfixの設定や運用として2025年に求められるものを最小範囲で実現し、手元でメールサーバを動かしてみることができる手順を解説したドキュメント。Postfixに関する書籍や入門書は最近見かけておらず、このリポジトリを読み進めながら触るのが結構良さそうという感触を得た。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7208&quot;&gt;RFC7208: Sender Policy Framework (SPF)&lt;/a&gt; ... SPFのRFC&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6376&quot;&gt;RFC6376: DomainKeys Identified Mail (DKIM) Signatures&lt;/a&gt; ... DKIMのRFC&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7489&quot;&gt;RFC7489: Domain-based Message Authentication, Reporting, and Conformance (DMARC)&lt;/a&gt; ... DMARCのRFC&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/draft-brand-indicators-for-message-identification/&quot;&gt;Internet Draft: Brand Indicators for Message Identification (BIMI)&lt;/a&gt; ... BIMIはまだRFCになっていない&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twilio-cms-prod.s3.amazonaws.com/documents/Generic_IP_Warmup_Schedule.pdf&quot;&gt;Generic IP Warm Up Schedule&lt;/a&gt; ... (メール送信者認証技術と直接関連ないが)新しいIPv4アドレスを使ってメールを送るにあたっての具体的なIPウォームアップの指標をSendGridが示してくれている表&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-smtp_supported_from&quot;&gt;
&lt;p&gt;ここでは2025年現在の視点から、現時点でわかりやすく理解するために「名乗りたい放題のプロトコル」と表現していますが、実際にはインターネット技術の発展とともに、現在のメールエコシステムを構成するパーツが一つずつ構成されていったのであって、SMTP自体は、シンプルな文書通信のためのプロトコルであるでしょうし、その成り立ちや技術に対する対する批判等の意味合いは持っていません。ただ、パーツが色々あるので、新米Web技術者が今からキャッチアップするのは、普段メールシステムに馴染みがないとなかなか大変だという感想を持っています。 &lt;a href=&quot;#user-content-fnref-smtp_supported_from&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-mail_provider_policy&quot;&gt;
&lt;p&gt;ここでは送信者の視点で「従う必要がある」などと書いていますが、実際には受信側からするとそのような方法でしかメールの確からしさを確認したり、大量受信による負荷を抑制することができませんし、メール全体のエコシステムとしてそのようなポリシーの公開や適用は必要である、と前向きに捉えています。 &lt;a href=&quot;#user-content-fnref-mail_provider_policy&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>GMO Developers Day 2024に登壇した</title>
      <link>https://memo.yammer.jp/posts/gmo-developers-day-2024</link>
      <pubDate>Sun, 01 Dec 2024 14:59:05 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/gmo-developers-day-2024</guid>
      <description>&lt;p&gt;昨日、11/29, 30に開催されたGMO Developers Day 2024の「EC決済 開発責任者対談」というセッションに登壇した。&lt;/p&gt;
&lt;p&gt;Developers Dayの登壇は昨年に続き2回目で、前回に引き続きGMOグループとして力入れてるなというのを感じる。&lt;/p&gt;
&lt;p&gt;今年も、去年私が登壇した枠と似たようなパネルディスカッションに近い形式で、 &lt;a href=&quot;https://x.com/inamoly&quot;&gt;@inamoly&lt;/a&gt; によるモデレータ+3人での対談を行った。事前の打ち合わせで何を話すか多少擦り合わせていたが、そのときに出てない話も本番では話していたり、対談の臨場感が現れた発表になったと思う。&lt;/p&gt;
&lt;p&gt;対談形式の発表は特定のメッセージを強く伝えるようなものではないが、当日聴いていただいていた参加者の層はけっこうバラエティ豊かだったようなので、日頃考えていることや実践していることがどのようなものであるか、等身大で知ってもらうという意味で、会場の雰囲気にマッチした発表になったのではないだろうか。&lt;/p&gt;
&lt;p&gt;今年はあまり緊張せずに望めたのだけど、発表がおわってから「他の人の2倍の時間2倍の速度で話していたので情報量4倍」「身振り手振りで全身使っているのがいつもどおり」などのお声をいただき、 (それはそれでよかったのかもしれないが) もうちょっと緊張するぐらいがよかったかもしれない。&lt;/p&gt;
&lt;p&gt;昨年もそうだったのだけど、このイベントはグループ横断でやるので対談する我々も打ち合わせで初めて出会うといったところがあり、近いセグメントの他の会社でどのようにやっているのかを聞けて私も新鮮な気持ちで学びになった。&lt;/p&gt;
&lt;p&gt;聴いていただいた方ありがとうございました。&lt;/p&gt;
&lt;p&gt;アーカイブはこちら: &lt;a href=&quot;https://m.youtube.com/live/WZVXaUOFIVA?t=16200s&quot;&gt;GMO Developers Day 2024【Day2 Track A】&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;この記事は、&lt;a href=&quot;https://adventar.org/calendars/9991&quot;&gt;GMOペパボ EC Advent Calendar 2024&lt;/a&gt;の1日目、そして&lt;a href=&quot;https://adventar.org/calendars/10317&quot;&gt;GMOペパボ エンジニア Advent Calendar 2024 (🎄会場)&lt;/a&gt;の1日目の記事でした。&lt;/p&gt;</description>
    </item>
    <item>
      <title>GMOペパボ EC事業部CTOに就任しました</title>
      <link>https://memo.yammer.jp/posts/cto-in-ec-div</link>
      <pubDate>Mon, 07 Oct 2024 02:00:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/cto-in-ec-div</guid>
      <description>&lt;p&gt;2024年10月1日付で、GMOペパボ株式会社 EC事業部CTOに就任しました。&lt;/p&gt;
&lt;h2&gt;事業部CTOとは&lt;/h2&gt;
&lt;p&gt;事業部CTOは、ペパボのエンジニアリングマネジメントラインのなかで、部門の技術領域の責任者として設けられていたSEL(シニアエンジニアリングリード)&lt;sup&gt;&lt;a href=&quot;#user-content-fn-ctl&quot; id=&quot;user-content-fnref-ctl&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;を、2024年2月に再定義&lt;sup&gt;&lt;a href=&quot;#user-content-fn-minicto&quot; id=&quot;user-content-fnref-minicto&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;した役職です。&lt;/p&gt;
&lt;p&gt;部門ごとに異なる事業を運営するペパボは、事業部門のなかに開発組織を含む様々な職種のパートナーがおり、それぞれ様々なサービスを提供しています。事業部CTOという役職は、技術と技術組織の責任者として部門を成長に導くという点は以前のSELと変わらず、部門をひとつの会社として見立てたときのCTOの果たすべき役割を、より強く明確にしたものといえます。&lt;/p&gt;
&lt;p&gt;ところでCTOとはどのようなものでしょうか？これを端的に説明したものとしては、次の文章がわかりやすいでしょう。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CTOとは、その会社が現在の成長段階で必要としている戦略的技術系幹部&lt;/p&gt;
&lt;p&gt;(エンジニアのためのマネジメントキャリアパス p217  - オライリー・ジャパン発行)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これを事業部に当てはめると、いまの事業部の成長段階に求められていることを技術の面からとらえ、長期的な視点で、成果を実現するための策を立案し実行すること、その枠組みが運用された状態をつくることが求められています。&lt;/p&gt;
&lt;h2&gt;やっていき&lt;/h2&gt;
&lt;p&gt;事業部CTOとしての私の仕事は、カラーミーショップをはじめとするEC事業部の事業をより一段と成長させ、ショップオーナー様に喜んでもらい、EC事業部の目標を達成し、そしてECの多様性をひろげること、それを実現するために技術と技術者組織としてできるあらゆる戦略をたて実行すること/それを支援し実現することです。&lt;/p&gt;
&lt;p&gt;既にEC事業部には前任の&lt;a href=&quot;https://twitter.com/kenchan&quot;&gt;@kenchan&lt;/a&gt;を中心に積み上げてきた、システムを支える様々な技術、そして素晴らしいパートナーのみなさんをはじめとする技術者組織がありますが、現状に満足しない私たちには、次なる挑戦が待っています。&lt;/p&gt;
&lt;p&gt;EC事業部を中心にパートナーのみなさんにはこれまで以上に頼ることが増えるでしょうし、皆さんの力を借りて前に進むことになると思います。いままで支えていただき感謝しています。今後ともどうぞよろしくお願いします。&lt;/p&gt;
&lt;p&gt;バーンとやっていくぞ〜！&lt;/p&gt;
&lt;h2&gt;お隣さん&lt;/h2&gt;
&lt;p&gt;同日にホスティング事業部CTOに就任した&lt;a href=&quot;https://twitter.com/takumakume&quot;&gt;@takumakume&lt;/a&gt;のポストはこちら。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://takumakume.github.io/blog/2024-10-01-hosting-division-cto/&quot;&gt;GMOペパボ株式会社 ホスティング事業部CTOに就任しました&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;kumeさんはあらゆることをバリバリ進めていて、話していると「負けていられないぞ」という気持ちになります。&lt;/p&gt;
&lt;h2&gt;お誘い&lt;/h2&gt;
&lt;p&gt;ペパボとペパボパートナーの話ばかりしていてきになったあなたにはこちら！いま絶賛採用募集中です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://recruit.pepabo.com/&quot;&gt;GMOペパボ株式会社 採用サイト&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;仕事中の私とのカジュアル面談も、とくに関係ないご飯や飲み会の誘いも歓迎してます！&lt;a href=&quot;https://twitter.com/yammerjp&quot;&gt;XのDM&lt;/a&gt;かなにかで連絡ください。&lt;/p&gt;
&lt;p&gt;また、&lt;a href=&quot;https://recruit.pepabo.com/features/graduate/&quot;&gt;26卒の新卒採用&lt;/a&gt;やってます。私も21卒で新卒で入ったので、ペパボやエンジニアリングマネジメントラインの仕事がきになるという方いたら声をかけてください、お話ししましょう！&lt;/p&gt;
&lt;p&gt;そして！特に大事なこちら！EC事業部としても採用してます。&lt;a href=&quot;https://open.talentio.com/r/1/c/pepabo/pages/90202?_gl=1*1v1e78l*_ga*Nzk1MjAxMDUuMTcwNTUwNTQ3Ng..*_ga_LER6JRTV8K*MTcyNzcxNDk4NC45LjEuMTcyNzcxNTAwMy4wLjAuMA..#_ga=2.34455265.1798052879.1727713029-79520105.1705505476&quot;&gt;Webアプリケーションエンジニア&lt;/a&gt;も&lt;a href=&quot;https://open.talentio.com/r/1/c/pepabo/pages/90748?_gl=1*jnasu4*_ga*Nzk1MjAxMDUuMTcwNTUwNTQ3Ng..*_ga_LER6JRTV8K*MTcyNzcxNDk4NC45LjEuMTcyNzcxNTEwMC4wLjAuMA..#_ga=2.265542863.1798052879.1727713029-79520105.1705505476&quot;&gt;デザイナー&lt;/a&gt;も！今がチャンス！まってます&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-ctl&quot;&gt;
&lt;p&gt;当初2016年に設定された時はCTL(チーフテクニカルリード)という名前でした。 &lt;a href=&quot;#user-content-fnref-ctl&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-minicto&quot;&gt;
&lt;p&gt;ある種CTOに近い役割が求められていることは&lt;a href=&quot;https://scrapbox.io/kenchan/GMO%E3%83%9A%E3%83%91%E3%83%9CEC%E4%BA%8B%E6%A5%AD%E9%83%A8%E3%81%AE%E3%83%81%E3%83%BC%E3%83%95%E3%83%86%E3%82%AF%E3%83%8B%E3%82%AB%E3%83%AB%E3%83%AA%E3%83%BC%E3%83%89%E3%81%AB%E5%B0%B1%E4%BB%BB%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F&quot;&gt;CTLができたその時から意識されていた&lt;/a&gt;わけですが、名前としてそれを表すことで期待と責任を示したことを、ここでは「再定義」と呼んでいます。 &lt;a href=&quot;#user-content-fnref-minicto&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>財務3表一体理解法を読んだ(2024年8月)</title>
      <link>https://memo.yammer.jp/posts/2024-08-pl-bs-cf-introduction</link>
      <pubDate>Sun, 22 Sep 2024 14:44:08 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/2024-08-pl-bs-cf-introduction</guid>
      <description>&lt;p&gt;8月に読んだ本のメモが下書きのまま眠っていたので投稿しておく。また当方は会計の専門家ではないので、この感想にツッコミどころがあったらこっそり教えてください。&lt;/p&gt;
&lt;h2&gt;はじめに&lt;/h2&gt;
&lt;p&gt;企業における会計のことを少しはわかっていなくてはと思い、友人に薦められた財務3表一体理解法という本を読んだ。&lt;/p&gt;
&lt;p&gt;学生時代も入社してからも会計のことを学んでおらず、PL (Profit and Loss Statement / 損益計算書) やBS (Balance Sheet / 貸借対照表)、CF (Cash Flow Statement / キャッシュフロー計算書) というのを名前は知っていても実態は正直わかっていないという状態だったが、本を通して全体感を知ることができた。&lt;/p&gt;
&lt;p&gt;知りたいことがまさに書かれていて、一冊目に読む本がこれでよかった。(正確性をとるとおそらく大胆に削っているところがあると本の中で但し書きされているが) PLとは？BSとは？というレベルの会計素人が、まず最初に雰囲気を知るにはとてもよいと思うので、同じ境遇の人がいたらぜひお勧めしたい。&lt;/p&gt;
&lt;h2&gt;印象に残ったこと&lt;/h2&gt;
&lt;h3&gt;前提&lt;/h3&gt;
&lt;p&gt;冒頭に前提として、すべての会社に共通する3つの活動は「お金を集める」「投資する」「利益をあげる」の3つからなるということがかかれている&lt;/p&gt;
&lt;p&gt;これらを数字で表現するのが財務3表であるとして、財務3表の概略的な説明が冒頭になされている。&lt;/p&gt;
&lt;h3&gt;財務3表の関係&lt;/h3&gt;
&lt;p&gt;93ページには、3表がどう関連してどう動くかが示されている。その後、本の中頃では、表題の通り財務3表を一体に理解できるよう、かんたんな仕分けをいくつか、常に財務3表にどう反映され、それらがどう繋がっているのかを示しながら説明が続く。各例をもとにそれぞれの関係を常に意識させながら説明が続くので、全体感を把握しやすい。&lt;/p&gt;
&lt;p&gt;会計を専門にする気が今のところない物としては、全体としてそれらがどういう役割で、ざっくりどういう意味を持っているのかということを知りたく、それが説明されていてとても良かった。&lt;/p&gt;
&lt;p&gt;その流れというのは、ざっくりと次のようなものだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PLによって資産の出入りが表現され、その積み重ねによってBSの利益剰余金が積み上がる&lt;/li&gt;
&lt;li&gt;前年度のBSをもとに今年度のPLをあて、CFをあてたら翌年のBSになる&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;そのほか印象に残ったこと(メモ)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;前提として、PLとBSの数字は必ずしも現金の動きを表すものではない&lt;/li&gt;
&lt;li&gt;BSのBalanceというのは「残高」という語から来ていると筆者は考えている&lt;/li&gt;
&lt;li&gt;りし ... 借り方と貸し方という表現は、現代におけるそれぞれの言葉の意味に紐づくというよりも、慣習的にそうなっているという側面が強い&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;身近な会計&lt;/h3&gt;
&lt;p&gt;本の中で直接触れられているわけではないが、この本を通して内製ソフトウェア開発をしている事業会社における、ソフトウェア資産計上と原価の違いを知ることができた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-principle&quot; id=&quot;user-content-fnref-principle&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;PLといわれても学園と言わないように、BSと言われても衛星放送と思わないように、CFといわれてもコンパクトフラッシュと聞き返さないように、この本を起点に会計に関する理解を少しずつ深めていきたい。&lt;/p&gt;
&lt;p&gt;ちなみにこの本はシリーズになっていて、分析編や発展編というのもある。とても良い本だったので早速発展編を買ったのだが、買ってから中を開くと今知るべき内容かは判断がつかなかったので、積んでおいて技術書のあいまに気が向いたら読むことにする。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-principle&quot;&gt;
&lt;p&gt;友人にこの話を聞いた時に、最初にソフトウェア資産計上の目的 (会計の原理原則として、投資家等にその会社の状況(ここでいえばソフトウェア資産)を正しく伝えるためにある) を教えてくれたことで、より理解が深まった &lt;a href=&quot;#user-content-fnref-principle&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>私と技術カンファレンス 2023 (雑文)</title>
      <link>https://memo.yammer.jp/posts/tech-conference-2023</link>
      <pubDate>Sun, 31 Dec 2023 14:51:18 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/tech-conference-2023</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://qiita.com/advent-calendar/2023/tech-conference&quot;&gt;技術カンファレンス Advent Calendar 2023&lt;/a&gt;、11日目の記事をお送りします。今は2023/12/31な訳ですが、今年中に出し切るということで先ほどから書き始めました。推敲していない雑文をお許しください。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;私がカンファレンスにはじめてちゃんと参加したのはPHP Conference Japn 2022であった。これはスポンサー枠で登壇したもので、緊張もしたけれど思ったよりもたくさんの方に聞いていただいて嬉しかった。&lt;/p&gt;
&lt;p&gt;社内のレビューによってとても良い発表ができたが、いっぽうで会社の代表なので、会社としての取り組みを紹介するというのが主だった。自分でプロポーザルを書いて出して自分のやったことを話したい、という気持ちを強くし、次は自分でプロポーザルを出すことにした。&lt;/p&gt;
&lt;p&gt;PHPerKaigi 2023ではLTのプロポーザルを出して、登壇できたのだけれど、とにかくこのイベントは楽しかったのを覚えている。カンファレンスは自分が普段能動的にキャッチアップするより少し外のことを知る機会になるし、会社に閉じない技術的なトピックについて話したり確認する場にもなるし、出会った人と談笑したりと、他では得られない経験を得られる。&lt;/p&gt;
&lt;p&gt;RubyKaigi 2023は、言語を作る人たちのお祭りというところで、規模もそうだが、ランタイムに関する話題がたくさんあったのが印象的だった。自分は言語を使う人なので全然ついていけない話題ばかりだけれど、学校の授業で習って教科書的なトピックだなと思っていたLALR(1)構文解析の今をしれたり、JITの今をしれたり、とても刺激的だった。Webというのはソフトウェアエンジニアリングの中でも一部の領域を扱っているだけなので、それよりも外の部分に視点を持つことを忘れずにいたい。&lt;/p&gt;
&lt;p&gt;PHPerKaigiのLTに登壇できることになったので、次はもっと長い枠の登壇をということで、PHP Conference Japan 2023にプロポーザルを出してみたけどこれは残念ながら通らず、このイベントは参加者とブース運営の人として参加した。セッションはあまり聞けていないのだけど、カンファレンスに参加し始めて1年くらいということもあって、少しずつ顔を見知った友人や知り合い、以前話したことのある方もいるというので、また話すのが楽しかったりした。(カンファレンスに限らず、今年は都合で行けなかった勉強会にも、来年は行きたい。)&lt;/p&gt;
&lt;p&gt;プロポーザルはその後も継続的に出していて、来年はいまのところ、&lt;a href=&quot;https://fortee.jp/yapc-hiroshima-2024/proposal/0e545260-61e1-465e-951c-91d6afb7782c&quot;&gt;YAPC::Hiroshima 2024&lt;/a&gt;と&lt;a href=&quot;https://event.shoeisha.jp/devsumi/20240215/session/4834&quot;&gt;Developers Summit 2024&lt;/a&gt;で採択いただけて話すことになっている。これに限らず、参加者、発表者、またもしかしたら別の形でも、カンファレンスに参加したり盛り上げたりして、会社に閉じずに、技術者として技術の向上に励んだり、楽しんだり、知見を広げたりしていきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;カンファレンスという場を作ってくださっている皆さんにはいつも感謝しています。自分も少しでもより良い場所になるように、関わっていけたらと思っています。&lt;/p&gt;
&lt;p&gt;それでは、良いお年を。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ISUCONに初めて参加した(2023年12月)</title>
      <link>https://memo.yammer.jp/posts/isucon13</link>
      <pubDate>Fri, 08 Dec 2023 14:43:12 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/isucon13</guid>
      <description>&lt;p&gt;(2024/09/22記) 去年のISUCON13に参加したときの記録が下書きのままになっていたので、いまさらですが公開します。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;同期の @homirun @yukun と一緒に、ISUCON13に参加しました。&lt;/p&gt;
&lt;p&gt;結論はこれ。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;くやしい、おもろい！&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1728340237146112188?ref_src=twsrc%5Etfw&quot;&gt;November 25, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;最後のスコアは1万点にギリギリ届かず満足できないけれど、何もわからんという感じにはならずやることはたくさん見えていたので、次回(が開催されるならば)ご期待ください！&lt;/p&gt;
&lt;h2&gt;やったこと&lt;/h2&gt;
&lt;h3&gt;前日まで&lt;/h3&gt;
&lt;p&gt;夏頃から、毎週1時間くらい業務後にあつまって練習していた。&lt;a href=&quot;https://gihyo.jp/book/2022/978-4-297-12846-3&quot;&gt;ISUCON本&lt;/a&gt;を読んで&lt;a href=&quot;https://github.com/catatsuy/private-isu&quot;&gt;private_isu&lt;/a&gt;をいじってみたり、APMを入 れてみたり。1時間でできることは限られているけれど、なんもわからんというところからちょっとずつ全体感をつかむこ とができた。&lt;/p&gt;
&lt;p&gt;前々日には、本番の半分くらいの時間で&lt;a href=&quot;https://github.com/isucon/isucon12-qualify&quot;&gt;ISUCON12の予選問題&lt;/a&gt;を解いた。ベンチマーカーのCLIの引数にIPアドレスを指定できることに気づかずベンチマーカー内の名前解決に困ったり、初手でSQLite -&gt; MySQL移行をしようとし詰まったり、ほぼ 何もできなかった。この経験はおそらく当日に生きていて、この日に先にハマっておいたおかげで、当日無理にロードバランシングに手をつけずに済んだ感がある。&lt;/p&gt;
&lt;p&gt;前々日と当日は、渋谷某ビルの(勝手)サテライト会場で開催した。物理的に集まってホワイトボードに構成を書いたりしながら同期的に進めるのは、結構楽しさがあった。&lt;/p&gt;
&lt;h3&gt;当日午前&lt;/h3&gt;
&lt;p&gt;当日の出来事は以下のような感じ。(全部覚えていないので、自分以外のメンバーがやってくれたことは書かれていないことも結構あると思う)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初手は競技とアプリケーションのドキュメントの読み合わせ&lt;/li&gt;
&lt;li&gt;次に、Cloud Formationで起動してそのままベンチマークを一回回してもらった&lt;/li&gt;
&lt;li&gt;最初はMySQLの中身をdumpして保全したりした。(これはあんまりいらなかったかも)&lt;/li&gt;
&lt;li&gt;Datadogをさくっと導入してくれたので、一番上に出ていた&lt;code&gt;/api/user/:username/statistics&lt;/code&gt;のうち、ランク算出のN+1を直す。&lt;code&gt;GROUP by user_id&lt;/code&gt;でSUM/COUNTするクエリにして、一番重そうなところを直したらボトルネックが他に移った。N+1がまだ残っているのを横目に見つつ、呼ばれる回数が少ないエンドポイントなので他を優先するために無視。&lt;/li&gt;
&lt;li&gt;裏ではPowerDNSをやめたりMySQLを分離したりタグ周りのN+1を潰したりしてくれていた&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;当日お昼頃&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;コードをローカルで編集しても試しづらいので、途中で占有できる実行環境が欲しくなり、Cloud Formationをつかって競技外のインスタンスを開発用に用意してもらって、そこで自分だけのVMを手に入れた。&lt;/li&gt;
&lt;li&gt;このあたりでサブウェイにみんなでランチを買いに行った気がする。エビアボカドを頼んだ。フットロングにはしなかった。&lt;/li&gt;
&lt;li&gt;Datadogの合計実行時間の長いクエリを上から眺めて、貼っていった。&lt;code&gt;ORDER BY created_at&lt;/code&gt;がいくつかあったけど主キーがAUTO INCREMENTだったから主キーでソートすることにしたりした。&lt;/li&gt;
&lt;li&gt;ここまでのVM分離とN+1とインデックス追加で10000点ちかく行っていた気がする。(合ってるっけ) このあたりまでは結構順調だった気がする&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;当日夕方&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/api/livestream/:livestream_id&lt;/code&gt;のN+1がひどいので直そうとしたが、バグらせてしまって元に戻すなど。ベンチマーカーがエラーを吐く状況をつかめなくて、再現できずに結局最後までこの変更を入れることはできず。&lt;/li&gt;
&lt;li&gt;裏では重そうな箇所をメモリでキャッシュする戦略を試してくれていたっぽい。詳しくはみていないがキャッシュのパージタイミングがむずそうっぽかった。&lt;/li&gt;
&lt;li&gt;MySQLのパラメータチューニングや、DNSとアプリのVMの分離で、+1000点弱あがっていそうだった&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;振り返り&lt;/h2&gt;
&lt;h3&gt;よかったこと&lt;/h3&gt;
&lt;p&gt;ローカルに開発環境を用意しようとしなかったのは良かったと思う。しゅっとできないと時間が食われてしまうので。&lt;/p&gt;
&lt;p&gt;チームメンバーが自分ができないことをバンバンしゅっとやってくれてとてもありがたい限りだった。yukunがDatadogをさっと入れて、なんなら競技時間中に全然わかっていない私にDatadogの使い方を説明してくれたり、homirunにミドルウェアまわりを完全に任せっきりにしていたが勝手にいい感じにしてくれていたり。&lt;/p&gt;
&lt;p&gt;Datadogが最強すぎて、スロークエリログもエンドポイントごとのalpでの解析もみずに、Datadogみておけばいいじゃんという感じだった。これのおかげで、次何やればいいかわからんみたいなことにはならずに「明らかにここらへんをやったほうがいい」がわかる状態になれた。&lt;/p&gt;
&lt;h3&gt;改善したいこと&lt;/h3&gt;
&lt;p&gt;設定ファイルやスクリプトなどは持ち合わせていなかったので、viキーバインドでないbashターミナルや、コミットメッセージを入力するときに起動するnanoに困ったりしていた。共有環境にdotfilesをそのまま流し込むと他の人も影響を受けるので、自分だけ効くような初期化スクリプトを用意しておく方がいいかも。&lt;/p&gt;
&lt;p&gt;明らかにN+1なのはすぐにみつかるけど、それをユニットテストもローカルの開発環境もない中、短い時間でコードを一気に書き換えきるみたいなことに慣れておらず、なかなかうまく直せなかった。&lt;/p&gt;
&lt;p&gt;コードを書いてから動作確認までのフィードバックループが長くなりがちなので、たとえばGETの正常系の動作確認などでもいいから、簡単なものはさっと動作確認できる環境を整えておいた方が良かったのかも。変更前と変更後で同じcurlコマンドの結果が一致することを確認する、みたいな。&lt;/p&gt;
&lt;p&gt;後半に取り組んでいた改善は結局入れられなかったので、バグらなそうな変更方針を建てて、走りきれそうな範囲を決めて直す、というふうにしたほうがよかったかもしれない。全部直すのは時間的に絶対無理なようなので。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;とてもおもしろい会を開催してくださった運営の皆様に感謝します。一緒に戦ってくれたチームメンバーに感謝します。くやしい、そして楽しかった！&lt;/p&gt;</description>
    </item>
    <item>
      <title>チームが気付き、変化する</title>
      <link>https://memo.yammer.jp/posts/team-dynamics-evolving</link>
      <pubDate>Sun, 03 Dec 2023 10:42:23 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/team-dynamics-evolving</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://adventar.org/calendars/8672&quot;&gt;GMOペパボ EC Advent Calender&lt;/a&gt;の2日目は、yammerから、私の所属するチームについての話題を紹介します。&lt;/p&gt;
&lt;p&gt;1日目の記事は、&lt;a href=&quot;https://twitter.com/kenchan&quot;&gt;@kenchan&lt;/a&gt;の『&lt;a href=&quot;https://scrapbox.io/kenchan/%E3%80%8C%E7%82%AD%E9%89%B1%E3%81%AE%E4%B8%AD%E3%81%AE%E3%82%AB%E3%83%8A%E3%83%AA%E3%82%A2%E3%80%8D%E3%81%AB%E3%81%AA%E3%82%8B&quot;&gt;「炭鉱のカナリア」になる&lt;/a&gt;』でした。自分が今年、消防車を呼べたとき、呼べなかった時はいつだっただろうか？と思い出しながら読みました。3日目の記事は&lt;a href=&quot;https://github.com/Tatsumi0000&quot;&gt;@tatsumi000&lt;/a&gt;の、「&lt;a href=&quot;https://blog.aespa.love/development-environment-nvim-2023&quot;&gt;開発環境.nvim 2023&lt;/a&gt;」です。Vimmerでありながら就業時間中はVSCodeのVimプラグインに甘んじている身として「1週間くらいNeoVimだけで生活してみようかな」と心が揺さぶられるトピックでした。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-timetravel&quot; id=&quot;user-content-fnref-timetravel&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;私が今いるチームは2023年の年初に発足し、はじまってからおよそ1年が経ちました。1年の中ではさまざまなことがありましたが、チームの中で違和感を感じるたびに、問題を発見し、解決策を見出し、一つずつ変化が加わっていったと感じています。今回は、そういった変化の中で一つ、コードレビューに関する変化を紹介します。&lt;/p&gt;
&lt;p&gt;半年ほど前、Pull Requestのコードレビューが溜まりがちだったあるとき、チームに「&lt;a href=&quot;https://pyama.fun/archives/4414&quot;&gt;良い環境で働く大切さ、良い環境を作り出すためには&lt;/a&gt;」という記事が持ち込まれました。
課題感と、その参照としてこの記事のURLがチームのSlackチャンネルに投稿されたことは、コードレビューに各々が課題間を抱えていることが言語化され、共通認識となるきっかけになりました。課題にチームが気づき、変化した瞬間でした。&lt;/p&gt;
&lt;p&gt;その投稿の後、コードレビューの速度を上げるために、&lt;a href=&quot;https://fujiharuka.github.io/google-eng-practices-ja/ja/review/reviewer/speed.html&quot;&gt;別のドキュメント&lt;/a&gt;なども参考に、いくつかの点が整理されました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;コードレビューは素早く行われる必要があること。少なくとも1営業日以内に返答すること。&lt;/li&gt;
&lt;li&gt;コードレビューが難しい時には、コメントを返す以外のアクションをとると良いこと。たとえば「コードレビューが難しい状態であることを伝える」「Pull Requestの内容や周辺領域の知識について口頭で説明を受ける」「ペアプログラミングをする」など。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こういった整理と認識合わせが行われてから、コードレビューレビューの速度が改善し、滞留することが少なくなったと感じています&lt;sup&gt;&lt;a href=&quot;#user-content-fn-me&quot; id=&quot;user-content-fnref-me&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;。レビュワーが早く返答するだけでなく、レビューのしやすいPull Requestや開発手順にするといった変化を含めて、半年経った今も、上記に示された速度の基準を満たし、ボトルネックになることが少ない状態を維持できていると考えています。&lt;/p&gt;
&lt;p&gt;この変化の重要な点は、チームのSlackチャンネルに、課題に対する呟きがあったことです。チームが問題に気づいて改善するためには、まず、誰かが違和感を感じ、それを共有することが必要です。コードレビューの他にも、たとえば実際にあった以下のような変化も、誰かが課題を共有したからこそ起こったものです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;スプリントゴールの定め方を見直す&lt;/li&gt;
&lt;li&gt;見積もり会を定期開催にする&lt;/li&gt;
&lt;li&gt;ふりかえりの進め方を変える&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;チームが発足して時間が経ち、成熟してきましたが、これからも、違和感に気づき、仕事の進め方に変化をもたらせるチームでありたい/あってほしいと思っています。今日までのチームはメンバー全員がつくってきたもの&lt;sup&gt;&lt;a href=&quot;#user-content-fn-support&quot; id=&quot;user-content-fnref-support&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;で、明日からのチームもメンバー全員が作り出すものです。&lt;/p&gt;
&lt;p&gt;チームのみんな、そして一緒に働いてきたパートナーの皆さん、2023年もお世話になりました。ありがとうございました。来年もどうぞよろしくお願いします。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-timetravel&quot;&gt;
&lt;p&gt;この記事が2日目のものなのに、3日目の記事の感想がかかれているために、時空が捻じ曲がってしまったのではないか？と心配したそこのあなた。その通りです(嘘です)。話がまとまらずに1日遅れてしまったことをどうかお許しください。 &lt;a href=&quot;#user-content-fnref-timetravel&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-me&quot;&gt;
&lt;p&gt;私自身もコードのレビューをする機会が多いので、自分の認識がアップデートされ、レビューの速度に注意を払うようになったという変化も含みます。 &lt;a href=&quot;#user-content-fnref-me&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-support&quot;&gt;
&lt;p&gt;もちろん、チーム外からのたくさんのサポートや、コラボレーションによって作られてきたものでもあります。 &lt;a href=&quot;#user-content-fnref-support&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>人月の神話を少し読む</title>
      <link>https://memo.yammer.jp/posts/the-mythical-man-month-essays-on-software-engineering</link>
      <pubDate>Thu, 13 Jul 2023 05:40:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/the-mythical-man-month-essays-on-software-engineering</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.maruzen-publishing.co.jp/item/?book_no=294733&quot;&gt;人月の神話&lt;/a&gt; (Frederick Phillips Brooks, Jr. 著、滝沢徹 訳、牧野祐子 訳、富澤昇 訳、丸善出版 発行)を、いくつかの章は流しながら読んだ。&lt;/p&gt;
&lt;p&gt;この本は1975年に初版がでたもので、そろそろ発売から50年になろうとしている。記事の中に書かれている個々の事象は「お、まじか」と驚くような (しかし当時としては妥当であっただろう) How Toも多数ある。50年経つことを前提に置いて、細かい事象にはあまり深入りせずに読むことにしていた。&lt;/p&gt;
&lt;p&gt;本の中で語られる「人」と「月」の常に等価交換できないということは、2023年の私の身の回りではありがたいことに当たり前に認識されているように思う。当たり前になっていることが、この本の功績なのだろう。&lt;/p&gt;
&lt;p&gt;本の主張の本質はそのあたりだと思うが、それ以外に本を読んだ中で気になったトピックをいくつか記す。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ソフトウェア実体は、どの2つの部分をとっても似ることが無いので (少なくとも文レベルより上では)、大きさの割にはおそらく他のどの人口構造物よりも複雑なものだ。似通っている部分があれば、2つの類似部分を1つ - 外部または内部サブルーチン - にする。この点においてソフトウェアシステムは、重複要素 (部品) が、豊富なコンピュータやビルあるいは自動車などとは全く異なっている p171&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ソフトウェア実体は、どの2つの部分をとっても似ることが無いと言い切れるかはわからないが、同一では無いとは言えると思う。ソフトウェア製品やソフトウェアデータの良いところの一つに、複製のコストがほぼかからないという点があるが、これをプログラムの内部構造に置き換えると、同一の操作を繰り返す場合はforや、関数、オブジェクトなどで処理をまとめられてしまう。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-squash-good-and-bad&quot; id=&quot;user-content-fnref-squash-good-and-bad&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;建築物や機械製品の場合は同一のパーツというのが多数含まれており、それらの組み合わせで製品が成り立つ。つまり、設計図の中に記述されるコンポーネントは重複がある。プログラムの場合は、重複がないように構造を変えてしまうことができるので、設計図の中のどれも同一のコンポーネントではない。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-realy_q&quot; id=&quot;user-content-fnref-realy_q&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;悲しいかな、自由形式で生成された英語のコマンドを確実に解釈する機能は、コマンドが音声であろうと文字であろうとも、現在の技術を超えてしまっている。p254&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これは初版にはなかった章で、おそらく1995年などが文章中の「現在」にあたるが、この記述はいま大きく変わろうとしているように思う。たとえばスマートスピーカーのようなものはそれを一部示していたし、LLMの台頭により、今後のユーザインタフェースは自然言語をベースにして複雑な、プロ向けの操作も実現可能になるかもしれない。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;プログラマは自分の担当でないモジュールの内部については、見せられるよりも隠蔽された方が非常に効率が良いのだと言う。p265&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これは、例えば一例として低級言語を使う時と高級言語を使う時の違いに近いところがあるだろう。コンピュータのなかで行われている抽象化を自分のプログラムの中でも実装せよ、ということだ。高級言語でメモリアロケーションやメモリ上のデータ配置について考える必要が減るように、OSの提供するシステムコールを使うことでハードウェアの制御を考えなくて良いように、APIを介して外部サービスを使うことで、細かな挙動を気にせずに機能を利用できるように、ということと本質的には一緒に思う。自分が書くプログラムのなかで、どうやると違和感なく理解できる、使いやすいインタフェースになるかを考え、試し、うまい抽象化の方法を見つけるしかない。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-squash-good-and-bad&quot;&gt;
&lt;p&gt;何をまとめて何をまとめないべきかはここでは考えないこととする &lt;a href=&quot;#user-content-fnref-squash-good-and-bad&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-realy_q&quot;&gt;
&lt;p&gt;ここまで書いてみて思ったが、実際のところ何が違うのかは建築物や機械製品に詳しくないのでわからないな、という気持ちになった。ソフトウェアも、サブルーチンの実体は定義が一つだが、その呼び出しは多数の箇所で記述される。非ソフトウェアのコンポーネント自体の設計図が一つで、そのコンポーネントの利用箇所が多数ある、という構造と何が違うのだろうか？わからなくなってきた。 &lt;a href=&quot;#user-content-fnref-realy_q&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>エンジニアのためのマネジメントキャリアパスを読む</title>
      <link>https://memo.yammer.jp/posts/the-managers-path</link>
      <pubDate>Mon, 10 Jul 2023 23:50:38 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/the-managers-path</guid>
      <description>&lt;p&gt;書籍「&lt;a href=&quot;https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%9E%E3%83%8D%E3%82%B8%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AD%E3%83%A3%E3%83%AA%E3%82%A2%E3%83%91%E3%82%B9-%E2%80%95%E3%83%86%E3%83%83%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89CTO%E3%81%BE%E3%81%A7%E3%83%9E%E3%83%8D%E3%82%B8%E3%83%A1%E3%83%B3%E3%83%88%E3%82%B9%E3%82%AD%E3%83%AB%E5%90%91%E4%B8%8A%E3%82%AC%E3%82%A4%E3%83%89-Camille-Fournier/dp/4873118484&quot;&gt;エンジニアのためのマネジメントキャリアパス&lt;/a&gt;」(Camille Fournier著、武舎 広幸、武舎 るみ訳、及川 卓也まえがき、オライリージャパン発行)を読んだ。&lt;/p&gt;
&lt;p&gt;私は一介のジュニアエンジニアで、今はシニアと呼ばれるような能力を身につけることを目指しており、マネジメントのキャリアを主軸に考えているわけではない。ただ、組織に対する視座や解像度が低いと感じることがあり、将来マネジメントのキャリアを拒んでいるわけではないので、気になってこの本を読んでみた。&lt;/p&gt;
&lt;p&gt;この本は、いちメンバーから上級のマネジメント職位に、順を追って話が進む。最初は自分自身が管理される側としてどのようにあるべきか、インターンのメンターに関する話題が取り扱われているので、自分のようなものも読んで得るものがあった。後半の高い職位に関する説明は「そういうふうにやっているのね」というのを俯瞰して流し読みしたという感じで、すぐに自分の知識として生かせるようなものではないが、解像度を読む前よりも多少高めるのに役だったと思う。&lt;/p&gt;
&lt;p&gt;これ以降は、本を読んで気になったところを、フレーズと共にいくつかピックアップして紹介する。&lt;/p&gt;
&lt;h2&gt;部下としての心得&lt;/h2&gt;
&lt;p&gt;第1章「マネジメントの基本」のなかで、マネジメントをするまえに、マネジメントをどうされるべきか、どのような立ち振る舞いが部下に求められているか/マネジメントがしやすいものかが説明されている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;上司に求めることの第1ですが、それは「1対1で行うミーティング(以下「1-1」」です。 p2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;上司に求めることの第2は「フィードバックの提供」です。 p4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;自分自身が何を望んでいるのか、何を学びたいのか、何が自分を幸せにするのかを考え抜いて明らかにする責任はひとえにあなた自身が負っているのです。 p9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;似たような話はあとがきにも書かれている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;人の管理がうまくなりたければ、自分自身を管理できるようにならなければならない。 p279&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本を読んだ中で、説明されている職位と自分の職位が最も一致する章だと思うが、自分自身が上長とどのようにやっていくべきかというのを改めて振り返る機会になった。1on1を、自分と上長の双方のより有意義なものにしていくために、自分が望んでいることを明確にし、そのために必要なことと現状を照らし合わせてフィードバックを得たり、それらを考えるための補助を求める、という行為をあらためて整理してやっていきたい。&lt;/p&gt;
&lt;h2&gt;メンターとしての傾聴&lt;/h2&gt;
&lt;p&gt;第2章「メンタリング」では、インターンやメンターのメンターとしての務めが書かれている。特に、メンターには傾聴が求められているとして、そのうえで以下のように触れられている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「傾聴」とは、指導相手が「口にする言葉だけを耳でとらえる行為」ではないこと。 p17&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;メンターとしての役割を果たす時は(もっと言うと実際それに限らず人とコミュニケーションするときは)、メンティーの些細なしぐさや表情も含めて、相手が何をどのように考えているかを汲み取ってコミュニケーションしていく必要がある。&lt;/p&gt;
&lt;p&gt;上記の点を含め、メンターとしてどういうことが求められているかが文章としていくつかの項目で示されていることはとてもありがたい。自分がサポートを受ける立場のときどうであったか、自分がサポートをしたときどうであったか、これからサポートのための準備やサポートをしていく上でどうするべきであるか、というのを見つめ直すことができる。&lt;/p&gt;
&lt;h2&gt;テックリードに求められるプロジェクト管理のスキル&lt;/h2&gt;
&lt;p&gt;第3章「テックリード」では、エンジニアチームの技術上のリーダーとしてどのように立ち振る舞うかが説明されている。そのなかの一つの「プロジェクトの管理」についての説明は以下のようなものだ。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;プロれジェクト管理に必須である「プロジェクトを分割する作業」には、システムを設計する作業との類似点が多々あるため、プロジェクト管理のスキルを習得するという経験は、人的管理を任されることを望んでいないエンジニアにとっても有意義であるはずです。p38&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;テックリードが最優先しなければならないのは「プロジェクトを推進するための大局的な視点を失わないこと」です。p41&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;テックリードの果たすべきプロジェクトプランナーとしての役割は「作業をデリバリ可能な単位におおまかに分割する」というものです。p42&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;企業としてソフトウェアを開発していくには、長いプロジェクトを俯瞰して、ある程度の進め方やスケジュールの算段が必要になる。&lt;/p&gt;
&lt;p&gt;普段の開発は、アジャイルやスクラムの枠組みの中で、設計し、作業を見積もり可能な粒度に分割し、見積もって、優先順位順に並べ替え、ベロシティを元にして、現時点でどれくらいかかるかなどがわかるように仕事を進める。&lt;/p&gt;
&lt;p&gt;とはいっても、そういう見積もりがすぐにはできないような先の見通しづらいプロジェクトや、年単位のプロジェクトの計画や管理、まだやるとは確実には決まっていない粒度の大きいプロジェクトの検討材料を集めるなどの仕事も必要で、それらは「見積もり」してやるわけにはいかない。&lt;/p&gt;
&lt;p&gt;テックリードといわれる職位の人が、そういったことに直面し、それをうまくやる術を仕事の中で身につけていっているということが説明されており、なるほどという気持ちになった。(つまり実際の方法は、本の中には書いていない。本の中で書き切れるような単純なものではないかもしれないのだろう。)&lt;/p&gt;
&lt;h2&gt;文化の構築&lt;/h2&gt;
&lt;p&gt;このの最後の章は「文化の構築」となっていて、この章も気になった。
文化を形作る上で、意思決定のプロセスから個人的要素を排除するための具体的な方法に、ポストモーテムやアーキテクチャレビューを挙げており、それらを実践する上でのアドバイスが示されていた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;事後検証の成果は、現実的な視点で取捨選択する p276&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;問題が起きた時のポストモーテムに対する実践的なアドバイスの一つに、上記の事柄が紹介されている。起こった問題を完璧に解消できればいいが、現実にはそんなに暇ではないし、解決策が無限に時間のかかるような非現実的なものであれば形骸化してしまう。ポストモーテムが血の通ったものとなるために、現実的な視点で、効果的な次のアクションを定めていく必要がある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;アーキテクチャレビューの価値は、その準備段階にある p277&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;言語やフレームワークストレージシステムやデベロッパーツールなど、システムやツールの大きな変更に対して行うべき「アーキテクチャレビュー」の実施方針のアドバイスとして、準備段階の重要性が求められている。
アーキテクチャレビューに限らず、誰かに説明して納得してもらうために、それを言語化して資料にまとめることは、その行為自体が自身のセルフレビューの一つになりうるし、準備段階が重要であることは納得がいく。&lt;/p&gt;
&lt;p&gt;ポストモーテムやアーキテクチャレビューに関する説明を読むことが、自分の会社の類似の事柄について、自分が取り組む上での実践的なコツのほかに、それらが企業においてどのような立ち位置でどうして重要とされているのか、そのしくみが用意されているのかを考えることのヒントとなった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以上。&lt;/p&gt;</description>
    </item>
    <item>
      <title>dotfiles管理の推しツール「yadm」の記事を寄稿しました (Software Design 連載最終回)</title>
      <link>https://memo.yammer.jp/posts/software-design-202307</link>
      <pubDate>Fri, 16 Jun 2023 01:45:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-design-202307</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://yadm.io&quot;&gt;yadm&lt;/a&gt; の紹介記事を、本日発売の&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202307&quot;&gt;Software Design 2023年7月号&lt;/a&gt;に書きました。昨年12月から続けている連載「開発環境 探究の道」の最終回として、dotfilesの管理をより便利にするための方法を説明しています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gp2s3/20230616-011135.jpg&quot; alt=&quot;Software Design 2023年1月号〜2023年7月号&quot;&gt;&lt;/p&gt;
&lt;h3&gt;yadmについて / 記事の紹介&lt;/h3&gt;
&lt;p&gt;yadmは、シェルスクリプトで実装されたdotfiles管理ツールです。可搬性に優れ、dotfiles管理に必要な多数の機能と、gitに準じたコマンド操作体系をもっています。
私も普段からyadmを使っており、容易に導入できて、とても気に入っている&lt;sup&gt;&lt;a href=&quot;#user-content-fn-favorite&quot; id=&quot;user-content-fnref-favorite&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;ものであり、ぜひみなさんに知っていただきたいと思って記事にしました。&lt;/p&gt;
&lt;p&gt;記事の中では、yadmの概要と使い始める方法以外に、管理対象のファイルをより柔軟にする、sparse-checkoutとの組み合わせの例も紹介しています。
dotfiles管理にこれから入門する人も、dotfiles管理を普段から別の方法でしている人も、ぜひこれを読んでyadmを試していただけると幸いです。&lt;/p&gt;
&lt;h3&gt;連載について&lt;/h3&gt;
&lt;p&gt;7ヶ月間にわたる連載&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7month&quot; id=&quot;user-content-fnref-7month&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;も、今月が最終回です。初めての技術雑誌の連載を無事終えられたのは、たくさんの方々に支えていただいたおかげでした。全ての記事を毎月レビューしてくださった&lt;a href=&quot;https://twitter.com/pyama86&quot;&gt;pyamaさん&lt;/a&gt;と、編集を担当してくださった西原さんをはじめとするSoftware Design編集部の方々には大変お世話になりました。また、連載開始時に相談にのってくださった&lt;a href=&quot;https://twitter.com/kenchan&quot;&gt;kenchanくんさん&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-kenchan&quot; id=&quot;user-content-fnref-kenchan&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;にもお世話になりました。&lt;/p&gt;
&lt;p&gt;そして、読者の感想の投稿や、Web上での言及をしてくださった方、記事を読んでくださった皆様がいるからこそ、続けることができました。本当にありがとうございました。&lt;/p&gt;
&lt;p&gt;連載は、開発環境を中心に、以下の内容を扱いました。 開発環境という言葉はひろく、人によって指す範囲が異なるため、連載では「LinuxやUNIXにおける、ソフトウェア開発をはじめとするテキストベースのファイル編集やターミナルでのコマンド実行の環境」を指すこととしています。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;回&lt;/th&gt;
&lt;th&gt;号&lt;/th&gt;
&lt;th&gt;タイトル&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;第1回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202301&quot;&gt;2023年1月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;dotfilesを管理して、再現可能な開発環境を作る&lt;/td&gt;
&lt;td&gt;Gitとシンボリックリンクを用いたdotfilesの管理構成、設定ファイルの分割と分岐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第2回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202302&quot;&gt;2023年2月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;シェルをカスタマイズする&lt;/td&gt;
&lt;td&gt;シェルの文法、bashとzshの設定ファイルのカスタマイズ(エイリアス、シェル関数、プロンプト、フィルターコマンドの活用)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第3回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202303&quot;&gt;2023年3月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;ターミナルをカスタマイズする&lt;/td&gt;
&lt;td&gt;ターミナルエミュレータAlacritty、ターミナルマルチプレクサtmux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第4回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202304&quot;&gt;2023年4月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;環境構築を自動化する&lt;/td&gt;
&lt;td&gt;設定の自動化とパッケージのインストールの自動化を行うシェルスクリプトの実装&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第5回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202305&quot;&gt;2023年5月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;テキストエディタをカスタマイズする&lt;/td&gt;
&lt;td&gt;VSCodeとVimの、基本操作と設定変更&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第6回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202306&quot;&gt;2023年6月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;拡張機能やプラグインを使う&lt;/td&gt;
&lt;td&gt;VSCodeとVim、zsh, tmuxの拡張機能やプラグイン、Language Serverによる開発支援&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第7回&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202307&quot;&gt;2023年7月号&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;dotfilesの管理を発展させる&lt;/td&gt;
&lt;td&gt;dotfiles管理ツールのyadmと、その活用方法&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;初回にdotfilesの説明をし、その上で、周辺のトピックへ広がるよう、進んでいきます。一方で、各号はそれぞれ独立しており、どれかの号だけでも読めるように書いています。気になるものがあれば、ぜひお読みください。(記事を読んだよ！という声を聞くと、さらに嬉しいです。)&lt;/p&gt;
&lt;p&gt;開発環境の探究はひろく深く、今回は扱わなかったツールや、私の知らないツールやHowToもたくさんあることと思います。ぜひみなさんがよいツールや方法を見つけたりつくったときは、ブログ、登壇やLT、記事、Twitter、他の人との会話、どんな手段でもそれを広げて共有いただけると嬉しいです。私はそのような話が大好きですし、きっと好きな方がたくさんいる話題です。&lt;/p&gt;
&lt;h3&gt;おわりに&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202307&quot;&gt;Software Design 2023年7月号&lt;/a&gt;は、私の記事以外にも、第一特集のgRPCで始めるWeb API開発や、第二特集のSvelteの話など、たくさんの技術情報が詰まっています。全国の書店もしくはWebで、ぜひお買い求めください。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-favorite&quot;&gt;
&lt;p&gt;シンボリックリンクを使った管理の抱える問題を解消できる点などが魅力的で使い始めました。連載の中でも今回の内容が一番書きたかったもので、yadmの良さが伝われば幸いです。 &lt;a href=&quot;#user-content-fnref-favorite&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7month&quot;&gt;
&lt;p&gt;準備なども含めると、企画が始動してから10ヶ月くらい経っています &lt;a href=&quot;#user-content-fnref-7month&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-kenchan&quot;&gt;
&lt;p&gt;今回の連載に繋がった、&lt;a href=&quot;https://memo.yammer.jp/posts/software-design-202206&quot;&gt;2022年6月号の特集記事&lt;/a&gt;のレビューでもお世話になりました。また、yadmはそのレビューの時にくんさんから教えていただいて使い始めたもので、今回の記事につながっています。 &lt;a href=&quot;#user-content-fnref-kenchan&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>LlamaIndexを使って、gawkプログラミングの相棒を作る</title>
      <link>https://memo.yammer.jp/posts/gawk-rubber-duck</link>
      <pubDate>Tue, 13 Jun 2023 05:10:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/gawk-rubber-duck</guid>
      <description>&lt;p&gt;LlamaIndexを使って手を動かしてみようということで、gawkプログラマーが使える、質問回答アプリケーションを作ってみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gawk-rubber-duck.yammer.jp&quot;&gt;gawk-rubber-duck&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;LlamaIndexとは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jerryjliu/llama_index&quot;&gt;LlamaIndex&lt;/a&gt;という、LLMアプリケーションのためのフレームワークがある。
Pythonで書かれたプログラムで、内部でOpenAI APIを実行するが、その前後の処理なども行ってくれるものである。&lt;/p&gt;
&lt;p&gt;LlamaIndexがどのようなものかの説明は、次の記事がわかりやすい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://recruit.gmo.jp/engineer/jisedai/blog/llamaindex-chatgpt-tuning/&quot;&gt;Llamaindex を用いた社内文書の ChatGPT QA ツールをチューニングする - GMOインターネットグループ グループ研究開発本部（次世代システム研究室）&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;記事の中程の、LlamaIndex 処理フローに丁寧に書いてある。主に以下のことをやっているようである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事前に与えられた知識となる文章を適切に分割し、embeddingでベクトル化しておく&lt;/li&gt;
&lt;li&gt;質問文をembeddingし、ベクトルの類似性を元に、関連の文章を取り出して、LLMに一緒に渡す。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LlamaIndexを使うと、モデルが学習済みで無い、かつ、一度に与えられる上限を超えた沢山の文章をベースに、文章生成ができる。&lt;/p&gt;
&lt;p&gt;公式ドキュメントに&lt;a href=&quot;https://gpt-index.readthedocs.io/en/latest/getting_started/starter_example.html&quot;&gt;チュートリアル&lt;/a&gt;が用意されているので、&lt;a href=&quot;https://zenn.dev/basd4g/scraps/e2eea84da6435d&quot;&gt;それを動かして雰囲気を掴んだ&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;gawk-rubber-duck&lt;/h2&gt;
&lt;p&gt;LlamaIndexをつかってみたいということで、一つアプリケーションを作ってみた。&lt;/p&gt;
&lt;p&gt;最近趣味でgawkのコードを書いているのだが、そのとき、gawkの公式マニュアルである、&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/&quot;&gt;The GNU Awk User&apos;s Guide&lt;/a&gt;をよく参考にしている。このマニュアルは分量がそこそこある英語の文章で、これをLlama-Indexと組み合わせて、gawkに特化した文章生成ができたら面白いのでは無いかと思ったのが、発想のはじまり。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%90%E3%83%BC%E3%83%80%E3%83%83%E3%82%AF%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0&quot;&gt;ラバーダック・デバッグ&lt;/a&gt;という言葉があるように、プログラマーの相棒といえばアヒルだろう。今回は賢いアヒルを用意したつもりでgawk rubber duckと名付け、gawkの質問に答えるWebアプリケーションとして作成/公開した。&lt;/p&gt;
&lt;h2&gt;作り方&lt;/h2&gt;
&lt;p&gt;以下、どのように作ったかを記録しておく。&lt;/p&gt;
&lt;h3&gt;インデックスの作成&lt;/h3&gt;
&lt;p&gt;まず、事前準備として、gawkの章ごとに分割されているHTML版のマニュアルをダウンロードし、HTMLタグを取り除いてプレーンテキストにする。(プレーンテキスト版も配布されてはいるが、全セクションが1つにまとまったファイルなので、意味のある単位で最初から分割されているHTML版のものを使った)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/pipeline/download.sh&quot;&gt;gawk-rubber-duck/pipeline/download.sh at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/pipeline/html2txt.js&quot;&gt;gawk-rubber-duck/pipeline/html2txt.js at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;次に、これをLlamaIndexに渡すと、入力が一定の粒度に分割され、それぞれがembeddingによってベクトル化された上で、JSONファイルとして出力される。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/pipeline/save.py&quot;&gt;gawk-rubber-duck/pipeline/save.py at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なお、多数の文章をOpenAI APIに渡すので、事前に金額感をつかむために、tiktokenというライブラリを使って、トークンの消費量を計算してから行った。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/pipeline/guess-token.py&quot;&gt;gawk-rubber-duck/pipeline/guess-token.py at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JSONに保存された文章やベクトルを元に、回答生成するのも数行でかける。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/pipeline/query.py&quot;&gt;gawk-rubber-duck/pipeline/query.py at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Webアプリケーションにする&lt;/h3&gt;
&lt;p&gt;Flaskを使って、HTTPリクエストを受け付けるようにする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/web/main.py#L38-L54&quot;&gt;gawk-rubber-duck/web/main.py at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;リクエストごとにOpenAI APIを実行するので、IPアドレスベースのレートリミットを導入した。&lt;a href=&quot;https://flask-limiter.readthedocs.io/en/stable/&quot;&gt;Flask-Limiter&lt;/a&gt;と、記憶領域には、無料枠のある&lt;a href=&quot;https://www.mongodb.com/ja-jp/atlas/database&quot;&gt;MongoDB Atlas&lt;/a&gt;を、パスワード認証で使っている。&lt;/p&gt;
&lt;p&gt;できたアプリケーションはDockerでまとめて、Cloud Runに載せた。OpenAI API Keyと、MongoDBへの接続情報は、シークレットマネージャで環境変数から差し込んでいる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/main/web/Dockerfile&quot;&gt;gawk-rubber-duck/web/Dockerfile at main · yammerjp/gawk-rubber-duck · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;実際のところ、今回のアプリケーションはひとまず作って公開してみた、という程度で、どこまで実用かはまだ未知数。&lt;/p&gt;
&lt;p&gt;LlamaIndexを使って試してみる、というのはそれこそPythonのプログラムを10行程度書けばできてしまった。入力を分割したり、ベクトル検索したりという部分も含めて何もしなくてもいいので、とりあえず試してみる、というのがとてもやりやすい。&lt;/p&gt;
&lt;p&gt;求めていた回答が出ているかといわれると、ちょっと微妙で、今回でいえば以下がみえている課題&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;適切な文章を探せるか&lt;br&gt;
LlamaIndexは、与えた文章を、最初にベクトル検索で絞り込むので、そのときに目的のものが絞り込めなければ、良い結果が出ないようである。例えば入力を日本語で与えると、そのままembeddingしても関係のある文章を引っ張って来れないようで(ここ間違っていたら指摘してください)、&lt;a href=&quot;https://github.com/yammerjp/gawk-rubber-duck/blob/0bc8212300992fea94addef18a05e5ed3b1d3cd3/web/main.py#L46-L49&quot;&gt;英語に翻訳してからLlamaIndexに渡す&lt;/a&gt;ようにしてみたりしている。&lt;/li&gt;
&lt;li&gt;文章から知見を抽出できるか&lt;br&gt;
今回入力に与えたThe GNU Awk User&apos;s Guideはおそらく昔からネット上に公開されているもので、言語モデル自体がこの情報を学習していると思われる。なので、LlamaIndexで情報を与えずとも、元々多少なりとも回答してくれるので、今回の方法が効果的かは疑問がある。&lt;/li&gt;
&lt;li&gt;品質の評価ができるか&lt;br&gt;
上記を含め、作ったものや仕組みがどれくらい実用に耐えうるか、方式を変えると改善しうるかというのは、評価する必要があるが、こういった具体的なユースケースにおいてどのように評価すればいいのかがわかっていない。作ってみたが、いまのところは作ってみて終わり、となっている。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;というわけで、以上、今回は作ってみたという記事。実用的はどうかは疑問があるが、デプロイまでできると一区切りした感があっていい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>awkで実装するUnion-Findと、ABC177 D</title>
      <link>https://memo.yammer.jp/posts/union-find</link>
      <pubDate>Mon, 05 Jun 2023 17:15:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/union-find</guid>
      <description>&lt;p&gt;最近、業務時間後のオフィスで「競プロもくもくわいわい会」というのをやっている。そこで&lt;a href=&quot;https://twitter.com/purple_jwl&quot;&gt;@purple_jwl&lt;/a&gt;さんよりUnion-Findを教えていただいたので、それをawkで実装して、&lt;a href=&quot;https://atcoder.jp/contests/abc177/tasks/abc177_d&quot;&gt;ABC177のD問題&lt;/a&gt;を解いてみる。&lt;/p&gt;
&lt;h2&gt;Union-Findとは&lt;/h2&gt;
&lt;p&gt;ここでは深く解説しないが、Union-Findについては、以下のサイトなどが参考になる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://algo-method.com/descriptions/132&quot;&gt;Union-Find とは - アルゴ式&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Union-Find はグループ分けを効率的に管理する、根付き木を用いたデータ構造です。
Union-Find を用いると、次の各クエリ(要求)を高速に処理できます。&lt;/p&gt;
&lt;p&gt;N 個の要素 0,1,⋯,N−1 があり、初期状態ではそれぞれ異なるグループに属しています。
各クエリでは次のどちらかの操作を行います。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;issame(x,y) : 要素 x,y が同じグループに属するかを調べる。&lt;/li&gt;
&lt;li&gt;unite(x,y) : 要素 x を含むグループと要素 y を含むグループとを併合する。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;複数のグループを統合して1つのグループにする操作(上記の&lt;code&gt;unite&lt;/code&gt;)と、複数の要素が同じ要素に属しているかを確認する操作(上記の&lt;code&gt;issame&lt;/code&gt;)ができるもので、これを使うことで、グループ分けの問題を解くことができる。ABCだとD問題などで出てくるらしい。&lt;/p&gt;
&lt;h2&gt;Union-Findのawk実装&lt;/h2&gt;
&lt;p&gt;これを、awkで実装すると以下のようになる。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-vec&quot; id=&quot;user-content-fnref-vec&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-awk&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Union-Findの内部のデータ構造は、各グループごとの木構造である&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# ある根を他の根の子にすることがUnion、ある頂点の根を求めることがFindにあたる。&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# Findした結果が同じ頂点なら、同じ木に属するとわかる&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# グラフは、次の変数に保持する&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# - uf_parent[x] ... 値xの親となる値&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# - uf_size[x] ... xが根のとき、その木の頂点数&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 新しい頂点を登録。辺はなく、自身が根になる&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; uf_add(x) {
  uf_parent[x] = x
  uf_size[x] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
}

&lt;span class=&quot;hljs-comment&quot;&gt;# uf_parentを再帰的にたどり、rootの値を返す&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; uf_root(x) {
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (uf_parent[x] == x) {
    &lt;span class=&quot;hljs-comment&quot;&gt;# 根&lt;/span&gt;
    return x
  }
  &lt;span class=&quot;hljs-comment&quot;&gt;# 再帰的に辿りながら、木の深さが浅くなるように辺を付け替えて高速化 (パス圧縮)&lt;/span&gt;
  return uf_parent[x] = uf_root(uf_parent[x])
}
 
&lt;span class=&quot;hljs-comment&quot;&gt;# xとyを同じ木に統合する&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; uf_unite(x, y,        rootX, rootY) {
  rootX = uf_root(x)
  rootY = uf_root(y)
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (rootX == rootY) {
    &lt;span class=&quot;hljs-comment&quot;&gt;# 既に同じ木ならば、何もしない&lt;/span&gt;
    return &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
  }
  &lt;span class=&quot;hljs-comment&quot;&gt;# 片方の根を、もう片方の根の子にする&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;#   木の深さが浅くなるよう、深い木の根の子として、浅い木の根を生やすことで高速化 (ランク結合)&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;#     ここでは、ランクではなく木に含まれる頂点数を測って深さの代わりとしているが、&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;#     これで本当に高速化されるのかは定かではない&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;#     次のページなどが参考になるかもしれない&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;#     ref: https://37zigen.com/union-find-complexity-1/&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (uf_size[rootX] &gt; uf_size[rootY]) {
    &lt;span class=&quot;hljs-comment&quot;&gt;# rootXを根とする&lt;/span&gt;
    uf_parent[rootY] = rootX
    uf_size[rootX] += uf_size[rootY]
  } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-comment&quot;&gt;# rootYを根とする&lt;/span&gt;
    uf_parent[rootX] = rootY
    uf_size[rootY] += uf_size[rootX]
  }
  return &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Union-Findのawk実装を実行してみる&lt;/h2&gt;
&lt;p&gt;この実装の挙動は、以下のBEGIN句を動かすと想像しやすいだろう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-awk&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 先ほどのUnion-Findの実装は同じなので省略&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;BEGIN&lt;/span&gt; {
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;)
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;)
  uf_add(&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;)

  uf_unite(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)
  uf_unite(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)
  uf_unite(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;)

  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[1]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[2]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[3]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[4]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[5]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_parent[6]: %d\n&quot;&lt;/span&gt;, uf_parent[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;

  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(1): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(2): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(3): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;)
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(4): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(5): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;)
  printf &lt;span class=&quot;hljs-string&quot;&gt;&quot;uf_root(6): %d\n&quot;&lt;/span&gt;, uf_root(&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行結果は以下のようになる&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;uf_parent[1]: 2
uf_parent[2]: 2
uf_parent[3]: 4
uf_parent[4]: 4
uf_parent[5]: 4
uf_parent[6]: 6

uf_root(1): 2
uf_root(2): 2
uf_root(3): 4
uf_root(4): 4
uf_root(5): 4
uf_root(6): 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この時の木構造は以下のようになっている。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/union-find-example-1-2-3-4-5-6.png&quot; alt=&quot;mermaid graph TD; 2--&gt;1; 4--&gt;3; 4--&gt;5; 6;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;ABC177 D問題を解く&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://atcoder.jp/contests/abc177/tasks/abc177_d&quot;&gt;D - Friends - Atcoder Beginner Contest 177&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Union-Findの練習問題としてお勧めされた問題。問題文中のグループではなく、友達関係を辺としてUnion-Findに落とし込み、木ごとの頂点数の最大値が答えになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-awk&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 先ほどのUnion-Findの実装は同じなので省略&lt;/span&gt;

NR==&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; {
  N=&lt;span class=&quot;hljs-variable&quot;&gt;$1&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (i=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i&amp;#x3C;=N; i++) {
    uf_add(i)
  }
}

NR&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; {
  uf_unite(&lt;span class=&quot;hljs-variable&quot;&gt;$1&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$2&lt;/span&gt;)
}
 
&lt;span class=&quot;hljs-keyword&quot;&gt;END&lt;/span&gt; {
  max = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; uf_size) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (max &amp;#x3C; uf_size[i]) {
      max = uf_size[i]
    }
  }
  print max
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;というわけで、awkでもD問題が解けることが示されてしまいました。言語ではなく、解く人の能力が求められる、ということですね (頑張りましょうという自分へのメッセージ)。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-vec&quot;&gt;
&lt;p&gt;ここでは&lt;code&gt;uf_parent&lt;/code&gt;と&lt;code&gt;uf_size&lt;/code&gt;という配列をハードコーディングしているが、これらの代わりに&lt;code&gt;vec[&quot;parent&quot;]&lt;/code&gt;、&lt;code&gt;vec[&quot;size&quot;]&lt;/code&gt;などとして、&lt;code&gt;vec&lt;/code&gt;を各関数の第一引数に渡せるようにすると、Union-Findのデータ構造を、複数扱えるようになる。 &lt;a href=&quot;#user-content-fnref-vec&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>OpenAI API Embeddingsを使った、関連記事の表示・検索</title>
      <link>https://memo.yammer.jp/posts/embedding-and-vector-similarity-matching</link>
      <pubDate>Sun, 04 Jun 2023 16:35:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/embedding-and-vector-similarity-matching</guid>
      <description>&lt;p&gt;このブログに、お試しで2つの機能を追加してみた。
ひとつは、&lt;a href=&quot;#related-articles&quot;&gt;関連記事の表示&lt;/a&gt;。もう1つは、&lt;a href=&quot;/search&quot;&gt;検索&lt;/a&gt;。
どちらも&lt;a href=&quot;https://platform.openai.com/docs/guides/embeddings/what-are-embeddings&quot;&gt;OpenAI API Embeddings&lt;/a&gt;を使って、記事の文章をベクトル化し、&lt;a href=&quot;https://www.pinecone.io&quot;&gt;Pinecone&lt;/a&gt;を使ってベクトルの類似度の近しいものを得ている。&lt;/p&gt;
&lt;p&gt;以下は、これをどのようにして作ったか、どのようにして動いているのかを説明する。&lt;/p&gt;
&lt;h2&gt;構成&lt;/h2&gt;
&lt;p&gt;作ったものの全体像は以下の図のとおり。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://blob.yammer.jp/embedding-and-vector-similarity-matching.png&quot; alt=&quot;OpenAI API EmbeddingsとPinecone APIに対し、手元のPCもしくはCloudFlare Workersからリクエストを発行する。記事を書いたら、記事内容をOpenAI API Embeddingsでベクトル化してPineconeに保存する(STEP 1)。次に、ある記事のベクトルをもとに、関連記事をPineconeから取得する(STEP 2)。Webページからの検索クエリは、CloudFlare Workersが受け取り、OpenAI API Embeddingsでベクトル化してから、Pineconeで類似するベクトルを得て、記事情報に変えて表示している。&quot;&gt;&lt;/p&gt;
&lt;p&gt;以下のようなことをやっている。出てくる要素は、「要素技術とロール」の項で後述する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;u&gt;STEP1: インデックス作成&lt;/u&gt;
すべての記事に対して、それぞれ、記事全文をOpenAI API Embediingsに渡してベクトル化し、それをPineconeに登録する&lt;/li&gt;
&lt;li&gt;&lt;u&gt;STEP2: 関連記事の探索&lt;/u&gt;
ある記事のベクトルをPineconeに渡し、それと類似度の高いベクトルを得る。そのベクトルの表す記事を、関連記事としてページ生成時に埋め込む。&lt;/li&gt;
&lt;li&gt;&lt;u&gt;STEP3: キーワード検索&lt;/u&gt;
ユーザが検索したキーワードは、CloudFlare Workersが受け取り、OpenAI API Embeddingsでベクトル化してから、Pineconeに渡して類似度の高いベクトルを得る。そのベクトルの表す記事を、検索結果として表示する。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;要素技術とロール&lt;/h2&gt;
&lt;p&gt;作ったといっても、次の2つのサービスのAPIを叩いているだけである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAI API Embedding&lt;/li&gt;
&lt;li&gt;Pinecone API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらへ、以下の2つの箇所からHTTPリクエストを発行している。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CloudFlare Workers&lt;/li&gt;
&lt;li&gt;手元のPC (Macbook)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OpenAI API Embeddings&lt;/h3&gt;
&lt;p&gt;OpenAI API Embeddingsの使い方は簡単。例えば「今日はいい天気です」をベクトル化するならば、以下のようになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ export OPENAI_API_KEY=ここにAPIキーを入れる
$ curl https://api.openai.com/v1/embeddings \
  -H &quot;Content-Type: application/json&quot; \
  -H &quot;Authorization: Bearer $OPENAI_API_KEY&quot; \
  -d &apos;{
    &quot;input&quot;: &quot;今日はいい天気です&quot;,
    &quot;model&quot;: &quot;text-embedding-ada-002&quot;
  }&apos;
{
  &quot;data&quot;: [
    {
      &quot;embedding&quot;: [
        0.0011353685,
        0.0045190547,
        -0.0039041303,
        ...1536次元の実数のベクトルが出力される。長いので省略
      ],
      &quot;object&quot;: &quot;embedding&quot;,
      &quot;index&quot;: 0
    }
  ],
  &quot;object&quot;: &quot;list&quot;,
  &quot;model&quot;: &quot;text-embedding-ada-002-v2&quot;,
  &quot;usage&quot;: {
    &quot;prompt_tokens&quot;: 8,
    &quot;total_tokens&quot;: 8
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あとは、ここで得られたベクトル同士の類似度を計算して、近しいものほど、より関連があるとして出力すればよい。&lt;/p&gt;
&lt;h3&gt;Pinecone API&lt;/h3&gt;
&lt;p&gt;類似したベクトルを探すのは、今回の例であれば総当たりで計算しても良いが&lt;sup&gt;&lt;a href=&quot;#user-content-fn-kishida-hatena&quot; id=&quot;user-content-fnref-kishida-hatena&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;、マネージドサービスを使うことにする。最初にみたのはGoogle CloudのVetex AI Matching Engineだったが、個人で小規模に使うには高いので、無料枠のある&lt;a href=&quot;https://www.pinecone.io&quot;&gt;Pinecone&lt;/a&gt;を使うことにした。&lt;/p&gt;
&lt;p&gt;まずIndexを1つ作る。次に、記事ごとのID (今回はURL末尾。この記事でいえば&lt;code&gt;embedding-and-vector-similarity-matching&lt;/code&gt;)をキーにして、先ほど得たベクトルを登録していく。すべて登録すると、関連記事や検索結果を得る準備が整う。&lt;/p&gt;
&lt;p&gt;関連記事を得るには、ある記事のベクトルをPineconeに渡して、類似のベクトル(とそれに紐づく記事ID)を得れば良い。キーワードや文章による検索は、文字列を予めOpenAI API Embeddingに通してベクトル化してから、類似のベクトル(と記事ID)を得ればよい。&lt;/p&gt;
&lt;h3&gt;CloudFlare Workers&lt;/h3&gt;
&lt;p&gt;検索ページ &lt;code&gt;https://memo.yammer.jp/search&lt;/code&gt; から受けた検索クエリを元に、OpenAI API EmbeddingsとPineconeへリクエストを発行するのに使っている。このブログはNext.jsを使っているが、SSGなので、APIキーを隠すためになんらかのバックエンドが必要だった。&lt;/p&gt;
&lt;p&gt;ブラウザから実行される公開されたエンドポイントなので、IPアドレスベースのRate Limitを実装した。&lt;a href=&quot;https://steemit.com/blog/@justyy/a-simple-rate-limiter-for-cloudflare-workers-serverless-api-based-on-kv-stores&quot;&gt;CloudFlare KVベースの実装を説明したブログ記事&lt;/a&gt;があったので、これをそのまま真似た。作ったものの中身はGitHubにある。(&lt;a href=&quot;https://github.com/yammerjp/memo-yammer-jp-similarity-matching&quot;&gt;yammerjp/memo-yammer-jp-similarity-matching&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;OpenAI APIもPinconeもNode.js用のクライアントライブラリがあるが、CloudFlare Workers内では&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&quot;&gt;Fetch API&lt;/a&gt;を直接使ってリクエストを発行している。余談だが、curlの実行例をChatGPTに渡したらFetch APIの実装をやってくれて便利だった。&lt;/p&gt;
&lt;h3&gt;手元のPC (Macbook)&lt;/h3&gt;
&lt;p&gt;現在は、以下の2つのことを手元のMacbookでやっている。継続的に使うようならGitHub Actionsに載せる予定。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;記事の内容をベクトル化 (&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/1c2f55be7fb2fdeaba409ff7e189c6bc3d533c55/bin/embedding.js&quot;&gt;&lt;code&gt;bin/embedding.js&lt;/code&gt;&lt;/a&gt;)してPineconeに登録する (&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/1c2f55be7fb2fdeaba409ff7e189c6bc3d533c55/bin/embedding.js&quot;&gt;&lt;code&gt;bin/genIndex.js&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;関連記事を得る (&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/1c2f55be7fb2fdeaba409ff7e189c6bc3d533c55/bin/embedding.js&quot;&gt;&lt;code&gt;bin/queryRelatedArticles.js&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記の2つは、すべての記事に対して処理を実行するスクリプトになっている。本当はすべての記事に対してやる必要はなく、差分更新すればいいのだが、Gitで記事管理しているSSGのサイトは、差分更新と相性が悪いので、どのようにやるか考えあぐねている。Pinecone以外に何らかのデータストアが外部に欲しい。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;便利なものが揃っていて、それらを繋ぎ込むだけで割と簡単に作れてしまった。&lt;/p&gt;
&lt;p&gt;関連記事は、記事によっては&lt;sup&gt;&lt;a href=&quot;#user-content-fn-this&quot; id=&quot;user-content-fnref-this&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;、結構いい結果が出ているようにみえる。検索も、まあまあいい感じではある。ただ、検索ワードを検索欄に自分で入力するUIは、単語ベースの完全一致の検索を想起するので「記事のどこかに検索ワードが出てくるのではないか」「だとしたらどこに出てくるのか」などが気になってしまう。何か他のものと組み合わせるのがよいのかもしれない。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-kishida-hatena&quot;&gt;
&lt;p&gt;同様のことをやっている@kisさんの先行事例では、Javaで内積を計算する処理を自前で書いているようです。 &lt;a href=&quot;https://nowokay.hatenablog.com/entry/2023/04/03/173313&quot;&gt;GPTのEmbeddingを使った近いエントリを探す処理がVector APIなどで10倍高速になった - きしだのHatena&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-kishida-hatena&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-this&quot;&gt;
&lt;p&gt;この記事の関連記事は微妙だが、これはそもそもあんまり似た記事を過去に書いていなかったのだと思う。 &lt;a href=&quot;#user-content-fnref-this&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>rtxはじめました</title>
      <link>https://memo.yammer.jp/posts/rtx</link>
      <pubDate>Tue, 30 May 2023 17:00:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/rtx</guid>
      <description>&lt;p&gt;ランタイム管理ツール&lt;a href=&quot;https://asdf-vm.com&quot;&gt;asdf&lt;/a&gt;と互換性のある、&lt;a href=&quot;https://github.com/jdxcode/rtx&quot;&gt;rtx&lt;/a&gt;を使い始めた。&lt;/p&gt;
&lt;p&gt;asdfのプラグインエコシステムに乗っかっていて、できることはasdfと基本的には同じのようだが、はやい&lt;sup&gt;&lt;a href=&quot;#user-content-fn-fast&quot; id=&quot;user-content-fnref-fast&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;などのメリットがある(後述)。&lt;/p&gt;
&lt;h2&gt;切り替え&lt;/h2&gt;
&lt;p&gt;切り替えは以下のような手順で進めた。dotfilesの差分はこんな感じ &lt;a href=&quot;https://github.com/yammerjp/dotfiles/commit/6a6951c1abc8f7227351c5857ad459127bbd7fc5&quot;&gt;yammerjp/dotfiles 6a6951c&lt;/a&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;シェルの設定ファイル(.zshrcなど)に書かれているasdfの読み込みをやめる&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;私の場合はsheldonのプラグインにしていたので、~/.config/sheldon/plugins.tomlの記述をひとまずコメントアウトした。&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;rtxをいれる&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Apple SiliconのmacOSを使っていたら以下のような感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl https://rtx.pub/rtx-latest-macos-arm64 &gt; ~/.local/bin/rtx
$ chmod u+x ~/.local/bin/rtx
# ~/.local/bin/はPATHが通っている前提
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;rtxの読み込みをシェルの設定ファイルに書く&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;複数端末で同じシェルの設定を書いているので、rtxをインストールしている端末だけに反映させたい。
以下のような内容を&lt;code&gt;.zshrc&lt;/code&gt;に追記&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-zsh&quot;&gt;if (which rtx &gt; /dev/null); then
  eval &quot;$(rtx activate zsh)&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;rtxの設定ファイルを配置&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;~/.config/rtx/config.toml&lt;/code&gt;に、以下のような内容のファイルを置く&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-toml&quot;&gt;[tools]
awscli = [&apos;latest&apos;]
go = [&apos;latest&apos;]
# heroku-cli = [&apos;latest&apos;]
nodejs = [&apos;latest&apos;, &apos;lts&apos;]
ruby = [&apos;latest&apos;, &apos;2.7.8&apos;]
php = [&apos;latest&apos;, &apos;7.4.33&apos;]
terraform = [&apos;latest&apos;, &apos;1.0.5&apos;, &apos;1.3.1&apos;, &apos;1.3.3&apos;, &apos;1.3.4&apos;, &apos;1.3.6&apos;, &apos;1.3.7&apos;]
[settings]
jobs = 4
experimental = true
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;各種ランタイムをインストール&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;rtx i&lt;/code&gt;とすれば、設定ファイルを見て足りないものを全部インストールしてくれるらしい&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ source ~/.zshrc
$ rtx i
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;いいところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;設定ファイルがXDG Base Directoryに従っている。すっきりしていい。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rtx i&lt;/code&gt;とだけ実行すればいいので良いので楽。わかりやすい。&lt;/li&gt;
&lt;li&gt;設定ファイルに複数バージョンを記述できる。&lt;/li&gt;
&lt;li&gt;インストールが早い。並列で実行してくれる。&lt;/li&gt;
&lt;li&gt;シェルの起動時に、設定ファイルにあるのに未インストールのものがあったら警告してくれたりする。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;なやみ&lt;/h2&gt;
&lt;p&gt;rtxに限らないが、他のツールを使うための基盤となるツールが増えていくと、それのセットアップが面倒になるという問題をはらんでいる。rtxはRust製なので、OSとCPUに合わせたバイナリを手に入れなければならない。&lt;/p&gt;
&lt;p&gt;shelldonに, rtxに, ... 気をつけていても、だんだん増えていく。asdfはシェルスクリプトでできていて、どの端末でも切り替えなく入れられるのでその点はいいのだけど、rtxはさきに書いたメリットがあるので使っていきたいところ。&lt;/p&gt;
&lt;p&gt;妥協案として、dotfilesリポジトリにバイナリをcommitしてしまって、yadmの&lt;a href=&quot;https://yadm.io/docs/alternates&quot;&gt;alternate files&lt;/a&gt;で環境ごとに実行ファイルを切り替えつつ使う、みたいにすると楽なのかもしれないとも思った。私の用途ではarm64のDariwin、x86_64のLinux、arm64のLinuxがあれば十分なはず。&lt;/p&gt;
&lt;p&gt;この場合、バージョンが上がるごとに違うバイナリをcommitすることになるので、dotfilesリポジトリの容量が増えてセットアップ時のダウンロード容量が増えるけど、そこはshallow cloneするなりしていくといい、のだろうか？...。長期的には微妙だろう。&lt;/p&gt;
&lt;p&gt;セットアップ用のシェルスクリプトを育ててもいいが、環境や状況によって必要なものの最低ラインが変わるので、区分けやセットアップ手順が煩雑になっていく。なるべくシンプルに、でも便利にするラインのせめぎ合いである。
手動で&lt;code&gt;brew install&lt;/code&gt;なり&lt;code&gt;curl &gt; &lt;/code&gt;なりを、コマンド一つ打てばいいというのはその通りなんですが、開発環境の構築はそれの積み重ねなんですね〜&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最後はrtxにあんまり関係ない話を書いてしまったが、なにはともあれrtxはいまのところ(まだ1日目)快適に使えている、もっとはやく入れればよかった。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-fast&quot;&gt;
&lt;p&gt;この記事に書かれている「はやい」「早い」はすべて体感です &lt;a href=&quot;#user-content-fnref-fast&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>エンジニアのためのドキュメントライティングを少し読む</title>
      <link>https://memo.yammer.jp/posts/docs-for-developers</link>
      <pubDate>Fri, 21 Apr 2023 00:55:17 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/docs-for-developers</guid>
      <description>&lt;p&gt;&lt;a href=&quot;/posts/working-effectively-with-legacy-code&quot;&gt;前回&lt;/a&gt;に引き続き、全部読まない読書の感想とメモを書いていく。前回記事では1週間で読み切るといいつつ、気づけば2週間経っていることには一旦目を瞑りたい。&lt;/p&gt;
&lt;p&gt;2冊目は「エンジニアのためのドキュメントライティング」。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E5%95%8F%E9%A1%8C%E8%A7%A3%E6%B1%BA%E3%81%A8%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E3%81%AE%E6%88%90%E5%8A%9F%E3%82%92%E5%B0%8E%E3%81%8F-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%83%A9%E3%82%A4%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0-%E3%82%B8%E3%83%A3%E3%83%AC%E3%83%83%E3%83%89%E3%83%BB%E3%83%90%E3%83%BC%E3%83%86%E3%82%A3/dp/4800590833&quot;&gt;ユーザの問題解決とプロダクトの成功を導く エンジニアのためのドキュメントライティング - Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;一週間読書の方法&lt;/h2&gt;
&lt;p&gt;本の感想に入る前に、どのように一週間読書をやっているかを紹介する。なお、ここで扱う書籍は技術書を中心としたもので、小説などは当てはまらない。&lt;/p&gt;
&lt;h3&gt;目次から読むところを選ぶ&lt;/h3&gt;
&lt;p&gt;全部読むことが目的ではなく、短い時間で読みたいところを読むのが目的である。そこで、最初から読み始めないようにしている。ついつい最初から読み始めてしまい、読み切るまでなかなか次の本にいけなくなることを避けるのが狙いである。&lt;/p&gt;
&lt;p&gt;目次のページをざっと眺めて、いくつか章を決めて書き留めておく。そして、決めた章のページに飛んで、そこから読み始める。この時、必ずしも数字の若い章から読み始める必要はなくて、読めそうなら一番読みたいところからどこでも読み始めて良い。&lt;/p&gt;
&lt;p&gt;最初に決めた章を読み切るか、読むのに一定時間が経ったら(ここで言えば1週間)、その本は完全理解()したとして終わりにし、次の本にいく。&lt;/p&gt;
&lt;p&gt;今回でいえば、3, 6, 9章を中心に読んだ。&lt;/p&gt;
&lt;h3&gt;まとめを活用する&lt;/h3&gt;
&lt;p&gt;途中の章から読むといっても、前後の文脈がないと難しいときもある。そういう時は、他の章の末尾にある「まとめ」だけを読む。数ツイート分くらいの分量でまとめてくれているので、他の章を読むための概要と文脈が把握できて、読み進めやすくなる。&lt;/p&gt;
&lt;p&gt;ここでまとめを読むのはあくまで次の章を読むためで、その章の知識を吸収することはまとめでだけでは大抵難しいことには気をつけておきたい。&lt;/p&gt;
&lt;h3&gt;メモをとって、感想をまとめる&lt;/h3&gt;
&lt;p&gt;必須ではないが、感想や学んだことをまとめておきたいので、読みながらページと気になったフレーズをメモしておく(付箋でもよさそう)。読み終わったら、このブログ記事のようにまとめる。&lt;/p&gt;
&lt;p&gt;必須にしてしまうと、読むスピードを落としたり、読む障壁になったりするので、メモや感想は必須とはしない。&lt;/p&gt;
&lt;p&gt;読みながら感想を書くのも、読む速度を律速してしまうので、単語や1文くらいに留める。一週間後には読み終えるので、その場で丁寧にメモしなくても思い出せるだろう(思い出せなかったら大事ではないだろう)とする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;このような方法で読んでいる。他の方がどのように読書しているかも知りたいので、ぜひアンサーブログで教えていただけると嬉しい。&lt;/p&gt;
&lt;p&gt;以降は実際に読んだ書籍の感想が続く。&lt;/p&gt;
&lt;h2&gt;書籍「エンジニアのためのドキュメントライティング」の感想&lt;/h2&gt;
&lt;p&gt;免責&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上述の通り、この感想記事は本の全部を読んだわけではありません、適宜読み飛ばしながら読んだ人の感想です。&lt;/li&gt;
&lt;li&gt;ドキュメントライティングについて読んだはずなのに、この記事の文章は微妙だな、と思ったら、チラシ裏のブログ記事として見逃してください。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;全体を通して&lt;/h3&gt;
&lt;p&gt;この本は、全体を通して、ドキュメントを書くときの標準的な方法を、最初から最後まで網羅的に説明している本にみえた(斜め読みだが)。自分の行為が言語化されて体系的に示されるというのは大変よい。これを通して、作業を客観的に捉えられるようになるだろう。&lt;/p&gt;
&lt;p&gt;普段やっていることは言語化されて再認識できた。逆にあんまり得意でないところは、書かれていることを順番にやることで、ドキュメントライティング力を底上げしてきたい。&lt;/p&gt;
&lt;h3&gt;白紙からの脱却&lt;/h3&gt;
&lt;p&gt;白紙を脱してドキュメントを書き始める方法として、以下のような方法が示されている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;これまでに集めた情報をドキュメントの冒頭にリストアップするところから、ドキュメントを作成開始できます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;読み手&lt;/li&gt;
&lt;li&gt;目的&lt;/li&gt;
&lt;li&gt;コンテンツパターン
(p72)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;文章を書くとき、白紙の状態から何を書くかまでのアウトラインを決めるところが腰が重い。このフェーズでは「文章を書くぞ」ではなく「リストアップするぞ」と思うことにして、書き始めのハードルを下げるのが大切だと思った。&lt;/p&gt;
&lt;h3&gt;どんな書き手でも&lt;/h3&gt;
&lt;p&gt;書き手によらず執筆は難しいものであると、以下のように述べられている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;どんな書き手でも行き詰まります。執筆は創造的で難しい仕事であるため、ときに継続が難しくなりま。行き詰まるのは執筆が下手だからではないのです！アウトライン濁声の最初の段階だったとしても、ドラフトを完成させる途中のどこかであったとしても、行き詰まるのは執筆プロセスの一部です。
(p85)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;このあとに続けて、いくつかのTipsが紹介されている。例えば以下のようなものである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完璧であることを意識せずにとにかく考えを書き出す&lt;/li&gt;
&lt;li&gt;TODOコメントを活用し、書きづらいところは飛ばす&lt;/li&gt;
&lt;li&gt;冒頭ではなく書きやすいところから書く&lt;/li&gt;
&lt;li&gt;メディアを変える (テキストエディタを変えてみたり、ホワイトボードに書き起こしたり、音声文字起こしを試してみたりする)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「どんな書き手でも行き詰まります。」という言葉はとても勇気づけられる。自分自身、文章を書いていてうまく書けずに行き詰まったとき、「自分はあまり執筆が得意でないのかもしれない」と自分の能力の問題にしてしまうことがある。真偽はおいておいて、それは自分が求めているクオリティを一発で導き出そうとしているのが問題なのではないかと思う。&lt;/p&gt;
&lt;p&gt;一発で完璧な完成形を作る必要はない。ソフトウェア開発と同様に、少しずつ改善することで文章を仕上げていけば良いという前提で、執筆に向き合っていきたい。同時にそれは時間がかかることであるので、はやく書き始めるのが大事、大事ですね！&lt;/p&gt;
&lt;p&gt;そこそこのボリュームのある文章を書くとき、箇条書きや各章のタイトルの一覧みたいなものを作って書き始めるのだけど、文章の肉付きがないまま箇条書きを完璧にしていくのは結構難しくて、結構行ったり来たり (文章を書いてみて、やっぱり箇条書きに戻る) ということがよくある。書いてみないとわからないということもあるので、まずは脳内をとにかく書き出して、納得いかない個々の部分を直していくという作業に落とし込んでやっていきたい。&lt;/p&gt;
&lt;h3&gt;最初のドラフトを完成させる&lt;/h3&gt;
&lt;p&gt;記事の下書きとしてひととおりの文章がかけた時に、全体をチェックする方法として、いかのようなものが挙げられている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;完了したかどうか判断するために、次の質問を自分に問いかけてみてください。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大見出しはドキュメントのゴールを要約しているか？&lt;/li&gt;
&lt;li&gt;複数の見出しによってドキュメントは十分に要約されているか？&lt;/li&gt;
&lt;li&gt;ドラフトは最初から最後まで読み手のニーズに答えているか？&lt;/li&gt;
&lt;li&gt;情報の流れは読み手にとって理解しやすいものか？&lt;/li&gt;
&lt;li&gt;フリクションログで見つけた課題は解決されているか？&lt;/li&gt;
&lt;li&gt;何らかのドキュメントパターンやテンプレートに正しく従っているか？&lt;/li&gt;
&lt;li&gt;全手順が動作することをテストし確かめたか？
(p91)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;ドラフト段階の記事が書き上がるのはとても大きなマイルストーンである。そこまで来れば自分で読み直したりレビューを貰ったりして個々の箇所を改善してけば、文章が完成できる。&lt;/p&gt;
&lt;p&gt;ついつい一通り文章がかけると舞い上がってしまって「できた」という気持ちになってしまう。しかし上に書かれたような項目をチェックリストで用意しておいて、このタイミングで満たされているかを確認しておくことで、次のステップで後戻りを減らせるだろう。とてもよいテクニックに思うので実践していきたい。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;というわけで、1(2)週間読書の第二回でした。2回目があってよかった。忙しさを理由に気づいたらついつい2週間になっていたが、来週こそは1週間で区切りたい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>レガシーコード改善ガイドを少し読む</title>
      <link>https://memo.yammer.jp/posts/working-effectively-with-legacy-code</link>
      <pubDate>Fri, 07 Apr 2023 00:41:21 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/working-effectively-with-legacy-code</guid>
      <description>&lt;h2&gt;1週間だけ読む取り組み&lt;/h2&gt;
&lt;p&gt;一冊の本を一週間で読めるだけ読むというのをやってみる。
買った本は積まれる一方だし、買いたい本のURLもPocketに溜まるばかり。そしていざ本を読み始めると、最初から頑張って全部読みがちである。そういった習慣を変えるために、1週間で読むのをやめて強制的に次の本に行くという方法を試してみる。&lt;/p&gt;
&lt;p&gt;一週間やってみて、全然読みきれないと感じた。ゾーンに入ってバーンと読んでしまえば今回の本などは読み切れるのかもしれないが、そうやって気合いを入れるのではなくて、趣味のプログラミングや雑誌の原稿や仕事のキャッチアップなどをする日々に馴染む範囲で日常的にどんどん読んでいきたいので、この取り組みをやり始めるわけである。&lt;/p&gt;
&lt;p&gt;書籍に載るような文章を書く手間を考えると、本の作者には適当な読み方をして申し訳ない面もある。しかし世の中には読みきれないほどの本があるし、読まないより読む方がいいだろう。&lt;/p&gt;
&lt;h2&gt;レガシーコード改善ガイドを少し読んだ感想&lt;/h2&gt;
&lt;p&gt;今回は一冊目、レガシーコード改善ガイド。本に示されたトピックをいくつか紹介しながら感想を述べる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.shoeisha.co.jp/book/detail/9784798116839&quot;&gt;https://www.shoeisha.co.jp/book/detail/9784798116839&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;変更の基本的な流れ&lt;/h3&gt;
&lt;p&gt;レガシーコードの変更には一連の手順がある。それは次のような手順であると紹介されている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;変更点を洗い出す&lt;/li&gt;
&lt;li&gt;テストを書く場所を見つける&lt;/li&gt;
&lt;li&gt;依存関係を排除する&lt;/li&gt;
&lt;li&gt;テストを書く&lt;/li&gt;
&lt;li&gt;変更とリファクタリングを行う&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(p21)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;既存の振る舞いをテストコードにより保護し、デグレしていないことを保証しつつリファクタリングや変更を加える手順である。
普段やっていること/やろうとしていることではある&lt;sup&gt;&lt;a href=&quot;#user-content-fn-pray&quot; id=&quot;user-content-fnref-pray&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;が、改めて言語化されて本の前半で整理されていて再確認になった。&lt;/p&gt;
&lt;h3&gt;検出と分離、接合部と許容点&lt;/h3&gt;
&lt;p&gt;書籍の中では、「検出」「分離」「接合部」「許容点」という語が定義されている。普段なんとなく「この変数の値を検証したい」「この部分を切り出せば良いのではないか」「ここで分割できるな」「ここでモックすればいいな」などと考えているが、これらに言葉が与えられることの意義は大きい。言葉が与えられることで考えがよりわかりやすく整理されて表現され、脳を占有する思考のメモリ領域が圧縮できる。&lt;/p&gt;
&lt;h4&gt;検出と分離&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;コードの計算した値にアクセスできない時に、それを検出するために依存関係を排除する(p25)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;コードをテストハーネスに入れて実行することすらできない時、分離するために依存関係を排除する (pp25-26)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例えば長いトランザクションスクリプトでは、一つのメソッドの中のある変数の挙動をテストしたいことがある。そういったもののコード実行時の挙動を&quot;検出&quot;するためにテストコードを書く。テストコードを書くために依存関係を排除しなければならないこともあるだろう。&lt;/p&gt;
&lt;p&gt;例えば実装が特定のソフトウェア外部との接続に依存している場合もあるだろう(ネットワーク通信やファイルシステム、ハードウェアなど)。そういった時には、テストのために、偽装オブジェクト/モックオブジェクトを作ってそれらを利用できるようにすることで&quot;分離&quot;する必要がある。&lt;/p&gt;
&lt;h4&gt;接合部と許容点&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;接合部(seam)とは、その場所を直接編集しなくても、プログラムの振る舞いを変えることのできる場所である。 (p41)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;どの接合部も許容点(enabling point)を持つ。許容点では、どの振る舞いを使うかを決定できる。(p41)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;オブジェクト指向&lt;sup&gt;&lt;a href=&quot;#user-content-fn-objective&quot; id=&quot;user-content-fnref-objective&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;の考えを取り入れた言語では、メソッドをオーバーライドしたり、インタフェースに異なる実装を与えると、コードの字面を一切変えずに挙動を変えることができる。例として、次にPHPのコードを示す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-php&quot;&gt;class Renderer
{
  function render(PrintableDevice $device) {
    $device-&gt;print();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで&lt;code&gt;print()&lt;/code&gt;メソッドがどのように振る舞うかは、&lt;code&gt;$device&lt;/code&gt;インスタンスが何かによって変わる。ここで&lt;code&gt;print()&lt;/code&gt;メソッドの呼び出しを接合部、&lt;code&gt;render&lt;/code&gt;メソッドの引数による&lt;code&gt;$device&lt;/code&gt;の引き渡しを許容点とと呼べる。&lt;/p&gt;
&lt;p&gt;たとえば外部通信をするような依存を持つコードをテストの中だけで実行しないようにできれば、そのコードをテストできる。依存関係を整理するときは、どこかを接合部や許容点とし、本番環境との振る舞いを変えてロジックをテストするコードを書くことになる。&lt;/p&gt;
&lt;h3&gt;もうウンザリです。何も改善できません&lt;/h3&gt;
&lt;p&gt;「もうウンザリです。何も改善できません」は第24章のタイトル。この章は&lt;a href=&quot;https://twitter.com/UVB_76&quot;&gt;@UVB_76&lt;/a&gt;さんにおすすめいただいた箇所で、とてもポエミーで勇気づけられる内容が書かれている。
2ページくらいですぐに読めるし、本の中の文章をそのまま読むからこそ感じられることがあると思うのでぜひ原文を読んでいただきたい。&lt;/p&gt;
&lt;p&gt;この章では、プログラムを書くことは本来楽しいことや、レガシーコードを抱えていることに落胆せず、毎日挑戦的に仕事を楽しむ方法を思い出させてくれる。やりがいを見つけ、テストによる保護でひどい状況を制御することで前進できると語ってくれている。現時点で私は落胆しているわけではない&lt;sup&gt;&lt;a href=&quot;#user-content-fn-my-work&quot; id=&quot;user-content-fnref-my-work&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;のだけど、それでも勇気づけられたし、落胆しそうになった時にまた読みたい。&lt;/p&gt;
&lt;h3&gt;次に読みたいところ&lt;/h3&gt;
&lt;p&gt;テストがかけてしまえば、それにより保護されることで安全に変更を加えることができるだろうが、今の自分には既存のコードを切り分けてテストを書くまでのプラクティスや知識が足りていないところがあると思うので、そういった実践的な部分や内容をより深掘りして読みたい。&lt;/p&gt;
&lt;h2&gt;終わりに&lt;/h2&gt;
&lt;p&gt;「次に読みたいところ」に書いたとおり、次の本に行く前にまだまだ読みたいところだけれど、そうやるとダラダラ読んでしまうだろうから、次の本に行こうと思う。
最初なのでブログを書くのにも気合が入ってしまった。次からはもう少し肩の力を抜いて、なるべく負荷にならない範囲で記録を残していきたい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-pray&quot;&gt;
&lt;p&gt;といいつつ、横着して、この本が横にある時に「編集して祈る」をやりそうになり、同僚とそのことを笑っていました。結局テストを書きました。肝に銘じます。(「編集して祈る」は書籍の中でテストを書いてリファクタリングや変更を繰り返す方法と対比され、よくない方法として紹介されている言葉です。) &lt;a href=&quot;#user-content-fnref-pray&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-objective&quot;&gt;
&lt;p&gt;オブジェクト指向とはなんぞやというのは脇に置いておきます。許してください。 &lt;a href=&quot;#user-content-fnref-objective&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-my-work&quot;&gt;
&lt;p&gt;レガシーという言葉は結構気を使う単語で、私の仕事がレガシーにまみれているような誤解を与えそうなので一応補足を書いておきます。もちろん大きかったり歴史の長いソフトウェアやサービスでは相対的に手が届きづらくなるコンポーネントや巨大化したコンポーネントも扱うけれども、それらが一定コントロールされた/したうえで最新の手法を取り入れつつチャレンジングな仕事ができる環境にいると思っています。 &lt;a href=&quot;#user-content-fnref-my-work&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>PHPerKaigi2023が最高だった</title>
      <link>https://memo.yammer.jp/posts/phperkaigi2023-day2</link>
      <pubDate>Sun, 26 Mar 2023 08:45:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/phperkaigi2023-day2</guid>
      <description>&lt;p&gt;昨日のPHPerKaigi2023最終日、自分はLTをしたのですが、登壇以外にもたくさんの体験をして本当に濃い一日でした。&lt;/p&gt;
&lt;p&gt;Day1のブログ: &lt;a href=&quot;https://memo.yammer.jp/posts/phperkaigi2023-day1&quot;&gt;PHPerKaigi2023に参加しています - memo.yammer.jp&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;LTで登壇&lt;/h3&gt;
&lt;p&gt;LTでペンライトを振るのも振られるのも楽しんだり。
登壇した内容は、PHP Conference 2022で出題したクイズの裏話として、当時の問題を振り返りながら、何を考えて作っていたか/作るならどうすべきかでした。&lt;/p&gt;
&lt;p&gt;クイズのことを覚えていた方もたくさんいらっしゃったようで、嬉しい限りです。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;LTの発表資料です！答えは最後のスライドにて&lt;br&gt;「クイズを作ってPHPに親しむ」&lt;a href=&quot;https://t.co/ef8QQPi3we&quot;&gt;https://t.co/ef8QQPi3we&lt;/a&gt;&lt;a href=&quot;https://x.com/hashtag/phperkaigi?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#phperkaigi&lt;/a&gt; &lt;a href=&quot;https://x.com/hashtag/a?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#a&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1639520377784397824?ref_src=twsrc%5Etfw&quot;&gt;March 25, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;!--

https://speakerdeck.com/yammerjp/make-quizzes-and-get-familiar-with-php

--&gt;
&lt;h3&gt;ランチ&lt;/h3&gt;
&lt;p&gt;Day1の夜にみたツイートを発端に、初めてお話しするPHPerの方々とランチに行きました。盛り上がっている勢いとコミュニティの暖かさと言い出した人と乗ってきた人、それらが揃って生まれたありがたい時間でした。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://x.com/hashtag/phperkaigi?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#phperkaigi&lt;/a&gt; 明日のお昼ご一緒出来るペチパーの方いらっしゃいませんか！(当方初ペチパー会議です)&lt;/p&gt;— たま (@tama_php) &lt;a href=&quot;https://x.com/tama_php/status/1639206526215946242?ref_src=twsrc%5Etfw&quot;&gt;March 24, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;h3&gt;聞いた発表&lt;/h3&gt;
&lt;p&gt;今日聞いた発表はこちら。感想は別の記事かフィードバックで書くことにします。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/98ad84b9-df03-4449-ab25-377761945005&quot;&gt;実例から学ぶ変化に強いテーブル設計 - 責務の分解とRDBMSの上手い使い方&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/e68c1ed6-8fb4-4ff9-9d99-99214d9dba8d&quot;&gt;いろいろなフレームワークの仕組みを index.php から読み解こう&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/ec6b9d08-f32e-4071-a81b-0ccdc0fc644f&quot;&gt;PHPの配列の内部実装について学びたくなった。&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/52f6eb96-bcff-4fcb-9439-2a5d7cb2cfde&quot;&gt;【実録】「PHP_CodeSniffer」で始める快適コードレビューライフ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/d3fc9ca1-1342-4a91-9113-7c934d072751&quot;&gt;他言語と比較して今こそ理解しよう！目指せ、列挙型マスター！　～なりたいな ならなくちゃ 絶対なってやる！～&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/4f172d63-d9e2-42c2-9805-7a0b94191abe&quot;&gt;PsySHを使った効率的なデバッグ方法について&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/56e27797-b4fa-49d2-9352-0f2660451dc3&quot;&gt;PHP8.xの新機能を使ってよい良いコードを書こう！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/e490a63f-abd9-498b-a729-05e1d3ecef66&quot;&gt;可能な限り確実にmkdirを成功させるには&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/033ee700-0a8e-44c5-9d30-2cb7e073712f&quot;&gt;あなたはPhpStormくんのショートカットキーを何個知っている？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/9e758cbe-9a7a-4d3f-83a9-64f8a2d9a42d&quot;&gt;初めてIT勉強会を開催するなら知っておくべき5選！〜PHP勉強会@東京や社内勉強会の運用からの知見〜&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/d9c2fd8a-b421-4b25-98eb-dccb1e6ef00d&quot;&gt;PHPマジックメソッドクイズ！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/e98b7956-6652-4fd5-817b-8df9ba1dd9e1&quot;&gt;フレームワークが存在しない時代からのレガシープロダクトを、Laravelに”載せる”実装戦略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/b7176a73-8b73-4a4d-9f94-603c68bc3d88&quot;&gt;PHPのARM向け最適化の中身を見てみた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/07411094-2fc1-4abd-904f-9470454531e6&quot;&gt;PHPerチャレンジ解説LT - サイボウズ株式会社&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このほか、すこしの時間ですがポスターセッションも読ませていただきました！&lt;/p&gt;
&lt;h3&gt;カンファレンスの廊下と懇親会&lt;/h3&gt;
&lt;p&gt;カンファレンスの廊下や懇親会、さらに2次会で、たくさんの人とお話ししました。いや本当にここに書ききれないくらいたくさんの出会いがあって、とても楽しい時間でした。自分から話しかけると、思っているより気さくに話に応じていただいたり、自分のあだ名をみて声をかけていただけることもあって、しょうもない話から本音の話までたくさんおはなしできました。&lt;/p&gt;
&lt;h3&gt;PHPerKaigiコミュニティと「熱」&lt;/h3&gt;
&lt;p&gt;PHPerKaigi参加以前、他のイベントに行った時にPHPerKaigiの札をかけている人に憧れを抱いたり、PHPerKaigiの話を熱く語っている人を見て「カンファレンスにここまで熱くなれるのいいなあ」と思っていました。&lt;/p&gt;
&lt;p&gt;初めて参加し、その熱のわけを体感しました。「これがPHPerKaigiなのか」ということを強く感じました。そう設計されているからか、コミュニティの人々の方向性からか、その両方からか、「自分が見ているだけ」「聞いているだけ」というのとは全く違った、双方向のコミュニケーションの生まれる、経験したことのない体験でした。&lt;/p&gt;
&lt;p&gt;物理的なカンファレンスが、PHPerKaigiが、こんなに濃いものなのかと感じた背景には、21卒でコロナ禍に働き始めたのでオンラインでの体験が当たり前になっていたことも関係しているかもしれません。&lt;/p&gt;
&lt;p&gt;あわせて読みたい:&lt;a href=&quot;https://soudai.hatenablog.com/entry/2023/03/25/170030&quot;&gt;PHPerKaigi2023で感じた、たった1つの真実 - そーだいなるらくがき帳&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;精進&lt;/h3&gt;
&lt;p&gt;技術的には、自分の至らなさを感じる場面が沢山ありました。ただ、至らないと感じれるくらいには目線が広がったとも思えるので、日々精進していくしか無いという気持ちです。中身の伴う質の高いアウトプットをできるように、技術力を高めて仕事や趣味で活かし鍛えていくというのを地道にやっていかねば。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;楽しい時間とたくさんの出会いをありがとうございました！ &lt;a href=&quot;https://x.com/hashtag/phperkaigi?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#phperkaigi&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1639648139501260801?ref_src=twsrc%5Etfw&quot;&gt;March 25, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>PHPerKaigi2023に参加しています</title>
      <link>https://memo.yammer.jp/posts/phperkaigi2023-day1</link>
      <pubDate>Fri, 24 Mar 2023 14:23:11 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/phperkaigi2023-day1</guid>
      <description>&lt;p&gt;昨日から始まっているPHPerKaigi、昨日はオンライン、今日は物理で参戦しています。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;これは、PHPerが増殖していると噂の謎の駅... &lt;a href=&quot;https://x.com/hashtag/phperkaigi?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#phperkaigi&lt;/a&gt; &lt;a href=&quot;https://t.co/uSM1BqewIx&quot;&gt;pic.twitter.com/uSM1BqewIx&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1639071029611089920?ref_src=twsrc%5Etfw&quot;&gt;March 24, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;初めてのPHPerKaigiですが、各発表やLTの独特の空気感がとても新鮮で、とても楽しんで参加できました。&lt;/p&gt;
&lt;p&gt;PHPer界隈のTwitterでよく見るぞ、という方の話を聞けたり、なんなら物理的に話すなどできて、カンファレンスよいなあという気持ちに浸っています。&lt;/p&gt;
&lt;p&gt;聞いたセッションはこちら。それぞれ細かい感想はフィードバックやまた別の記事で書くことにしますが、どれも面白く楽しく聞かせていただきました！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/280706e0-7158-4237-8202-c9d64330b96f&quot;&gt;PHPで学ぶ&quot;Cacheの距離&quot;の話&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/90c0d39b-108b-4104-b93e-f7e0711003c6&quot;&gt;Win Testing Trophy Easily / テスティングトロフィーを獲得する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/7e212cb2-be37-43e8-b6ee-5236d259fcbf&quot;&gt;時間を気にせず普通にカンニングもしつつ ISUCON12 本選問題を PHP でやってみる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/95e4dd94-5fc7-40fe-9e1a-230e36404cbe&quot;&gt;詳説「参照」：PHP 処理系の実装から参照を理解する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/86b0f058-2b05-4a06-a7d3-825aec7997bb&quot;&gt;PHP Parserで学ぶPHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/b9414c59-cb8f-4654-84c7-ade44744295e&quot;&gt;安全にプロセスを停止するためにシグナル制御を学ぼう！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/d3084a8f-89b5-48d6-8a81-59c460b3b3e0&quot;&gt;Rector ではじめる &quot;運用を止めない&quot; PHP アップグレード&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/dc54af9b-f879-47b6-9737-12ae6e84bf1d&quot;&gt;CodeCrafters にチャレンジして PHP で Redis を作ってみる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/4a67cc68-83f0-492d-86ca-54304fc256c8&quot;&gt;パフォーマンスを改善せよ！大規模システム改修の仕事の進め方&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/b84ab856-7c83-46a8-829e-84adbc1e7921&quot;&gt;不幸を呼び寄せる命名の数々　 ～君はそもそも何をされてる方なの？～&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/f4d1dc93-718b-44c7-8be2-edd66a253e630&quot;&gt;PHPで構築したWordPressをObservabilityツールで見てみる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/8e702c28-702b-4033-a16b-1481147be718&quot;&gt;stdClassって一体何者なんだ？！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/f90ff566-8535-4a0e-8ff2-99f3c8cc3f66&quot;&gt;特徴、魅力を知って、各PHPフレームワークを使いこなそう！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/f06e249f-ed18-4fde-b072-32b94131bc7f&quot;&gt;セキュリティテストでより安心できるリリースにしよう&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/5d3c8e21-b7f1-44c5-9088-f0c7769452f7&quot;&gt;PeachPieを使ってPHPを.NETで動かしてみた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/87d825dd-eba2-4fe9-8945-cf83d8b845e5&quot;&gt;mpyw共同登壇：“推測するな、計測せよ“をNew Relic x Laravelで実践&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;明日はLTに登壇します！今日の盛り上がりに少しビビっている面もありますが、うろたえずにやっていくぞ！もし時間があればぜひ聞きに来てください。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fortee.jp/phperkaigi-2023/proposal/d2d5fcfe-1661-4901-81d0-df071fa63bab&quot;&gt;クイズを作ってPHPに親しむ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内容は、PHP Conference2022のPHPクイズの裏話という側面もあります。知らない方も楽しめるように、それを知っている方はもっと楽しめるように作ったつもりです。&lt;/p&gt;
&lt;p&gt;それでは会場で、オンラインで、また明日お会いしましょう！
1日会場にいる予定なので、知っている方も初めてお会いする方もどなた様も話しかけてくれると嬉しいです。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;これが噂の… &lt;a href=&quot;https://x.com/hashtag/phperkaigi?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#phperkaigi&lt;/a&gt; &lt;a href=&quot;https://x.com/hashtag/a?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#a&lt;/a&gt; &lt;a href=&quot;https://t.co/rkX26kAwXe&quot;&gt;pic.twitter.com/rkX26kAwXe&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1639174451249160192?ref_src=twsrc%5Etfw&quot;&gt;March 24, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;LT、謎の盛り上がりだったな..&lt;/p&gt;</description>
    </item>
    <item>
      <title>ターミナルをカスタマイズする Software Design連載 開発環境 探求の道 第3回</title>
      <link>https://memo.yammer.jp/posts/software-design-202303</link>
      <pubDate>Fri, 17 Feb 2023 02:20:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-design-202303</guid>
      <description>&lt;p&gt;本日2/17発売の月刊誌 &lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202303&quot;&gt;Software Design 2023年3月号&lt;/a&gt;に、連載第3回目の記事を寄稿しました。&lt;/p&gt;
&lt;p&gt;今回は「ターミナルをカスタマイズする」と題して、Alactirryとtmuxの基本的な使い方を紹介しています。UnixやLinuxの技術者がふれる時間の長いターミナルを使いこなすことで、快適に作業できることを目指す内容です。&lt;/p&gt;
&lt;p&gt;ぜひ書店でお買い求めください。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/software-design-202303.jpg&quot; alt=&quot;Software Design 2023年3月号&quot;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Smart Keyboard Folio を買った(2023年2月)</title>
      <link>https://memo.yammer.jp/posts/smart-keyboard-folio</link>
      <pubDate>Wed, 01 Feb 2023 14:43:02 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/smart-keyboard-folio</guid>
      <description>&lt;p&gt;(2024/09/22記)2023年2月ごろに、Smarty Keyboard Folioを買って、その感想を書いた記事が下書きに残っていたので公開する。最近はあんまり持ち歩いていないんだけど、一時期はだいたいiPadだけを持ち歩いていて、とても気に入って使っていた。dotfilesの連載記事の寄稿も、何割かはiPad + Smarty Keyboard Folioを使ってsshしてVimで書いていたはず。結構快適だった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;iPad Air 4の機動力を上げたくて、Smart Keyboard Folioを買った。&lt;/p&gt;
&lt;h2&gt;購入の動機&lt;/h2&gt;
&lt;p&gt;コンパクトな自作キーボードをiPadと一緒に持ち歩いて作業するということはときどき試していた。しかし、どうしてもiPadと分離しているので、ケーブルを接続するのが煩雑だし、膝の上などの不安定な場所では広げづらく、これらの点ではノートパソコンの使い勝手にかなわないと感じていた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-self-built&quot; id=&quot;user-content-fnref-self-built&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;これらの課題感を解消する目的で買ったのが、Smart Keyboard Folioである。特にiPad Air4はカメラが1つしかないので、2018年ごろに発売された第一世代のものが使え、定価より安く買えるとのことだった。&lt;/p&gt;
&lt;h2&gt;いいところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ケーブルを繋げずに外部キーボードが使える&lt;/li&gt;
&lt;li&gt;iPadと磁石で結合しているので、机の上などの安定した箇所でなくてもつかえる&lt;/li&gt;
&lt;li&gt;薄い&lt;/li&gt;
&lt;li&gt;軽くてコンパクト&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;iPadと磁石でしっかりくっつくということはとてもよい。他の一般のキーボードにはない利点で、膝の上で使ううえではとても役に立つ。&lt;/p&gt;
&lt;p&gt;キーボードが薄いので、パームレストなしで良いところもよい。&lt;/p&gt;
&lt;p&gt;キーボード自体が軽くてコンパクトなこともよい。iPadがはいるボディバッグを持っているのだが、これと合わせて出かけるのが楽しみだ。&lt;/p&gt;
&lt;h2&gt;満足できないところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;キータッチが重い (特にスペースキーが押しづらい)&lt;/li&gt;
&lt;li&gt;パームレストが無い&lt;/li&gt;
&lt;li&gt;キーボードがたわむ&lt;/li&gt;
&lt;li&gt;配列のカスタマイズの幅&lt;/li&gt;
&lt;li&gt;ESCキーがない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;買ってみたはいいものの、膝の上でのタイピング体験はあまり良くない。一番はキータッチが気に入らない。結構硬いのでしっかり押し込まないと反応しない。特にスペースキーが如実で、押したつもりなのに反応していないこともある。他のキーを押していても指先が疲れる感じがある。&lt;/p&gt;
&lt;p&gt;パームレストが無いことも気になる。膝の上にノートパソコンを載せてタイピングしているときは、実はパームレストに手のひらを乗せることでキーボードを固定していた。なので、安定感に欠ける。&lt;/p&gt;
&lt;p&gt;さらに、キーボード自体がたわむのも気になる。膝の上に乗せた時の安定感が、やはりノートパソコンに比べて欠けてしまう。&lt;/p&gt;
&lt;p&gt;キー配列のなかで、Escキーが無いことも気になるが、これはユースケースが特殊なので仕方がないだろう。iPadには修飾キーをリマップする機能が付いているので、いくらかカバーできるものの、CtrlとEscとShiftとTabキーを押しやすい位置に配置するにはキーやリマップ機能が足りない。これは自作キーボードと比較してしまうとしょうがない部分ではある。&lt;/p&gt;
&lt;p&gt;これらのいくらかは事前に展示されている商品を試すなどして薄々わかっていたところではあるが、キーのリマップなどは、US配列とVimで使ってみないとわからないところもあるので、まあこんなもんかなという感じ。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;いろいろ書いたが、やはり収まりの良さとコンパクト感はすばらしいし、使い心地は慣れれば解決する側面もあると思うので、しばらく持ち歩いて使ってみることとしたい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-self-built&quot;&gt;
&lt;p&gt;自作キーボード自体はとても気に入っています。iPadを不安定な場所で使うというユースケースには、一般に外付けのキーボードは合わないということでした。 &lt;a href=&quot;#user-content-fnref-self-built&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>シェルをカスタマイズする Software Design連載 開発環境 探求の道 第2回</title>
      <link>https://memo.yammer.jp/posts/software-design-202302</link>
      <pubDate>Wed, 18 Jan 2023 13:20:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-design-202302</guid>
      <description>&lt;p&gt;本日発売の月刊誌&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2023/202302&quot;&gt;Software Design 2023年2月号&lt;/a&gt;に、連載記事の第2回を寄稿しました。&lt;/p&gt;
&lt;h2&gt;開発環境 探求の道&lt;/h2&gt;
&lt;p&gt;連載「開発環境 探求の道」は、UnixやLinux上で、自分好みの開発環境をつくり、探求する道を紹介する連載です。
連載の中では、テキストエディタやシェルやターミナルに関するツールを紹介し、インストールからカスタマイズまで、手元で試せるような記事となっています。&lt;/p&gt;
&lt;h2&gt;シェルをカスタマイズする&lt;/h2&gt;
&lt;p&gt;第2回「シェルをカスタマイズする」では、bashとzshの設定ファイルを編集するのが主な内容となっています。
関連してgitのエイリアス機能やfzfにも触れます。&lt;/p&gt;
&lt;p&gt;シェルの設定ファイルを編集したことがない方や、コピペして貼り付けたことはあるが、中に書かれていることが実はよくわかっていないという方をはじめとして、シェルに興味のある方にぜひ読んでいただきたい内容です。&lt;/p&gt;
&lt;p&gt;記事の中ではシェルスクリプトの文法も含めて紹介しており、記載した設定例をもとに、自分の環境にあうように設定を自分でカスタマイズする第一歩になればと思って記事を書きました。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;Software Design 2023年2月号は「開発環境 探求の道」以外にも、多数の連載や特集があります。今号の第一特集はドメイン設計に関するもので、第二特集はログに関するものです。&lt;/p&gt;
&lt;p&gt;どちらも気になるので、私も読むのを楽しみにしています。ぜひ、お近くの書店またはWebサイトからお買い求めください。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ubuntu DesktopにAlacrittyをインストールする</title>
      <link>https://memo.yammer.jp/posts/how-to-install-alacritty</link>
      <pubDate>Sun, 15 Jan 2023 16:54:41 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/how-to-install-alacritty</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://alacritty.org&quot;&gt;Alacritty&lt;/a&gt;は、公式ではLinux向けのバイナリが配布されていないので、どこかから入手するか、自分でビルドする必要があります。&lt;/p&gt;
&lt;p&gt;以下では、Ubuntu Desktop 22.04上でビルドし、インストールする方法を紹介します。なお、この記事の内容は2023/01/16時点のものです。また、&lt;a href=&quot;https://github.com/alacritty/alacritty/blob/master/INSTALL.md&quot;&gt;公式に提供されているインストール用ドキュメント&lt;/a&gt;を参考にしています。&lt;/p&gt;
&lt;h3&gt;簡易的に利用するとき&lt;/h3&gt;
&lt;p&gt;ビルドされた実行ファイルをPATHの通った場所に配置するのみで良い場合は、こちらの方法を実行します。デスクトップのランチャー上にアイコンを表示したり、マニュアルをインストールした場合は、後述の「本格的に利用する」を参考にしてください。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Alacrittyのビルドに必要なaptパッケージをインストールする
$ sudo apt-get install cmake pkg-config libfreetype6-dev libfontconfig1-dev libxcb-xfixes0-dev libxkbcommon-dev python3 curl
# https://rustup.rs/ に従い、Rustの開発ツールをインストールする
# 実行するとインストールオプションを選択する画面が現れるので、「1) Proceed with installation (default)」を選択する (1を入力後にエンターを押す)
$ curl --proto &apos;=https&apos; --tlsv1.2 -sSf https://sh.rustup.rs | sh
# cargoコマンドを利用するために、シェルの設定ファイルを再読み込みする
$ source ~/.bashrc
$ cargo install alacritty
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了したら、シェル上でコマンド&lt;code&gt;alacritty&lt;/code&gt;を実行することで、Alacrittyを起動できます。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/how-to-install-alacritty-run.png&quot; alt=&quot;コマンドでAlacrittyを起動する&quot;&gt;&lt;/p&gt;
&lt;h3&gt;本格的に利用するとき&lt;/h3&gt;
&lt;p&gt;マニュアルをインストールしたり、デスクトップのランチャー上にアイコンを表示したい場合は、以下の手順でインストールします。&lt;/p&gt;
&lt;h4&gt;(必須) ビルド・インストールする&lt;/h4&gt;
&lt;p&gt;シェル上で以下のコマンドを順番に実行してください。ビルドに必要なツールをインストールし、ソースコードを入手してから、ビルドします。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Alacrittyのビルドに必要なaptパッケージをインストールする
$ sudo apt-get install cmake pkg-config libfreetype6-dev libfontconfig1-dev libxcb-xfixes0-dev libxkbcommon-dev python3 curl git

# https://rustup.rs/ に従い、Rustの開発ツールをインストールする
#   実行するとインストールオプションを選択する画面が現れるので、1を入力後にEnterキーを押す
#   (「1) Proceed with installation (default)」を選択する)
$ curl --proto &apos;=https&apos; --tlsv1.2 -sSf https://sh.rustup.rs | sh

# cargoコマンドを利用するために、シェルの設定ファイルを再読み込みする
$ source ~/.bashrc

# Alacrittyのソースコードを入手する
$ git clone https://github.com/alacritty/alacritty.git ~/alacritty
$ cd ~/alacritty

# バイナリをPATHの通った場所に配置する
$ cp target/release/alacritty /usr/local/bin 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;/usr/local/bin&lt;/code&gt;に配置できたら、シェル上で&lt;code&gt;alacritty&lt;/code&gt;コマンドを起動すると、Alacrittyが起動し、ウィンドウが現れることが確認できます&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/how-to-install-alacritty-run.png&quot; alt=&quot;コマンドでAlacrittyを起動する&quot;&gt;&lt;/p&gt;
&lt;h4&gt;(任意) デスクトップのランチャー上にアイコンを表示する&lt;/h4&gt;
&lt;p&gt;デスクトップのランチャー上にAlacrittyを表示するには、シェル上で、以下のコマンドを順番に実行してください。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# デスクトップのランチャー上にアイコンを表示し、GUI環境でクリックするだけで起動できるようにする
$ cd ~/alacritty
$ sudo cp extra/logo/alacritty-term.svg /usr/share/pixmaps/Alacritty.svg
$ sudo desktop-file-install extra/linux/Alacritty.desktop
$ sudo update-desktop-database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了すると、GUIキー (キーボードによっては、WindowsキーやCommandキー) を押下したあと、&lt;code&gt;Alacritty&lt;/code&gt;とタイプすると、Alacrittyのアイコンが表示されます。クリックするとAlacrittyが起動します。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/how-to-install-alacritty-icon.png&quot; alt=&quot;Alacrittyのアイコンが表示される&quot;&gt;&lt;/p&gt;
&lt;h4&gt;(任意) マニュアルをインストールする&lt;/h4&gt;
&lt;p&gt;Alacrittyのマニュアルをインストールするには、シェル上で、以下のコマンドを順番に実行してください。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# manコマンドで、Alacrittyのマニュアルを閲覧できるようにする
$ cd ~/alacritty
$ sudo mkdir -p /usr/local/share/man/man1
$ gzip -c extra/alacritty.man | sudo tee /usr/local/share/man/man1/alacritty.1.gz &gt; /dev/null
$ gzip -c extra/alacritty-msg.man | sudo tee /usr/local/share/man/man1/alacritty-msg.1.gz &gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了すると、コマンド&lt;code&gt;man alacritty&lt;/code&gt;で、Alacrittyのマニュアルを閲覧できます。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/how-to-install-alacritty-man.png&quot; alt=&quot;Alacrittyのマニュアルが閲覧できる&quot;&gt;&lt;/p&gt;
&lt;h3&gt;(任意) bash補完を利用可能にする&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;alacritty&lt;/code&gt;コマンドをbash上で実行するとき、Tabキーで補完をするには、以下のコマンドを順番に実行してください。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# bash上で、alacrittyコマンドの補完をできるようにする
$ mkdir -p ~/.bash_completion
$ cp extra/completions/alacritty.bash ~/.bash_completion/alacritty
$ echo &quot;source ~/.bash_completion/alacritty&quot; &gt;&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了すると、bash上で&lt;code&gt;alacritty &lt;/code&gt;と入力した後にTabキーを押すと、補完候補が表示されるようになります。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/how-to-install-alacritty-completion.png&quot; alt=&quot;Alacrittyのbash補完が表示される&quot;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>連載「最強の開発環境 探求の道」をSoftware Designではじめます</title>
      <link>https://memo.yammer.jp/posts/software-design-202301</link>
      <pubDate>Fri, 16 Dec 2022 00:50:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-design-202301</guid>
      <description>&lt;p&gt;本日、12月16日(金)発売の&lt;a href=&quot;https://gihyo.jp/dp/ebook/2022/978-4-297-12740-4&quot;&gt;Software Design 2023年1月号&lt;/a&gt;より、表題のとおり「最強の開発環境 探求の道」という連載をはじめます。
全国の書店やネットで購入いただけますので、よろしければお手にとって読んでいただけると嬉しいです。&lt;/p&gt;
&lt;h2&gt;連載の内容とねらい&lt;/h2&gt;
&lt;p&gt;連載では、LinuxやUNIXの環境における、シェル、ターミナル、エディタ、dotfilesなどの使い方やカスタマイズを扱います。
これらに興味がある方におすすめです。
また、コマンドラインの環境に詳しくない/なんとなく使っているが、これから使いこなせるようになりたい方にも読んでいただきたい内容となっています。&lt;/p&gt;
&lt;p&gt;記事の中では実際に試せる設定例も示しますし、その解説も、できる限りあわせて行います。
開発環境の目的や用途は十人十色ですので、自分にあったものを構築できるよう、設定の内容を理解していただけるよう努めます。
設定をコピペして動かすのももちろんよいのですが、その内容を理解すると、ご自身で応用でき、カスタマイズの幅が広がるでしょう。&lt;/p&gt;
&lt;p&gt;1月号から数回にわたって、トピックごとに開発環境の構成要素を説明する形で連載を進めます。
初回は、Gitを用いたdotfilesの管理構成の構築です。&lt;/p&gt;
&lt;p&gt;LinuxやUnixの開発環境を構築するとき、dotfilesを管理していればカスタマイズがより捗ります。
連載の次回以降に扱うカスタマイズも、初回の管理構成のうえで試すことで、Gitによる履歴管理の恩恵に預かれるでしょう。
これから設定を書く方も、すでに何らかの設定がある方も、dotfilesをGitで管理して、自分好みの開発環境の探求の道を一緒に歩んでいきましょう。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/software-design-202301.jpg&quot; alt=&quot;Software Design 2023年1月号&quot;&gt;&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;私の連載ももちろん読んでいただきたいですが、ほかにも連載記事が多数収録されています。
私自身、前号に続く他の連載記事を読むのが楽しみです。
「魅惑の自作シェルの世界」の第2回や「再発見！ デスクトップLinux入門」の最終回などを始めとして、じっくり読ませていただきます。&lt;/p&gt;
&lt;p&gt;連載だけでなく、特集「アルゴリズムを使いこなしたい」「PostgreSQL 15の最新機能」や、特別付録の仕事猫ステッカー第2弾も魅力的ではありませんか。
ぜひお近くの書店で手にとってみてください。&lt;/p&gt;</description>
    </item>
    <item>
      <title>日報 インターネット出張公開版</title>
      <link>https://memo.yammer.jp/posts/20221214</link>
      <pubDate>Thu, 15 Dec 2022 01:00:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20221214</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://adventar.org/calendars/7443&quot;&gt;GMOペパボ EC Advent Calendar 2022&lt;/a&gt;の14日目は、「日報 インターネット出張公開版」です。私やんまーが、12/14の日報を書きます。&lt;/p&gt;
&lt;p&gt;13日目はよぴさんの「&lt;a href=&quot;https://note.com/kusomigi5170/n/n48fd187eb8ef&quot;&gt;半分営業半分コンサルみたいな職種からEC業界に転職して感じたこと　〜よぴ的営業マインド語りも添えて〜&lt;/a&gt;」でした。
記事の中に出てきた「お客さんの理想とサービスでできることの限界の中間地点を一緒に模索する」という表現が印象的で、営業という仕事に対するよぴさんの熱さを感じました！&lt;/p&gt;
&lt;p&gt;さて、14日目アドベントカレンダーは、日報についてです。
私の勤めるGMOペパボ社内では、書きたい人々が思い思いに日報を書く文化があります。
社内のNotionには「みんなの日記」というデータベースがあり、そこに日報や日記が書かれることが多いです。
私も、毎日ではありませんが、ときおりNotionに日報を書いています。&lt;/p&gt;
&lt;div style=&quot;width: 60%; margin: 0 auto&quot;&gt;
&lt;div&gt;
あわせて読みたい: &lt;a href=&quot;https://careerhack.en-japan.com/report/detail/1511&quot;&gt;GMOペパボが全社員300名で使うNotion活用術｜リモートワークでも情報共有をスムーズに！&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;img alt=&quot;https://careerhack.en-japan.com/report/detail/1511&quot; src=&quot;https://blob.yammer.jp/daily-report-20221214-notion.jpg&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;日報のフォーマット&lt;/h2&gt;
&lt;p&gt;私の場合は新卒研修で使っていたフォーマットが馴染んでいるので、そのときの項目を反映した書いたテンプレートを用意しています。
テンプレートがあると書き出しが楽になるので助かっています。いまは、各項目の全ては埋めなくとも良いことにして、時間をかけすぎずに書きたいことや伝えたいことにフォーカスしています。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot;&gt;&amp;#x3C;!-- 日報のテンプレート --&gt;

## いまの気持ち
## やったこと
## わかったこと
## 次にやること
&lt;/code&gt;&lt;/pre&gt;
&lt;div style=&quot;width: 60%; margin: 0 auto&quot;&gt;
&lt;div&gt;
あわせて読みたい: &lt;a href=&quot;https://diary.shu-cream.net/2021-01-05:%20%E3%82%B7%E3%83%A3%E3%82%A6%E3%83%88%E3%82%A2%E3%82%A6%E3%83%88&quot;&gt;2021-01-05: シャウトアウト - けんちゃんくんさんのWeb日記&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;img alt=&quot;https://diary.shu-cream.net/2021-01-05:%20%E3%82%B7%E3%83%A3%E3%82%A6%E3%83%88%E3%82%A2%E3%82%A6%E3%83%88&quot; src=&quot;https://blob.yammer.jp/daily-report-20221214-format.jpg&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;2022/12/14の日報&lt;/h2&gt;
&lt;p&gt;それではここから日報です。&lt;/p&gt;
&lt;h3&gt;今の気持ち&lt;/h3&gt;
&lt;p&gt;物理出社を活かしてたくさんの人と喋った日だったので、皆さんのパワーを感じる日でした！&lt;/p&gt;
&lt;p&gt;特に、新卒同期の homirunとの「やっていく会」では、データの整合性に関するアイデアをもらって、今後の実装のイメージが湧いたのでとても有意義な時間でした。
「やっていく会」は、最近週次ではじめた取り組みで、homirunと二人で行っている雑談会兼相談会です。
事前に議題は決めず、お互いトピックがあればその場に持ち寄る方式で進めています。&lt;/p&gt;
&lt;p&gt;我々は、同じサービスを、異なる事業部から、異なる観点で開発運用しています。私はWebアプリケーションエンジニアとして、homirunはSREとして、それぞれの強みの領域や、持つ知見が異なります。
チームの垣根を超えてお互いの知見を共有する機会を強制的に作ることで、私はインフラレイヤでわからないところや気になるところを助けてもらったり、逆にhomirunにアプリケーションレイヤの話をしたりしています。&lt;/p&gt;
&lt;p&gt;2人で草の根的に始めた取り組みは、お互いに効果が生まれていると感じます。
タスクの困りポイントの解消や、懸念の先回りした発見などに役立っています。
今後は、この取り組みを少し広げ、他の人も呼ぶなどして、レイヤやチーム、事業部を超えた連携のきっかけとしたいと目論んでいます。&lt;/p&gt;
&lt;h3&gt;やったこと&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;参画中のプロジェクトの開発 (コードを書いたり)&lt;/li&gt;
&lt;li&gt;参画中のプロジェクトの定例ミーティング&lt;/li&gt;
&lt;li&gt;エンジニアの人々とカレー屋さんでランチ&lt;/li&gt;
&lt;li&gt;「やっていく会」&lt;/li&gt;
&lt;li&gt;隣のチームとテスタブルなコードに関する雑談&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;https://blob.yammer.jp/daily-report-20221214-curry.jpg&quot; alt=&quot;これはお昼のカレーです&quot;&gt;
&lt;div style=&quot;text-align: center; margin-top: 0&quot;&gt;
これはお昼のカレーです
&lt;/div&gt;
&lt;h3&gt;わかったこと&lt;/h3&gt;
&lt;p&gt;(省略)&lt;/p&gt;
&lt;h3&gt;次にやること&lt;/h3&gt;
&lt;p&gt;(省略)&lt;/p&gt;
&lt;h3&gt;シャウトアウト&lt;/h3&gt;
&lt;p&gt;参画中のプロジェクトメンバーの皆さん、いつも話しすぎてしまう私に付き合ってくださったり、仕事を巻き取ってくださったり、とても感謝しています。これからもよろしくお願いします。&lt;/p&gt;
&lt;p&gt;「やっていく会」でアイデアをくれた&lt;a href=&quot;https://twitter.com/h0mirun_deux&quot;&gt;homirun&lt;/a&gt;、感謝です。&lt;/p&gt;
&lt;p&gt;ランチをSlackで呼びかけてくださった&lt;a href=&quot;https://twitter.com/inoway46&quot;&gt;inoway&lt;/a&gt;さん、とても良い時間になりました。ありがとうございます。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/UVB_76&quot;&gt;ikaruga&lt;/a&gt;さんと&lt;a href=&quot;https://github.com/its532&quot;&gt;symmonds&lt;/a&gt;さん、夕方に雑に乗り込んでいったあと、私の触っていないロールの話を聞けたり、テスタブルなコードについて議論できて、勉強になりました。ありがとうございました。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;こうして振り返ると、出社ならではのコミュニケーションを活かせた一日でした。
そして、皆さんに助けられながら、日々仕事が出来ているのだと改めて感じます。&lt;/p&gt;
&lt;p&gt;ところで、この記事をGMOペパボで一緒に働きたいと思ったあなた！
GMOペパボでは、新しい仲間を募集しています。募集中の職種や、詳しい社内の環境や制度に関しては &lt;a href=&quot;https://recruit.pepabo.com/&quot;&gt;GMOペパボ株式会社 採用サイト&lt;/a&gt;をご覧ください。&lt;a href=&quot;https://recruit.pepabo.com/features/graduate/&quot;&gt;エンジニア新卒採用に関する情報をまとめたページ&lt;/a&gt;も公開中です！&lt;/p&gt;
&lt;p&gt;以上で、アドベントカレンダー14日目を終わります。一日遅れてしまったことをここでお詫びします。&lt;/p&gt;
&lt;p&gt;15日目はしべさんです！&lt;/p&gt;
&lt;div style=&quot;padding-top: 16px; text-align: center&quot;&gt;
  &lt;iframe src=&quot;https://adventar.org/calendars/7443/embed&quot; width=&quot;100%&quot; height=&quot;450&quot; frameborder=&quot;0&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;</description>
    </item>
    <item>
      <title>jpro: JavaScriptで書くJSON processor</title>
      <link>https://memo.yammer.jp/posts/jpro</link>
      <pubDate>Fri, 02 Dec 2022 00:18:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/jpro</guid>
      <description>&lt;p&gt;この記事は、&lt;a href=&quot;https://adventar.org/calendars/7722&quot;&gt;🎅GMOペパボエンジニア Advent Calendar 2022&lt;/a&gt;の2日目のものです。&lt;/p&gt;
&lt;p&gt;みなさんは、JSON processorを使っていますか？ええ、&lt;a href=&quot;https://github.com/stedolan/jq&quot;&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt;のようなツールのことです。世は大JSON時代、値を抽出したり、変換したりする機会も多いことでしょう。&lt;/p&gt;
&lt;p&gt;ところで、&lt;code&gt;jq&lt;/code&gt;の抽出クエリやコマンドラインオプション、さらっと書けますか？私はあんまり得意じゃないです。そこで、&lt;a href=&quot;https://github.com/yammerjp/jpro&quot;&gt;JavaScriptで書けるJSON processor「&lt;code&gt;jpro&lt;/code&gt;」&lt;/a&gt; をつくりました。&lt;/p&gt;
&lt;h2&gt;使ってみる&lt;/h2&gt;
&lt;p&gt;実際に使ってみましょう。Node.jsとnpmが使える環境ならば、事前のインストールなしに、「&lt;code&gt;npx jpro&lt;/code&gt;」で実行できます&lt;sup&gt;&lt;a href=&quot;#user-content-fn-npx&quot; id=&quot;user-content-fnref-npx&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。以下では、私が最近書いた記事のタイトル5つを、&lt;a href=&quot;https://rsss.yammer.jp/v0/json_feed&quot;&gt;JSON Feed&lt;/a&gt;から抽出しています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/jpro-feed-titles.gif&quot; alt=&quot;jproを使って、著者の、最近の記事5つを抽出する&quot;&gt;&lt;/p&gt;
&lt;h2&gt;抽出クエリはJavaScriptで書く&lt;/h2&gt;
&lt;p&gt;記事タイトルの「JavaSciriptで書く」とは、JSONの抽出・変換クエリをJavaScriptで書けることを指しています。&lt;code&gt;jpro&lt;/code&gt;の引数に指定する抽出クエリは、次のようなJavaScriptコード片です。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javaScript&quot;&gt;.items.slice(0,5).map(p=&gt;p.title)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与えたコード片は、暗黙に、「&lt;code&gt;output = input&lt;/code&gt;」に続くものとして解釈されます。
つまり、次のようなコードとして実行されます。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javaScript&quot;&gt;output = input.items.slice(0,5).map(p=&gt;p.title)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで出てくる変数&lt;code&gt;input&lt;/code&gt;は、標準入力のJSONをパースしたJavaScript Objectです。変数&lt;code&gt;output&lt;/code&gt;は、標準出力されるJSONのもとになるJavaScript Objectです。
&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice&quot;&gt;&lt;code&gt;slice&lt;/code&gt;&lt;/a&gt;と&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot;&gt;&lt;code&gt;map&lt;/code&gt;&lt;/a&gt;はそれぞれ配列のメソッド、&lt;code&gt;p=&gt;p.title&lt;/code&gt;は&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;アロー関数&lt;/a&gt;です。&lt;/p&gt;
&lt;p&gt;JavaScriptの文法をそのまま使って「標準入力のうち、itemsキーの値である配列のうち、はじめから5つを取り出し、さらに、titleというキーのみを抽出する」ということが書けます。&lt;/p&gt;
&lt;h2&gt;JSON以外の入出力もできる&lt;/h2&gt;
&lt;p&gt;さらに、先ほどのコード片には出てこなかった&lt;code&gt;stdin&lt;/code&gt;や&lt;code&gt;stdout&lt;/code&gt;という変数を用いると、JSON以外の入出力も行えます。たとえば以下の例では、JSONではなく、行ごとの文字列を出力しています。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl -s https://rsss.yammer.jp/v0/json_feed \
  | npx jpro &apos;;stdout=input.items.slice(0,5).map(p=&gt;p.title).join(&quot;\n&quot;)&apos;
Asahi Linuxを使う
Fitbit Charge 5を買った
Python実践機械学習システム100本ノックの準備
印象に残った仕事の話をきく話
HerokuからCloud Run + Litestreamへ移行した
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;jpro&lt;/code&gt;のクエリで使える、用意された変数は以下のとおりです。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;変数&lt;/th&gt;
&lt;th&gt;役割&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;標準入力のJSONをパースしたJavaScript Object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;標準出力のJSONに変換されるJavaScript Object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stdin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSONとしてパースする前の標準入力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stdout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;標準出力される文字列 (&lt;code&gt;null&lt;/code&gt;と&lt;code&gt;undefined&lt;/code&gt;以外の値が代入されれば、&lt;code&gt;output&lt;/code&gt;の代わりに、&lt;code&gt;stdout&lt;/code&gt;の値が標準出力される)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;jq&lt;/code&gt;はJSONの抽出を主目的にした記法を持ち、&lt;code&gt;jpro&lt;/code&gt;よりも短いクエリで記述できる場合が多いでしょう。一方、&lt;code&gt;jpro&lt;/code&gt;はJavaScriptコードをevalするというシンプルなつくり&lt;sup&gt;&lt;a href=&quot;#user-content-fn-implemention&quot; id=&quot;user-content-fnref-implemention&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;であり、JavaScriptの文法がそのまま使えます。ちょっと凝ったことをするときも、JavaScriptを知っていれば、比較的簡単に書けることと思います。&lt;/p&gt;
&lt;p&gt;コマンドラインでJSONを抽出するとき、記法に悩む必要はありません。やりたいことがすぐにできることは、素早さに繋がり、価値になります。&lt;code&gt;jpro&lt;/code&gt;が、JSON抽出のひとつの選択肢になれば幸いです。&lt;/p&gt;
&lt;h2&gt;🎅 / 🎄 GMOペパボエンジニア Advent Calendar 2022&lt;/h2&gt;
&lt;p&gt;この記事は、&lt;a href=&quot;https://adventar.org/calendars/7722&quot;&gt;🎅GMOペパボエンジニア Advent Calendar 2022&lt;/a&gt;の2日目のものでした。今年のペパボエンジニアには🎅(サンタ会場)のほかにも、&lt;a href=&quot;https://adventar.org/calendars/7784&quot;&gt;🎄(ツリー会場)&lt;/a&gt;があります。&lt;/p&gt;
&lt;p&gt;昨日は、よしこさんの未経験転職したい人へのエッセイ、あつい記事でした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://note.com/yoshikouki/n/n81b44928b656&quot;&gt;エンジニアの未経験転職を希望する方へ未経験転職した経験から伝えたいこと｜yoshikouki｜note&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;明日は、inowayさんの記事です！&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://inoway46.hatenablog.com/entry/2022/12/03/141106&quot;&gt;【入社エントリー】ペパボカレッジを全力でおすすめしてみる - 脈絡はありません&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;追記: プログラミングが楽しくなった、アウトプット量が増えた、というところが印象的でした！&lt;/p&gt;
&lt;div style=&quot;padding-top: 16px; text-align: center&quot;&gt;
  &lt;iframe src=&quot;https://adventar.org/calendars/7722/embed&quot; width=&quot;100%&quot; height=&quot;450&quot; frameborder=&quot;0&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
  &lt;div&gt;
      iframeでカレンダーを埋め込めるようなので追加してみました
  &lt;/div&gt;
&lt;/div&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-npx&quot;&gt;
&lt;p&gt;「&lt;a href=&quot;https://www.npmjs.com/package/jpro&quot;&gt;&lt;code&gt;npm install -g jpro&lt;/code&gt;&lt;/a&gt;」を実行し、システムにインストールすることもできます。このほうが、コマンドの起動が速いようです。 &lt;a href=&quot;#user-content-fnref-npx&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-implemention&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/jpro/blob/eb8dea10be51879517ab3bc36a8a2164829e7f2d/index.js&quot;&gt;&lt;code&gt;jpro&lt;/code&gt;の実装&lt;/a&gt;はいたって単純です。コードはいかなるnpm packageにも依存しておらず、たったの62行、しかもその2/3はヘルプメッセージです。やっていることは主に、先ほど示した4つの変数の準備と、クエリのeval、出力だけです。実装よりも、この記事の執筆の方が時間がかかっています。 &lt;a href=&quot;#user-content-fnref-implemention&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Asahi Linuxを使う</title>
      <link>https://memo.yammer.jp/posts/asahi-linux</link>
      <pubDate>Mon, 14 Nov 2022 16:55:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/asahi-linux</guid>
      <description>&lt;p&gt;Apple Silicon搭載のPC上でLinuxをブートするという魅力的なプロジェクト、Asahi Linuxを手元のMacBook (2020, M1, 256GB SSD, 16GB Memory) で動かしてみた。&lt;/p&gt;
&lt;p&gt;MacBookはハードウェアとしてすごく良く出来ていると思うが、ときどきLinux Desktopだったらもっといいなと感じることもあり、Asahi Linuxのことが気になっていた。
現在リリースされているのはα版。
一部のハードウェアが動かなかったりするものの、自己責任の範囲で、手軽にデュアルブート環境を構築できる。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;FirefoxとAlacrittyが動くことがわかって、ブラウザを開きつつ、一通りコマンドが叩ける環境ができた。
普段使いしても趣味用の個人端末であれば、そんなに困らなそう。
M1 MacBookの上でLinuxを動かすというだいぶチャレンジングに見えるプロジェクトだけど、手元の環境は、いまのところとても安定していてびっくりした。
気になるところでいうと、現在動かないが使えると嬉しいハードウェアは以下の通り。&lt;/p&gt;
&lt;h3&gt;スリープ&lt;/h3&gt;
&lt;p&gt;スリープが現時点で出来ないのは残念。しかし、M1 Macbookの電池持ちが良すぎて、家の中で使う分には画面オフでも十分使えそう。
一日外に持ち出したりはまだしていないので、そのときは気になるかもしれない。&lt;/p&gt;
&lt;h3&gt;DisplayPort on USB Type-C&lt;/h3&gt;
&lt;p&gt;外部モニタへの出力もできたら嬉しい。しかし、モニタに出力するなら普通のamd64のデスクトップマシンを使えばいいのではと考えれば、なくてもなんとかなる気持ちになる。&lt;/p&gt;
&lt;h3&gt;スピーカー&lt;/h3&gt;
&lt;p&gt;スピーカーも動けば嬉しいが、不意にYoutubeを開いたりせずに済むので、実は使えないほうが生産性に寄与すると思うことにする。&lt;/p&gt;
&lt;p&gt;ほかにもWebカメラなど動かないものはあるけれど、気になるのは実はこれくらい。結構ふつうに使えてしまってすごいなあという気持ちになっている。&lt;/p&gt;
&lt;h2&gt;OSのインストール&lt;/h2&gt;
&lt;p&gt;公式サイトの案内のとおり、curlで得たシェルスクリプトを走らせると、ウィザード形式で順に進む。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://asahilinux.org/2022/03/asahi-linux-alpha-release/&quot;&gt;https://asahilinux.org/2022/03/asahi-linux-alpha-release/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;事前にドキュメントに目を通しておいて、かつウィザードの注意文言に従って進めれば問題なさそうだった。
インストールの進め方は以下の動画で紹介されている。&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;embed-youtube embed-wrapper&quot; style=&quot;text-align: center;&quot;&gt;&lt;iframe class=&quot;embed-youtube&quot; width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/SoszrV0TG3U?feature=oembed&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;私が試した限りでは、一つだけ詰まりポイントがあった。
前半でSSDに新たなパーティションを追加するところがあるのだけど、そこでコケて先に進めなかった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11-12 22:28 root         ERROR    Process execution failed
Traceback (most recent call last):
  File &quot;/private/tmp/asahi-install/main.py&quot;, line 852, in &amp;#x3C;module&gt;
    InstallerMain().main()
  File &quot;/private/tmp/asahi-install/main.py&quot;, line 704, in main
    while self.main_loop():
  File &quot;/private/tmp/asahi-install/main.py&quot;, line 824, in main_loop
    return self.action_resize(parts_resizable)
  File &quot;/private/tmp/asahi-install/main.py&quot;, line 635, in action_resize
    self.dutil.resizeContainer(target.name, val)
  File &quot;/private/tmp/asahi-install/diskutil.py&quot;, line 208, in resizeContainer
    self.action(&quot;apfs&quot;, &quot;resizeContainer&quot;, name, size, verbose=2)
  File &quot;/private/tmp/asahi-install/diskutil.py&quot;, line 38, in action
    subprocess.run([&quot;diskutil&quot;] + list(args), check=True)
  File &quot;/private/tmp/asahi-install/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py&quot;, line 528, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command &apos;[&apos;diskutil&apos;, &apos;apfs&apos;, &apos;resizeContainer&apos;, &apos;disk0s2&apos;, &apos;178919571456&apos;]&apos; returned non-zero exit status 1.
11-12 22:28 root         INFO     MSG: If you need to file a bug report, please attach the log file:
11-12 22:28 root         INFO     MSG:   /private/tmp/asahi-install/installer.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;調べてみるとこれは結構よくある問題らしく、インストール前にディスクユーティリティからFirst Aidを実行しておくといいらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://support.apple.com/ja-jp/HT210898&quot;&gt;https://support.apple.com/ja-jp/HT210898&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First Aidを実行してから、再度スクリプトを走らせると順調にインストールできた。&lt;/p&gt;
&lt;h2&gt;初期設定&lt;/h2&gt;
&lt;p&gt;Arch Linuxをあまり使ったことないので、ちょっと探りながら以下のようなことをやった。なお、ソフトウェアのインストールは、
Arch Linux向けの非公式パッケージである&lt;a href=&quot;https://wiki.archlinux.jp/index.php/Arch_User_Repository&quot;&gt;AUR&lt;/a&gt;にバイナリが上がっているけどamd64のみ対応、というのがぼちぼちあるみたい。そこらへんは自分でビルドしたりバイナリを手に入れたりすると良さそう。&lt;/p&gt;
&lt;h3&gt;ホームディレクトリ配下のディレクトリを英名にする&lt;/h3&gt;
&lt;p&gt;ホームディレクトリ配下に作られるディレクトリ &lt;code&gt;デスクトップ&lt;/code&gt; などを &lt;code&gt;Desktop&lt;/code&gt; などの英語表記へ変更する。Ubuntuなどもそうだけれど、言語設定を日本語にしたとき、毎度変更していると思う。
最初から言語設定で英語を選択しておいても良かったかもしれない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.jp/index.php/XDG_%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA&quot;&gt;https://wiki.archlinux.jp/index.php/XDG_%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ LANG=C xdg-user-dirs-update --force
$ mv ~/デスクトップ/* ~/Desktop
$ rmdir ドキュメント デスクトップ 画像 ビデオ テンプレート ダウンロード 公開 音楽
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;KDEシステム設定を好みのものに&lt;/h3&gt;
&lt;p&gt;KeyboardのCap LockをCtrlにする。入力デバイス &gt; キーボード &gt; 詳細 &gt; キーボードオプションを設定 &gt; Caps Lock behavior &gt; Make Caps Lock an additional Ctrl&lt;/p&gt;
&lt;p&gt;電源ボタンを押すとロックをかける。電源管理 &gt; ボタンイベント設定 &gt; 電源ボタンが押されたとき &gt; スクリーンをロック を選択&lt;/p&gt;
&lt;h3&gt;最新のパッケージにする&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ pacman -Syu
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;yadmをinstallして、dotfilesを初期化&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo pacman -S yadm
# まだSSHキーがないので、httpsでcloneする
$ yadm clone https://github.com/yammerjp/dotfiles.git
$ yadm remote remove origin
$ yadm remote add origin git@github.com:yammerjp/dotfiles.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SSHキーを発行して、GitHubに登録しておく&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ ssh-keygen-me
# https://github.com/yammerjp/dotfiles/blob/650d39e02fcb0b698f03acac8fca722acab35666/.config/zsh/alias.zsh#L29-L31
# https://github.com/settings/ssh/new
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;IMEを設定する&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ pacman -S fcitx5-im fcitx5-mozc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;/etc/environment&lt;/code&gt;に以下を追記&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GTK_IM_MODULE=&quot;fcitx5&quot;
QT_IM_MODULE=&quot;fcitx5&quot;
XMODIFIERS=&apos;@im=fcitx5&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再ログインすると、タスクトレイにIMEの項目が出現する&lt;/p&gt;
&lt;h3&gt;1Passwordにログイン&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/ja/firefox/addon/1password-x-password-manager/&quot;&gt;https://addons.mozilla.org/ja/firefox/addon/1password-x-password-manager/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Alacritty, xclip, tmuxをインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo pacman -S alacritty xclip tmux
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;yayをインストール&lt;/h3&gt;
&lt;p&gt;AURのパッケージを管理するのに使えるツール&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd /tmp
$ git clone https://aur.archlinux.org/yay-bin.git
$ cd yay-bin
$ makepkg -si
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ghをインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ yay -S github-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ghqをインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd /tmp
$ wget https://github.com/x-motemen/ghq/releases/download/v1.3.0/ghq_linux_arm64.zip
$ unzip ghq_linux_arm64.zip
$ mv ghq_linux_arm64/ghq ~/.local/bin/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;好みのフォントであるHackGenNFをインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ wget https://github.com/yuru7/HackGen/releases/download/v2.7.1/HackGen_NF_v2.7.1.zip
$ unzip HackGen_NF_v2.7.1.zip
$ mv HackGen_NF_v2.7.1 HackGenNF
$ sudo mv HackGenNF /usr/share/fonts
$ fc-cache -fv
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;asdfでnodejsとrubyとphpをインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.10.2
$ source ~/.zshrc #事前にasdfのロード処理を書き込み済みだった
$ asdf plugin add nodejs
$ asdf install nodejs lts
$ asdf global nodejs lts
$ node --version

$ asdf plugin add ruby
$ asdf install ruby latest
$ asdf global ruby latest
$ ruby --version

$ asdf plugin add php
# 依存が結構ある
# ref: https://github.com/asdf-community/asdf-php/blob/master/.github/workflows/workflow.yml#L30
$ sudo pacman -S autoconf base-devel gd bison curl gettext git gd libcurl-openssl-1.0 libedit mlocate oniguruma postgresql-libs mysql re2c
$ sudo updatedb
$ asdf install php latest
$ asdf global php latest
$ php --version

$ asdf plugin add golang
$ asdf install golang latest
$ asdf global golang latest
$ go version
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;自宅ではしばらくAsahi Linuxを使ってみることにする。
ちなみに、この文章もAsahi Linux上のAlacritty + NeoVimから書いている。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Fitbit Charge 5を買った</title>
      <link>https://memo.yammer.jp/posts/fitbit-charge-5</link>
      <pubDate>Mon, 14 Nov 2022 16:54:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/fitbit-charge-5</guid>
      <description>&lt;p&gt;スマホをFelica非搭載のものに乗り換えるために、Suicaを使える機器が欲しくてFitbit Charge 5を買った。
決済ができれば十分という条件で、なるべく安いスマートウォッチ(スマートバンド)を探して、この機種に帰着した。
買ってから2週間くらい経ったので感想を書いてみる。&lt;/p&gt;
&lt;h2&gt;🤔決済&lt;/h2&gt;
&lt;p&gt;まず、Suicaについて。
腕につける端末でSuicaを使えるのは体験がよい。
改札だったり、お店だったりで支払うとき、とても楽だし、スムーズでいい感じ。&lt;/p&gt;
&lt;p&gt;ただし、気になるポイントもいくつかある。
一つは、オートチャージできないのが残念 (これは事前にわかっていた)。もともとオートチャージを使っていないので、なくても許容できるが、あったほうが気を使わずに済むので嬉しかった。&lt;/p&gt;
&lt;p&gt;また、チャージに待たされるのが気になりポイント。
チャージはFitbitアプリのみから行えるが、1分くらい待たされるのが結構長く感じる。Felica搭載のAndroid端末でSuicaチャージするときはいつも結構待たされると感じているが、それ以上に長い。&lt;/p&gt;
&lt;p&gt;Visaタッチがうまく使えないのも少し残念。
Fitbit Charge 5は、Suica以外にも、一部のデビットカードでをVisaタッチを利用できる。
たまたま対応カードを持っていたので設定したが、これは今のところうまく動かない。
お店で数回試してみたものの無反応で、別の物理カードでVisaタッチして払ってしまっている。
事前の設定や操作のやり方が間違っているのか、登録したカード&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;が古いものだからなのか、私のもっている端末が不良品だからなのか、何が原因かわかっていない。&lt;/p&gt;
&lt;p&gt;ただ、身の回りではSuicaさえあればわりとなんとかなってしまうので、支払い方法も統一できるしまあいいか、ということでSuicaだけ使っている。
これで特に不満はない。&lt;/p&gt;
&lt;h2&gt;🤔アラーム&lt;/h2&gt;
&lt;p&gt;起きれた時はいい感じ。
指定した30分のうち、睡眠の浅いタイミングでアラームを鳴らしてくれる「スマートアラーム」という機能がある。
タイミングがいいときは浅い眠りのときに手首の振動で起きられるのだけど、振動していないのか、私が気づかないのか、起きれないときもある。
気づかないときもあるということは、いまのところはこれにすべてを頼るというのは厳しい。
とはいえ、起きれるときの体験は結構よくて、ぬるっと起きれる。&lt;/p&gt;
&lt;h2&gt;🤔ヘルスケアとフィットネストラッキング&lt;/h2&gt;
&lt;p&gt;使いこなせていない。
Fitbitといえばヘルスケア系の機能が充実しているイメージがあるが、私の場合は、とりあえず手首につけているというだけの状態である。
歩数が気軽に見れたり、睡眠のトラッキングをしてくれたりするのは便利だが、あるから使っている、という程度である。他の機能も含め、使いこなせている感じは全然ない。&lt;/p&gt;
&lt;h2&gt;😆重量&lt;/h2&gt;
&lt;p&gt;軽い。
もともと腕時計をつけたりするのはそんなに好んでいないのだけれど、この端末は気にならない。バンドの位置を緩めにしておけば一日中つけていられるし、寝ているときもつけたままで問題ない。&lt;/p&gt;
&lt;h2&gt;😆充電&lt;/h2&gt;
&lt;p&gt;電池持ちがすこぶる良い。
公称では1週間くらいもつらしく、試していないが本当にそれくらいいけそうにみえる。
私の場合は、シャワーを浴びるときだけ、洗面所に置いている充電器で充電している。これを毎日やっていればフル充電されて困らない。
なぜこんなにバッテリーが持つのか、ただただ感心してしまう。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;腕につけるSuicaとして買って、概ねその用途で使っていて満足している。&lt;/p&gt;
&lt;p&gt;本当はフィットネストラッキングを活用できるくらい運動をすればよいのだが、あまり身体を動かせておらず、その部分をまるまる享受できてない。
Fitbit Charge 5の機能に、1時間の歩数が250歩未満だと身体を動かすようバイブで促されるというのがある。まずはそれに従うところからやっていかねば。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;JNB時代のファミマTカード付きのデビットカード &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Python実践機械学習システム100本ノックの準備</title>
      <link>https://memo.yammer.jp/posts/python-ml-100-knocks-setup</link>
      <pubDate>Mon, 14 Nov 2022 16:53:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/python-ml-100-knocks-setup</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/Python%E5%AE%9F%E8%B7%B5%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0100%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF-%E4%B8%8B%E5%B1%B1%E8%BC%9D%E6%98%8C-ebook/dp/B0928FD1P8/ref=sr_1_1?keywords=Python%E5%AE%9F%E8%B7%B5%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0100%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF&amp;#x26;qid=1668239148&amp;#x26;qu=eyJxc2MiOiIyLjI4IiwicXNhIjoiMS44OSIsInFzcCI6IjEuOTIifQ%3D%3D&amp;#x26;s=digital-text&amp;#x26;sr=1-1&quot;&gt;Python実践機械学習システム100本ノック&lt;/a&gt;を手元で動かしながら読んでみている。&lt;/p&gt;
&lt;p&gt;Docker環境でJupyter Notebookを動かすサンプルコードがダウンロードできるが、そのままではビルドに失敗するので、requirements.txtにあるバージョンを書き換えるなどして動くように整えた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jupyter==1.0.0
numpy==1.21.0
pandas==1.5.1
openpyxl==3.0.4
scikit-learn==1.1.3
matplotlib==3.3.2
japanize-matplotlib==1.1.2
seaborn==0.11.0
ipywidgets==7.5.1
ipympl==0.5.8
xlrd==1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あわせて、Dockerfileとdocker-compose.ymlをやりやすい形に書き換えた。
ディレクトリ構成は以下のようにしている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .env
├── .env.example
├── .gitignore
├── Dockerfile
├── Makefile
├── README.md
├── docker-compose.yml
├── requirements.txt
└── src
    └── samples
        ├── 01
        │   ├── 1章_分析に向けた準備を行う10本ノック.ipynb
        │   ├── 1章_分析に向けた準備を行う10本ノック_answer.ipynb
        │   ├── m_area.csv
        │   ├── m_store.csv
        │   ├── tbl_order_202004.csv
        │   ├── tbl_order_202005.csv
        │   └── tbl_order_202006.csv
        ...
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-Makefile&quot;&gt;# Makefile
.PHONY: build-image run build-image:
        bash -c &apos;docker-compose build --build-arg UID=&quot;`id -u`&quot; --build-arg GID=&quot;`id -g`&quot;&apos;
run:
        docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Dockerfile&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; ubuntu:&lt;span class=&quot;hljs-number&quot;&gt;22.04&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; apt-get update &amp;#x26;&amp;#x26; apt-get install -y \
    python3 \
    python3-pip \
    curl \
    git \
  &amp;#x26;&amp;#x26; rm -rf /var/lib/apt/lists/*

&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; USERNAME=app
&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; GROUPNAME=app
&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; UID=&lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; GID=&lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; groupadd -g $GID $GROUPNAME &amp;#x26;&amp;#x26; \
  useradd -m -s /bin/bash -u $UID -g $GID $USERNAME

&lt;span class=&quot;hljs-keyword&quot;&gt;USER&lt;/span&gt; $USERNAME
&lt;span class=&quot;hljs-keyword&quot;&gt;WORKDIR&lt;/span&gt; /home/$USERNAME/

&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; PATH $PATH:/home/$USERNAME/.local/bin

&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt; ./requirements.txt /home/$USERNAME/requirements.txt
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; pip3 install -r /home/$USERNAME/requirements.txt

&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; PYTHONIOENCODING utf-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; LANG C.UTF-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; LC_ALL C.UTF-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# docker-compose.yml
# docker-compose.yml
version: &apos;3.5&apos;

services:
    jupyter_notebook:
        build:
            context: .
            args:
              - UID:1000
              - GID:1000
              - USERNAME:app
              - GROUPNAME:app
            dockerfile: ./Dockerfile
        volumes:
            - ./src:/home/app/src
        ports:
            - &quot;8888:8888&quot;
        environment:
            TZ: &quot;Asia/Tokyo&quot;
        networks:
            - default
        command: jupyter notebook --ip=0.0.0.0 --port=8888 --allow-root --no-browser --NotebookApp.notebook_dir=&apos;/home/app/src&apos; --NotebookApp.token=&apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文はまだ最初の方しか試せていないが、読みやすいし、Jupyter Notebook上で試せるのでテンポよく進んでいい感じ。&lt;/p&gt;</description>
    </item>
    <item>
      <title>印象に残った仕事の話をきく話</title>
      <link>https://memo.yammer.jp/posts/talking-about-your-own-impressive-work</link>
      <pubDate>Mon, 14 Nov 2022 16:52:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/talking-about-your-own-impressive-work</guid>
      <description>&lt;p&gt;とある飲み会で、下のツイートにある質問の「(今まで携わった|最近やった)仕事の中で、印象に残ったもの」というテーマの話を、とある方が振ってくれて、聞いたり話したりしていた。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;「今まで担当したお仕事で特にがんばった、印象に残ってるもの」というテーマ、志向性やバリューの源泉がわかって、お話聞くの興味深かった〜たまに自問自答していくのもよさそうだわね〜&lt;/p&gt;— ねもつ (@_nemozzz) &lt;a href=&quot;https://x.com/_nemozzz/status/1591101355162497024?ref_src=twsrc%5Etfw&quot;&gt;November 11, 2022&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;この質問がめちゃくちゃよかった。
周りの人がどんな仕事をしているか、というのを把握する機会はあれど、それをどういう印象で受け止めているのかや、仕事の中でのおもしろポイント、その人が価値に感じていることを知れる機会というのは案外少ないかもしれない。
同じ仕事の内容でも人によって捉え方が違うだろうし、仕事の内容を知るだけでなくて「どう考えているのか」というのを聞けるのがよい。
話を聞くのが楽しいしおもしろかった。&lt;/p&gt;
&lt;p&gt;また、話す立場としても、自分自身で仕事の内容をどう捉えているのか振り返るいい機会だった。
ツイートの通りしばらく時間が立ってから自問自答するのもよいだろうし、他の人の話もきいてみたい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>HerokuからCloud Run + Litestreamへ移行した</title>
      <link>https://memo.yammer.jp/posts/cloud-run-litestream</link>
      <pubDate>Wed, 12 Oct 2022 01:15:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/cloud-run-litestream</guid>
      <description>&lt;h2&gt;はじめに&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.heroku.com/next-chapter&quot;&gt;Herokuの無料枠が終了&lt;/a&gt;することにあわせて、個人で動かしているRailsアプリケーションを他の場所へ移行する。
いままで無料で使わせていただいたこと感謝しつつも、月千円ほど払うほどのアプリケーションでもないので、ほぼ無料で移行できそうな場所を探すことにした。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;コンテナをホスティングできるGoogle Cloud Runは従量課金制だが、個人で使う分にはほぼ無料なので、これを選ぶことにする。
Cloud Runで使うRDBは一般にはGoogle Cloud SQLが推奨されていそうだが、ここでは安さのためにSQLite3 + Litestream + Google Cloud Storage(以下GCS)を使うこととしたい。&lt;/p&gt;
&lt;h2&gt;実装の方向性&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://litestream.io&quot;&gt;Litestream&lt;/a&gt;は、SQLite3のデータベースを、オブジェクトストレージやNFS、SFTPのストレージにレプリケーションできるOSSのソフトウェア。&lt;/p&gt;
&lt;p&gt;今回はコンテナの起動時にデータベースをGCSから復元し、コンテナの実行中はGCSへレプリケーションしつづける動作を実装する。
Dockerコンテナのエントリポイントに設定するシェルスクリプトのなかで、アプリケーションの起動前に処理を加えて対応する。&lt;/p&gt;
&lt;p&gt;コンテナの同時実行数は0~1にしている。
0にしていいのかは微妙だが、個人でしか使っていないうえ、大して重要なデータを扱っているわけでもないのでひとまずこれで様子を見ることにする。&lt;/p&gt;
&lt;h2&gt;移行の手順&lt;/h2&gt;
&lt;p&gt;ざっくり以下の手順で進めた。&lt;/p&gt;
&lt;h3&gt;SQLite3化&lt;/h3&gt;
&lt;p&gt;まず、PostgreSQLからSQLite3へ移行する。
Railsに用意されたコマンド &lt;code&gt;./bin/rails db:system:change --to=sqlite3&lt;/code&gt; を実行するだけで、環境問わずSQLite3で動くように修正された。&lt;/p&gt;
&lt;p&gt;あわせてDocker化しておく。
適当なDockerfile (とdocker-compose.yml) を書いて、手元のPCのDocker上で立ち上がるようにした。&lt;/p&gt;
&lt;h3&gt;LitestreamとGCSの利用&lt;/h3&gt;
&lt;p&gt;Litestreamのレプリケーション先にGCSを利用するので、GCSのセットアップをする。
まず、GCSにバケットを作り、接続情報を用意する。
権限を絞るためにサービスアカウントを作成し、取得した認証情報のJSONを保存しておく。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
2023/01/17追記: くのきみさんから教えていただき、Cloud RunとLitestreamの組み合わせの場合、GCSの認証情報はよしなに取得してくれるようです。この記事で行っているような認証情報の設定は不要であることがわかりました。
&lt;/summary&gt;
&lt;blockquote&gt;
&lt;p&gt;On a Compute Engine VM or Cloud Run service, Litestream will automatically pick up the credentials associated with the instance from the instance’s metadata server.
&lt;a href=&quot;https://litestream.io/guides/gcs/&quot;&gt;https://litestream.io/guides/gcs/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://x.com/yammerjp?ref_src=twsrc%5Etfw&quot;&gt;@yammerjp&lt;/a&gt; &lt;br&gt;参考になりました！それはそれとしてGCSに必要なクレデンシャルはCloud Runインスタンスから拾ってくれるらしいので、自分で設定する必要はなさそうな気がしました &lt;a href=&quot;https://t.co/WorBOBanVl&quot;&gt;https://t.co/WorBOBanVl&lt;/a&gt;&lt;a href=&quot;https://t.co/kPx31i4S4C&quot;&gt;https://t.co/kPx31i4S4C&lt;/a&gt;&lt;/p&gt;— くのきみ (@knokmki612) &lt;a href=&quot;https://x.com/knokmki612/status/1614856237774168064?ref_src=twsrc%5Etfw&quot;&gt;January 16, 2023&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;くのきみさん、情報提供ありがとうございます。&lt;/p&gt;
&lt;hr&gt;
&lt;/details&gt;
&lt;p&gt;つぎに、Dockerコンテナ起動時にLitestreamによる復元とレプリケーションを設定する。&lt;/p&gt;
&lt;p&gt;Dockerfileでは、Litestreamのインストールと設定ファイルの設置を行っている。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Dockerfile&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; rubylang/ruby:&lt;span class=&quot;hljs-number&quot;&gt;3.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;-focal

&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; mkdir /app
&lt;span class=&quot;hljs-keyword&quot;&gt;WORKDIR&lt;/span&gt; /app

&lt;span class=&quot;hljs-comment&quot;&gt;# Google Cloud Storageへの接続情報を保存するファイルのパスを事前に指定しておく。&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# コンテナイメージにこのファイルを含める必要はない。&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; GOOGLE_APPLICATION_CREDENTIALS /app/.gcs-credentials.json

&lt;span class=&quot;hljs-keyword&quot;&gt;ENV&lt;/span&gt; TZ Asia/Tokyo
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; apt update \
 &amp;#x26;&amp;#x26; apt install -y sqlite3 \
 &amp;#x26;&amp;#x26; apt-get clean \
 &amp;#x26;&amp;#x26; rm -rf /var/lib/apt/lists/*

&lt;span class=&quot;hljs-comment&quot;&gt;# Litestreamのバイナリを設置する。&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;ADD&lt;/span&gt; https://github.com/benbjohnson/litestream/releases/download/v0.3.8/litestream-v0.3.8-linux-amd64-static.tar.gz /tmp/litestream.tar.gz
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz

&lt;span class=&quot;hljs-keyword&quot;&gt;ADD&lt;/span&gt; Gemfile /app/Gemfile
&lt;span class=&quot;hljs-keyword&quot;&gt;ADD&lt;/span&gt; Gemfile.lock /app/Gemfile.lock
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt; bundle install

&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt; . /app

&lt;span class=&quot;hljs-comment&quot;&gt;# Litestreamの設定ファイルを設置する。&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt; ./litestream.yml /etc/litestream.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# litestream.yml
dbs:
  - path: /app/db/production.sqlite3
    replicas:
      - url: gcs://____YOUR_BACKET_NAME____/db/production.sqlite3
  - path: /app/db/staging.sqlite3
    replicas:
      - url: gcs://____YOUR_BACKET_NAME____/db/staging.sqlite3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;entrypoint.shでは、データベースを復元してからレプリケーションを開始する。
あわせて以下も実装している。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;開発環境や初回起動時は、データベースの復元の代わりに、マウントされたファイルを使う、もしくは&lt;code&gt;rake db:migrate:reset&lt;/code&gt;する。&lt;/li&gt;
&lt;li&gt;ポート番号は&lt;code&gt;$PORT&lt;/code&gt;を優先して利用する。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;接続情報は環境変数に集約する。LitestreamはGCSへの接続情報として&lt;code&gt;$GOOGLE_APPLICATION_CREDENTIALS&lt;/code&gt;にJSONファイルへのパスが入ることを期待する。コンテナイメージに接続情報を含めないために、JSONをbase64でエンコードして環境変数に保存しておき、起動時に書き出す。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;entrypoint.sh&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash -e

# entrypoint.sh

if [ &quot;$RAILS_ENV&quot; = &quot;&quot; ]; then
  DATABASE_FILE=&quot;db/development.sqlite3&quot;
else
  DATABASE_FILE=&quot;db/$RAILS_ENV.sqlite3&quot;
fi
DATABASE_FILE_FULLPATH=&quot;/app/$DATABASE_FILE&quot;
DATABASE_FILE_BACKET_FULLPATH=&quot;gcs://____YOUR_BACKET_NAME____/$DATABASE_FILE&quot;


# PORT番号は$PORTを優先する
if [ &quot;$PORT&quot; = &quot;&quot; ]; then
  PORT=8080
fi
EXEC_COMMAND=&quot;bundle exec rails server -p $PORT -b 0.0.0.0&quot;


if [ &quot;$RAILS_ENV&quot; = &quot;production&quot; ] || [ &quot;$RAILS_ENV&quot; = &quot;staging&quot; ] ; then
  USE_LITESTREAM=&quot;true&quot;
else
  USE_LITESTREAM=&quot;false&quot;
fi


# Litestreamを使う場合は、データベースをGCSから復元する
if [ &quot;$USE_LITESTREAM&quot; = &quot;true&quot; ] ; then
  # GCSの接続情報を環境変数から読み込み、base64デコードしてからファイルに書き込む
  # (事前に、接続情報をbase64エンコードして環境変数に設定しておく)
  if [ &quot;$GOOGLE_APPLICATION_CREDENTIALS&quot; = &apos;&apos; ] || [ &quot;$GOOGLE_APPLICATION_CREDENTIALS_BASE64&quot; = &apos;&apos; ] ; then
    echo &quot;Need to set \$GOOGLE_APPLICATION_CREDENTIALS and \$GOOGLE_APPLICATION_CREDENTIALS_BASE64&quot;
    exit 1
  fi
  echo &quot;$GOOGLE_APPLICATION_CREDENTIALS_BASE64&quot; | base64 --decode &gt; &quot;$GOOGLE_APPLICATION_CREDENTIALS&quot;

  # GCSからデータベースを復元する
  litestream restore -v -if-replica-exists -o &quot;$DATABASE_FILE_FULLPATH&quot; &quot;$DATABASE_FILE_BACKET_FULLPATH&quot;
fi

# データベースを初期化する (初回起動時は復元されたファイルがないため)
if ! [ -f &quot;$DATABASE_FILE_FULLPATH&quot; ] &amp;#x26;&amp;#x26; [ &quot;$ALLOW_RESET_DATABASE&quot; = &apos;true&apos; ]; then
  rake db:migrate:reset
  # ここで初期化用のSQLを流してもよい
  # if [ -f &quot;$SETUP_SQL_PATH&quot; ]; then
  #   cat &quot;$SETUP_SQL_PATH&quot; | sqlite3 &quot;$DATABASE_FILE_FULLPATH&quot;
  # fi
fi

if ! [ -f &quot;$DATABASE_FILE_FULLPATH&quot; ]; then
  echo &quot;$DATABASE_FILE_FULLPATH is not found...&quot;
  exit 1
fi


if [ &quot;$USE_LITESTREAM&quot; = &quot;true&quot; ] ; then
  # Litestreamによってレプリケーションしながら、アプリケーションを起動する
  exec litestream replicate -exec &quot;$EXEC_COMMAND&quot; -config /etc/litestream.yml
else
  # shellcheck disable=SC2090
  exec $EXEC_COMMAND
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;アプリケーションのデプロイ&lt;/h3&gt;
&lt;p&gt;Staging環境をつくって、ひとまずは&lt;code&gt;gcloud&lt;/code&gt;コマンドで手動でデプロイしたあとに、GitHubのリポジトリと紐付けて自動デプロイがなされるように設定した。&lt;/p&gt;
&lt;p&gt;Cloud RunとLitestream関係ないが、&lt;code&gt;RAILS_ENV=production&lt;/code&gt;として動かすためやコンテナ上で動かすための設定(&lt;code&gt;RAILS_LOG_TO_STDOUT&lt;/code&gt;や&lt;code&gt;RAILS_SERVE_STATIC_FILES&lt;/code&gt;など)をいくつか調整した。&lt;/p&gt;
&lt;h3&gt;データの移行&lt;/h3&gt;
&lt;p&gt;HerokuのPostgreSQLからのデータの移行は、&lt;code&gt;pg_dump&lt;/code&gt;を用いた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# 接続先の認証情報を得る
$ heroku pg:credentials:url --app APPNAME
# 認証情報を使って、データベースの内容をINSERT文形式で取得する。
$ pg_dump --data-only --no-owner --no-privileges --disable-dollar-quoting --no-acl --inserts -h HOSTNAME -U USERNAME DBNAME &gt; data.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得られた&lt;code&gt;data.sql&lt;/code&gt;をちょこちょこ編集して、SQLite3で読み込めるINSERT文だけにする。
SQLを流し込むのはローカルPC上で実施した。
&lt;code&gt;entrypoint.sh&lt;/code&gt;を一時的にすこし変えて、&lt;code&gt;rake db:migrate:reset&lt;/code&gt;のあとに&lt;code&gt;data.sql&lt;/code&gt;を流し込むようにしておく。&lt;/p&gt;
&lt;p&gt;さきほどの&lt;code&gt;entrypoint.sh&lt;/code&gt;を使えば、環境変数に応じてローカルPC上でも本番環境のデータベースをレプリケーションできる。
&lt;code&gt;RAILS_ENV=production&lt;/code&gt;としてコンテナを立ち上げて、データが挿入されているのを確認したら移行はおわり。&lt;/p&gt;
&lt;h3&gt;感想&lt;/h3&gt;
&lt;p&gt;Cloud Run + Litestream + GCSはコールドスタート時は少し時間がかかるが、Herokuの無料枠とさして変わらないかむしろ早いかもしれない。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;
それ以外の動作は結構サクサクしていていい感じ。&lt;/p&gt;
&lt;p&gt;ローカルでも気軽に同じ構成で動かせたりして結構よいので、Cloud RunでLitestreamを使うテンプレートを用意したい気持ちになった。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;お金がかかってもよい場合のホスト先はRenderやFly.io、もしくはHerokuのEco Dynoなどがありそう。&lt;a href=&quot;https://blog.jnito.com/entry/2022/10/04/104100&quot;&gt;Herokuの新しい有料プランのまとめと、無料プラン終了後の個人的な移行方針について - give IT a try&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://christina04.hatenablog.com/entry/access-gcs-bucket-with-iam-policy&quot;&gt;特定のGCSバケットにのみアクセスできるサービスアカウントの作り方 - Carpe Diem&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt; 参考: &lt;a href=&quot;https://zenn.dev/oubakiou/articles/382839bfc65931&quot;&gt;Cloud RunとLitestreamで激安GraphQL/RDBサーバーを動かす&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;Cloud Runでは環境変数&lt;code&gt;PORT&lt;/code&gt;を参照することがおすすめされている。&lt;a href=&quot;https://cloud.google.com/run/docs/migrating?hl=ja&quot;&gt;既存のサービスを移行する  |  Cloud Run のドキュメント  |  Google Cloud&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;データ量が大変少ない単純なアプリケーションだからということもあるだろう。 &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>CloudFront Functionsで指定したURLにリダイレクトさせる</title>
      <link>https://memo.yammer.jp/posts/cloudfront-functions-redirect</link>
      <pubDate>Sat, 08 Oct 2022 01:25:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/cloudfront-functions-redirect</guid>
      <description>&lt;p&gt;CloudFront Functionsというサービスがあり、軽量のJavaScriptコードをデプロイしてCloudFrontディストリビューションに紐づけることができるらしい。
他のサーバレスの実行環境との比較は以下の記事が参考になる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/jp/blogs/news/introducing-cloudfront-functions-run-your-code-at-the-edge-with-low-latency-at-any-scale/&quot;&gt;CloudFront Functions の導入 – 任意の規模において低レイテンシーでコードをエッジで実行 | Amazon Web Services ブログ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.classmethod.jp/articles/amazon-cloudfront-functions-release/&quot;&gt;エッジで爆速コード実行！CloudFront Functionsがリリースされました！ | DevelopersIO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ちょうどdotfilesリポジトリのセットアップ用スクリプトを取得できるエンドポイントを用意したかったので、今回はCloudFront Functionsで他のURLへの302リダイレクトを発行するエンドポイントを作成してみる。&lt;/p&gt;
&lt;p&gt;まずは、AWSコンソールのCloudFrontのページへ行き、左側のメニューから「関数」を選択する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cloudfront-functions-01.png&quot; alt=&quot;関数の作成&quot;&gt;&lt;/p&gt;
&lt;p&gt;「関数を作成」を選択すると、サンプルコード付きのCloudFront Functionsの関数(実行できる一単位)が一つ作成される。&lt;/p&gt;
&lt;p&gt;今回はリダイレクトしたいので、以下のようなコードに書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;function handler(event) {
    var response = {
            statusCode: 302,
            statusDescription: &apos;Found&apos;,
            headers: {
                &quot;location&quot;: { &quot;value&quot;: &apos;https://raw.githubusercontent.com/yammerjp/dotfiles/master/setup.sh&apos; }
            }
    };
    return response;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;テストタブでは関数を動作させてどんなレスポンスが返るかをみることができる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cloudfront-functions-redirect-test.png&quot; alt=&quot;テスト実行の結果を確認する様子&quot;&gt;&lt;/p&gt;
&lt;p&gt;問題なさそうであれば、発行タブから「関数を発行」する。
さらに作成した関数をCloudFrontのディストリビューションに紐付け、実際のWebからのリクエストで発火するようにする。&lt;/p&gt;
&lt;p&gt;手元でcurlコマンドを実行してみると、実際にリダイレクトが確認できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl http://dot.yammer.jp --verbose
*   Trying 2606:4700:3031::6815:2cf8...
* TCP_NODELAY set
* Connected to dot.yammer.jp (2606:4700:3031::6815:2cf8) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: dot.yammer.jp
&gt; User-Agent: curl/7.64.1
&gt; Accept: */*
&gt;
&amp;#x3C; HTTP/1.1 302 Found
&amp;#x3C; Date: Thu, 06 Oct 2022 16:17:57 GMT
&amp;#x3C; Content-Length: 0
&amp;#x3C; Connection: keep-alive
&amp;#x3C; Location: https://raw.githubusercontent.com/yammerjp/dotfiles/master/.bin/download.sh
&amp;#x3C; X-Cache: FunctionGeneratedResponse from cloudfront
&amp;#x3C; Via: 1.1 b4dadadff1d09a3efb8a9374bdfc2848.cloudfront.net (CloudFront)
&amp;#x3C; X-Amz-Cf-Pop: NRT12-C2
&amp;#x3C; Alt-Svc: h3=&quot;:443&quot;; ma=86400, h3-29=&quot;:443&quot;; ma=86400
&amp;#x3C; X-Amz-Cf-Id: Hx-hLyCjKYgzxYXB_cUrSQgtHDgQW-maDnfZvaXmn0mtzPu2hC_YSg==
&amp;#x3C; CF-Cache-Status: DYNAMIC
&amp;#x3C; Report-To: {&quot;endpoints&quot;:[{&quot;url&quot;:&quot;https:\/\/a.nel.cloudflare.com\/report\/v3?s=E2QYl2tLkUVmKzT2wAiYJhTp9NTPLj2s%2BtOwP%2Fx%2Fuq5qeDKYK5gttDmaBH8k1BxB9d0GPK8prNS7I5UMpG1aeUijjhl%2B32uT87m%2FhRGc6Jt9CGY1DHnld3Fku21CCEGZu2cnl6g2Yf1pvEU2&quot;}],&quot;group&quot;:&quot;cf-nel&quot;,&quot;max_age&quot;:604800}
&amp;#x3C; NEL: {&quot;success_fraction&quot;:0,&quot;report_to&quot;:&quot;cf-nel&quot;,&quot;max_age&quot;:604800}
&amp;#x3C; Server: cloudflare
&amp;#x3C; CF-RAY: 755fb5ce8bceafab-NRT
&amp;#x3C;
* Connection #0 to host dot.yammer.jp left intact
* Closing connection 0
$ curl -sL http://dot.yammer.jp | head -30
#!/bin/bash -e

if [ &quot;$(whoami)&quot; = &quot;root&quot; ]; then
  echo &quot;The script must be running without root.&quot;
  exit 1
fi

REPO=&quot;yammerjp/dotfiles&quot;

DOTFILES_DIR=&quot;$HOME/src/github.com/$REPO&quot;
if [ -d &quot;${DOTFILES_DIR}&quot; ]; then
  echo &quot;Dotfiles is already exist.&quot;
  echo &quot;${DOTFILES_DIR}&quot;
else

cat &amp;#x3C;&amp;#x3C;-&quot;EOF&quot;



      .o8                .    .o88o.  o8o  oooo
     &quot;888              .o8    888 `&quot;  `&quot;&apos;  `888
 .oooo888   .ooooo.  .o888oo o888oo  oooo   888   .ooooo.   .oooo.o
d88&apos; `888  d88&apos; `88b   888    888    `888   888  d88&apos; `88b d88(  &quot;8
888   888  888   888   888    888     888   888  888ooo888 `&quot;Y88b.
888   888  888   888   888 .  888     888   888  888    .o o.  )88b
`Y8bod88P&quot; `Y8bod8P&apos;   &quot;888&quot; o888o   o888o o888o `Y8bod8P&apos; 8&quot;&quot;888P&apos;




$
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Alacrittyを使っていく</title>
      <link>https://memo.yammer.jp/posts/alacritty</link>
      <pubDate>Tue, 06 Sep 2022 15:22:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/alacritty</guid>
      <description>&lt;h2&gt;Alacritty とは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://alacritty.org&quot;&gt;Alacritty&lt;/a&gt;はクロスプラットフォームなターミナルエミュレーター。
yamlで設定を記述できること、クロスプラットフォームであること、動作が早いことが特徴である。&lt;/p&gt;
&lt;h2&gt;IMEのインラインサポート&lt;/h2&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;おぉぉぉぉぉ&lt;br&gt;ついに、alacrittyにIMEのインラインサポートが入った！！ちゃんと変換中の位置も考慮されてdeleteもできてる！！！&lt;br&gt;よし、乗り換えるぞ！&lt;a href=&quot;https://t.co/J0rF12hJl2&quot;&gt;https://t.co/J0rF12hJl2&lt;/a&gt; &lt;a href=&quot;https://t.co/tADAMBfHTe&quot;&gt;pic.twitter.com/tADAMBfHTe&lt;/a&gt;&lt;/p&gt;— karasu@オフトゥン大好き (@Ket0104) &lt;a href=&quot;https://x.com/Ket0104/status/1566430771702665216?ref_src=twsrc%5Etfw&quot;&gt;September 4, 2022&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;AlacrittyにIMEで入力した時に未確定な文字列を表示する対応が入ったらしい。&lt;/p&gt;
&lt;p&gt;対応されたのが嬉しかったので、早速ビルド&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;して手元のMacBook Airで使うことにした。
実は以前、この変換前文字列の表示がサポートされていないことを理由に使うのをやめてしまっていたのであったので、待望の機能である。&lt;/p&gt;
&lt;h2&gt;ビルドして使ってみる&lt;/h2&gt;
&lt;p&gt;ビルドはめちゃ簡単で、cargoコマンドが使えれば依存関係に困るとかもない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# 事前にRustのビルド環境を入れておく
$ brew install rust

# cloneして...
$ git clone git@github.com:alacritty/alacritty.git
$ cd alacritty

# make appするだけでmacOS向けの実行ファイルをビルドできる
$ make app

# 適当なディレクトリに移動して、アプリケーションを起動する
$ cp -r target/release/osx/Alacritty.app ~/Application
$ open ~/Applications/Alacritty.app
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;設定ファイルを記述する&lt;/h2&gt;
&lt;p&gt;Alacrittyの特徴のひとつはyamlで設定を記述できることだと思うので、ひとまず設定ファイルを記述してみる。&lt;/p&gt;
&lt;p&gt;Alacritty.ymlの設定は&lt;a href=&quot;https://wiki.archlinux.jp/index.php/Alacritty&quot;&gt;Arch Linuxのwiki&lt;/a&gt;などが参考になる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yuru7/HackGen&quot;&gt;HackGen&lt;/a&gt;というフォントがみやすくて好みなので、これを設定する。&lt;/p&gt;
&lt;p&gt;ちなみにmacOSにインストールされたフォント名は &lt;code&gt;fc-list&lt;/code&gt; で確認できる&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ fc-list | grep HackGen
/Users/yammer/Library/Fonts/HackGen-Regular.ttf: HackGen:style=Regular
/Users/yammer/Library/Fonts/HackGen35-Bold.ttf: HackGen35:style=Bold
/Users/yammer/Library/Fonts/HackGen35Console-Regular.ttf: HackGen35 Console:style=Regular
/Users/yammer/Library/Fonts/HackGen35Console-Bold.ttf: HackGen35 Console:style=Bold
/Users/yammer/Library/Fonts/HackGenConsole-Regular.ttf: HackGen Console:style=Regular
/Users/yammer/Library/Fonts/HackGenConsole-Bold.ttf: HackGen Console:style=Bold
/Users/yammer/Library/Fonts/HackGen35-Regular.ttf: HackGen35:style=Regular
/Users/yammer/Library/Fonts/HackGen-Bold.ttf: HackGen:style=Bold
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# alacritty.yaml
font:
  normal:
    family: HackGen Console
    style: Regular
  bold:
    family: HackGen Console
    style: Bold
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでいい感じになった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/alacritty.png&quot; alt=&quot;alacrittyを使っているスクリーンショット&quot;&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
ありがとう、iTerm2
&lt;/summary&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ brew uninstall --cask iterm2
==&gt; Uninstalling Cask iterm2
==&gt; Backing App &apos;iTerm.app&apos; up to &apos;/opt/homebrew/Caskroom/iterm2/3.4.10/iTerm.app&apos;
==&gt; Removing App &apos;/Applications/iTerm.app&apos;
==&gt; Purging files for version 3.4.10 of Cask iterm2
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;ちゃんと確認していないが、マージされた日付的に2022/09/06時点でのリリースに含まれていてビルドしなくてもよかったかもしれない。(未確認) &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>プログラマのための文字コード技術入門を読んだ(2022年9月)</title>
      <link>https://memo.yammer.jp/posts/introduction-of-character-code-for-programmer</link>
      <pubDate>Thu, 01 Sep 2022 14:42:09 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/introduction-of-character-code-for-programmer</guid>
      <description>&lt;p&gt;(2024/09/22記) 2022年の9月に読んだ本の記事が、下書きとして残っていたままだったので公開します。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;業務で文字コードに触れる機会があったのですがそもそも文字コードというものに詳しくないので「改定新版 プログラマのための文字コード技術入門」という本を読みました。&lt;/p&gt;
&lt;p&gt;本を読む前は文字コードにはいくつかの規格があることを知っている程度の理解であったので、なによりもまず勉強になりました。また後述するいくつかの概念は背景とともに説明があって知っておかないと規格を理解しづらいので、本を買ってよかったという気持ちになりました。&lt;/p&gt;
&lt;p&gt;それだけでなく、この本を結構読むのが楽しく、平日の数日間で勢いで読み切ってしまうほどでした。&lt;/p&gt;
&lt;h2&gt;学べたこと: 文字の単位&lt;/h2&gt;
&lt;p&gt;私達が普段扱う文字は、何がひとつなのか、どれを同じ文字として扱うのか等の境界が実はあいまいで奥深いことを認識しました。
たとえばbyte(8bit)単位で考えると、「あ」は2byteにも3byteにもなり得ます。UTF-16では多くの文字は4byteで表され、処理系においてもそう扱われることがありますが、「𠮟」はサロゲートペアなので8byteで1つの文字を表します。濁点のついた文字は「が」はそれ自体に符号位置が与えられている場合もありますし、「か」と「゛」を分けて符号化したものの結合文字として表現されることもあります。「𠮟」「叱」は十分に似ていそうですが、同じ文字でしょうか？「😀」は文字といえるでしょうか？
普段当たり前にキーボードで入力している文字ですが、それらは符号化文字集合によって符号位置が定まっているだけでなく、複数の文字を一つの文字のように表す結合文字や、文字の単位としての書記素、どのような字形変化であれば同じ文字とみなすかを定めた漢字の包摂規則など、様々な概念に基づく定義の上に成り立っていることを認識しました。&lt;/p&gt;
&lt;h2&gt;学べたこと: ISO/IEC 2022の概念&lt;/h2&gt;
&lt;p&gt;1バイトや２バイトのメジャーな符号化方式のいくつかが従うISO/IEC 2022の符号化文字集合の符号位置と符号化方式のコードポイントの対応付の概念を学びました。&lt;/p&gt;
&lt;p&gt;G0-G3のバッファに符号面を呼び出した後、GLやGRにそれを呼び出し、呼び出し方を変えたり変えなかったりしながら文字列を表現するということを知りました。&lt;/p&gt;
&lt;h2&gt;そのほかに学べたこと&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文字コードや符号化文字集合における「文字」はどう認識されているのか (byte，正規化、書記素、結合文字などの概念、包摂規則)&lt;/li&gt;
&lt;li&gt;文字コードのメジャーな規格とその変遷、文字コード間の関係&lt;/li&gt;
&lt;li&gt;ISO/IEC 2022の基本概念１バイト/2バイトの符号化方式で基本となるGL，GR，G0からG3のバッファ&lt;/li&gt;
&lt;li&gt;区点番号の概念&lt;/li&gt;
&lt;li&gt;BMPとサロゲートペア、utf-8のバイト数(3,4,6)、BOM&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;学べなかったこと&lt;/h2&gt;
&lt;p&gt;外字/機種依存文字の詳細&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;というわけで、ここまでが下書きとして文章で書き出していた内容でした。&lt;/p&gt;
&lt;p&gt;2024年にはとりあえずutf8mb4に相当するようなものを使っておけば意識することのない文字コードですが、本を一冊読むとインデックスが生えて、必要な時の引き出しが増えるので便利です。&lt;/p&gt;
&lt;p&gt;本当は学んだことをあとから振り返りやすいようにもっと詳細に書きたくて箇条書きや単語レベルのメモを書いていたようですが、書ききっていなかったので以降はまた文字コードに思いを馳せるときがきた時のために、自分向けのメモとして残しておきます。&lt;/p&gt;
&lt;h2&gt;そのほかのメモ&lt;/h2&gt;
&lt;h3&gt;符号化文字集合&lt;/h3&gt;
&lt;h3&gt;JIS X 208&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1978年に制定され、その後複数回改定された日本で最も基本的な２バイト符号化文字集合&lt;/li&gt;
&lt;li&gt;JIS第1水準、第2水準の漢字が含まれる&lt;/li&gt;
&lt;li&gt;ISO/IEC 2022準拠。第一バイト(行)第二バイト(列)ともに0x21-0x7Eの94行x94列に収まる組み合わせ&lt;/li&gt;
&lt;li&gt;区点番号 ... 94行x94列の表のどこに位置するかを表す表記。例えば愛は16行目六列目に位置するので16区6点という。&lt;/li&gt;
&lt;li&gt;対応する符号化方式としてShift_JISやEUC-JP、ISO-2022-JPなどがある&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JIS X 212&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JISX 208と組み合わせて使うことを前提とした２バイト符号化文字集合&lt;/li&gt;
&lt;li&gt;94x94&lt;/li&gt;
&lt;li&gt;EUC-JPでは使う方法が提供されているがShift_JISでは使えない&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JIS X 213&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JIS X 208を拡張した２バイト符号化文字集合&lt;/li&gt;
&lt;li&gt;2000年に制定され2004年に改定されたため、JIS2000、JIS2004などと呼ばれることがある&lt;/li&gt;
&lt;li&gt;JIS X 212とはかなりの文字が重複する&lt;/li&gt;
&lt;li&gt;94x94を2面持つ&lt;/li&gt;
&lt;li&gt;1面はJIS X 208の空き領域に文字を追加したもの(追加された漢字はJIS第3水準)&lt;/li&gt;
&lt;li&gt;2面は漢字のみ (JIS第4水準)
&lt;ul&gt;
&lt;li&gt;JIS X 212で定義されている区点番号を避けている&lt;/li&gt;
&lt;li&gt;EUC-JPのJIS X 212と区別がつくように&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;符号化方式としてはShift_JIS-2004、ISO-2022-JP、EUC-JIS-2004&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Latin-1 (ISO/IEC 8859-1)&lt;/h3&gt;
&lt;p&gt;MySQL5系のデフォルトで設定されることでおなじみ
8ビット1バイトの符号化文字集合で、西ヨーロッパ言語向けの文字をふくむ
GLにASCIIを固定し、GRにLatin-1で定義した文字が使われる&lt;/p&gt;
&lt;h3&gt;そのほか書きたかったこと&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JIS X 208 212 213 eucJP-ms IBM拡張&lt;/li&gt;
&lt;li&gt;Unicode ISO/IEC 10646(UCS) JIS X 0221&lt;/li&gt;
&lt;li&gt;BMP&lt;/li&gt;
&lt;li&gt;正規化&lt;/li&gt;
&lt;li&gt;書記素&lt;/li&gt;
&lt;li&gt;IBM拡張&lt;/li&gt;
&lt;li&gt;NEC拡張&lt;/li&gt;
&lt;li&gt;NEC選定IBM拡張&lt;/li&gt;
&lt;li&gt;EUC-JP(GLはASCIIで固定)&lt;/li&gt;
&lt;li&gt;eucJP-ms&lt;/li&gt;
&lt;li&gt;Shift_JIS EUC-JP JISX 208の関係&lt;/li&gt;
&lt;li&gt;各言語処理系での実装&lt;/li&gt;
&lt;li&gt;Rubyの実装(CP51932, EUC_JP, EUCJP_MS)&lt;/li&gt;
&lt;li&gt;PHPの実装&lt;/li&gt;
&lt;li&gt;Goの実装&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Clean Architectureを読んだ</title>
      <link>https://memo.yammer.jp/posts/clean-architecture</link>
      <pubDate>Tue, 23 Aug 2022 14:30:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/clean-architecture</guid>
      <description>&lt;p&gt;書籍「&lt;a href=&quot;https://www.kadokawa.co.jp/product/301806000678/&quot;&gt;Clean Architecture&lt;/a&gt;」を読みました。
副題は「達人に学ぶソフトウェアの構造と設計」となっており、ソフトウェアの構造や設計について見識をあまり持たない私は、この副題のとおり達人に学ぼうという気持ちで読みました。&lt;/p&gt;
&lt;h2&gt;本書で学べたこと (印象に残ったこと)&lt;/h2&gt;
&lt;p&gt;本書を読むことで、&quot;依存の方向&quot;と&quot;境界の決定&quot;に関する考え方を学びました。
これらをはじめとする、本書で学んだ考え方を以下に紹介します。&lt;/p&gt;
&lt;p&gt;なおこの記事では、書籍のタイトルや内容に反して、クリーンアーキテクチャとは何かやクリーンアーキテクチャの図に関する話はほとんど出てきません。それを構成する考え方に重きをおいて紹介します。
以下に示す考え方をみてみると、同心円状に書かれるクリーンアーキテクチャの図も依存の方向と境界の決定などの考え方を適用してできあがる図であるといえると思っています。&lt;/p&gt;
&lt;h3&gt;依存の方向&lt;/h3&gt;
&lt;p&gt;アプリケーションのアーキテクチャにおいて、依存の方向を揃えることは重要です。&lt;/p&gt;
&lt;p&gt;(例えばJavaではインタフェースを定義するなどして&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;)ポリモーフィズムを利用して処理の流れとソースコード上の依存の向きを逆転&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;させることを、依存性の逆転と呼びます。
この依存性の逆転を用いて、クリーンアーキテクチャにおける上位のレベル (ビジネスロジックに近いもの) が下位のレベル (システムの入出力に近いもの) に依存しないよう、また循環依存とならぬよう、依存の向きを揃えることが様々なシチュエーションに適用して説明されています。&lt;/p&gt;
&lt;h3&gt;境界の決定&lt;/h3&gt;
&lt;p&gt;アプリケーションのアーキテクチャの検討において、実装の境界&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;をどこにどの程度明確に作るかは、状況ごとにその都度考えて決定する必要があります。
なぜならば、アプリケーションの内容だけでなく、その周辺環境 (開発組織や開発頻度)、今後の開発計画など様々な要因で境界の最適解が異なるからです。&lt;/p&gt;
&lt;p&gt;ユースケースのすべて、運用上の制約、チームの構造、デプロイ要件などは実装前に明らかになっているとは限らないし、またこれは開発運用を続けるうちに変化していくものです。
これらの変化に合わせて適切なタイミングで適切に境界を定めて分割できるよう、選択肢を残しながらそのときどきに合わせて判断を続けていく必要があると考えられます。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;その他の事柄 (書籍で扱われる話題のメモ)&lt;/summary&gt;
&lt;p&gt;書籍で扱われているトピックが大変多いので、ここではメモとしていくつか列挙します。
詳細については書籍にあたればわかる程度の粒度で記載しています。&lt;/p&gt;
&lt;h4&gt;アーキテクチャに関連する原則&lt;/h4&gt;
&lt;p&gt;この書籍では以下のように多数の原則が紹介されています。これらをすべて厳密に守りましょうと主張しているというよりも、これらの原則が言い表している物事の方向性を明らかにして、望むべきアーキテクチャを考えるヒントとしている、というように感じました。&lt;/p&gt;
&lt;p&gt;いっぽう私はこれらの原則に明るいわけではなかったので、どういうものか、いつ適用するか、何が嬉しいのかを把握することにも役立ちました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SOLID原則 (単一責任の原則、オープン・クローズドの原則、リスコフの置換原則、インターフェイス分離の原則、依存関係逆転の原則)&lt;/li&gt;
&lt;li&gt;コンポーネントの凝集性に関する原則 (再利用・リリース等価の原則、閉鎖性共通の原則、全再利用の原則)&lt;/li&gt;
&lt;li&gt;コンポーネントの結合に関する原則 (非循環依存関係の原則、安定依存の原則、安定度・抽象度等価の原則)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Mainコンポーネントは最も詳細&lt;/h4&gt;
&lt;p&gt;Mainコンポーネント (アプリケーションの起動時に実行されるコード) はもっとも詳細な部分であり、プラグインとして環境によって取り替えられるような作りにすべきであるという考え方が紹介されていました。&lt;/p&gt;
&lt;p&gt;例えばユニットテスト実行時を考えてみると、アプリケーションのエントリポイントとは別の箇所から処理の実行が始まるでしょう。
つまりMainコンポーネントは、依存する側になるよう依存性の逆転を生かすべきコンポーネントのひとつであることがわかります。&lt;/p&gt;
&lt;h4&gt;アーキテクチャの変遷&lt;/h4&gt;
&lt;p&gt;(これは直接的には語られていませんが、ところどころで出現する話を私が解釈して勝手に書いています。)&lt;/p&gt;
&lt;p&gt;書籍の中ではアーキテクチャの完全な正解を教えてくれるというより、アーキテクチャを考える上でのいくつかの要素を揃えてくれているように思います。&lt;/p&gt;
&lt;p&gt;書籍の考え方を適用すると、マイクロサービスアーキテクチャや(本書では言葉こそ出てきませんが)モジュラーモノリスも、それらが特別なものではなく、境界の決定の仕方の選択肢のひとつであると感じました。&lt;/p&gt;
&lt;h4&gt;フレームワークなんかと結婚するな！&lt;/h4&gt;
&lt;p&gt;著者はフレームワークと結合することに否定的な考え方を持っています。
昨今のWebアプリケーション開発ではフレームワークに則って作ることがよくあると思いますが、ロックインされないような開発方法を提示するとともに、フレームワークとの密な結合をとった場合の考え方を結婚に例えて「病めるときも...」と記述しているのが少し皮肉的です。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;このほかに、同心円状のクリーンアーキテクチャの図や、オブジェクト指向プログラミングがもたらしたものに関する記述も印象的でした。&lt;/p&gt;
&lt;hr&gt;
&lt;/details&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;この本は英語の原著に対する訳本だったのですが、文調がたいへん読みやすく感じました。著者/訳者の文章の書き方に憧れます。&lt;/p&gt;
&lt;p&gt;書籍の内容について、これはアプリケーションを設計/開発するときのヒントのひとつになる内容でした。
今の自分にとっては結構よい本という感触がありますが、一方で全てを吸収する能力があったかというとこれは疑問です。開発経験のあるアプリケーションの数が多ければ、いまよりも詳細に書籍の指すことが理解できるだろうとも思います。&lt;/p&gt;
&lt;p&gt;この本を読んで、自分が関わるアプリケーションがどんなアーキテクチャを持っているかを考えるきっかけになりました。またよいアーキテクチャを提案する能力も一部学ぶことができました。一方で、よいアーキテクチャを選択する能力は本書を読んでもそれほど得られていないでしょう。書籍を通して学んだ考え方をもとに、実際のアプリケーションと照らし合わせて考えを膨らませ経験を重ねることで得られるように思います。
精進します。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;書籍ではJavaを扱っているのでJavaを挙げていますが、いわゆる動的型付け言語ではインタフェースを定義せずとも同名のメソッドがあれば振る舞いが定まるポリモーフィズムが実現できそうです。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;ソースコード上の依存の向きは次のように考えられるでしょう。例えばあるインスタンスBをAが呼び出すときは、AはBに依存しているといえます。一方であるインタフェースCをAが呼び出し、BはインタフェースCを実装したクラスのインスタンスであったとすると、AはCに依存し、BもCに依存します。これによりAからBに向く依存がなくなり、依存性の逆転がなされたといえます。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;境界が何を指すのかは書籍では明確には定義されていないように思います。私が思うに、クラス、ファイル、ディレクトリ、(各言語に付属の)パッケージや名前空間、などがそれぞれ粒度の異なる境界といえるでしょう。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>WiresharkでHTTP通信の内容を確認する</title>
      <link>https://memo.yammer.jp/posts/wireshark</link>
      <pubDate>Tue, 23 Aug 2022 13:32:06 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/wireshark</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.wireshark.org&quot;&gt;Wireshark&lt;/a&gt;はネットワークプロトコルアナライザとよばれるソフトウェアで、通信の内容を確認することができる。&lt;/p&gt;
&lt;p&gt;以下では簡単な使い方として、curlコマンドを使って手元のPCからインターネット上のサーバへHTTP通信した場合のパケットの内容を、tcpdumpでキャプチャし、最後にWiresharkのGUI画面上で確認する手順を示す。
なお、実行したPCは macOS 11.6 BigSur (Apple M1) だが、他の環境でも同様の手順で実行できると思われる。&lt;/p&gt;
&lt;h2&gt;パケットのキャプチャ&lt;/h2&gt;
&lt;p&gt;まずはじめに、キャプチャするパケットを絞り込めるよう、事前に通信先のIPアドレスを調べておく。
次に、tcpdumpコマンドをsudoで実行し、キャプチャするパケットの通信先IPアドレスを指定した上で、内容を適当なファイルに書き込む。 (ここでは&lt;code&gt;/tmp/memo-yammer-jp&lt;/code&gt;とする。)&lt;/p&gt;
&lt;p&gt;(後述のcurlコマンド実行後、キャプチャが終わったらCtrl-cで終了する。)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ dig @8.8.8.8 memo.yammer.jp +short
199.36.158.100
$ sudo tcpdump host 199.36.158.100 -w /tmp/memo-yammer-jp
Password:
tcpdump: data link type PKTAP
tcpdump: listening on pktap, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
^C11 packets captured
243 packets received by filter
0 packets dropped by kernel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;別のウィンドウでシェルを開き、curlコマンドを実行してキャプチャされるパケットを送受信する。
ここでは内容が確認できるよう、暗号化されていないHTTPプロトコルを指定している。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl http://memo.yammer.jp --verbose
*   Trying 199.36.158.100...
* TCP_NODELAY set
* Connected to memo.yammer.jp (199.36.158.100) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: memo.yammer.jp
&gt; User-Agent: curl/7.64.1
&gt; Accept: */*
&gt;
&amp;#x3C; HTTP/1.1 301 Moved Permanently
&amp;#x3C; Server: Varnish
&amp;#x3C; Retry-After: 0
&amp;#x3C; Location: https://memo.yammer.jp/
&amp;#x3C; Content-Length: 0
&amp;#x3C; Accept-Ranges: bytes
&amp;#x3C; Date: Tue, 23 Aug 2022 13:26:48 GMT
&amp;#x3C; Connection: close
&amp;#x3C; X-Served-By: cache-hnd18733-HND
&amp;#x3C; X-Cache: HIT
&amp;#x3C; X-Cache-Hits: 0
&amp;#x3C; X-Timer: S1661261209.536052,VS0,VE0
&amp;#x3C;
* Closing connection 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;パケットの内容の確認&lt;/h2&gt;
&lt;p&gt;tcpdumpをCtrl-cで終了し、パケットがキャプチャできたら、出力されたファイルをWireshark&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;から確認してみる。
Wiresharkを起動し、ファイルを開くボタンを選択する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wireshark-start-up.png&quot; alt=&quot;Wiresharkの起動画面&quot;&gt;&lt;/p&gt;
&lt;p&gt;次に、ファイル名を指定して開く。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wireshark-open-file.png&quot; alt=&quot;Wiresharkでファイル名を指定して開く&quot;&gt;&lt;/p&gt;
&lt;p&gt;すると、パケットのキャプチャ結果が表示され、画面の中央部にはHTTPのヘッダが表示されているのがわかる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wireshark-capture-packet.png&quot; alt=&quot;Wiresharkで表示したHTTPのヘッダ&quot;&gt;&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Wiresharkは次のURLからダウンロードできる。 &lt;a href=&quot;https://www.wireshark.org/download.html&quot;&gt;https://www.wireshark.org/download.html&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>abbrはじめました。</title>
      <link>https://memo.yammer.jp/posts/zsh-abbr</link>
      <pubDate>Thu, 04 Aug 2022 01:26:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/zsh-abbr</guid>
      <description>&lt;p&gt;同僚に教えてもらった &lt;a href=&quot;https://github.com/olets/zsh-abbr&quot;&gt;zsh-abbr&lt;/a&gt;を導入しました。&lt;/p&gt;
&lt;h2&gt;zsh-abbrとは&lt;/h2&gt;
&lt;p&gt;abbr は abbreviation の略で、おそらくもともとfish shellに組み込まれた機能とコマンド名を指しているようです。fishのabbrコマンドは、短いコマンド名を展開するalias コマンドに似た働きをするものです。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;alias&lt;/code&gt;コマンドとの違いは以下のようなところにあります&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;実行前にプロンプト上で短いコマンド名を展開してから実行される
&lt;ul&gt;
&lt;li&gt;historyには展開された結果が記録に残る&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;短いコマンド名を入力したあとスペースキーを入力しても、プロンプト上で展開される&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;zsh-abbrはfishのabbrコマンドと同等のものをzsh上でも再現できるzshプラグインです。筆者はzshを使っているので、本記事ではzsh-abbrを導入します。&lt;/p&gt;
&lt;h2&gt;導入&lt;/h2&gt;
&lt;p&gt;なるべくシンプルな状態を維持する目的でzshプラグインは入れないようにしていたのですが、複数のホストで環境を再現しやすいよう、zsh-abbrを導入するにあたってプラグインマネージャーも一緒に導入しました。&lt;/p&gt;
&lt;p&gt;zshプラグインは速そうな&lt;a href=&quot;https://github.com/zdharma-continuum/zinit&quot;&gt;Zinit&lt;/a&gt;を選びました。&lt;/p&gt;
&lt;h3&gt;Zinitの導入&lt;/h3&gt;
&lt;p&gt;インストールはREADMEに書いてある通り進めるだけです。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ bash -c &quot;$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/zdharma-continuum/zinit/HEAD/scripts/install.sh)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のコマンドを実行すると、&lt;code&gt;~/.zshrc&lt;/code&gt; に設定の読み込みなどが追記されるので &lt;code&gt;source ~/.zshrc&lt;/code&gt; として読み込めば利用できるようになっています。&lt;/p&gt;
&lt;h3&gt;zsh-abbrの導入&lt;/h3&gt;
&lt;p&gt;github.comに公開されているzshプラグインは、ユーザ名とリポジトリ名を指定すると利用できるようになります。
以下の一行を &lt;code&gt;~/.zshrc&lt;/code&gt; の、Zinitの読み込み処理の下に記述しました。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-zsh&quot;&gt;# ~/.zshrc
zinit light olets/zsh-abbr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ref: &lt;a href=&quot;https://github.com/zdharma-continuum/zinit#loading-and-unloading&quot;&gt;https://github.com/zdharma-continuum/zinit#loading-and-unloading&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;導入例&lt;/h3&gt;
&lt;p&gt;ここまでの記述は、&lt;code&gt;~/.zshrc&lt;/code&gt;などの起動時の読み込まれるzshスクリプト内に記述すると良いでしょう。&lt;/p&gt;
&lt;p&gt;一例として、以下のようになるかと思います。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-zsh&quot;&gt;# ~/.zshrc

# Zinitのインストール時に挿入される、初期化関連の記述
### Added by Zinit&apos;s installer
if [[ ! -f $HOME/.local/share/zinit/zinit.git/zinit.zsh ]]; then
    print -P &quot;%F{33} %F{220}Installing %F{33}ZDHARMA-CONTINUUM%F{220} Initiative Plugin Manager (%F{33}zdharma-continuum/zinit%F{220})…%f&quot;
    command mkdir -p &quot;$HOME/.local/share/zinit&quot; &amp;#x26;&amp;#x26; command chmod g-rwX &quot;$HOME/.local/share/zinit&quot;
    command git clone https://github.com/zdharma-continuum/zinit &quot;$HOME/.local/share/zinit/zinit.git&quot; &amp;#x26;&amp;#x26; \
        print -P &quot;%F{33} %F{34}Installation successful.%f%b&quot; || \
        print -P &quot;%F{160} The clone has failed.%f%b&quot;
fi

source &quot;$HOME/.local/share/zinit/zinit.git/zinit.zsh&quot;
autoload -Uz _zinit
(( ${+_comps} )) &amp;#x26;&amp;#x26; _comps[zinit]=_zinit

### End of Zinit&apos;s installer chunk

# Zinitを用いてzsh-abbrを利用する
zinit light olets/zsh-abbr
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;設定&lt;/h2&gt;
&lt;h3&gt;zsh-abbrの設定&lt;/h3&gt;
&lt;p&gt;zsh-abbrには、既に貼られているaliasを読み込んで保持する機能があります。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
今回はこれを利用することにして、以下のコマンドを実行します。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ abbr import-aliases
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;gitのaliasもzsh-abbrで展開する機能が備わっているようなので、同様にgitのaliasも読み込みます。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ abbr import-git-aliases
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import-git-aliases&lt;/code&gt;を利用すると、gに続けてエイリアスをタイプしたり、もしくはエイリアスを直接コマンドとしてプロンプトに入力すると展開されます。
たとえば私は &lt;code&gt;git d&lt;/code&gt; が &lt;code&gt;git diff&lt;/code&gt; となるようなエイリアスをgitの設定に書き込んでいます。この場合、プロンプトに &lt;code&gt;gd&lt;/code&gt; や &lt;code&gt;d&lt;/code&gt; と入力すると &lt;code&gt;git diff&lt;/code&gt; が実行されることになります。&lt;/p&gt;
&lt;h3&gt;細かな工夫&lt;/h3&gt;
&lt;h4&gt;git aliasの入れ子を排除&lt;/h4&gt;
&lt;p&gt;私のもともとの設定にはgitやzshのaliasが入れ子になっている場合があったため、入れ子を排除するような記述に書き換えました。&lt;/p&gt;
&lt;p&gt;たとえば、gitでは以下のような設定をしていました。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.gitconfig
[alias]
        di = &quot;diff --ignore-all-space&quot;
        ds = &quot;di --staged&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このようなとき、zsh-abbrは &lt;code&gt;gds&lt;/code&gt; を &lt;code&gt;git di --staged&lt;/code&gt; とは展開してくれますが、 &lt;code&gt;git diff --ignore-all-space --staged&lt;/code&gt; とまでは展開してくれません。
全て展開するために、aliasが入れ子にならないよう、以下のように設定を書き換えることとしました。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.gitconfig
[alias]
        di = &quot;diff --ignore-all-space&quot;
        ds = &quot;diff  --ignore-all-space --staged&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;あえてgit aliasを入れ子にする&lt;/h4&gt;
&lt;p&gt;gitのaliasのうちコマンド実行であるもの (&lt;code&gt;!&lt;/code&gt;で始まるもの) は展開に対応していないようなので&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;、これらはあえてaliasを張っています。&lt;/p&gt;
&lt;p&gt;以下に例を示します。
登録しているgitのaliasを表示するコマンド &lt;code&gt;alias&lt;/code&gt; と &lt;code&gt;als&lt;/code&gt; をgitの設定に記述しています。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.gitconfig
[alias]
        alias = &quot;!git config --list | grep -e &apos;^alias&apos; | sed -e &apos;s/alias\\.//&apos; -e &apos;s/=/\\t\\t/&apos;&quot;
        als = alias
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この場合&lt;code&gt;alias&lt;/code&gt; はabbrに対応していませんが、その短縮系である&lt;code&gt;als&lt;/code&gt;はabbrに対応しています。
つまり &lt;code&gt;galias&lt;/code&gt; は実行できませんが、&lt;code&gt;gals&lt;/code&gt; とコマンド入力すると abbrを介して &lt;code&gt;git alias&lt;/code&gt; が実行されます。
さらにこれはgitのもともとのalias機能を介してコマンド実行がなされるので、gitのaliasの一覧が表示されるということになります。&lt;/p&gt;
&lt;p&gt;gitのaliasについて、入れ子に対応していないこととコマンド実行に対応していないことをうまく活かして一部展開されるような状態をつくってみました。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;実行時にどんなコマンドを実行しているか都度表示されることで、画面共有時などに役立ちそうです。
historyの検索に展開されたものが記録されるという恩恵はしばらく使い続けないと効果が感じられないと思うので、この設定で運用してみようと思います。&lt;/p&gt;
&lt;p&gt;ちなみにタイトルについて補足しておくと、冷やし中華はまだ始めていません。(今夏食べた記憶がない。)&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;保存した内容は&lt;code&gt;abbr&lt;/code&gt;コマンドで操作できるようです。また記録先としては&lt;code&gt;$ABBR_USER_ABBREVIATIONS_FILE&lt;/code&gt;に保存されているようです。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/olets/zsh-abbr/blob/91280150cf8de09f84ab02c00fc04605400ea914/zsh-abbr.zsh#L337&quot;&gt;https://github.com/olets/zsh-abbr/blob/91280150cf8de09f84ab02c00fc04605400ea914/zsh-abbr.zsh#L337&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Software Designへ寄稿しました (2022年6月号 第1特集 Appendix dotfilesのススメ)</title>
      <link>https://memo.yammer.jp/posts/software-design-202206</link>
      <pubDate>Wed, 18 May 2022 02:00:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-design-202206</guid>
      <description>&lt;p&gt;技術評論社の&lt;a href=&quot;https://gihyo.jp/magazine/SD/archive/2022/202206&quot;&gt;Software Design 2022年6月号&lt;/a&gt; 第1特集 Appendix へ「dotfilesのススメ」という記事を寄稿させていただきました。
本日5/18発売で、全国の書店やWebでお買い求めいただけます。&lt;/p&gt;
&lt;p&gt;「dotfilesのススメ」は、UnixやLinuxなどでツールの設定を記述するファイルであるdotfilesの管理構成をつくるハンズオン記事になっています。
GitHub上にdotfilesリポジトリをつくることを通してdotfilesに入門できます。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.bashrc&lt;/code&gt;や&lt;code&gt;.zshrc&lt;/code&gt;や&lt;code&gt;.gitconfig&lt;/code&gt;に何書いてるかよくわからない方、dotfilesをあまり知らない方、dotfilesの管理が気になっているんが手をつけていない方などにぜひ読んでいただきたい内容になっています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/software-design-202206-2.jpg&quot; alt=&quot;Software Design 6月号&quot;&gt;&lt;/p&gt;
&lt;p&gt;寄稿のきっかけは、 技術評論社の方が私の書いたブログ記事を読んでメールをくださったことでした。
執筆の経験がなかったのでメールをいただいたときは大変驚きましたが、いまは無事寄稿を終えて安堵しています。&lt;/p&gt;
&lt;p&gt;このブログは技術メモをはじめとして自分が忘れないための備忘録や日本語の文章を書く練習として始めたものです。
ブログを書いてアウトプットすることは思考を整理したり良いものを共有したりするだけでなく偶然の機会を生むこともあるので、改めて文章を書くことを続けていこうと思います。&lt;/p&gt;
&lt;p&gt;執筆にあたり、Software Designの編集を担当してくださった担当者様やレビューをしてくださった上長に大変お世話になりました。
執筆や校正に関してフォローいただきありがとうございました。&lt;/p&gt;
&lt;p&gt;さてさて、この記事を呼んだ皆様方はどうぞ書籍を手にとってご覧いただき、ご購入ください！
寄稿記事の感想はぜひ&lt;a href=&quot;https://gihyo.jp/magazine/support/questionnaire&quot;&gt;技術評論社のプレゼント応募付き読者アンケート&lt;/a&gt;や&lt;a href=&quot;https://twitter.com/yammerjp&quot;&gt;@yammerjp&lt;/a&gt;にお寄せいただけると嬉しいです。
記事の寄稿依頼はメール(me[at]yammer.jp)ないし&lt;a href=&quot;https://twitter.com/yammerjp&quot;&gt;@yammerjp&lt;/a&gt;までお寄せください。&lt;/p&gt;</description>
    </item>
    <item>
      <title>cocot46を組み立てた(Build Log)</title>
      <link>https://memo.yammer.jp/posts/cocot46</link>
      <pubDate>Mon, 16 May 2022 17:30:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/cocot46</guid>
      <description>&lt;p&gt;トラックボールとロータリーエンコーダを搭載したキーボード、cocot46を組み立てました。
40%でColumn staggeredな配列が魅力的なキーボードです。&lt;/p&gt;
&lt;h2&gt;経緯&lt;/h2&gt;
&lt;p&gt;購入のきっかけはcocot46の作者の&lt;a href=&quot;https://twitter.com/aki27kbd&quot;&gt;@aki27kbd&lt;/a&gt;さんが再販予定をツイートされているのを見かけたことでした。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://x.com/hashtag/cocot46lp?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#cocot46lp&lt;/a&gt; は、手持ちのトラックボールモジュール在庫の数だけキットに同梱したものを近日中にboothにて頒布します。無印の &lt;a href=&quot;https://x.com/hashtag/cocot46?src=hash&amp;#x26;ref_src=twsrc%5Etfw&quot;&gt;#cocot46&lt;/a&gt; も同様にトラックボールモジュールを同梱したものを遊舎工房に委託予定です。どちらも在庫限りとなる予定なので、気になる方はこの機会にぜひ。&lt;/p&gt;— aki27 (@aki27kbd) &lt;a href=&quot;https://x.com/aki27kbd/status/1515311831375843335?ref_src=twsrc%5Etfw&quot;&gt;April 16, 2022&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;トラックボール一体型のキーボードが気になっていたものの、1Uのトラックボールユニットは終売となっていて手に入れるのが難しそうだと思っていた時だったので、ツイートをみかけて嬉しくなりました。
このあとは再販するのを待っていて、在庫が復活した日に注文しました。
その日の夜には売り切れていたので、トラックボール一体型のキーボードを求めている人が結構いるのかもしれません。&lt;/p&gt;
&lt;h2&gt;買ったもの&lt;/h2&gt;
&lt;p&gt;キースイッチはPlanck Keyboardに取り付けていて静音性に安心感のあるGateron Ink v2 Silent Blackを使用しました。&lt;/p&gt;
&lt;p&gt;キーキャップもPlanck Keyboardのときにお世話になったTALP Keyboardのブランクキーキャップを選びました。あらたにアプリコットのキーを買いましたが、色味がかわいいので気に入っています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cocot46-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;写真にはシルバーのロータリーエンコーダ用ノブが写っていますが、これは寸法的に取り付けられず誤って買ってしまったものでした。ロータリーエンコーダにノブが付属しているので今のところは困っていません。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;商品名&lt;/th&gt;
&lt;th&gt;個数&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;単価(円)&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;小計(円)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://shop.yushakobo.jp/products/2817?variant=40863445549217&quot;&gt;【委託】cocot46（トラックボールモジュール付き）&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://shop.yushakobo.jp/products/3762&quot;&gt;ロータリーエンコーダ 24クリック / プッシュスイッチ付き / 高さ20mm (EC12互換品)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;330&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;330&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.net/items/60f987230d4f3a07a4652ec3&quot;&gt;XDA PBT ブランク キーキャップ (ホワイト/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2090&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.net/items/616a3e71ac36613c126c4fa0&quot;&gt;XDA PBT ブランク キーキャップ (アプリコット/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;440&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/items/5b6e593d5f78663893000482&quot;&gt;XDA PBT ブランク キーキャップ (グレー/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;440&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://shop.yushakobo.jp/products/gateron-ink-switches&quot;&gt;Gateron Ink スイッチ v2 (10個入り) Silent Black&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1320&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TALP KEYBOARD キースイッチ 10個以上購入で5%オフ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TALP KEYBOARD 送料&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;合計&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;25805&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;40%だからということもありますが、結構安い気がします。
特にcocot46のキットは、同梱されていたパーツが多かった割に値段が安かったように思います。&lt;/p&gt;
&lt;h2&gt;組み立て&lt;/h2&gt;
&lt;p&gt;組み立ては&lt;a href=&quot;https://github.com/aki27kbd/cocot46/blob/main/doc/buildguide.md&quot;&gt;ビルドガイド&lt;/a&gt;の通りに素直に進めました。
チップ抵抗を途中で机の下に落として探す工程が一番難しかったです。&lt;/p&gt;
&lt;p&gt;組み立てたのちに、Google ChromeからREMAPを開いてファームウェアを書き込み、その後REMAP上から配列の設定などを行いました。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cocot46-4-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;こだわり&lt;/h2&gt;
&lt;h3&gt;配列&lt;/h3&gt;
&lt;p&gt;基本はPlanck Keyboardに設定していた時のものを踏襲し、QWERTY配列でレイヤを4つ配置し、うち3つを普段から使うものとしました。
配列には以下のようなこだわりを含んでいます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;矢印キーはレイヤーキーとhjklの同時押し (Vimライクな配列)&lt;/li&gt;
&lt;li&gt;macOSの絵文字入力ウィンドウ用キー (Ctrl + Cmd + Space) を配置&lt;/li&gt;
&lt;li&gt;macOSのウィンドウ切り替え用ショートカット (Ctrl + ↑) を配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;cocot46はロータリーエンコーダを回転させるとPageUp, PageDownが入力される配列となっており、ロータリーエンコーダを回してスクロールするのが楽しいです。&lt;/p&gt;
&lt;p&gt;PageUp, PageDownでは移動幅が大きすぎるときのために、Karabiner Elementsを使って、ロータリーエンコーダを押し込んだときはトラックボールの移動がスクロール入力になるような設定を追加しています。&lt;/p&gt;
&lt;p&gt;ref: &lt;a href=&quot;https://ke-complex-modifications.pqrs.org/#mouse_motion_to_scroll&quot;&gt;Change mouse motion to scroll (rev 3)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/keymap_cheatsheet_cocot46.png&quot; alt=&quot;cocot46のキーマップ&quot;&gt;&lt;/p&gt;
&lt;h3&gt;ケーブル&lt;/h3&gt;
&lt;p&gt;Pro MicroとPCの接続には&lt;a href=&quot;https://www.amazon.co.jp/%E3%82%B5%E3%83%B3%E3%83%AF%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88-microUSB%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB-%E3%83%9E%E3%82%B0%E3%83%8D%E3%83%83%E3%83%88%E7%9D%80%E8%84%B1%E5%BC%8F-QuickCharge-500-USB060/dp/B07GQVHP67/ref=asc_df_B07GQVHP67/&quot;&gt;マグネット式で着脱できるUSBケーブル&lt;/a&gt;を用いています。
ケーブルの脱着が楽になるだけでなく、力がかかると外れる特性を活かして端子の保護としても働いています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cocot46-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;ホームポジション&lt;/h3&gt;
&lt;p&gt;ブランクキーキャップのみで構成されていてホームポジションを示す突起がないので、ひとまずマスキングテープを貼り付けて、触り心地だけでホームポジションがわかるようにしました。
色味が外側のキーと似ていて満足しています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cocot46-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;改良したいところ&lt;/h2&gt;
&lt;p&gt;以下の気になる点をファームウェアや配列やキーキャップに手を入れて、より気に入った環境をつくっていこうと考えています。&lt;/p&gt;
&lt;h3&gt;レイヤーキーの反応時間/反応順&lt;/h3&gt;
&lt;p&gt;レイヤーキーと同時押しで入力する&lt;code&gt;-&lt;/code&gt; (ハイフン) が、押下タイミングの癖で、デフォルトレイヤーの&lt;code&gt;c&lt;/code&gt; が入力されてしまうことが多いです。
おそらく親指(レイヤーキー)の押すタイミングが遅いまたは離すタイミングが早いことに起因して、素早く入力するときにうまくデフォルトレイヤー外のキーを押せないでいます。&lt;/p&gt;
&lt;p&gt;過去に他のキーボードでファームウェアに手を入れて解決したような気がするので、思い出したら同様の処置をしようかと思っています。(対策前に慣れる可能性もありそうです)&lt;/p&gt;
&lt;h3&gt;左クリック/右クリックのキーの差別化&lt;/h3&gt;
&lt;p&gt;トラックボールを触りながらだと左クリック/右クリックキーを他のキーと押し間違えるので、高さの違うキーキャップに変えるなり位置を変えるなりしようか考えています。(これも対策前に慣れる可能性もありそうです)&lt;/p&gt;
&lt;h3&gt;最下段のキー配列の見直し&lt;/h3&gt;
&lt;p&gt;現在の配列は、右下に配置したウィンドウ切替用の Ctrl + ↑キーと、その隣ののBack Spaceキーを押し間違えがちです。
押し間違えても影響が小さくなる/押し間違えずに済むように、最下段のキー配列を改めて考え直そうと思っています。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;トラックボール一体型のキーボードは、手首の移動距離を短くしたり机上をスッキリさせたいという思惑がありました。
このどちらも満たせたので嬉しいです。
まだ使い慣れていないので、しばらくはcocot46で生活していこうと思います。&lt;/p&gt;
&lt;p&gt;(この記事はcocot46で書かれました。)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/cocot46-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>歳をとった</title>
      <link>https://memo.yammer.jp/posts/24-years-old</link>
      <pubDate>Mon, 16 May 2022 17:25:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/24-years-old</guid>
      <description>&lt;p&gt;先月誕生日を迎えて歳をとりました。&lt;/p&gt;
&lt;p&gt;干芋で祝ってくださった同期の方々、ありがとうございました！
送っていただいてから少し時間が経ってしまっているものもありますが、感謝をこめて紹介します。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;ちいさめの水筒。社の食堂でのみものを入れるのに重宝します。蓋がしっかりついているので変にこぼしたりする不安もなくてとてもよいです。&lt;/p&gt;
&lt;p&gt;レンジでパスタ。4人前まで一気に茹でられる大きいもので、パスタを茹でる時に鍋を使わなくていいのがよいです！パスタは簡単に素早くつくれるので、リモートワークのお昼になりがちです。
2個あるので8人までいけます！(そんなには茹でない)&lt;/p&gt;
&lt;p&gt;人に頼む技術。こういうことができるようになると、仕事をよりうまく回せるようになりそうでよいなあと思います。&lt;/p&gt;
&lt;p&gt;シェル・ワンライナー160本ノック。シェル芸に憧れがあるので、身につけていきます！&lt;/p&gt;
&lt;p&gt;ホットプレート/たこ焼き器。これのおかげで新居でたこ焼きができるようになりました！同期を呼んでタコパをしたい。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;たこ焼きはシャバシャバの液で、一面溢れるくらいに流して作るとまんまるになることを学びました。
写真にあるのはちょうど今日日曜日の夜に食べたものですが、家で作ったたこやきのなかで相当上位の出来 (形) だと自負しています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;オレオ (箱買い)。美味しいですよね、オレオ。箱買いでたくさんあるのでしばし安泰かと思いきや結構なスピードで食べてしまっていてもう残り半分を切っています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;クリーニングブラシ。机の上、モニター周りにほこりがたまりがちなのでこれで綺麗にします。&lt;/p&gt;
&lt;p&gt;焼き芋メーカー。ちょっと気になっていたものだったんですが、コンセントにつないで放置するだけで焼き芋ができる面白いものです。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;べにはるかを買ってつくってみたら、しっとりやわらか食感に仕上がって、蜜が飛び出てきてとても美味でした。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/wish-list-202204-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Kubernetes完全ガイド。Kubernetesなんもわからんので勉強します..&lt;/p&gt;
&lt;p&gt;Clean Architecture。業務のアプリケーションに触れるようになってから、設計めちゃ大事だなという気持ちを強くしているので、学びます。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;昨年の1年は就職したというのもあってやはり仕事のことが印象に残っています。
がむしゃらでやらないとどうしようもないところもあるのですが、今年はプライベートも充実させられるよう、うまく物事をコントロールできたらよいと考えています。&lt;/p&gt;</description>
    </item>
    <item>
      <title>秘匿情報を含む.bashrcを分割する</title>
      <link>https://memo.yammer.jp/posts/devide-bashrc</link>
      <pubDate>Sun, 10 Apr 2022 19:52:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/devide-bashrc</guid>
      <description>&lt;p&gt;dotfiles(ドットで始まる設定ファイル)の管理のために、Gitリポジトリを作成しGitHubにdotfilesという名前で公開するときに注意すべきこととして秘匿情報の扱いが挙げられます。&lt;/p&gt;
&lt;p&gt;秘匿情報が &lt;code&gt;.bashrc&lt;/code&gt; に含まれているとき、それをそのままGit管理してGitHubに公開することには問題があります。
ここでいう秘匿情報とはGitHubのパーソナルアクセストークンやAWSのアクセス用シークレットキーなどの認証時のパスワードの代替となるようなものをはじめとする、他の人に見せてはいけない情報のことです。&lt;/p&gt;
&lt;p&gt;こういった内容を含む&lt;code&gt;.bashrc&lt;/code&gt;は分割し、秘匿情報の含まない部分のみGit管理下に置くのがよいでしょう。&lt;/p&gt;
&lt;p&gt;今回は以下のような&lt;code&gt;~/.bashrc&lt;/code&gt;があったとき、秘匿情報の含む部分と含まない部分に分割する手法を紹介します。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;# ~/.bashrc

# 秘匿情報
GITHUB_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# 秘匿情報以外の記述
alias his=&quot;cat $HISTFILE | grep&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このファイルを秘匿情報の含む&lt;code&gt;~/.bashrc.local&lt;/code&gt;と秘匿情報の含まない&lt;code&gt;~/.bashrc&lt;/code&gt;に分割します。
さらに、秘匿情報の含まない&lt;code&gt;~/.bashrc&lt;/code&gt;は、秘匿情報の含む&lt;code&gt;~/.bashrc.local&lt;/code&gt;を内部で読み込むようにします。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;# ~/.bashrc-private

# 秘匿情報
GITHUB_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;# ~/.bashrc

# 秘匿情報を読み込む
source ~/.bashrc.local

# 秘匿情報以外の記述
alias his=&quot;cat $HISTFILE | grep&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;source&lt;/code&gt;はBashの組み込みコマンドのひとつで、指定したファイルを読み込みカレントシェルで実行します。
この例で言えば、&lt;code&gt;source&lt;/code&gt;コマンドが書かれている部分に&lt;code&gt;~/.bashrc.local&lt;/code&gt;の内容が書かれているのと同じ動きになります。&lt;/p&gt;
&lt;p&gt;こうすることで、&lt;code&gt;~/.bashrc&lt;/code&gt;はGitリポジトリに含めて公開しても問題ない状態になりました。
&lt;code&gt;source ~/.bashrc.local&lt;/code&gt; という記述から何らかの情報を読み込んでいることはわかりますが、その中身が何であるかは&lt;code&gt;.bashrc&lt;/code&gt;を読んでもわかりません。&lt;/p&gt;
&lt;p&gt;この記事に従って秘匿情報を分割した場合、以降&lt;code&gt;~/.bashrc.local&lt;/code&gt; は公開せずに手元の環境に留めておくようにしてください。&lt;/p&gt;
&lt;p&gt;なお、今回のような&lt;code&gt;.bashrc&lt;/code&gt;の分割は秘匿情報に限らず他のことにも応用できます。
特定のOSのみ指定したファイルを読み込むようなif文を記載すれば、設定をOSによって切り替えることも可能です。&lt;/p&gt;</description>
    </item>
    <item>
      <title>神奈川県民から埼玉県人へ</title>
      <link>https://memo.yammer.jp/posts/moving-to-saitama</link>
      <pubDate>Thu, 31 Mar 2022 14:13:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/moving-to-saitama</guid>
      <description>&lt;p&gt;2年ほど実家に戻っていましたが改めて引っ越し、神奈川県民から埼玉県人になりました。
ちなみに神奈川では県&quot;民&quot;と言うけれど埼玉では県&quot;人&quot;と言う気がします。なんででしょうね？&lt;/p&gt;
&lt;p&gt;会社への通勤時間はおよそ1時間といったところで、引越し前と比べたらだいぶ近くなったので時々通うのにちょうどよい距離かなと思っています。&lt;/p&gt;
&lt;h2&gt;🎉&lt;/h2&gt;
&lt;p&gt;単なる引っ越しにお祝いを頂いてしまいました。ありがとうございました🙏この場を借りて感謝をお伝えします。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/move-to-saitama-2022-wishlist-presents.jpg&quot; alt=&quot;いただいた引越し祝い&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;タオル。タオル研究所というところのものらしく同期の欲しい物リストで見つけて気になっていたもの。結構ふわふわで良さげです。最近はバスタオルをやめて家のタオルをすべてフェイスタオルに統一してます。&lt;/li&gt;
&lt;li&gt;キッチンハイター。強い。&lt;/li&gt;
&lt;li&gt;カントリーマアム。考え事をすると糖分が欲しくなります。一袋開けると一気に食べてしまいます。&lt;/li&gt;
&lt;li&gt;洗濯用ハンガー、ちょこちょこ乾燥機NGな服があって重宝します。&lt;/li&gt;
&lt;li&gt;延長コード。机からコンセントが離れているので、Macbookや液晶など諸々を繋ぐのに使います。5mあるので安心😆&lt;/li&gt;
&lt;li&gt;デスク下マット。フローリングの上に椅子のキャスターが当たらないようになります。マットが広くて悠々と椅子を動かせるようになりました。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/move-to-saitama-2022-tsudanuma.jpg&quot; alt=&quot;デスク用フロアマット&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; margin-top: 0;&quot;&gt;
&lt;p&gt;これは埼玉に突如出現した津田沼&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;荷物を運ぶ&lt;/h2&gt;
&lt;p&gt;荷物の移動はクロネコヤマトの単身パックを利用しました。
冷蔵庫電子レンジと身の回りのものを積み込んで3万円弱だったと記憶しています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/move-to-saitama-2022-before.jpg&quot; alt=&quot;引越し荷物突き込み前&quot;&gt;&lt;/p&gt;
&lt;p&gt;上の写真の荷物を積み込んでもらって、残ったのは積みきれなかったダンボール2つ。
これとリモートワークで直前まで使うオフィスチェアとモニタとを宅急便で別送しました。(4つで7000円弱)
実家から出るので荷物が少なめで、単身パック+宅急便はわりとよい選択だったと思います。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/move-to-saitama-2022-after.jpg&quot; alt=&quot;引越し荷物突き込み後&quot;&gt;&lt;/p&gt;
&lt;p&gt;机、ベッド、洗濯機などは引越し先で購入しました。
いろいろお金がかかるので金銭感覚が若干おかしくなります。&lt;/p&gt;
&lt;h2&gt;住民票と書類手続&lt;/h2&gt;
&lt;p&gt;一般に住民票を移すのには旧自治体への転出届と新自治体への転入届が必要です。
しかしながら私の住んでいた旧自治体には「マイナンバーカードまたは住民基本台帳カードによる転出の特例」という制度があり、マイナンバーカードを使ってWebから転出届が出せました。
平日に役所に行く手間が省けて大変助かりました。&lt;/p&gt;
&lt;p&gt;引っ越したあと新自治体の市役所への転入届と警察署への免許証住所変更に行きましたが、これらはフレックスタイム制を活用して出勤前にサクッと手続きできて社の制度に感謝でした。
こういうたぐいのものは書類を書いて窓口に向かうので、開店時間のちょい前くらいに行くのがちょうどよいかもしれません。(開店時間に行ったら先客がいました)&lt;/p&gt;
&lt;h2&gt;ドラム式洗濯機&lt;/h2&gt;
&lt;p&gt;引っ越しに合わせてドラム式洗濯機を買いました。
洗濯機は社会人になったらドラム式を買おうと決めていて、20万円ほど払ってPanasonicの洗濯機 (&lt;a href=&quot;https://panasonic.jp/wash/products/na_lx113a.html&quot;&gt;NA-LX113AL&lt;/a&gt;) を購入しました。たかい。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
ヒートポンプ式とヒーター式
&lt;/summary&gt;
&lt;p&gt;洗濯機は買うにあたって事前にちょこちょこ調べていました。&lt;/p&gt;
&lt;p&gt;ドラム式洗濯機にはヒートポンプ式とヒーター式という2種類があるそうです。&lt;/p&gt;
&lt;p&gt;ヒートポンプ式は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本体代が高め&lt;/li&gt;
&lt;li&gt;電気代は安め&lt;/li&gt;
&lt;li&gt;エアコンで使われるようなヒートポンプが洗濯機内に入っていて、衣類に当てた風を冷やして乾燥させ、暖かくして再度衣類に吹き付けるらしい&lt;/li&gt;
&lt;li&gt;衣類が傷みにくい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ヒーター式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本体が安め&lt;/li&gt;
&lt;li&gt;電気代は高め&lt;/li&gt;
&lt;li&gt;ドライヤーを当てるように、衣類に直接熱風を当てるのでしっかり乾く&lt;/li&gt;
&lt;li&gt;衣類が痛みやすい&lt;/li&gt;
&lt;li&gt;湿気を含んだ空気が排出されて室内に充満しやすい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という特徴があるそうです。どうせならということでちょっと高いですがヒートポンプ式を選びました&lt;/p&gt;
&lt;p&gt;洗剤の自動投入機能がつくと一気に値段が跳ね上がるらしく、そういうのがついていない洗濯と乾燥だけのベーシックなモデルで乾燥容量の多いものを選びました。&lt;/p&gt;
&lt;p&gt;調べていると季節によって大きく値段が変わるらしく、もし買えるなら秋頃などの新製品発売前だと安く買えるそうです。&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;ドラム式洗濯機を買ってから、家の中の乾燥不可の布を見るたびに悔しい気持ちが芽生えるようになりました。
もっとも、私の買った洗濯機は音も静かで洗濯乾燥容量も大きく、乾燥後の触り心地もよいので大満足です。&lt;/p&gt;
&lt;h2&gt;インターネット&lt;/h2&gt;
&lt;p&gt;リモートワークで働いている私にとって、インターネット回線の品質は死活問題です。
話すと長くなりそうでここでは割愛しますが、現在はケーブルテレビの回線と楽天のLTE回線を使っており、後日フレッツ光も利用できるようになる予定です。まあまあ調べた &lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; のでどこかにまとめておきたい気持ち。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;そんなこんなで引越しから1ヶ月近く経った今でもダンボールをテレビ台代わりにしていたりするものの、ぼちぼち新生活が始まりました。
家の周りにまだ慣れていなくて駅との往復くらいしかしてないですが、散歩したりして愛着が湧いた土地になるとよいなと思います。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;机下用のマットを欲しいものリストに設定していたら「マットの上は津田沼だと思って生活してください」と託されました。最近は心のなかで机の周りのことをひそかに津田沼と呼んでいます。埼玉にも海ができたといえるでしょう。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;引っ越しの見積もりをWebで申し込んだら大量に電話がかかってきて疲弊しました。疲弊して嫌になったので金額がわかりやすい単身パックにしたという節もあります。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;IPv4 PPPoEとIPv4 over IPv6 を同時に接続して、外部からDMZへの通信はPPPoEで、内部から外部への接続はIPv4 over IPv6でやれるような構成しようと目論んでいます。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Web Components (ShadowDOM) でもページ内リンクをしたい</title>
      <link>https://memo.yammer.jp/posts/shadow-dom-internal-link</link>
      <pubDate>Thu, 31 Mar 2022 04:01:55 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/shadow-dom-internal-link</guid>
      <description>&lt;p&gt;HTMLではページ内リンクができる。
id属性ないしname属性で指定した文字列を &lt;code&gt;#&lt;/code&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; の後ろにつけてリンク先のパスとして指定すると、当該の要素が画面上部に来るようにスクロールする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&amp;#x3C;p id=&quot;content&quot;&gt;
  hello!
&amp;#x3C;/p&gt;

&amp;#x3C;p style=&quot;height: 2000px; background-color: red;&quot;&gt;
  blank
&amp;#x3C;/p&gt;

&amp;#x3C;a href=&quot;#content&quot;&gt;
  「hello!」へ飛ぶ
&amp;#x3C;/a&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このページ内リンクをShadowDOM内の要素からShadowDOM内にむけて行いたいとき、そのままではできない。
同じような動きを実現する方法として、クリックイベントをもとにShadowDOMの中の要素を探してJavaScriptによってスクロールする動作を実装してみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const eventListener = (event: Event) =&gt; {
  const element = event.target as HTMLElement
  if (element.tagName !== &apos;A&apos;) {
    return true
  }
  const href = element.getAttribute(&apos;href&apos;) ?? &apos;&apos;
  if (!/^#/.test(href)) {
    return true
  }
  const anchorName = href.substring(1)
  const theNameElements = shadowRoot.querySelectorAll(`[name=${anchorName}], #${anchorName}`)
  if (theNameElements.length &gt; 0) {
    theNameElements[0].scrollIntoView()
    event.preventDefault()
    return false
  }
  return true
}
shadowRoot.addEventListener(&apos;click&apos;, eventListener)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このブログの記事の本文はいま本文用のCSSのスコープを狭める実装の一つとしてShadowDOMに包むようにしていて、上記のようなコードを書くことでページ内リンクのスクロールを実現している。
単純な実装なので何か考慮できていない場合をみつけたら教えていただけると嬉しい。&lt;/p&gt;
&lt;p&gt;実装: &lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/7bed6bc062217d7c7d16ab0a39821987e3dd3f45/src/components/article.tsx#L8-35&quot;&gt;https://github.com/yammerjp/memo.yammer.jp/blob/7bed6bc062217d7c7d16ab0a39821987e3dd3f45/src/components/article.tsx#L8-35&lt;/a&gt;&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;ちなみにこの &lt;code&gt;#&lt;/code&gt; を使ったページ内の特定の要素を表す機能は&lt;a href=&quot;https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid&quot;&gt;HTMLの仕様書&lt;/a&gt;内ではフラグメントと呼ばれているらしい。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>リバースSSHトンネルでVPSを介していつでも自宅のPCに繋ぐ</title>
      <link>https://memo.yammer.jp/posts/ssh-to-home</link>
      <pubDate>Thu, 24 Feb 2022 13:15:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/ssh-to-home</guid>
      <description>&lt;p&gt;外出先で手元のラップトップ (MacBook Air) からポートを公開していない自宅のサーバ&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (Ubuntu) へsshしたいときの記録。
数ヶ月くらい前から安価なVPSを借りて、そこを中継地点として外出先からいつでも自宅のサーバにsshできるようにしている。&lt;/p&gt;
&lt;h3&gt;ひとまず繋ぐ&lt;/h3&gt;
&lt;p&gt;以下の接続ができるようにしておく。&lt;/p&gt;
&lt;p&gt;ラップトップの公開鍵を自宅サーバとVPSに、自宅サーバの公開鍵をVPSに登録 (&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; に追記) して、sshできることを確認する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自宅のラップトップ -&gt; 自宅のサーバ&lt;/li&gt;
&lt;li&gt;自宅のラップトップ -&gt; VPS&lt;/li&gt;
&lt;li&gt;自宅のサーバ -&gt; VPS&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt; on ラップトップ&lt;/h4&gt;
&lt;p&gt;中継するVPSとその先の自宅サーバへの接続情報を書いておく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.ssh/config
Host home-server
  HostName 192.168.2.3
  IdentityFile ~/.ssh/id_rsa
  User home-username
Host bastion-vps
  HostName bastion-vps.example.com
  IdentityFile ~/.ssh/id_rsa
  User vps-username
Host home-server-remote
  Hostname localhost
  User home-username
  IdentityFile ~/.ssh/id_rsa
  ProxyJump bastion-vps
  Port 2222
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt; on 自宅サーバ&lt;/h4&gt;
&lt;p&gt;中継するVPSへの接続情報を書いておく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.ssh/config
Host bastion-vps
  HostName bastion-vps.example.com
  IdentityFile ~/.ssh/id_rsa
  User ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;繋いでみる&lt;/h4&gt;
&lt;p&gt;自宅サーバからVPSへsshして、VPSの空きポートから自宅サーバのsshポートへリバーストンネルを張る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# user@home-server
$ ssh -fN -R 2222:localhost:22 bastion-vps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この状態で、自宅サーバと異なるネットワークに所属するラップトップからsshをする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# VPSの22番ポート、2222番ポートを伝って自宅サーバへsshする
$ ssh home-server-remote
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多段sshの際にラップトップの秘密鍵を使う利点は、自宅サーバに入るための鍵をVPSが保持していないこと。
仮にVPSにログインして自宅サーバのSSHポートにパケットを送れる状態になったとしても、自宅サーバへsshできる秘密鍵を持たなければ自宅サーバは乗っ取れない。&lt;/p&gt;
&lt;h3&gt;サービスとして登録する&lt;/h3&gt;
&lt;p&gt;自宅サーバのsystemdに登録して、常にリバーストンネルが貼られている状態を維持する。&lt;/p&gt;
&lt;p&gt;まず、ファイル &lt;code&gt;/lib/systemd/system/bastion-tunnel.service&lt;/code&gt; に以下を記述する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Create SSH reverse tunnel (reverse port forwarding) from bastion-vps.example.com
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/ssh -f -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -i /path/to/id_rsa -R 2222:localhost:22 vps-username@bastion-vps.example.com
RestartSec=3
Restart=always
StartLimitBurst=0

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作成したServiceを有効化する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo systemctl daemon-reload
$ sudo systemctl enable bastion-tunnel.service
$ sudo systemctl status bastion-tunnel.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常にリバーストンネルが貼られていることをsshして確認してみる。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;以上の手順を踏むと、自宅のIPがわからなくても、ポートを公開していなくても、いつでもVPSを経由してsshできる。
自宅サーバの中で作業をしておけば外に行ってもiPadから作業を続行できたりするし、外で特定のファイルが欲しくなったりx86_64のLinux環境が欲しくなったときにそこそこのスペックのものをサッと使えるのもいい。
ふとしたときに便利。&lt;/p&gt;
&lt;p&gt;今はsshのみをトンネリングしているが、他のプロトコルもポートフォワーディングして使うと便利そう。(認可周りは別途検討が必要そう)&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;サーバといってもインターネットに公開・提供しているわけではなく、適当なものをビルドしたり作業したり宅内向けのアプリケーションを一時的にホストしていたりする自分用の常時起動Linuxマシンである。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Ruby製のCLIを作ってgemにしてみる</title>
      <link>https://memo.yammer.jp/posts/file_charset_validator</link>
      <pubDate>Wed, 09 Feb 2022 13:20:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/file_charset_validator</guid>
      <description>&lt;p&gt;会社に入ってからRubyを触る機会がちょこちょこあるが、Rubyのことをあんまりわかっていないという感覚があるので機会をみつけてRubyで何かをつくるというのをやっていきたい。
今日はその中でファイルの文字コードを確認する処理をCLIとして実装してみた話。&lt;/p&gt;
&lt;h2&gt;作ったもの&lt;/h2&gt;
&lt;p&gt;実装するものは比較的シンプルで、渡されたファイルが指定された文字コードで解釈できるか否かを判定する。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
Rubyのワンライナーで書くこともできる規模感のものだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ find path/to/dir -type f | ruby -e &apos;STDIN.reject{|path| IO.binread(path.chomp).force_encoding(Encoding::UTF_8).valid_encoding?}.each{|f| puts f}.empty? or (puts &quot;... There are invalid encoding files&quot;;exit 1)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手元のファイルを確認するだけならワンライナーでいいが、一応テストを書いて動作が明らかであることを示したり、なによりRubyのライブラリってこんな感じで作るんやでというのを知っておくためにCLIとして実装してgemにしてみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://rubygems.org/gems/file_charset_validator&quot;&gt;https://rubygems.org/gems/file_charset_validator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;さっきのワンライナーと同じことを以下で行える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ gem install file_charset_validator
$ find path/to/dir -type f | file_charset_validator --encoding UTF_8
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CLIを作ってgemにする手順&lt;/h2&gt;
&lt;p&gt;新しくRubyでCLIを作るのは雛形が用意されていて、以下のコマンドを実行するとディレクトリごと作ってくれる&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ bundle gem your_gem_name -t -b
# -t ... テストも生成
# -b ... 実行ファイルも生成
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作ったgemのビルドやローカルへのインストール、公開などもrakeタスクが用意されているのでシュッとできる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# gemをビルドする (gemはhogehoge.gemという単一のファイルにまとめられるらしい)
$ bundle exec rake build

# テストを実行する
$ bundle exec rake test

# ローカルにgemをインストールする
$ bundle exec rake install

# gitのリリースタグを打って、gemを公開する
# 事前に https://rubygems.org でアカウントを作り、`$ curl -u YOUR_USERNAME https://rubygems.org/api/v1/api_key.yaml &gt; ~/.gem/credentials` などとしておくとRubyGemsに公開できる。
$ bundle exec rake release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンドライン引数やヘルプコマンドの出力などはthorに任せてしまうと楽。
作った雛形の your_gem_name.gemspec に &lt;code&gt;spec.add_dependency &quot;thor&quot;&lt;/code&gt; などと書いて bundle install して、Thorクラスを継承したクラスを実装し、.start を呼べばいい。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;お作法がわかっていないので作りたいものを作る時間よりもお作法を学ぶ時間がほとんど出会ったが、目的はそれなのでよかった。
RubyGems、(npmに比べて) パッケージの名前空間が比較的空いている気がして、不用意に変な名前を占有してはいけないなという気持ちになった。&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;文字コードの判定は例えば &lt;code&gt;$nkf --guess&lt;/code&gt; コマンド等でも行えるが、誤検知を避けて「ある文字コードとして解釈できるかを検証する」という目的を果たすツールは見つけられなかったので作った。いろいろなところで必要そうなので見つけられていないだけで多分どこかにあるでしょう。知っている方は教えてください。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>graspad - iPad用の握れるキーボード</title>
      <link>https://memo.yammer.jp/posts/graspad</link>
      <pubDate>Wed, 26 Jan 2022 14:41:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/graspad</guid>
      <description>&lt;p&gt;昨年秋&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;に3Dプリンタを買って作りたかったのがiPad用のキーボード。
iPadケースの背面にキーボードがくっついていて、iPadを横から握ったまま物理キーボードを打てる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-grasped.jpg&quot; alt=&quot;graspadを手で握って保持しているとき&quot;&gt;&lt;/p&gt;
&lt;p&gt;左右の2パーツから成っていて、iPadの左右から差し込み、2つをつなぐ配線とiPadのType-Cをつなぐことで使える。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-with-cables.jpg&quot; alt=&quot;graspadの内側に配線がある様子&quot;&gt;&lt;/p&gt;
&lt;p&gt;キー数は42キーで、3x6のキーが背面の左右に、親指で押す用の側面のキーが3つずつ左右にある。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-overlooking.jpg&quot; alt=&quot;graspadを上から俯瞰したとき&quot;&gt;&lt;/p&gt;
&lt;p&gt;本記事では、この少し変わったキーボードの製作過程を記す。&lt;/p&gt;
&lt;h2&gt;設計&lt;/h2&gt;
&lt;h3&gt;着想&lt;/h3&gt;
&lt;p&gt;iPadに物理キーボードを使いたいと思っていたのだが、普通のキーボードを繋ぐだけでは安定した机の上でしか使えないし、それならMacbookで代用できてしまう。
電車の中やベッドやソファでゴロゴロしながら物理キーボードが使えたらいいなと思って、iPadを横持ちで握ったままキー入力が出来ることを目指して作った。&lt;/p&gt;
&lt;p&gt;制作に当たって以下のような製品を参考にした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nintendo Switch&lt;/li&gt;
&lt;li&gt;VAIO Type U&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://internetcom.jp/201361/t-blade-back-typing-keyboard-for-ipad?utm_source=pocket_mylist&quot;&gt;T-BLADE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://m.youtube.com/watch?v=8H_bXomQsm4&amp;#x26;utm_source=pocket_mylist&quot;&gt;Yogitype&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.mynavi.jp/article/20210107-1625679/?utm_source=pocket_mylist&quot;&gt;LAVIE MINI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最初は思いつきだったが、3Dプリンタが案外やすく買えることに気づいてしまってからは割と勢いで完成までこぎつけた。&lt;/p&gt;
&lt;h3&gt;キー配列&lt;/h3&gt;
&lt;p&gt;キー数を42キーにするのは結構初期の段階で決めていた。
普段使っている配列と同程度で、今の私の中で実用に耐えうる最低限のキー数である。
これより少ないのは未知の領域。&lt;/p&gt;
&lt;p&gt;キー数をもとに、iPadのケースにキーボードが付いていたらという体で考えてみる。
適当な図を書きながらこんな感じでは？と構想をふくらませたのが以下のスケッチ。
この時点で概ねの形は決まっていた。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-concept.png&quot; alt=&quot;graspadの構想とスケッチ&quot;&gt;&lt;/p&gt;
&lt;p&gt;寸法をみていくと、キーの数と配置からキーピッチを抑える必要があることに気づいた。
iPadの大きさは176mm x 248mm、横持ちをするとすると高さ方向に176mm以下に抑えなければならない。
176mmの方向に並べるキー数を、下から6(裏面)+3(側面)-1(裏面上段と側面下段を重ねる)とすると、キーピッチ20mmでは160mmで結構ギリギリである。iPadの側面には電源ボタン、上部にはカメラなどがあり、Apple Pencilを上部に配置することにするとこれでは高さが足りない。
挟ピッチの16mmとすると16mm x8=128mmとなってだいぶ余裕が出るのでよい。&lt;/p&gt;
&lt;h3&gt;PCB&lt;/h3&gt;
&lt;p&gt;キーボードのスイッチを固定、配線する基盤をどうするか考える。
挟ピッチで格子配列となるとmcsp lp&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;というキーボードを改造するか、専用の基板を作るか、基盤無しで3Dプリンタで作った筐体にマウントするかなどを考えてたが、途中でte96という素晴らしいキットに出会う。
te96は分割後に再構成できる自作キーボード用のPCBで、row-staggeredやcolumn-staggered、格子配列などの形に自由に組み立てられる。キーボードのピッチ幅も1方向は16mm-20mmの可変で、組み立て時に自分で決めることができる。
今回の用途にぴったりで、16mmピッチの格子配列、親指部分も切り取って別基盤として用意できるのでとても都合の良い基盤だった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-te96.jpg&quot; alt=&quot;te96の基板&quot;&gt;&lt;/p&gt;
&lt;h3&gt;ケースとキーボード筐体の一体化&lt;/h3&gt;
&lt;p&gt;当初は市販品のiPadケースに3Dプリンタで作った筐体を貼り付けることを想定していたが、組み立ての手間を減らすため、ケースとキーボード筐体を一体型にしてまとめて印刷するよう針転換した。
しかしながらこれは後から思えば良くない判断だった。
筐体を構成する樹脂のPLAは硬くしなりづらい素材で、iPadのケースにしようとしても、少し出っ張らせてパチっとはめ込むような構造にし難い。
しならずともiPadにつけられるよう、左右から差し込む構造とすることが決定し、あわせて左右をまたぐ配線をコネクタで繋ぐ必要が出てきてしまった。
さらにコネクタを経由する配線を減らそうとして、Pro Micro(と互換機)を計2台使うことにもなった。&lt;/p&gt;
&lt;h3&gt;iPadの大きさとiPadケースのモデリング&lt;/h3&gt;
&lt;p&gt;今回の題材であるiPad Air 4をはじめとするApple製品は、公式にその寸法を示したガイドラインが公開されている。
(&lt;a href=&quot;https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf&quot;&gt;Accessory Design Guideline for Applie Devices&lt;/a&gt;)
これをもとに、0.1mm程度の精度で設計、印刷した。
ケースの大きさはガイドラインに示されているiPadの寸法よりも余裕を見て少し大きくする必要があり、これは試作を繰り返して決定した。試作には上部ないし下部のみで30時間くらい印刷にかかるので結構面倒な作業であった。&lt;/p&gt;
&lt;h2&gt;組み立て&lt;/h2&gt;
&lt;h3&gt;使用部品&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;部品&lt;/th&gt;
&lt;th&gt;点数&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;フィラメント PLA 黒 1.75mm 1kg&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;試作一回 (筐体半分) につき300gくらい使用した&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;te96&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Kailh Choc 赤軸&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;なるべく薄くするためにKailh Chocを選んだ。赤軸のキースイッチが手元に丁度2個余っていたので40個買ってピッタリ使った。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;mcsp lp向け挟ピッチキーキャップ&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Kailh Choc用の16mmピッチで使えるキーキャップは他に選択肢がなかった。DMM.makeで3Dプリンタによって印刷されたものが届いた。相当力を入れないとキースイッチに刺さらないので、同じものを購入される方は注意されたい。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;ジャンパケーブル&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;左右の筐体間をつなぐコネクタとして使っている&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;はんだ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0.3mmなどの細いものを用意しておくとやりやすい&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;導線&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;PCB間 (親指部分との配線)や、PCB内でも各columnとPro Micro間を導線で配線する必要がある&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;スズメッキ線&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;te96のrow同士の配線に使った&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Pro Micro、Elite-C&lt;/td&gt;
&lt;td&gt;1ずつ&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;左右の筐体に一つずつ使うが、iPadとの接続はUSB Type-Cで行うので、下の Type-C to Type-C ケーブルが使えるように片方はPro Micro互換のElite-Cを使うこととした&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;UGREEN USB Type-Cケーブル&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;片方がL字になっていて、長さが50cmで長すぎないType-C to Type-Cのケーブル。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;組み上げ&lt;/h3&gt;
&lt;p&gt;筐体を印刷し、次にキーボードを組み立て、最後にそれらをはめこんでから一部配線をしてキーマップを書き込む、という手順で行った。&lt;/p&gt;
&lt;p&gt;キーボードは&lt;a href=&quot;https://github.com/e3w2q/te96-keyboard/blob/master/doc/custom_layout/readme_jp.md&quot;&gt;マニュアル&lt;/a&gt;にあるような感じで組み立てていく。キーピッチは16mmになるように、最狭間隔で固定する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-te96-devided.jpg&quot; alt=&quot;te96のPCBを切断して分割した状態&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-te96-join.jpg&quot; alt=&quot;te96の基盤を連結した状態&quot;&gt;&lt;/p&gt;
&lt;p&gt;ピンヘッダを差し込んで基盤を接合するときは、裏にマスキングテープを貼って出っ張らないようにするといい。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-te96-with-masking-tape.jpg&quot; alt=&quot;te96で基盤連結用のピンヘッダをはんだづけするときは、裏側をマスキングテープで止めておくとピンの長さをぴったりにできる&quot;&gt;&lt;/p&gt;
&lt;p&gt;基盤同士が接合できてテスターで導通を確認したら、ダイオードとキースイッチ、PCB内の配線、Pro MicroとElite-C、PCB間の配線をはんだ付けしていく。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-te96-with-promicro.jpg&quot; alt=&quot;te96にProMicroを組付けた状態&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-assemble-keyswitch.jpg&quot; alt=&quot;キースイッチを組み付けた状態&quot;&gt;&lt;/p&gt;
&lt;p&gt;キーキャップをはめてキーマップを書き込み動作確認する&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-assemble-only-keyboard.jpg&quot; alt=&quot;キーボードの配線を済ませて動作確認する状態&quot;&gt;&lt;/p&gt;
&lt;p&gt;最後に筐体に組み付けて完成。&lt;/p&gt;
&lt;p&gt;PCBの筐体への固定は、PCBにある2.15mmの穴に筐体の突起を差し込む方式とした。これは試作を繰り返す中で思いついた。
また、複数の基板を接合する際に間隔が開いて寸法がずれて差し込めなくなるのを防ぐために、筐体の一部を切り取ったような治具を印刷し、この上で組立を行っていた。&lt;/p&gt;
&lt;p&gt;親指のキー部分は、キーボードを差し込むための筐体側の突起のある台座を別部品として印刷して、筐体本体に差し込むこととした。印刷方向の兼ね合いで、突起を水平方向に空中に印刷するのが難しいためである。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-printed.jpg&quot; alt=&quot;3Dプリンタで印刷した筐体&quot;&gt;&lt;/p&gt;
&lt;p&gt;ちなみに各パーツの固定が甘かったので瞬間接着剤を流したら分解できなくなった。接触不良などが発生しても直せなくて困る。悲しい。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/graspad-assembe-to-prototype.jpg&quot; alt=&quot;連結前のPCBを試作した筐体に組み付けてみる&quot;&gt;&lt;/p&gt;
&lt;h3&gt;キーマップの書き込み&lt;/h3&gt;
&lt;p&gt;こちらも&lt;a href=&quot;https://github.com/e3w2q/te96-keyboard/blob/master/doc/custom_layout/readme_jp.md#%E3%83%95%E3%82%A1%E3%83%BC%E3%83%A0%E3%82%A6%E3%82%A7%E3%82%A2&quot;&gt;マニュアル&lt;/a&gt;を参考にセットアップした。&lt;/p&gt;
&lt;p&gt;途中から、ProMicroだけでなくElite-Cにも書き込む必要が出てきたので、以下のようなコマンドで書き込みを行なった。
ProMicroに書き込む際は、リセットボタンの代わりに RSTとGNDをショートさせていたが、Elite-Cは何もしなくても勝手に書き込みが始まった。(と思う)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/qmk_firmware/commit/ce2a69222718b825d787d52fd7ad7476862ec417&quot;&gt;https://github.com/yammerjp/qmk_firmware/commit/ce2a69222718b825d787d52fd7ad7476862ec417&lt;/a&gt; に私のキーマップを置いている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Pro Micro
$ sudo make e3w2q/te96:test:avrdude
$ sudo make e3w2q/te96/rev1:yammerjp:avrdude
# Elite-C
$ sudo make e3w2q/te96:test:dfu
$ sudo make e3w2q/te96/rev1:yammerjp:dfu
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;(次回作があったら)改善したい点&lt;/h2&gt;
&lt;h3&gt;te96組立時にショートさせない&lt;/h3&gt;
&lt;p&gt;te96の基盤を切り刻んで、ピンヘッダと接合部品を用いて繋げるのだが、そのときに意図しないショートに注意。特に16mmピッチにする場合は、外側に17-19mmピッチ用の穴があり、誤ってこれが基盤の近くにあるCherry MXの穴とぶつかるとrowとcolumnが導通してしまいキーボードとして機能しなくなる。 (やってしまってむりやり分解した。)&lt;/p&gt;
&lt;p&gt;Cherry MXの穴は接合する基盤の片側にしかないので、ショートしないように接合部品を配置すべきだった。&lt;/p&gt;
&lt;h3&gt;分解可能性を高める&lt;/h3&gt;
&lt;p&gt;試作を繰り返す中で加えた修正に、キーボードの固定方法がある。
te96には直径2.15mmの穴が複数箇所に開いており、この大きさに合わせた特記を筐体に用意して差し込むことで固定することとしようとした。
はめ込むだけで済むようにしたかったが、実際にはゆるゆるだったので瞬間接着剤で固定した。これにより分解がしづらい状況となってしまったので、瞬間接着剤ではなくネジで固定できる構造とすると問題が起きても修理しやすくなっただろう。&lt;/p&gt;
&lt;h3&gt;左右の筐体を接合するコネクタの改善/廃止&lt;/h3&gt;
&lt;p&gt;キーボードをiPadに装着する際、2つの筐体をはめこんでコネクタを繋ぐ必要がある。ここに2.54mmのピンヘッダ用のコネクタを使ってしまっているので、極性に気をつける必要があるし気軽につけ外しできない。マグネットでくっついたり無線で通信したり、そもそも筐体が2分割されていないと嬉しい。&lt;/p&gt;
&lt;h3&gt;キーボードを背面ではなく側面に配置する&lt;/h3&gt;
&lt;p&gt;作ってみてわかったのだが、タイピングできる速度はびっくりするくらい遅い。
慣れの問題だろうと思っていたがそれだけではなく、構造に問題がありそうである。&lt;/p&gt;
&lt;p&gt;iPadの背面にキーボードがあると、筐体の重さを手で支えているおかげか手の平を胸方向に向けるからか手に遊びがなく、キーが押しづらいと感じる。
手の筋肉の弛緩を見誤ったのがまずかった。&lt;/p&gt;
&lt;p&gt;これを解決する方法として、iPadの側面にキーボードを配置して&quot;前ならえ&quot;したような体勢で打てるようにしたい。&lt;/p&gt;
&lt;h3&gt;CherryMX互換キーキャップ&lt;/h3&gt;
&lt;p&gt;キーストロークが深い方が気持ちいいのでは。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;動作するところまでは持っていけた。
3Dプリンタの精度が案外高くて、筐体もそれなりの形で作れたように思う。
椅子の上で使ったりベッドの上で寝転がって使ったりすることもできる。
(タイピング速度は遅いが...笑)&lt;/p&gt;
&lt;p&gt;ちなみに何回か試行錯誤したのでこれくらい失敗した筐体がある。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.basd4g.net/graspad-prototypes.jpg&quot; alt=&quot;失敗した筐体群&quot;&gt;&lt;/p&gt;
&lt;p&gt;以上、というわけで次回作にご期待ください。なおいつ作られるのかは未定です。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;/posts/anycubic-mega-s&quot;&gt;前回の記事&lt;/a&gt;も含めて10月ごろに書いた文章が眠っていたので引っ張り出してきた。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://booth.pm/ja/items/2668919&quot;&gt;mcsp lp&lt;/a&gt; というキーボード、今回の製作に関係なく結構気になっています。欲しい。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>2021年に3Dプリンタに入門した - Anycubic Mega S</title>
      <link>https://memo.yammer.jp/posts/anycubic-mega-s</link>
      <pubDate>Wed, 26 Jan 2022 14:40:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/anycubic-mega-s</guid>
      <description>&lt;p&gt;昨年の秋に3Dプリンタを買ったので、その経緯と3Dプリンタに入門して学んだことを記します。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;サンプルを印刷してみる &lt;a href=&quot;https://t.co/hdrNYcBRn7&quot;&gt;pic.twitter.com/hdrNYcBRn7&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1439779993307942916?ref_src=twsrc%5Etfw&quot;&gt;September 20, 2021&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;作りたいものがあって、3Dプリンタの印刷サービスを検討していたが高すぎたのが事の発端です。
作りたいものの寸法が大きかったため依頼すると2万円くらいするとわかり、更に安価な3Dプリンタ本体が2-3万円くらいで入手できることがわかり、これは試してみてもいいのではという気持ちになりました。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;3Dプリンタを選ぶ&lt;/h2&gt;
&lt;p&gt;家庭用3Dプリンタには光造形方式と熱積層方式があり、今回は熱積層方式のものを購入しました。前者は印刷可能サイズが小さいが精巧で模型などに向き、前者は印刷可能サイズが大きいが精巧さに劣るのでDIYなどに向くという違いがあります。
精巧さで劣ると言っても結構いい感じに作れます。(後述の写真を参考に)&lt;/p&gt;
&lt;p&gt;熱積層方式のプリンタの中でも安価な家庭モデルでメジャーなものとして、Ender 3 Pro、Anycubic MEGA S、Flashforge 3、といった機種が挙げられます。このなかでも前者のほうが安価、印刷可能サイズが大きい、カスタマイズ幅&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;が広い、組み立てが大変、といった特徴があるようです。&lt;/p&gt;
&lt;p&gt;印刷したいもののサイズと価格面からFlashForge &lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;が消え、組み立て部位が多いと精度が担保しづらいのではないかという不安からEnder 3 Proを避けることとし、Anycubic Mega S を選びました。
昨年と比較してセール含め1.5万円くらい値段が下がっているらしいことも、この選択を後押ししました。&lt;/p&gt;
&lt;p&gt;Anycubic Mega S の積層可能範囲は 210mm x 210mm x 205mm で、そこそこ大きいと思います。
大きいものを印刷すると結構時間がかかるので、この範囲に収まらないものは組み立て式にしたり3Dプリンタの印刷物は一部の部分のみに使うなど、工夫してものをつくるとよさそうです。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/anycubic-mega-s.jpg&quot; alt=&quot;Anycubic Mega S&quot;&gt;&lt;/p&gt;
&lt;h2&gt;フィラメント&lt;/h2&gt;
&lt;p&gt;熱積層型の3Dプリンタでは、樹脂を熱で溶かしながら射出して印刷します。その樹脂がフィラメントです。&lt;/p&gt;
&lt;p&gt;フィラメントを選ぶ上での軸はいくつかあるようですが、最初でよくわからないのと失敗したくないのでなるべくメジャーっぽいもの、PLAの太さ1.75mmで黒1kg、安すぎず品質管理されてそうなものを選びました。
(特に問題なく印刷できたので、使い切った後も同じものを買い足しました。 &lt;a href=&quot;https://www.amazon.co.jp/gp/product/B084S9NP2T/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;#x26;psc=1&quot;&gt;https://www.amazon.co.jp/gp/product/B084S9NP2T/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;#x26;psc=1&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;フィラメントは材質がいくつか選べるようですが、PLAやPLA+が簡単に印刷できます。この材質は硬く印刷後の整形に向きません。
強度の高く加工しやすいABSなどを選ぶ手もありますが、こちらは熱変化による収縮が大きく、印刷が失敗する可能性が上がるので最初は選ばないほうがよいようです。
フィラメントの量は 1kgや3kgが一般的なようです。3Dプリンタによってはあまり大きすぎるリールはフィラメント台に置けない可能性があるので、自分の3Dプリンタの機種で問題ないかを確認しておくとよいでしょう。
フィラメントは品質もある程度気にする必要があるらしく、あまりに安くて質の悪いものだと、フィラメントの太さが均一でなく、ノズルに詰まって印刷に失敗したり印刷が汚くなることがあるらしいです。&lt;/p&gt;
&lt;p&gt;慣れてきたらここら辺を変えてコストを抑えたり印刷物の特徴に合わせた材質にしたりということができるようです。&lt;/p&gt;
&lt;p&gt;ネット上では一部Anycubic Mega Sにはフィラメントが1kg付属すると書いてあるレビューもありましたが、私の場合は数十gのおまけだけで付属しませんでした。
同じ機種を買われる方は特に、最初からフィラメントも同時購入するとよさそうです。&lt;/p&gt;
&lt;h2&gt;組み立て&lt;/h2&gt;
&lt;p&gt;Anycubic Mega Sはゆっくりやっても数十分で組み立てることができます。
台座に印刷ヘッドを含む上部を差し込んで数カ所ネジ止めし、フィラメント台もネジ止めします。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/anycubic-mega-s-boxed.jpg&quot; alt=&quot;Anycubic Mega Sが届いた時の様子&quot;&gt;
&lt;img src=&quot;https://blob.yammer.jp/anycubic-mega-s-before-assembling.jpg&quot; alt=&quot;Anycubic Mega Sは下部と上部を組み立てるだけ&quot;&gt;&lt;/p&gt;
&lt;h2&gt;印刷台の調整&lt;/h2&gt;
&lt;p&gt;熱積層式の3Dプリンタは、印刷前に印刷台とヘッドの間の間隔が一定になるよう、印刷台を調整する必要があります。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ヘッドと印刷台を傷つけないようにA4のコピー用紙を印刷台に置く&lt;/li&gt;
&lt;li&gt;電源を入れる&lt;/li&gt;
&lt;li&gt;念の為モータに電流が流れていない状態にする。タッチパネルから、Setup &gt; Motor (off) &gt; Done!と出るとよい&lt;/li&gt;
&lt;li&gt;手動でヘッドと台座を動かして、調整場所まで移動する。左手前側の角に近いところで、ヘッド先が下がったときに台座の平面からはみ出ない位置の範囲で動かす。&lt;/li&gt;
&lt;li&gt;タッチパネルから、Tools &gt; Home &gt; Home Z とするとヘッドが自動で下まで下がる&lt;/li&gt;
&lt;li&gt;印刷台下の手回しネジを回して高さを調整する。コピー用紙を動かそうとすると少し抵抗があるが力を入れれば動かせるくらいが良い。どのくらいの力で動くかを手で大体覚えておく。紙の動かす方向は水平の一方向にまっすぐもありだし水平のヘッドを中心とした回転方向に引っ張ってみるのもよい&lt;/li&gt;
&lt;li&gt;左手前が調整できたら、ヘッドを手動で動かして右手前、右後ろ、左後ろも同様に調整する。終わったらまた右手前、左手前、、と納得行くまで繰り返す。（1周やって戻ってくるだけと紙がスルスル動く状態になっていたりする。)最後に印刷台中央のヘッドとの間隔が同様であることを確認する。&lt;/li&gt;
&lt;li&gt;タッチパネルから、Tools &gt; Axis &gt; 10 (+Z) を10回押すとヘッドが上がる&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ひとまず、印刷を終わるごとにやっています。
Youtuberのイチケンさんの動画ではそんなに頻繁にやらなくても良いと語られているので、それほどずれないとわかったらやらなくて良いかもしれません。&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;embed-youtube embed-wrapper&quot; style=&quot;text-align: center;&quot;&gt;&lt;iframe class=&quot;embed-youtube&quot; width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/4JEHVZTRjXY?feature=oembed&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;ちなみにこの動画、とてもよくできていて3Dプリンタを買う前にイメージを掴むのに大変役立ちました。&lt;/p&gt;
&lt;h2&gt;印刷してみる&lt;/h2&gt;
&lt;p&gt;印刷のためには以下の2つのソフトが必要になります&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3D CAD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;印刷物の3Dデータを作成するのに必要です。インターネットから印刷データをダウンロードする場合は不要です。Fusion360というソフトが非商用だと無料に使えるので、ひとまずこれを試してみるのが良いと思います。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;3D CADはあまり使ったことないのですが、基本は平面を作って引き伸ばすという方法を繰り返せばそこそこの物が作れるようです。スケッチを選んで、面を選んで、面上に図を書いて、引き伸ばす。これをこれをくり返せば結構いろいろな図形を作ることができます。
あわせてフィレット （角を削って曲面にする) と回転引き伸ばしを組み合わせて、直線方向以外の整形も行えますが、これらの処理には注意が必要です。
私が3Dプリンタを使うとき、印刷物して実物を見てからモデルを調整するということが何度も発生しておりこういうときにフィレットされていると面を引き伸ばすことが難しくなります。フィレットしてない版を保存しておき、実際にどこかで利用されるときは毎度フィレットを行う、という方法を取れば、手戻りは少なくなりそうです。&lt;/p&gt;
&lt;p&gt;Fusion360には保存時に同一ファイル内でバージョン管理ができ、バージョンごとにに名前をつけられるなどの機能があるのですが、試行錯誤して作るデジタルデータはgitで管理したくなるなという気持ちになりました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;スライサー&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3Dモデルからgcode (3Dプリンタが読み込める形式) への変換に必要です
Ultimaker Cura というソフトを使っています。
3D CADからSTL形式で出力したモデルを、Ultimaker Curaで、印刷設定をしてgcodeで出力します。
印刷設定としては、 in fill (印刷時、内部の充填率を決められる。25〜30%くらいがよく使われているらしい)、印刷方向、サポート材の有無などが決められます。&lt;/p&gt;
&lt;p&gt;gcode形式のファイルができたら、SDカードへ保存します。
gcodeファイルをSDカードに入れてAnyvubic Mega Sに差し込み、タッチパネルからファイルを選びます。&lt;/p&gt;
&lt;p&gt;最初は付属のSDカードに入っていたフクロウを印刷してみましたが、 大きさが5cmくらい、1時間半程度で印刷が終わりました。
フィギュアを作る予定ではないので十分満足できる精度だと思います。
2.5万円ということでもしかしたらまともに使い物にならないかもと期待していなかったのですが、全然そんなことなく、色々なことに活用できそうです。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/anycubic-mega-s-owl-printed.jpg&quot; alt=&quot;Anycubic Mega Sで印刷したフクロウ&quot;&gt;&lt;/p&gt;
&lt;p&gt;印刷のコツとして、以下のような点がありそうです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;積層方向を考慮する ... 積層方向によって、縮みや歪みや強度に差があるので、3Dモデルの設計だけでなく印刷方向の決定も印刷の成功に関わってきます。&lt;/li&gt;
&lt;li&gt;印刷後は台座が冷えるのを少し待つと良い ... Anycubicの台座は特殊な素材が使われているようで、プラットフォームが熱い間 (印刷中) はずれないように吸着し、印刷後冷めると剥がれやすくなります。印刷後は焦ってすぐ剥がすよりも少し待った方が、台座を傷つけずに済みます。&lt;/li&gt;
&lt;li&gt;大きな部品は分割する ... 大きな部品は印刷に時間がかかるので待ち時間が増えます。それだけでなく、トライアンドエラーをするのが億劫になります。組み立て式にしたり一部に切り出したりすると試作しやすく、良いものが作りやすいと思います。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;私個人としては買ってよかったです。
印刷したいものが安価に印刷できて満足でした。
安価に販売されているので、買ってみたが全然使い物にならなかったなどということも想像してましたが、予想以上に&quot;普通に&quot;使えました。&lt;/p&gt;
&lt;p&gt;しかしながらモデルを作って印刷して改良して、を繰り返すのはそこそこ時間がかかるので、そういった手間を覚悟で楽しむものだなあという感じです。
(3D CADへの習熟度が上がればもっと気軽につくっていけるのかもしれません)&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;3Dプリンタはもっと高価なものだと思っていたのに随分手頃になりました。 例えば&lt;a href=&quot;https://nico.ms/sm21538472&quot;&gt;2012年頃の動画に出てくる3Dプリンタ&lt;/a&gt;は積層間隔が0.3mm、自分で加工しながらMDF材からなるたくさんのパーツを組み立てています。(たしか当時リアルタイムで見ていた動画です。ニコニコ動画の #ニコニコ技術部 タグをみてワクワクしていた頃です。) 私の買った3Dプリンタは金属製で主に3つのパーツをネジ止めするだけでよいものです。それが2.5万円ですから、低廉化が進んでいますね。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;3Dプリンタはカスタマイズする文化があるようで、あとからパーツを交換して静音化や印刷精度の向上などをはかる事ができるようです。購入する前は興味がなかったのですがいざ届いてみるとちょっと静音化に手を出したくなったりします。 動作音 (とくに機械動作音ではなくモータドライバの電子音) がそこそこな音で、同じ部屋で寝るのは難しいレベルの騒音でした。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;FlashForgeは印刷部分が囲われていてかっこいいですが、これは格好良さではなく庫内の温度を高く保つためなんだそうです。ABSで印刷するときはこういった囲いがあるほうが印刷に成功しやすいらしい。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;M1 Macbook Airだとデュアルディスプレイにしたときに小ウィンドウの表示がバグっている気がする。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>情報処理技術者試験にはミックスサンド (DBスペシャリスト試験を受けました)</title>
      <link>https://memo.yammer.jp/posts/database-specialist-examination</link>
      <pubDate>Sun, 19 Dec 2021 08:13:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/database-specialist-examination</guid>
      <description>&lt;p&gt;2021/10/10に令和3年度秋期データベーススペシャリスト試験を受験しました。
情報処理技術者試験は通算4回目、高度情報は2回目 (春にネットワークスペシャリスト落ち)、データベーススペシャリストは今回が初でした。&lt;/p&gt;
&lt;p&gt;合格したので、この度晴れてみくりさんと結婚できる権利を得ました。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://togetter.com/li/1058081&quot;&gt;#逃げ恥 リストラ候補の津崎平匡さんの資格欄「応用情報技術者、データベーススペシャリスト、基本情報技術者」 - togetter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以下、対策したことを記録します。&lt;/p&gt;
&lt;h2&gt;参考書&lt;/h2&gt;
&lt;p&gt;いままではインプレスの過去問題集を毎度買っていたのですが、今回は翔泳社の「うかる！データベーススペシャリスト」を購入しました。&lt;/p&gt;
&lt;p&gt;結果からいうとこれは大正解で、午後問題の解説がめちゃくちゃ丁寧なので知識があまりない状態でも解説から吸収することができました。
インプレスの過去問題集は、ネットワークスペシャリストの午後問題を勉強しているときに解説がサラッとしすぎていてわからんなあという気持ちになっていました。
「うかる！データベーススペシャリスト」には各問題のパターンと解き方も参考書に丁寧に解説されているので、試験申し込んだときに一読し、あとで解くときに読み直すと良いように思います。&lt;/p&gt;
&lt;p&gt;インプレスの過去問題集は書籍自体をPDFダウンロードできるのが気に入って前回まで買っていました。
翔泳社の書籍の電子版はKindleで販売されていますが、こういう参考書は書き込んでなんぼなのでKindleアプリ上で勉強するのは厳しいものがあります。
PDFでの販売をしてくれるとより買いやすくなるのですが...&lt;/p&gt;
&lt;h2&gt;試験勉強の時間軸&lt;/h2&gt;
&lt;p&gt;試験勉強を始めたのは申込みをした8月中旬からでした。
参考書を前からざっくり読んだ後、問題演習として初めに取り組んだのは午前Ⅱ対策です。
1分半程度で解く規模の問題なので軽い気持ちで勉強しやすく、知識中心なのでまずはこれから手を付けました。&lt;/p&gt;
&lt;p&gt;9月に入った頃に午前Ⅱ対策を終わりにして午後対策に移りました。
午後Ⅱは1問解くのに2時間かかるので、休日に午後Ⅱ、平日に午後Iとして、並行して過去問を解いていました。
しかしながら特に午後Ⅱはとにかく文章が長いしやってると眠くなるし、この頃からモチベーションも薄れてきて勉強ペースが落ちがちに。
結局参考書で紹介された再重要問題の半分くらい解いたところで試験前日になりまして、残りの問題は解説を読んで雰囲気を掴んで当日を迎えました。&lt;/p&gt;
&lt;p&gt;情報処理技術者試験は申し込んだとき一番モチベーションが高い気がします。
毎度試験会場は半分〜7割くらいしかいないのでみんなそんな感じなんじゃないかな。
申込時のモチベーションとその勢いでどこまで勉強できるか、それをどれだけ維持できるかが大事なのかなと思っています。&lt;/p&gt;
&lt;h2&gt;各試験区分の対策と感想&lt;/h2&gt;
&lt;h3&gt;午前Ⅰ&lt;/h3&gt;
&lt;p&gt;応用情報技術者試験を受けたのが2年以上前なので午前1の免除はありませんでした。
いけるやろ」と無勉強で望んだのものの意外とと解けない問題もありました。
さらに大々的にマークミスをしていまい、少し危なっかしい点数でした。
問題番号と解答用紙のマーク位置はよく確認しましょう。&lt;/p&gt;
&lt;h3&gt;午前Ⅱ&lt;/h3&gt;
&lt;p&gt;午前Ⅱは選択式の問題で、データベースに関連する幅広い知識が問われます。
対策としては参考書についてくる200問を繰り返し解いていました。
データベース何もわからん人間でSQLすら怪しい状態でしたが、間違えたところに絞りながら2,3周すればそこそこ解けるようになりました。&lt;/p&gt;
&lt;p&gt;SQLはどうやって学べばええんやというときは、PostgreSQLやMySQLの日本語ドキュメントを参考にすることが多かったです。
参考書では簡潔に書かれ読み取れないことも含めて丁寧に書かれており読みやすい内容でした。
(それが標準SQLであるかは確認する必要があります。)&lt;/p&gt;
&lt;p&gt;情報処理技術者試験の選択問題対策はどれも範囲が広いので雑にググって知らない言葉をなんとなく頭に入れておくのがよいと思っているのですが、ことSQLにおいては信頼できなさそうな量産ブログがたくさん引っかかるので最初から的を絞った方がよかったです。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;今思えばSQLに関する本を一冊買うなどしてもよかったように思います。&lt;/p&gt;
&lt;h3&gt;午後I&lt;/h3&gt;
&lt;p&gt;午後Iの問題は出題形式がいろいろありますが、一部の問題は午後IIをコンパクトにしたようなものもあります。
午後Ⅱの対策をある程度進めてから午後Iに取り掛かった方が効率が良いように思います。&lt;/p&gt;
&lt;h3&gt;午後Ⅱ&lt;/h3&gt;
&lt;p&gt;参考書によるとデータベーススペシャリストの午後Ⅱは出題形式が定番になっていて、前述の通りその問題が出来ないと受からないかつそれが出来れば午後I対策にもなるとのこと。
午後Ⅱのもっとも定番な問題である概念データモデルと関係スキーマに関する問題を何問か解いていきました。
業務ロジックが文章で説明されており、未完成の概念データモデルと関係スキーマを完成させるのが主な問題の内容です。&lt;/p&gt;
&lt;p&gt;が、この問題、とにかく問題の文章量が多い。
1問あたり12ページくらいあります。
iPadではページ切り替えが多すぎて厳しいので印刷して紙でやったほうがいいでしょう。&lt;/p&gt;
&lt;h2&gt;試験のためのTips&lt;/h2&gt;
&lt;h3&gt;概念データモデルの記法&lt;/h3&gt;
&lt;p&gt;午後問題では概念データモデルが必ず出てきます。
それぞれの記号に関する意味は注意書きとして試験問題の前半に書いてありますが、これは例年同じものです。&lt;/p&gt;
&lt;p&gt;午後問題の勉強を始めるときに初めに時間をとってじっくり読むことをお勧めします。
この記法にしたがって概念データモデルを書く問題も頻出です。
私は読まずに問題を解いていて、対策中盤くらいまでなんだかよくわからない記法が使われているなあという気持ちになっていました。&lt;/p&gt;
&lt;h3&gt;午後Ⅱ開始前の...&lt;/h3&gt;
&lt;p&gt;当日は各試験区分が始まる15分くらい前から説明が始まります。
午前中は受験票の回収がありますが、午後にもなると説明や準備もすぐに終わって解答開始まで10分くらい無の時間が訪れます。
携帯も切って参考書も閉まったあとで、じっと座っているだけの時間です。&lt;/p&gt;
&lt;p&gt;ここの時間は空想をするくらいしかないと思っていたのですが、午後IIには未完成の概念データモデルを埋める定番問題があります。
これを解くにはたくさんの問題文から情報を抽出して回答する必要があるので全体を掴んでおくと結構よかったりします。
そしてこの問題は解答用紙に未完成の図が書いてあるので、試験開始前になんとなく問題に出てくる用語とその関係を見ることができてしまいます。ます😜&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;データベーススペシャリストに合格したところで実際の業務上でわからないことは沢山あると思いますが、ひとまず一定の知識を習得できた意味で受験してよかったです。&lt;/p&gt;
&lt;p&gt;タイトルのミックスサンドは試験当日に食べたお昼のメニューです。
情報処理技術者試験の試験会場は私が参加した限りでは大抵どこかの学校で開かれます。
コンビニが近くになかったり、あっても混み合うことが予想されるので、駅を降りたあたりのコンビニでご飯を買うとよいと思っています。&lt;/p&gt;
&lt;p&gt;今回もコンビニに寄ったのですが、その時ふと以前の試験のときにミックスサンドを買ったことを思い出しまして。
コンビニに売っている普通のミックスサンドですが妙に美味しかった記憶が残っており今回も同様のものを選びました。&lt;/p&gt;
&lt;p&gt;起床時間が早く空腹を感じて午前Ⅱの前に美味しくいただきました。
次に情報処理技術者試験を受けることがあったら、またミックスサンドを選ぶかもしれません。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;このブログも個人が書いているもので、大して信頼できる情報ではないのだった &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>ECテックカンファレンスの前と後</title>
      <link>https://memo.yammer.jp/posts/newcomer-in-development-team-supplement</link>
      <pubDate>Thu, 16 Dec 2021 01:43:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/newcomer-in-development-team-supplement</guid>
      <description>&lt;p&gt;&lt;a href=&quot;/posts/newcomer-in-development-team&quot;&gt;前の記事に書いたとおり&lt;/a&gt;先日&lt;a href=&quot;https://pepabo.connpass.com/event/231478&quot;&gt;ペパボECテックカンファレンス&lt;/a&gt;に登壇しました。
今日はテックカンファレンスの内容ではなく発表前後に考えていたことと気持ちをいくつか記します。&lt;/p&gt;
&lt;h2&gt;「新卒」という言葉を使わない&lt;/h2&gt;
&lt;p&gt;発表に際してひとつ気をつけていたことに「新卒」という言葉をあまり使わないことがあります。&lt;/p&gt;
&lt;p&gt;テックカンファレンスの目的や狙いが記載された社内向けのissueを登壇が決まった頃に読んだ記憶があります。
これと今までやってきたこととを照らし合わせ自らの発表を聞いて欲しい人をジュニア層 &lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; のエンジニアと定めていました。&lt;/p&gt;
&lt;p&gt;私は新卒で入社したのでその体験をこれから新卒で入社される方や興味のある方に向けて話す行為は普通は一定程度価値があると思います。
しかしながら実は聞いて欲しい人として定めたジュニア層のエンジニアと、私の所属する会社の今後の新卒採用の募集方針は重なる部分が少なくなっています。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
このことを鑑みると「新卒」という言葉を聞いて会社に興味を抱いてくださっても募集要項とは重ならずミスマッチが発生することになります。&lt;/p&gt;
&lt;p&gt;そこで聞いて欲しい人と伝えたい内容を合わせるために、新卒かどうかにかかわらず「新しくチームに入る人」という視点で内容を組み立てることとしました。
これであれば新卒に限定せずエンジニアに広く聞いてもらえる内容となります。
チームで働いている人は誰でも人を迎え入れたりチームに加わったりした経験があるはずですし、今後チームで働きたい人にとっても聞く耳を持ってもらえることと思います。&lt;/p&gt;
&lt;h2&gt;技術的にどんなことに取り組んだかを軸にしない&lt;/h2&gt;
&lt;p&gt;テックカンファレンスですから技術に興味のある人が集まり技術について発表する場であることは明らかでしょう。
しかしながら今回発表したようなチームとしてうまくやるための手法も、技術による価値提供を支えるために技術者に求められることの一つに思います。&lt;/p&gt;
&lt;p&gt;もちろん技術の話は面白いし現にたくさんの方々が技術の話をされたわけですが、一方で今の私が技術の話に触れたとき内容が中途半端になることを恐れていました。
日々の仕事は難しく面白いものでありエンジニアであるから技術を用いた課題解決をしているわけでありますが、今やっている事柄は業務知識に密接に紐づいたものであったり事業部の物事をキャッチアップしたりする機会が多く、切り取り方が難しいと感じていたのです。&lt;/p&gt;
&lt;p&gt;しばらく考えてもあまり良い内容が思い浮かばず、発表が近づいてきた段階で自分で決めたのが「技術的にどんなことに取り組んだかを軸にしない」ことでした。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;
中途半端に技術の話をするよりも、どのように考え何を感じたのかの方がきっと面白味があるし、私の発表の目的&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;のひとつであった「このサービスで働くのはこんな感じか」を想像しやすいのではないかと考えました。&lt;/p&gt;
&lt;p&gt;テクニカルな内容にあまり触れなかったのは結果としてよかったと感じています。
今の私に話せることを発表に落とし込んだつもりですが、一方で他の方々の発表を聞いて「技術的にこんなことをやっているぞ」と自慢できるくらい成果を出せるようになりたいとも思ったので、来年以降たくさん成果を出して発表の場に立ちたいと思います。&lt;/p&gt;
&lt;h2&gt;聴衆は&quot;あなたの発表&quot;を聞きに来ているのです。&lt;/h2&gt;
&lt;p&gt;発表前に社内のSlackに投稿されていた文章がいい話だったのでここで触れます。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初めての発表で緊張していたり、どういう反応がくるか不安になってしまうというのはよくわかります。
しかし、あなたの発表を見に来ている人は、他の誰でもない「あなた」の発表を見たくて見に来ているのです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://diary.shu-cream.net/%E8%81%B4%E8%A1%86%E3%81%AF%22%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AE%E7%99%BA%E8%A1%A8%22%E3%82%92%E8%81%9E%E3%81%8D%E3%81%AB%E6%9D%A5%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%99&quot;&gt;聴衆は&quot;あなたの発表&quot;を聞きに来ているのです - けんちゃんくんさんのWeb日記&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(どうぞ上記の記事を全文お読みください)&lt;/p&gt;
&lt;p&gt;当日は緊張していましたが、何か一つでも持ち帰ってもらえるものがあればという気持ちで内容に自信を持って臨むことができました。
オンラインで発表していたので聴講者の顔は見えませんが、何人もの人に発表を聞いていただけたようで本当に嬉しいです。&lt;/p&gt;
&lt;p&gt;次にまた発表の機会があったときこの文章を読んで気持ちを整えたいと思っています。
あわせて自らの話を聞く時間をとってくださる人のために内容に自信をもてるだけの準備をしなければと感じます。&lt;/p&gt;
&lt;h2&gt;Speaker Deckにスライドを公開する&lt;/h2&gt;
&lt;p&gt;当日の発表スライドはSpeaker Deckにアップロードしました。
公開にあたって気をつけたことがあるので紹介します。&lt;/p&gt;
&lt;h3&gt;Google SlidesとSpeaker Deckの相性&lt;/h3&gt;
&lt;p&gt;どうもGoogle Slidesで出力した日本語を含むPDFはSpeaker Deckで公開すると崩れるようです。(太字部分が白抜き文字になる)
これを回避するために一旦Keynoteで読み込んでからPDFにするなどしました。
Keynoteに読み込むとスライド内のオブジェクトの位置ズレなどが発生するので、それを修正する必要もありました。&lt;/p&gt;
&lt;h3&gt;Speaker DeckのタイトルとURL&lt;/h3&gt;
&lt;p&gt;Speaker Deckで公開したスライドのURLはタイトルから生成されるようになっています。
日本語の場合はローマ字読みのアルファベットに置き換えられますが、完全に正しい読みになるわけではありません。
これを回避するために発表名の末尾に&lt;code&gt;/&lt;/code&gt;を付けて続けて半角英数字などをおくと、&lt;code&gt;/&lt;/code&gt;の後の半角英数字のみがURLになるようです。&lt;/p&gt;
&lt;p&gt;これを生かして以下のようなタイトルとURLとしました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;タイトル: 「開発チームの新しいエンジニアメンバーがうまくやるには / newcomer-in-development-team」&lt;/li&gt;
&lt;li&gt;URL: 「&lt;a href=&quot;https://speakerdeck.com/yammerjp/newcomer-in-development-team%E3%80%8D&quot;&gt;https://speakerdeck.com/yammerjp/newcomer-in-development-team」&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上、雑多ですが、発表に際してどんなことを考えていたかを記しました。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;ジュニア層のエンジニアとは&lt;a href=&quot;https://tech.pepabo.com/2020/07/30/pepabo-engineering-2020-summer/&quot;&gt;ペパボのエンジニアの各種制度 2020 夏 - ペパボテックブログ&lt;/a&gt; で示されている1-3等級相当のエンジニアのことを指して言っています。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://pepabo.com/news/information/202112131500&quot;&gt;GMOインターネットグループ共通2023年度新卒採用エントリーを開始しました - GMOペパボ株式会社&lt;/a&gt; にある通りの採用基準が定められています。これは新卒の採用基準であって、例えば&lt;a href=&quot;https://recruit.pepabo.com/info/career/&quot;&gt;ジュニア層向けの中途採用&lt;/a&gt;や&lt;a href=&quot;https://recruit.pepabo.com/info/collage/&quot;&gt;未経験者向け研修付き採用「ペパボカレッジ」&lt;/a&gt;などはこれに該当せず、募集が開かれています。(2021/12/16時点) &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;発表の趣旨から離れすぎない範囲で技術的な内容に触れてはいます。(環境作成タスクの内容や自動テストなど) &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;私の発表を聞いて「このサービスで働くのはこんな感じか」「このサービスで働くのは面白いぞ」「このサービスで働いてみたい」などの感情を想起してもらいたいと思っていました。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>開発チームの新しいエンジニアメンバーがうまくやるには</title>
      <link>https://memo.yammer.jp/posts/newcomer-in-development-team</link>
      <pubDate>Mon, 13 Dec 2021 15:03:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/newcomer-in-development-team</guid>
      <description>&lt;p&gt;こんにちは、2021/12/09に開催された&lt;a href=&quot;https://pepabo.connpass.com/event/231478&quot;&gt;ペパボECテックカンファレンス&lt;/a&gt;にて、記事名と同じタイトルで発表をしました。
当日のスライドはSpeaker Deckで公開しています。&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe class=&quot;speakerdeck-iframe&quot; frameborder=&quot;0&quot; src=&quot;https://speakerdeck.com/player/aff516d8e9404ef5b58c114f714fff87&quot; title=&quot;開発チームの新しいエンジニアメンバーがうまくやるには / newcomer-in-development-team&quot; allowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; webkitallowfullscreen=&quot;true&quot; style=&quot;border: 0px; background: padding-box padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 560px; height: 314px;&quot; data-ratio=&quot;1.78343949044586&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;今日はその発表の内容を記事として紹介します。&lt;/p&gt;
&lt;h2&gt;開発チームの新しいエンジニアメンバーがうまくやるには&lt;/h2&gt;
&lt;p&gt;私は4月に新卒でWebアプリケーションエンジニアとして入社し、今は10人弱のチームに配属となってから3ヶ月ほどが経ちました。
会社のGitHub Enterprise Server上では、配属からこれまでで約60のPull Requestを開き、マージし、デプロイされました。
Pull Requestの数と成果は必ずしも一致しませんが、配属から今日までの間、昨日を細かく分割して実装しデプロイするということを続けています。&lt;/p&gt;
&lt;p&gt;チームメンバーが私を迎え入れるにあたってしてくれたことは、業務経験の無い自分が開発に取り組むにあたってとても役に立つものでした。
以下では自らが意識的に取り組んだことと合わせて「新しいメンバーが〇〇するには」という題目で紹介します。&lt;/p&gt;
&lt;h2&gt;1.新しいメンバーが業務知識を素早く獲得するには&lt;/h2&gt;
&lt;p&gt;Webサービスのアプリケーション開発において、業務知識への理解は欠かせません。
ここでいう業務知識とは、そのサービスを成立させるためのアプリケーションの構成やそれらのアプリケーション固有の仕様などをはじめとした、エンジニアが業務を進める上で必要なそのサービス特有の知識のことを指しています。&lt;/p&gt;
&lt;p&gt;このような知識は開発チームに参加したのちに獲得する必要があり、素早く獲得すればより早く広範囲のタスクを扱えるようになるでしょう。&lt;/p&gt;
&lt;h3&gt;アプリケーションの構成に関する共有会を開く&lt;/h3&gt;
&lt;p&gt;(チームメンバーが私にしてくれたこと)&lt;/p&gt;
&lt;p&gt;チームメンバーに業務知識の共有会を開いていただいたことは、業務知識の獲得に直接的に大きく影響を与えました。
独自のアーキテクチャを持つアプリケーションのディレクトリごとの構成や各レイヤの関係性をざっくりと説明をしてもらったことでその後のコードリーディングが捗ったように思います。&lt;/p&gt;
&lt;p&gt;他にもリレーショナルデータベースの重要なテーブルの関係性についてレクチャーをいただいたことも良い機会でした。
私の開発するサービスは多数のロールがデータベースを介して連携をしています。即ち特定のロールの処理を見てもそれ自体がサービスの動作を表しているわけではなく、他ロールでどのように使われているかを知る必要があります。
こういった広い範囲の挙動を把握するためには、全体感をつかむ説明を受けた方がアプリケーションの挙動を把握するのが楽になります。&lt;/p&gt;
&lt;h3&gt;少しずつ取り組む領域を広げる&lt;/h3&gt;
&lt;p&gt;(チームメンバーが私にしてくれたこと)&lt;/p&gt;
&lt;p&gt;配属初期にいただいたタスクに関連するコード上の領域が少しずつ広がっていったことも業務知識を素早く獲得するに寄与しました。私は元々フロントエンド寄りのスキルセットであったので、Webフロントエンド領域のテンプレートやVueコンポーネントの実装からはじめて、次にWebサーバサイド領域のController層、Model層の開発に関わり、さらに他のロールや外部APIとの通信、バッチといった部分へ手を広げていきました。
大きなコードベースの中で少しずつコードリーディングの範囲を広げられたことはスムーズに開発に参加できた要因のひとつでした。&lt;/p&gt;
&lt;h3&gt;チームに回ってくるタスクに「やります」と言う&lt;/h3&gt;
&lt;p&gt;(自らが意識していること)&lt;/p&gt;
&lt;p&gt;業務知識を素早く獲得するために私が心掛けていることの1つとして、チームに回ってくるタスクに積極的に「やります」と手を挙げることがあります。
開発チームにおいて、お問い合わせやパートナー (社員のこと) からの依頼に起因して、もともとの計画に含まれない突発的なタスクが発生することがときどきあります。
こういったタスクの中には配属後少し時間が経ち慣れてくればある程度対応できそうなものもあります。
自らのできることが少ないからこそ、できることは積極的に巻き取ることでチームに貢献しようとしています。&lt;/p&gt;
&lt;p&gt;チームとしての生産性を高めるという点だけでなく、こういったタスクはときに自らの知っている領域を広げるきっかけになることがあります。
例えば私はあるロールのDockerを用いた開発環境を作成するタスクに取り組みましたが、これはまさに自らの知っている領域を広げるものでした。&lt;/p&gt;
&lt;p&gt;普段はコードベースの大きい中心的なロールに対して開発を行なっており、CI/CD環境が整備され、Gitの操作やSlackとの連携によって、深く知らずとも簡単にデプロイできる環境が整っています。&lt;/p&gt;
&lt;p&gt;一方開発環境の作成では、そのようなCI/CD環境が普段どのようなことを行なっているのかを一定程度追う必要がありました。
また、Webアプリケーションのエントリポイントに到達する前に、インフラレベルでHTTPリクエストがどのようにルーティングされているかといったことについても一定程度理解する必要がありました。
これらの知識は中心的なロールを含む他のロールにも適用でき、ブラックボックスとして扱っていたサービスを構成する要素の一部がどんなことをしているかを知ることができました。&lt;/p&gt;
&lt;p&gt;手を挙げてタスクを受け取ることで、こういった毛色の違うタスクに触れる&lt;/p&gt;
&lt;h2&gt;2.新しいメンバーがチームに馴染むには&lt;/h2&gt;
&lt;p&gt;昨今は心理的安全性という言葉が取り沙汰され、開発チームのメンバー同士の関係もプロダクトの提供する価値に影響を与えることが広く知られていることと思います。
私の所属するチームにおいてもチームメンバー同士の関係を良好に保ち、意見を積極的に交換できるような関係性を築くような取り組みがなされています。&lt;/p&gt;
&lt;h3&gt;お互いの強み/弱みを知る&lt;/h3&gt;
&lt;p&gt;(チームメンバーが私にしてくれたこと)&lt;/p&gt;
&lt;p&gt;チームメンバーがお互いの強み/弱みを知るために「ドラッカー風エクササイズ」という手法のチームビルディングのためのワークショップを開催していただきました。これは私がチームメンバーと相互理解を深めることに役立った出来事の1つでしょう。
「ドラッカー風エクササイズ」はお互いの特徴の自己認識と他者認識を書き出して、期待値をすり合わせるための手法です。
自らの思っている強み/弱みを伝えるきっかけになりますし、自分以外のチームメンバー同士でどのような関係が築かれているかを知る機会になります。
ペパボにおけるドラッカー風エクササイズの取り組みは会社のブログに紹介がありますので以下の記事をご覧になると良いかと思います。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://tech.pepabo.com/2017/07/07/the-drucker-exercise/&quot;&gt;「ドラッカー風エクササイズ」で期待をすりあわせて安全なチームに - ペパボテックブログ&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;コミュニケーションの場を用意する&lt;/h3&gt;
&lt;p&gt;(チームメンバーが私にしてくれたこと)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;フードコート&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;私の事業部のいくつかのチームにはフードコートという取り組みがあります。いつでも開かれているビデオミーティング会場で、お互いが好きな時に入ることができます。私の所属するチームのメンバーの多くは予定がない時などはここにいて、チームメンバーに話したい時にマイクをonにするといった運用がなされています。
フードコートに居る義務はなく、集中して業務に取り組みたいときなどには入らないという選択肢をとることもできます。
仕事を始めたて且つチームに参加したての自分にとって、発話のハードルが下がったのでありがたい取り組みでした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事業部お茶会&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;リモートワークの中では、偶発的な同期コミュニケーションの機会はあまりありません。
このためチームメンバーが事業部の人を招いた座談会を定期的に開催してくれています。
他チームの人と業務に関係あるかどうかに関係なくいろいろな話をする機会が生まれることは、視野が広がる機会となっています。&lt;/p&gt;
&lt;h3&gt;日報を書く&lt;/h3&gt;
&lt;p&gt;(自らが意識していること)&lt;/p&gt;
&lt;p&gt;チームメンバーとの相互理解を深めるために大事なことの一つに自己開示があります。
日報を書くことで、自らがどんなことを考えて仕事をしているか、どんな感情であるか、何を理解していて何を理解していないのかを知ってもらう機会となります。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
また、チームメンバー以外の人が見てコメントをくれることもあります。&lt;/p&gt;
&lt;p&gt;日報のフォーマットとしては「今の気持ち」「やったこと」「わかったこと」「次にやること」の4つに分けて記述するようにしています。&lt;/p&gt;
&lt;h2&gt;3.新しいメンバーが開発の提案をするには&lt;/h2&gt;
&lt;h3&gt;複数の選択肢を挙げる&lt;/h3&gt;
&lt;p&gt;(自らが意識していること)&lt;/p&gt;
&lt;p&gt;開発において、要件を達成する手法を自分で決められない/決めないとき、複数の選択肢を提案することで、自らに足りない業務知識や技術的知見を補ってもらえるようにしています。&lt;/p&gt;
&lt;p&gt;このとき、あわせて自分が最も良いと思う選択肢を1つ選ぶよう心がけています。
自分が選んだものと実際に選ばれたものの差異が学びになるので、自分で1つ選ぶことはこれからも続けていきたいと思っています。&lt;/p&gt;
&lt;h3&gt;テストコードを書く&lt;/h3&gt;
&lt;p&gt;(自らが意識していること)&lt;/p&gt;
&lt;p&gt;Pull Requestを開発における実装の提案の場として考えると、Pull Requestも新しいメンバーが開発の提案をうまくやる必要のある場の一つでしょう。
適当なPull Requestを投げてばかりではレビュアーの負担は増大するばかりです。&lt;/p&gt;
&lt;p&gt;レビューしやすい Pull Request にするという意味でテストコードは有用です。
コードの一定の質が担保されるだけでなく、入出力が明確になったり、依存が明らかになったりするという利点が考えられるでしょう。&lt;/p&gt;
&lt;p&gt;ちなみにテストコードの書き方については新卒研修の中でのカリキュラムがとても役に立ちました。
ペパボの2021年度の新卒エンジニア研修では、&lt;a href=&quot;https://railstutorial.jp/chapters/beginning?version=6.0&quot;&gt;Railsチュートリアル内&lt;/a&gt;でのMinitestによる自動テスト、&lt;a href=&quot;https://tech.pepabo.com/2021/09/22/igaiga-workshop/&quot;&gt;RSpec書き方講座&lt;/a&gt;、&lt;a href=&quot;https://tech.pepabo.com/2021/06/18/tdd-workshop-2021/&quot;&gt;TDDワークショップ&lt;/a&gt;など、ソフトウェア開発における自動テストがどのような役割を持ちどのように作るべきかを学ぶことができました。
今はRSpecだけでなくPHPUnitやJestを用いたテストコードを書く機会がありますが、これらのテストフレームワークを使う上でも研修で学んだ内容が役に立っています。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;以上のような取り組みを通して、開発チームに新しくエンジニアとして加わったメンバーが、業務知識を素早く獲得し、チームに馴染み、開発の提案をして、ユーザへの価値提供に取り組んでいます。
チームメンバーが新しく私を迎え入れるためにしてくれたことが今の開発に生きていると感じています。&lt;/p&gt;
&lt;p&gt;これらの事例が、チームに新しく加わる人や、新しい人を迎えるチームにとって参考になれば幸いです。また、チームに加わった3ヶ月で自分がどのように感じ何が役に立っていたかの取り組みを残しておくことで、将来チームメンバーを迎え入れる側になったときにこれを見返してよい環境を提供できるようになれればと思います。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;同時にこれら (どんなことを考えて仕事をしているか、どんな感情であるか、何を理解していて何を理解していないのか) を言語化することで自らに対して明らかにする機会ともなります。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>複数の環境に適応する、階層構造のdotfiles</title>
      <link>https://memo.yammer.jp/posts/layered-dotfiles</link>
      <pubDate>Thu, 02 Dec 2021 05:00:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/layered-dotfiles</guid>
      <description>&lt;p&gt;こんにちは、やんまーです。
もう師走、早いですね...
この記事は&lt;a href=&quot;https://adventar.org/calendars/6375&quot;&gt;GMOペパボアドベントカレンダー&lt;/a&gt;の2日目のものです。&lt;/p&gt;
&lt;p&gt;昨日は&lt;a href=&quot;https://twitter.com/_doew&quot;&gt;daiki&lt;/a&gt;さんの「&lt;a href=&quot;https://blog.d-sato.net/?p=116&quot;&gt;社会人エンジニアな僕が研究を続ける理由&lt;/a&gt;」でした。
記事の中の研究を通して自己表現をされているという表現が印象的でした。仕事に精を出しながらも、仕事とは異なるところで時間をとって継続的に物事に取り組むということに尊敬の念を持ちます。
私も見習いたいものです。&lt;/p&gt;
&lt;p&gt;今日は変わって実践的な内容です。私の開発環境 dotfilesを紹介します。&lt;/p&gt;
&lt;h2&gt;dotfiles とは&lt;/h2&gt;
&lt;p&gt;Unix / Linux の環境において、&lt;code&gt;~/.bashrc&lt;/code&gt;、 &lt;code&gt;~/.vimrc&lt;/code&gt;、 &lt;code&gt;~/.gitconfig&lt;/code&gt; のように &lt;code&gt;.&lt;/code&gt; から始まる各アプリケーションの設定ファイルが &lt;code&gt;$HOME&lt;/code&gt; ディレクトリに配置されることがよくあります。
これらの設定ファイルを自分の持っている複数のPCに適用したいというモチベーションや、PCを乗り換えた時のためにバックアップして復元したいというモチベーションから、ローカルのストレージ以外にも保存するということが行われています。&lt;/p&gt;
&lt;p&gt;こういった設定ファイル群とこれらをローカルストレージ以外の場所に保存することを指して dotfiles と呼び、GitHubのリポジトリで公開するなどしている人もいます。
かくいう私も自らの設定ファイルを保存・公開している人の一人で、GitHubのリポジトリ (&lt;a href=&quot;https://github.com/yammerjp/dotfiles&quot;&gt;yammerjp/dotfiles&lt;/a&gt;) から誰でも見れるようにしています。&lt;/p&gt;
&lt;h2&gt;単純なdotfiles&lt;/h2&gt;
&lt;p&gt;本記事で後述する複数環境に対応した構成のまえに、単純なdotfilesの構成として &lt;a href=&quot;https://github.com/yammerjp/dotfiles-mini&quot;&gt;yammerjp/dotfiles-mini&lt;/a&gt; をみてみましょう。
このリポジトリには次のようなファイルがあります。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ファイル名&lt;/th&gt;
&lt;th&gt;ファイルの役割&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.gitconfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;gitの設定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.tmux.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;tmuxの設定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.vimrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;vimの設定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.zshrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;zshの設定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;リポジトリ全体の説明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;dotfilesを適用するシェルスクリプト&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;ここで注目するのは &lt;code&gt;run.sh&lt;/code&gt; というシェルスクリプトです。
内容の一部を抜粋すると以下のようになっています。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;# リポジトリをダウンロードする
# ========================================
cd &quot;$HOME&quot;
git clone https://github.com/yammerjp/dotfiles-mini.git
cd dotfiles-mini


# シンボリックリンクを貼る
# ========================================
DOTFILES_DIR=`pwd`
ln -s &quot;$DOTFILES_DIR/.zshrc&quot; ~/.zshrc
ln -s &quot;$DOTFILES_DIR/.vimrc&quot; ~/.vimrc
ln -s &quot;$DOTFILES_DIR/.gitconfig&quot; ~/.gitconfig
ln -s &quot;$DOTFILES_DIR/.tmux.conf&quot; ~/.tmux.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHubからダウンロードしてくることと、設定を適用すること (シンボリックリンクを作成し &lt;code&gt;~/.zshrc&lt;/code&gt; などで参照できるようにすること) を行なっています。
このように設定を保存・公開するだけでなく、あわせて設定を適用するスクリプトを付属させておくと便利に使えます。&lt;/p&gt;
&lt;h2&gt;複数環境にする需要&lt;/h2&gt;
&lt;p&gt;さてさて、上記のように各アプリケーションの設定を保存・公開し、適用するスクリプトも用意できたのですが、しばらくするとさらに欲が出てきてしまいます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;複数のOSの環境 (片方がLinux、片方がmacOS) が手元にあり、それぞれの設定を管理したい &lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;同じOSの複数の環境 (職場のPCと自宅のPC) が手元にあり、それぞれの設定を管理したい&lt;/li&gt;
&lt;li&gt;会社で使っている設定は公開したくないが、自宅で使っている設定は公開したい&lt;/li&gt;
&lt;li&gt;複数の環境の設定の一部を共通化したい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このように複数の環境が存在しそれぞれ異なる設定を保持したい場合や、設定の公開範囲を制御したい場合に役立つのが、今回紹介する複数環境に適応した階層構造のdotfilesです。&lt;/p&gt;
&lt;h2&gt;階層構造の実装&lt;/h2&gt;
&lt;p&gt;公開範囲や適用環境を複数定めることができるように、以下のような構成をつくります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;いくつかの設定ファイルを含むディレクトリを複数用意する (階層とよぶ)&lt;/li&gt;
&lt;li&gt;用意した階層の中から任意の順番で任意の個数の階層を選び、順番に適用する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;複数の階層 (ディレクトリ) に分割することで、一部はGitHubのパブリックリポジトリに置かないという選択肢もとれますし、一部のPCでは特定の階層を適用しないという選択肢もとれます。
また、&lt;code&gt;順番に適用する&lt;/code&gt; とあるように、各階層で設定ファイルが重複するとき、優先順位を指定することができるようにしています。&lt;/p&gt;
&lt;p&gt;具体的に私の環境は以下のようなディレクトリの階層構造になっています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自宅のMacbook Air
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/Darwin--arm64&quot;&gt;&lt;code&gt;Darwin--arm64&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/Darwin&quot;&gt;&lt;code&gt;Darwin&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/common&quot;&gt;&lt;code&gt;common&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;会社のMacbook Pro
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;company&lt;/code&gt; 階層&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/Darwin--x86_64&quot;&gt;&lt;code&gt;Darwin--x86_64&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/Darwin&quot;&gt;&lt;code&gt;Darwin&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/f246a47414789fb17372fe6ee44f238405d7c194/env/common&quot;&gt;&lt;code&gt;common&lt;/code&gt; 階層&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;全ての環境に共通の設定を集めた最も下の階層として &lt;code&gt;common&lt;/code&gt; 階層を配置しています。
その上の階層として、macOSのみに必要な設定を &lt;code&gt;Darwin&lt;/code&gt; 階層に、さらに上の階層として arm64 / x86_64 の macOS に必要な設定をそれぞれ &lt;code&gt;Darwin--arm64&lt;/code&gt; 階層, &lt;code&gt;Darwin--x86_64&lt;/code&gt; 階層に配置し、commonなどの下の階層の設定を一部上書きます。
加えて最上位の階層として、会社のPCで利用している公開できない設定などを含んだ &lt;code&gt;company&lt;/code&gt; 階層を配置し、これは会社のGitサーバで管理するようにしています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/layered-dotfiles.png&quot; alt=&quot;階層構造のdotfilesのイメージ図&quot;&gt;&lt;/p&gt;
&lt;p&gt;このような階層構造は、各設定ファイルを適用する (シンボリックリンクを貼る) スクリプトを工夫することで実現しています。
実際に実行されるスクリプトの動作とともに紹介します。
例えば以下のようなコマンドを実行することを考えます。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ DOTFILE_DIRS=&quot;$HOME/src/github.com/yammerjp/dotfiles/env/Darwin--arm64:$HOME/src/github.com/yammerjp/dotfiles/env/Darwin:$HOME/src/github.com/yammerjp/dotfiles/env/common&quot; ./bin/dotfiles link
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/baa8cd1ecc183481ab29a402607cdc638864f6f5/bin/dotfiles&quot;&gt;&lt;code&gt;bin/dotfiles&lt;/code&gt;&lt;/a&gt; は変数 &lt;code&gt;$DOTFILE_DIRS&lt;/code&gt; に &lt;code&gt;:&lt;/code&gt; で区切られたディレクトリの列が指定されることを期待します。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
また指定されたディレクトリ列がそのまま、各階層のルートディレクトリとなります。なお先に記述されたものが上位の階層として扱われます。&lt;/p&gt;
&lt;p&gt;今回でいえば上位から順に3つの階層をもちます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Darwin--arm64&lt;/code&gt; 階層 &lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/baa8cd1ecc183481ab29a402607cdc638864f6f5/env/Darwin--arm64&quot;&gt;&lt;code&gt;$HOME/src/github.com/yammerjp/dotfiles/env/Darwin--arm64&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Darwin&lt;/code&gt; 階層 &lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/baa8cd1ecc183481ab29a402607cdc638864f6f5/env/Darwin&quot;&gt;&lt;code&gt;$HOME/src/github.com/yammerjp/dotfiles/env/Darwin&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;common&lt;/code&gt; 階層 &lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/baa8cd1ecc183481ab29a402607cdc638864f6f5/env/common&quot;&gt;&lt;code&gt;$HOME/src/github.com/yammerjp/dotfiles/env/common&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;それぞれの階層のディレクトリにあるファイルからホームディレクトリへ、シンボリックリンクが作成されます。
このとき、それぞれの階層のディレクトリの中で、階層の起点となるディレクトリから同名の相対パスのファイルがあれば、その中で最も上位の階層のファイルのみホームディレクトリへシンボリックリンクが貼られます。&lt;/p&gt;
&lt;p&gt;例えば各階層 (&lt;code&gt;Darwin--arm64&lt;/code&gt;, &lt;code&gt;Darwin&lt;/code&gt;, &lt;code&gt;common&lt;/code&gt;) に &lt;code&gt;.zshrc&lt;/code&gt; があるとき、最も上位の階層のものである &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/baa8cd1ecc183481ab29a402607cdc638864f6f5/env/Darwin--arm64/.zshrc&quot;&gt;&lt;code&gt;Darwin--arm64&lt;/code&gt; 階層の &lt;code&gt;.zshrc&lt;/code&gt;&lt;/a&gt; から &lt;code&gt;$HOME/.zshrc&lt;/code&gt; へシンボリックリンクが貼られます。&lt;/p&gt;
&lt;h2&gt;各設定ファイルでの工夫&lt;/h2&gt;
&lt;p&gt;上述のように同名のファイルは上位階層が優先されてしまうので、設定ファイルの一部を共通化したいときは、ファイルを分割して用意することで対応しています。&lt;/p&gt;
&lt;p&gt;例えば &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/f246a47414789fb17372fe6ee44f238405d7c194/env/common/.zshrc&quot;&gt;&lt;code&gt;common&lt;/code&gt; 階層の &lt;code&gt;.zshrc&lt;/code&gt;&lt;/a&gt; は無視されてしまうので、設定の中身は同階層の &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/f246a47414789fb17372fe6ee44f238405d7c194/env/common/.zshrc-common&quot;&gt;&lt;code&gt;.zshrc-common&lt;/code&gt;&lt;/a&gt; に切り出し、&lt;code&gt;.zshrc&lt;/code&gt; ではそれを読み込むだけにします。
同様に &lt;code&gt;Darwin&lt;/code&gt; 階層では内容を &lt;code&gt;.zshrc-darwin&lt;/code&gt; に、 &lt;code&gt;Darwin--arm64&lt;/code&gt; 階層では内容を &lt;code&gt;.zshrc-darwin-arm64&lt;/code&gt; に記述し、各 &lt;code&gt;.zshrc&lt;/code&gt; は自身の階層と下位階層の &lt;code&gt;~/.zshrc-*&lt;/code&gt; を読み込むだけにして、上書きされても問題ないようにしています。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/layered-dotfiles-overwriting.png&quot; alt=&quot;.zshrcは上書きされるので、.zshrc-*に切り出している様子のイメージ図&quot;&gt;&lt;/p&gt;
&lt;p&gt;このような行為は他の設定ファイルでも行なっていて、例えば &lt;code&gt;.gitconfig&lt;/code&gt; にも include の仕組みがあるので、&lt;code&gt;.gitconfig&lt;/code&gt; は上書きされてもいいように &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/f246a47414789fb17372fe6ee44f238405d7c194/env/common/.gitconfig-common&quot;&gt;&lt;code&gt;.gitconfig-common&lt;/code&gt;&lt;/a&gt; に設定を書いて &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/f246a47414789fb17372fe6ee44f238405d7c194/env/common/.gitconfig&quot;&gt;&lt;code&gt;.gitconfig&lt;/code&gt;&lt;/a&gt; はそれを読み込むだけにしています。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;こうして工夫をすることで、自宅のUbuntuでも、会社のMacbookでも、サクッと用意したEC2でもすぐに自分の環境が用意できる仕組みを作っています。
設定ファイルだけでなく、パッケージのインストールやOSの設定の変更などのスクリプトも管理しようとしています。
これは生産性を向上させるためというより、それを歌いながらもdotfilesを育てていくのが楽しいだけなのですが、少しばかりは便利になっているはずです。
今日は私のdotfilesを紹介したので、ぜひ皆さんのご自慢のdotfilesがあれば教えてください。&lt;/p&gt;
&lt;p&gt;というわけでアドベントカレンダー2日目の記事を終わりにします。
何も考えずに「ええやろ！」という気持ちで2日目にエントリーしましたがひとまず書き終え安心しています。
明日は&lt;a href=&quot;https://twitter.com/ch11aki&quot;&gt;akichan&lt;/a&gt;さんです、バトンを託します！&lt;/p&gt;
&lt;hr&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;このことだけであれば、OSごとに設定が違うときは各設定ファイルの中で分岐するように記述すれば解決できるものもあるでしょう。例えば &lt;code&gt;~/.zshrc&lt;/code&gt; などは if 文で分岐すれば済みます。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;実際には &lt;code&gt;common&lt;/code&gt; や &lt;code&gt;Darwin&lt;/code&gt;, &lt;code&gt;Darwin--arm64&lt;/code&gt; といったディレクトリはデフォルトで指定されるようにしています。OS(とLinuxならディストリビューション名) とCPUのアーキテクチャから、&lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/f246a47414789fb17372fe6ee44f238405d7c194/bin/link-list.sh#L37-L42&quot;&gt;それぞれの環境に即した3-4階層を定めています&lt;/a&gt;。会社のGitリポジトリで管理している設定やGitHubのプライベートリポジトリで管理している設定を適用したいときに、 &lt;code&gt;$DOTFILE_DIR&lt;/code&gt; などの変数にそのディレクトリのパスを与えると、デフォルトの3-4層に上位階層としてこれを加えた状態となるようにしています。階層の追加は後からでもできる (コマンドを叩けばシンボリックリンクを貼り直せる) ので、新しい環境では (そのOSとアーキテクチャに即した設定を用意していれば) &lt;code&gt;./bin/dotfiles link&lt;/code&gt; とするだけでよくて、あとから必要な階層を足していくようにして運用しています。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>master push をしないために</title>
      <link>https://memo.yammer.jp/posts/restrict-git-master-push</link>
      <pubDate>Tue, 09 Nov 2021 01:31:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/restrict-git-master-push</guid>
      <description>&lt;p&gt;昨日、master push をしてしまいましたので懺悔します。&lt;/p&gt;
&lt;p&gt;私の会社の開発は、GitHub Enterprise Server上のPull Requestベースで行われており、開発した機能をPull Reqeustにしてレビューを貰ってからマージすることとなっています。
しかしながら昨日の私は、ローカルで作ったcommitをそのままリモートリポジトリのmasterブランチにpushしてしまいました。
masterにマージするだけでは本番にはデプロイされませんが、複数のチームが開発しているリポジトリであり、各方面に迷惑をおかけしました。&lt;/p&gt;
&lt;p&gt;私がやらかした後、master pushを防ぐ術を教えていただいたので、以下に記します。&lt;/p&gt;
&lt;h2&gt;GitHub上で branch protection を行う&lt;/h2&gt;
&lt;p&gt;ルールを設定し、force pushできないようにしたり、レビュー必須としたりすることで特定のブランチが不当に変更されることを防ぎます。&lt;/p&gt;
&lt;p&gt;(当該リポジトリでは masterブランチに対し branch protection は設定されていましたが、私が管理者権限を持っていたのでpushできてしまいました。)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule&quot;&gt;ブランチ保護ルールを管理する - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&quot;include administrators&quot; を有効にする&lt;/h2&gt;
&lt;p&gt;GitHubのbranch protectionの設定の中で、&quot;include administrators&quot; (管理者を含める) という項目が設定できます。
これにより、管理者権限を持つ人であっても、branch protectionのルールが適用されるようになります。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches#include-administrators&quot;&gt;保護されたブランチについて - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;ローカルのGit Hooksでmaster/mainへのpushを制限する&lt;/h2&gt;
&lt;p&gt;gitには特定の操作の前後にスクリプトを実行できるhooksという機能があります。
hooksは、グローバルに有効なスクリプトを指定することもできるので、これを用いて以下のような設定を記述します。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;~/.gitconfig&lt;/code&gt; にグローバルに有効なhooksのディレクトリを指定&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;~/.gitconfig&lt;/code&gt; に以下のように記述することで、そのコンピュータでgitコマンドを実行したとき、常に &lt;code&gt;~/.config/git/hooks&lt;/code&gt; 以下のhooksが参照されるようになります。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[core]
        hooksPath = ~/.config/git/hooks
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;~/.config/git/hooks/pre-push&lt;/code&gt; にmaster/mainブランチへのpushを禁止するよう記述 / ローカルフックを呼び出すよう記述&lt;/h3&gt;
&lt;p&gt;グローバルなhooksに指定されたディレクトリの下に、実行権限をもつ &lt;code&gt;~/.config/git/hooks/pre-push&lt;/code&gt; というファイルを配置し、以下のような記述をします。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash -e

lines=&quot;$(cat)&quot;

# branch protection
# 標準入力 $lines にブランチ名などが渡される
# $lines をもとに、master/mainブランチへのpushであれば、終了コードを1としてpushを中断
function restrict_master_push() {
  echo &quot;$lines&quot; | while read local_ref local_sha1 remote_ref remote_sha1
  do
    if [[ &quot;$remote_ref&quot; = &quot;refs/heads/master&quot; ]]; then
      echo &quot;Do not push to master branch!!!&quot; 1&gt;&amp;#x26;2
      exit 1
    fi

    if [[ &quot;${remote_ref}&quot; = &quot;refs/heads/main&quot; ]]; then
      echo &quot;Do not push to main branch!!!&quot; 1&gt;&amp;#x26;2
      exit 1
    fi
  done
}

case &quot;$(git config remote.origin.url)&quot; in
  # 自分しか使わないリポジトリなど、master/mainにpushしてよいものはskipするようにする
  &quot;git@github.com:yammer/dotfiles.git&quot; )
    echo &apos;skip restrict_master_push()&apos; 1&gt;&amp;#x26;2
    ;;
  * )
    restrict_master_push
    ;;
esac


# kick local hooks
# グローバルにgit hooksを指定してしまうと、各リポジトリのhooksは実行されない
# そこで、このシェルスクリプト内で、各リポジトリのhooksを読み込んで実行するようにする
git_root=`git rev-parse --show-superproject-working-tree --show-toplevel | head -1`
hook_name=`basename $0`
local_hook=&quot;${git_root}/.git/hooks/${hook_name}&quot;

if [ -e $local_hook ]; then
  echo &quot;$lines&quot; | bash &quot;$local_hook&quot; $*
  exit &quot;$?&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;~/.config/git/hooks&lt;/code&gt; 以下の他のhooksにも、ローカルフックを呼び出すよう記述&lt;/h3&gt;
&lt;p&gt;以下のファイル名の実行ファイルを作成し、スクリプトを記述します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/applypatch-msg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/commit-msg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/fsmonitor-watchman&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/post-update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/pre-applypatch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/pre-commit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/pre-merge-commit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/pre-rebase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/pre-receive&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/prepare-commit-msg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/push-to-checkout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.config/git/hooks/update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash -e

lines=&quot;$(cat)&quot;

# anything

# kick local hooks
# グローバルにgit hooksを指定してしまうと、各リポジトリのhooksは実行されない
# そこで、このシェルスクリプト内で、各リポジトリのhooksを読み込んで実行するようにする
git_root=`git rev-parse --show-superproject-working-tree --show-toplevel | head -1`
hook_name=`basename $0`
local_hook=&quot;${git_root}/.git/hooks/${hook_name}&quot;

if [ -e $local_hook ]; then
  echo &quot;$lines&quot; | bash &quot;$local_hook&quot; $*
  exit &quot;$?&quot;
if
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>ユニコーン企業のひみつを読んだ</title>
      <link>https://memo.yammer.jp/posts/competing-with-unicorns</link>
      <pubDate>Wed, 18 Aug 2021 13:28:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/competing-with-unicorns</guid>
      <description>&lt;p&gt;8月も折り返し、いかがお過ごしでしょうか？8月は夏ですね。夏といえば夏休み、夏休みといえば宿題、読書感想文&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。ということで読んだ本の感想を綴ります。読書メモが下書きに溜まってしまっているので消化する試みです。&lt;/p&gt;
&lt;p&gt;書籍「ユニコーン企業のひみつ」を読みました。
本書はSpotify をはじめとするテック企業が、スタートアップのような勢いのある価値提供をどうやってスケールさせているかを説明する、ソフトウェア開発企業の組織づくりについて説明されたものです。&lt;/p&gt;
&lt;p&gt;今年の4月に日本語訳版が発売され、私の所属する会社の社内で広く読まれているようです。
本書籍内でも言及されるSpotifyモデルと呼ばれる組織体制を、社内でもいくつかの事業部で取り入れています。
そういった背景から書籍内で用いられている「スクワット」「チャプター」「トライブ」といった言葉が会話に出現するので、知っていないとコミュニケーションコストが高くなってしまいもったいないと感じ、7月の4連休にガッと読みました。&lt;/p&gt;
&lt;p&gt;書籍内では次のようなことが言及されています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;権限を持つ職能横断の小さなチーム(スクワット)によって組織を構成することで、自己組織化が進み、強力なデリバリーを届ける&lt;/li&gt;
&lt;li&gt;イテレーションを回そう&lt;/li&gt;
&lt;li&gt;スクワットが価値提供する際の障壁を、組織として排除することで、本質的な課題に注力できる&lt;/li&gt;
&lt;li&gt;今日のソフトウェア開発はマラソンであり、一朝一夕にて成立するものではない&lt;/li&gt;
&lt;li&gt;目的(ミッション)をかかげ、それに至る方法はチームが考えることが大切。スクラムをただやるだけでは開発者はチケットを消化する機械になってしまう。それでは競争に勝てない&lt;/li&gt;
&lt;li&gt;会社組織におけるこれらの事柄は文化と深い関わりがある。文化の醸成も重要&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;書籍の内容を通して、マネジメントを行う立場ではない一介のジュニアエンジニアとしては、次のことがまず自分にできることに思います。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;そういた背景をもって組織づくりがされていると知る&lt;/li&gt;
&lt;li&gt;目的を見て本質的な課題解決には何が必要かを考える&lt;/li&gt;
&lt;li&gt;局所最適化しない。会社として価値提供するためには自分の仕事を限定しない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;より良いサービスを届けるために文化は維持したまま、構成やあり方を変革し続けられる柔軟な組織は魅力的ですし、そういった組織の一翼を担う人として力が発揮できるようになりたいものです。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;昔は宿題を最終日にまとめてやってやる人間で、宿題の定番である読書感想文もあまり好んでおりませんでした。そんな人間も10年したら備忘録や思考整理のために自主的に読書の感想をWebに投稿しているのだから不思議です。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>アプリケーションをつくる英語を読んだ</title>
      <link>https://memo.yammer.jp/posts/english-for-apps</link>
      <pubDate>Wed, 14 Jul 2021 14:54:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/english-for-apps</guid>
      <description>&lt;p&gt;会社の先輩に教えていただいた「アプリケーションをつくる英語」を読んだ。&lt;/p&gt;
&lt;p&gt;この本はアプリケーション開発においてUIに表示される言葉を中心に、それらを英語でどう表現すればよいかのヒントが書かれている本である。
三部構成で前半の二部は辞書的に単語や表現が紹介され、最後の一部が読み物になっている。&lt;/p&gt;
&lt;p&gt;前半の辞書的な部分は、プログラムを書く中で命名に迷ったり、エラーメッセージを書いたりするときに役立ちそうだった。
紹介されている単語や言い回しは比較的厳選されている。
自分の表したいニュアンスの言葉が確実にあるわけではないと思うが、ソフトウェアやUIに関係する言い回しに絞って書かれている。
迷ったときには和英辞書と合わせて、本書のPDF版を検索して参照したい。&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;後半の読み物のなかでは、35.3.2節 キャピタリゼーション (どの文字を大文字にするか) が特に気になった。&lt;/p&gt;
&lt;p&gt;恥ずかしながら本書を読んで明確なルールを初めて知ったのだが、文頭を大文字にするセンテンススタイル (通常の文に用いられる) の他に、より大文字にする単語数が多いタイトルスタイル/ヘッドラインスタイルと呼ばれるスタイルがある。
名前の通り本のタイトルなどに使われるスタイルで、以下のようなルールがある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;名詞、形容詞、副詞、代名詞はキャピタリゼーションする&lt;/li&gt;
&lt;li&gt;文の最初と最後の単語はキャピタリゼーションする&lt;/li&gt;
&lt;li&gt;冠詞 (a、an、the) と接続詞 (and、butなど) はキャピタリゼーションしない。ただし文の最初と最後の場合はする&lt;/li&gt;
&lt;li&gt;4文字以内の前置詞 (at、by、for、inなど) はキャピタリゼーションしない。ただし文の最初と最後の最後の場合はする&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div style=&quot;text-align: center; width: 100%; color: #505050; font-size: 14px;&quot;&gt;
(アプリケーションをつくる英語 西野竜太郎著 p262)
&lt;/div&gt;
&lt;p&gt;たとえばPCのGUIアプリケーションであればウィンドウのタイトルやメニューバーなどにタイトルスタイルが用いられている場合もあるだろう。
例えばREADMEの章ごとのタイトルなどにも用いられるかもしれない。&lt;/p&gt;
&lt;p&gt;UIなどにおいては完全な文を書くというシチュエーションと同じかそれ以上に単語や連文節で物事を表す機会があるだろうから、どういった規則で表せれば良いかのルールを学べたのはありがたい。&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;後半の読み物の部分はそれほど分量がなくすぐに読めて、前半の辞書的な部分は長く使える、ひと粒で二度美味しい本だった。
コンピュータと戯れている限り英語とは離れられないので、もっと仲良くなっていかねばならない。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ソフトウェアは幽霊などではない。👻</title>
      <link>https://memo.yammer.jp/posts/software-is-not-ghost</link>
      <pubDate>Wed, 07 Jul 2021 00:15:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/software-is-not-ghost</guid>
      <description>&lt;p&gt;ソフトウェアを開発していると、ときどき幽霊に出会うことがある。正確にはまるで幽霊のしわざかに思えるような謎の挙動に悩まされるときがある。&lt;/p&gt;
&lt;p&gt;実際には幽霊などおらずコンピュータは書かれたとおりに動作しているだけで、さらに大抵は自分がプロトコルや仕様を把握していないか誤ったプログラムを書いているのだが。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;幽霊&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1412326675157688326?ref_src=twsrc%5Etfw&quot;&gt;July 6, 2021&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; width: 100%; color: #505050; font-size: 14px;&quot;&gt;
  これは私がOAuth2.0の仕様を把握していなかったが故に謎と思った挙動になやまされたとき。
&lt;/div&gt;
&lt;p&gt;複数の要因が重なっていたりして挙動の説明がすぐにはつかないとき、原因を追求するためにだいたい次のようなことをする。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原因を考える (現状を整理する、アタリをつける)&lt;/li&gt;
&lt;li&gt;挙動を確認するためにプログラムを実行する (手を動かす)&lt;/li&gt;
&lt;li&gt;仕様やドキュメント等を調べる&lt;/li&gt;
&lt;li&gt;人に聞く&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ここでは特に1つめの原因を考える事と2つめの手を動かす事について注目する。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
これらは、手を動かさないとわからない事を考えても意味は無いし、逆に無鉄砲に手を動かしても意味はない。現状を整理すること、アタリをつけること、手を動かしてみること、これらを組み合わせてやっていく必要がある。&lt;/p&gt;
&lt;p&gt;しかしながら特に昨日の私は原因を考えることと手を動かすことの比率が悪かった。またそもそも、目下の謎な挙動に対峙するとき、あまり自分の行動を分解して自らで認識せず全部一緒くたにしてやっているところがある。それですぐ解決できれば良いが、深みにハマったときに困る。&lt;/p&gt;
&lt;p&gt;二分探索的に考えていた筈が条件に漏れがあったり、試せばすぐにわかったことを最後まで放置していたりする &lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; のはこういったところに原因があるかもしれないと思っていて、だとすると改善の余地がある。&lt;/p&gt;
&lt;p&gt;そこで、次に対峙するときは今整理してアタリをつけるべきなのか、情報が足りないから手を動かすべきなのか、自分の現状を認識して意識的に切り替えることを試してみたい。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;
そのとき脳内で私が発すべき言葉は「現状を整理したいのか？新たな情報を得たいのか？ (=手を動かすべきか) 」という二択の自らへの問いかけである。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;3 のドキュメントを調べるという行為についても英語の仕様書をさくっとしっかり理解できるようにするだとかライブラリのコードを読み込むといった部分ががまだまだだし、4の人に聞くという行為も業務の中で最適なタイミングを逃していたり状況を整理して伝えるのが下手で時間がかかったりと、結局全部未熟なので粛々とやっていくしかない。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;解決したあとだからそう思うだけかもしれないが。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;実際には脳の力をそんなところに使う余裕はないのかもしれない。一方で業務でエンジニアリングに取り組むなら、時間的な見積もりをすべきである点と、再現可能な手法で行動して成果をあげるために自分の状態を認識するのは大切だろう点から、無心に対峙するのではなく上記の方法を試してみるべきだと感じた。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>初出社、ワクチン接種</title>
      <link>https://memo.yammer.jp/posts/20210624</link>
      <pubDate>Thu, 24 Jun 2021 14:19:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20210624</guid>
      <description>&lt;p&gt;日記です。雑多なトピックが以下に続きます。&lt;/p&gt;
&lt;p&gt;4月に入社した会社に、今日はじめて出社しました。
新型コロナウィルスのワクチン接種が主な理由で、くわえて同期をはじめとして何人かに出会うなどしました。&lt;/p&gt;
&lt;p&gt;今日の主なイベントであるワクチン接種ですが、大変スムーズで拍子抜けしました。
受付をして打つのは一瞬、15分経過観察しておわり。
職域接種のためいわゆるモデルナ筋注といわれるものを打って今は9時間ほど、腕が重いですね。&lt;/p&gt;
&lt;p&gt;社の方々と会うのはちょっと緊張。
人との接触は抑える必要もあるのであまりたくさん会話できるわけでもなく、会えていない人もたくさんいて、それらは未来の機会に託しました。
新型コロナウィルスが一日でも早く収束することを願います。&lt;/p&gt;
&lt;p&gt;初出社してみたものの、持っていく荷物がまだあんまりまとまっていないですね。
バッグが重く、荷物も取り出しづらく、もうちょっと減らしたいです。
16インチMacBookは家で使うには最高なんだがなあ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今日を経て、出社は大変だなという気持ちとともにリモートワーク環境の有り難さを改めて感じます。
出社を前提にしていない場所に住んでることもあり、会社までは2時間弱かかります。
通勤ラッシュを避けれたものの人出は多く、ちょっとこれが毎日は厳しい気がします。&lt;/p&gt;
&lt;p&gt;最近、社会人になって最初の仕事がリモートワークでは社会人としての能力が身につかないという話をいただきました。
私は社会人をまだ2ヶ月しか経験していないので社会人としての能力が何を指すのかも、リモートワークしか経験していないのでその真偽も、毎日の出社に使うエネルギーやコストが有用でそれだけの価値のあるものかどうかもわかりません。&lt;/p&gt;
&lt;p&gt;ただしリモートワークは、コミュニケーションの工夫や自己管理が求められる反面、出社しないことで体力的/時間的な余裕はきっと大きいでしょうから、それを有効に生かしていかねばという思いです。&lt;/p&gt;
&lt;p&gt;そんなこんなで会社に行った報告です。
次の出社もワクチン接種でしょうか。
その頃には梅雨が明けていますかね。&lt;/p&gt;</description>
    </item>
    <item>
      <title>curldocというWeb APIの仕様書形式 兼 モックサーバを作っている</title>
      <link>https://memo.yammer.jp/posts/curldoc-development</link>
      <pubDate>Mon, 21 Jun 2021 00:40:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/curldoc-development</guid>
      <description>&lt;p&gt;こんにちは。最近は会社の技術研修を粛々と受けています。
6月に入ってからはRailsチュートリアルを進めていて、ちょうど先週に終わりました。Railsは大変多機能であるとヒシヒシ感じています。
Ruby自体も今まで書いたことがなかったので、私の経験のある言語とは結構毛色が違っていて面白い気分です。
残業も特になく給料をいただきながら勉強している謎の身分ですが、権利をありがたく享受してスーパーエンジニアに成長したいと思います。&lt;/p&gt;
&lt;p&gt;そんなこんなとは別で、趣味で最近作り始めたのがcurldocというツールです。&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://github.com/yammerjp/curldoc.git&quot;&gt;curldoc&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;curldocのcurlはコマンドの&lt;a href=&quot;https://curl.se&quot;&gt;curl&lt;/a&gt;から来ています。
平たく言うと、curlコマンドとそのレスポンスを記述したMarkdownファイルを読み込んで立ち上がるモックサーバを作っています。&lt;/p&gt;
&lt;p&gt;そもそもcurlはHTTPリクエスト&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;を送ることができるコマンドですが、実はこれ、ただ単なるコマンドだけでなく、HTTPリクエストを表す汎用的なフォーマットなのではないかと思っています。
PostmanやChrome開発者ツールにも、送信したリクエストをcurl形式で書き出す機能があったりします。&lt;/p&gt;
&lt;h2&gt;curldocの仕様書の形式&lt;/h2&gt;
&lt;p&gt;これをもとに、curlコマンドとその実行結果を書いたら簡易的なAPI仕様書になります。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
例えば次のような、リクエストとレスポンスのペアをひたすらMarkdownファイルに記述します。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot;&gt;

リクエストを以下に記す。

```curldoc-request
curl http://localhost:3000/hello --header &apos;Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l&apos;
```

レスポンスを以下に記す。

```curldoc-response
{
    &quot;message&quot;: &quot;hello&quot;
}
```

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この形式のよいところは2つあります。&lt;/p&gt;
&lt;h3&gt;シンプル&lt;/h3&gt;
&lt;p&gt;１つ目はシンプルであることです。
curlコマンドは前述のようにGUIアプリケーションから書き出せるし、広く普及しているフォーマットでもあります。&lt;/p&gt;
&lt;p&gt;APIドキュメントを記述する形式としては例えばSwaggerなどが既にあります。
大変良くできたツールであると思いますが、どうしても記法を学んだり、対応するツールがある言語やフレームワークの上でしか使えなかったりと、場合によっては多機能すぎることもあるでしょう。
小さなアプリケーションを作る場合やハッカソンで素早く作る場合、社内向けツールでドキュメント整備の優先順位が低い場合など、APIの仕様を簡単にテキストにまとめるほうが良い場合もあるのではないでしょうか。
curldocはまさにそれです。
なるべく知識を必要とせず、簡単に、しかし齟齬無く最低限の要求を満たすAPIドキュメントの形式がcurldocです。&lt;/p&gt;
&lt;p&gt;シンプルであるからこそ、JSONだろうがXMLだろうがHTMLだろうがHTTPであれば自由に記述できます。&lt;/p&gt;
&lt;h3&gt;実行可能&lt;/h3&gt;
&lt;p&gt;2つ目は実行可能であることです。
curlコマンドは本来はコマンドですから実行可能です。
シェルに貼り付けてエンターを押せば試せます。
HTTPサーバを開発してデバッグする時、テストする時、既に開発されたものを使ってみるとき、コピペしてエンターを押すだけで試せるなんてなんと素晴らしい仕様書でしょうか。&lt;/p&gt;
&lt;h2&gt;片手落ちの「実行可能」の片手を作る&lt;/h2&gt;
&lt;p&gt;ここまでは単に「curlコマンドの形式でドキュメントを記述すると楽だよ」という話でした。
しかし、2つ目の実行可能であるという点は片手落ちです。
もともとAPI仕様書はクライアント側とサーバ側で認識を合わせるため、双方のためにあります。
しかしながらcurlコマンドはクライアントなので、実行可能であるのは片方の立場だけです。
サーバを開発する人はcurlコマンドで確認できますが、クライアントを開発する人は実際のサーバができあがるまで実行できません。&lt;/p&gt;
&lt;p&gt;そこで出現するのがcurldocです。
curldocはAPI仕様の書かれたMarkdwonファイルを元にモックサーバを立ち上げます。
Markdownファイルに書かれたものと同様のリクエストが来たら、対応するレスポンスを返すだけのモックサーバです。
curldocというアプリケーションによって、上記の形式のAPI仕様書が、クライアントサイドにとってもサーバサイドにとっても実行可能になることでしょう。&lt;/p&gt;
&lt;p&gt;モックサーバなので、開発にもテストにも用いることができるはずです。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;これから&lt;/h2&gt;
&lt;p&gt;まだ作りかけのアプリケーションについて雄弁に語ってしまいました。
現状でも一応ベーシックな機能としては動いていて、Markdownファイル上でHTTPのヘッダやボディを指定すると比較してくれたりします。
とはいえやりたいことは以下のようにまだまだあります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON形式のリクエストボディの比較を柔軟に行う&lt;/li&gt;
&lt;li&gt;指定されなかったHTTPレスポンスヘッダをよしなに埋める&lt;/li&gt;
&lt;li&gt;ライブラリとして提供できるインタフェースを追加する&lt;/li&gt;
&lt;li&gt;ドキュメントを書く&lt;/li&gt;
&lt;li&gt;npm publishする&lt;/li&gt;
&lt;li&gt;curlオプションのサポートを増やす&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;頑張って作るぞ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/curldoc.git&quot;&gt;https://github.com/yammerjp/curldoc.git&lt;/a&gt;&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;curlはHTTPに限らず様々なプロトコルをサポートしているようです。なんでも出来すぎてびっくりするくらい。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;もともと5月末にハッカソン的にWebアプリケーション開発をやったときの感想から生まれたアイデアのツールです。サーバサイドとフロントエンドを別の人間が開発するとき、APIの認識をさくっとあわせるにはcurlコマンドによるリクエスト例を記述していく方法が結構はかどりました。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;モックサーバを必要とするのはクライントアプリケーションだろう。→クライアントアプリケーションといえば特にWebではJavaScriptだろう。→ JavaScriptのテストで用いるならJavaScriptから起動できたほうが良いよねということでNode.jsで作っています。コマンドだけでなくライブラリとして提供したいと思っています。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;別に作っているAtomPubのクライアントのテストが結構汚くて、JSONではないAPIクライアントのモックサーバが欲しくて作っている側面もあります。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>リモートワークの馴染む、4月の新卒研修 (GMOペパボ)</title>
      <link>https://memo.yammer.jp/posts/pepabo-11th-training</link>
      <pubDate>Tue, 11 May 2021 13:38:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/pepabo-11th-training</guid>
      <description>&lt;p&gt;2021年4月1日にGMOペパボ株式会社 (以下ペパボ) に入社しました。&lt;/p&gt;
&lt;p&gt;これからソフトウェアエンジニアとして成長し活躍することを夢見てやる気に満ち溢れています。
その第一歩として4月9日から4月30日までの約3週間、全職種で取り組むペパボの新卒研修に参加したので感想を記します&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。
ええ、それはその、大変楽しい研修期間でした。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/pepabo-11th-training-ogp.png&quot; alt=&quot;新卒メンバー全員のイラスト&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; width: 100%; color: #505050; font-size: 14px;&quot;&gt;
CS研修でお世話になった&lt;a href=&quot;https://twitter.com/_wtmy&quot;&gt;ワタミユ&lt;/a&gt;さんが書いてくださった新卒の我々のイラスト
&lt;/div&gt;
&lt;h2&gt;リモートワークでうまくやる&lt;/h2&gt;
&lt;p&gt;ペパボは2020年6月にリモートワークを基本とした働き方に移行し、今年の研修は全てオンラインで実施されました。
私自身、入社後にまだ一度も出社していません。&lt;/p&gt;
&lt;p&gt;リモートワークの環境で新卒入社することに少なからず不安はありました。
大学のときはオンラインによるコミュニケーションのとりにくさや物理的な距離感を強く感じることも多かったからです。&lt;/p&gt;
&lt;p&gt;しかしながらその些細な不安は全くの杞憂で、リモートワークを前提として、それを当たり前のものとして過ごしていました。
ただただ、たった一本のイーサネットケーブルを介してよくもこれだけの情報や感情をやりとりできるものだと驚きを感じています。&lt;/p&gt;
&lt;h2&gt;情報がオープンであること&lt;/h2&gt;
&lt;p&gt;リモートワークでうまくやれている理由の一つとして社内の情報がオープンであることが挙げられます。
&lt;a href=&quot;https://tech.pepabo.com/2021/03/18/documentation-in-pepabo/&quot;&gt;社内規定や手続・制度の情報にアクセスしやすい&lt;/a&gt; だけでなく、サービスに関する情報 (お客様の個人情報などは除く)、はたまた&lt;a href=&quot;https://hr.pepabo.com/column/2020/02/07/3330&quot;&gt;人事評価資料&lt;/a&gt;までもが社内でひろく公開されています。&lt;/p&gt;
&lt;p&gt;オンラインで活動する上で情報の非対称性は非常につらくて、大学時代に研究室で「昔の研究に関する情報が必要だったら声をかけて」と言われていたがそもそもどんな情報があるのかがわからない.. といった経験をした身からすると、入社後にすぐに様々な情報にアクセスでき会社のことをよく知れることはリモートワークでの安心感を生みました。&lt;/p&gt;
&lt;h2&gt;Slackの流れる早さ&lt;/h2&gt;
&lt;p&gt;物理的なオフィスに出社していない私は、Slackに出社していると言っても過言ではないでしょう。
Slackでの会話が活発で円滑であるからこそ、オンラインでも距離感を感じずにコミュニケーションをとることができます。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/pepabo-11th-training-morning.png&quot; alt=&quot;出社に相当するSlackのメッセージ&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; width: 100%; color: #505050; font-size: 14px;&quot;&gt;
出社の様子
&lt;/div&gt;
&lt;p&gt;研修についてもSlackをフルに活用しています。
講義をきく機会も多かったのですが、そういったときに講義の解釈を話しあったり、他の人が知る関連情報を得られたり、些細な疑問を話してみたりといった会話が生まれます。
同期の&lt;a href=&quot;https://twitter.com/yagijinjin&quot;&gt;やぎじん&lt;/a&gt;の言葉を借りるとまさに「&lt;strong&gt;隣の人と話しながら講義を受けることができる、新しい研修のかたち&lt;/strong&gt;」でした。&lt;/p&gt;
&lt;p&gt;講義を担当されたパートナー&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;の方にも「リアクションがあるので話しやすい」と言っていただけたし、ただ聞いてメモをするより話も広がり講義を振り返る補足資料にもなり、加えて記憶の定着も良いように感じ、楽しいだけでなく大変有意義な時間でした。
オンラインだからこそできた研修であったように思います。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/pepabo-11th-training-res.jpg&quot; alt=&quot;講義中にたくさんのコメントが付き、返信件数が1時間で100件を超えているSlackのスクリーンショット&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; width: 100%; color: #505050; font-size: 14px;&quot;&gt;
1時間程の講義でどんどん流れるSlack
&lt;/div&gt;
&lt;h2&gt;意識していたこと&lt;/h2&gt;
&lt;p&gt;リモートワークの環境において、新卒として入社した自分もうまくやるために「自分の感情・状況を相手に伝える」ことを意識していました。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;例えばMeetやZoomでは伝わりづらいので大きく🙆‍♂️と意思表示するなどジェスチャーしたり。
日報では自分の感情を正直に書くことも、困っていることや疑問があったら自発的にSlackに書き込むこともその一つです。
発言しやすいように複数のチャネルを使いこなす意味で、Slackの個人用パブリックチャンネルを作ってみたりもしました。
ほかには&lt;a href=&quot;https://note.com/ayanck/n/n976ecaf220c4&quot;&gt;背景で遊んだ&lt;/a&gt;のも新卒11期生のパートナーの方々と仲良くなりたい気持ちだったと思います。&lt;/p&gt;
&lt;p&gt;オンラインではどうしても些細な気持ちの変化は伝わりづらいし一対一でコミュニケーションをする機会も減ってしまいます。
だからこそ自己開示が必要であると思うし、より自分から状況や感情を伝える必要があります。&lt;/p&gt;
&lt;p&gt;新卒研修においてオンラインでのコミュニケーションが円滑に進んだのはきっと、入社前から培われたペパボの文化と既に日常となっていたリモートワークの土壌があったからでしょう。
リモートワークには様々なツールの活用や制度の整備ももちろんですが、個々人がオンラインに即したコミュニケーション方法や振る舞いに適応していくことがとても大切であると感じました。&lt;/p&gt;
&lt;p&gt;オンラインに即したコミュニケーションはきっと社内でたくさんの人が実践していることではないかと思います。
他の人や同期を見て学び、真似て、上記のような意識していたことに繋がりました。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;とても楽しく充実した一ヶ月でした。
研修の中で新しく学んで吸収すること、業務の難しさとそれに取り組まれるパートナーの方々の凄さを知ることなど、多面的な切り口からの研修を通して、目的とされていた「ペパボで働く土台をつくる」は達成されたと思います。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;入社を歓迎してくださったパートナーの皆さん、研修を企画・実施してくださったパートナーの皆さん、一緒に盛り上げてくれた同期の仲間、本当にありがとうございました。&lt;/p&gt;
&lt;p&gt;一ヶ月働いた実感として、ペパボの人々はとてもおもしろくて親切であるし、サービスを使う意味でも働く意味でもおすすめできる会社です。&lt;/p&gt;
&lt;p&gt;技術研修は5月以降も続きます。
サービスを、ペパボを、世の中をもっとおもしろくできるよう&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;、まずは目の前の研修に一つ一つ取り組んでいきます。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;記事内であまり触れていない研修内容については他の人が書いたブログが参考になります。「&lt;a href=&quot;https://note.com/asuka_okochi_131/n/na15e6e7dbcde&quot;&gt;🌸【21卒】ペパボでの新卒研修を終えて🌸｜きなこ｜note&lt;/a&gt;」 や 「&lt;a href=&quot;https://zuruzurura.men/blog/2021-05-10-%E7%A4%BE%E5%86%85%E7%A0%94%E4%BF%AE%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8A/&quot;&gt;社内研修振り返り | zuruzurura.men&lt;/a&gt;」 など。 その他にも子育てと新卒研修に触れたブログ記事「&lt;a href=&quot;https://note.com/rimomonga/n/n1fb576224805&quot;&gt;子育て新卒、ペパボで働き始めて1ヶ月｜うえだり｜note&lt;/a&gt;」も読み応えがあります。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;ペパボでは働く仲間のことをパートナーと呼びます。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;入社前にも教えていただき、新卒研修の中でも触れられていたブログ記事 (&lt;a href=&quot;https://diary.shu-cream.net/2020/07/06/01.html&quot;&gt;自分の気持ちを正しく表現する | けんちゃんくんさんのWeb日記&lt;/a&gt;)がもとになっています。新卒の私が正直な感情を伝えるとそれを受け止めてくださるパートナーの方々がいることは本当にありがたいことです。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;各研修内容のそれぞれに目的や目標が設定され何のために研修に参加するかが明確であったこと、定期的に時間を設けて振り返ることなど、研修を有意義なものにするための工夫が随所に凝らされていたと振り返りながら感じました。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;「もっとおもしろくできる」は&lt;a href=&quot;https://pepabo.com/company/vision/&quot;&gt;ペパボの企業理念&lt;/a&gt;)です。 &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>ブログをNext.jsに置き換える</title>
      <link>https://memo.yammer.jp/posts/blog-with-nextjs</link>
      <pubDate>Fri, 07 May 2021 13:07:57 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/blog-with-nextjs</guid>
      <description>&lt;p&gt;ゴールデンウィーク明けの平日、いかがお過ごしだろうか。
私の場合は新卒研修のブログ記事を書こうと思ったものの、その記事を投稿するためのブログを弄っているうちにゴールデンウィークが終わってしまった。&lt;/p&gt;
&lt;p&gt;そんなわけでここ数日は、「そろそろちゃんと触るか〜」と思っていたNext.jsを使ってこのブログを作り変えていた。
見た目は似ているけど中身はイチから作ったので別物である。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;機能追加をしたいことがあったりしたので前々からJavaScriptのフレームワークに載せ替えたいと思っていて、やっと腰が上がった次第。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
本当は1,2日でサクッと終わらせてしまってブログ投稿用のエディタを作ろうと思っていたのだけど全然思うようには進まず、結局閲覧画面だけ作って終わった。&lt;/p&gt;
&lt;p&gt;以下にここ数日の感想をいくつかの話題に分けて記す。&lt;/p&gt;
&lt;h3&gt;ブログのデザイン&lt;/h3&gt;
&lt;p&gt;デザインは変わっていないようで細かいところが少し変化したり、機能追加されていたりする。
つくりながら他のブログを眺めるなどして、見やすそうな部分を参考にしたりした。&lt;/p&gt;
&lt;p&gt;具体的には例えば、記事ページ末尾にある隣の記事へのリンクについて。
よくこういったリンクは next / prev とやってしまいがちだけれど、どっちが古い投稿へのリンクでどっちが新しい投稿へのリンクかわからなくなったりするので、「古い記事」「新しい記事」と書いてあるのをみて「良いな」と思ったので真似た。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/blog-with-nextjs-neighbor-articles-link.png&quot; alt=&quot;記事ページ末尾の隣の記事へのリンクの新旧比較&quot;&gt;&lt;/p&gt;
&lt;p&gt;ブログのデザインといえば、完成の見た目が定まっていなかったので結構作っては壊してを繰り返していたのは効率が悪かったのかもしれない。
例えば記事一覧ページは記事ごとにカバー画像を表示するように作ってみたあと、やっぱりみづらそうで止めた。
figmaなどを使って事前にどんなものを定めるなど、そういうのをやったほうがよかったかもなあ。
(やったことない。)&lt;/p&gt;
&lt;h3&gt;remarkがよき&lt;/h3&gt;
&lt;p&gt;Hugoから置き換えた理由の一つに、Markdownのパースを改造できるようにしたかったからというモチベーションが有った。
今回使ったMarkdownパーサのremarkがよく出来ていて、プラグインを追加するとパース時の機能や記法を追加できる。
既によくあるMarkdown記法は既存のプラグインで対応できるし、新たな記法を追加するときはプラグインを作ってMarkdownやHTMLのASTに介入できるようで夢が広がる。&lt;/p&gt;
&lt;p&gt;本当はここらへんを重点的に開発して記事の執筆時に使える記法や記事の出力時の見た目をもっとリッチにしたかったのだけど、Next.jsでブログを作る時点で時間切れになってしまった。&lt;/p&gt;
&lt;h3&gt;Next.jsのよさ&lt;/h3&gt;
&lt;p&gt;Nuxt.jsみたいにフォルダ構成をはじめとした規約が定まっていて、秩序を感じるのはよい。&lt;/p&gt;
&lt;p&gt;簡単なAPIが書けるのもよい。Vercelを使えば一緒にデプロイもできそうで、ここらへんは開発元がホスティングサービスをやっている強みだなと感じた。&lt;/p&gt;
&lt;p&gt;getStaticPropsとかgetServerSideProps、getStaticPathsとかの関数があるのもよくて、何処に何を書けば良いのか、いつ何処で実行されるのかがわかりやすいのが良い。
Nuxt.jsではここらへんどうなってたっけ？configでSPAかSSRかSSGか選べたのは覚えているんだけど...&lt;/p&gt;
&lt;h3&gt;ReactとJSXの記法への小言&lt;/h3&gt;
&lt;p&gt;Reactに触ったのも久しぶりで、JSXと後述するCSS-moduleに一言ずつ。&lt;/p&gt;
&lt;p&gt;JSXを久々に書いたがちょっと書きづらい。
特にDOMを条件分岐したいとき、その部分のJSXElementは変数に入れるのが良いのか最後のReturn文に埋め込むのが良いのか迷うなどした。
埋め込むとしたら即時実行関数の中でifを書くか三項演算子を使うかだと思うけど、どちらも記号だらけであんまり見やすい表記じゃなさそうと思った。
Vue.jsのv-ifとかのほうがみやすさを感じる。&lt;/p&gt;
&lt;p&gt;Vue.jsの独自記法を覚えなくていいといえばそうだけど、その意味で言えばVue.js/Nuxt.jsはJSX覚えなくていいからな。
(逆にJSXElementを繰り返すときは配列をmapできるのでスッキリ書けて気持ちいい。)
記法は慣れの要素が多分に含まれるので、小言を言っても仕方ないね。&lt;/p&gt;
&lt;h3&gt;CSS-moduleはつらくないか？&lt;/h3&gt;
&lt;p&gt;前項のJSX記法は好みの問題と思うが、一方でCSSの適用方法については根が深い。
もともとReact/Next.jsでコンポーネントにCSSを適用するならCSS-moduleかCSS in JS (Styled components)の2種類の方法から選ぶらしい。
特にNext.jsはパフォーマンスの理由でCSS-moduleを推してるのだけどこれがあんまり良いと思えなかった。
一般的なCSSはセレクタを使って適用する要素を決めるが、CSS-moduleはCSSのスタイルの集合(&lt;code&gt;{&lt;/code&gt;から&lt;code&gt;}&lt;/code&gt;まで)を、HTML要素で指定して指し示すような形になる。&lt;/p&gt;
&lt;p&gt;CSSが多重に適用されることはなくなるのでシンプルになるけれど、一方で宣言的に書けていたCSSの良さを殺しているのでは？と感じた。
あとメディアクエリが使えない/使いづらかったり、するのも気になった。
結局移行前のものを活かすという意味もあって、CSS-moduleもCSS in JSも使わずに1枚のCSSにすべてを書き込んで作っていて、途中でCSS-moduleで分割するかとなったのだけど上述のつらみを感じて止めてしまった。&lt;/p&gt;
&lt;p&gt;今回の開発を通して改めてVue.jsのシングルファイルコンポーネント好きだなあと感じた。&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;そんなこんなで予定がなくなってずっと家にいたゴールデンウィークだけれどコンピュータと仲良くなろうと遊んでいたのでよき休日だった。&lt;/p&gt;
&lt;p&gt;このブログへの機能追加はまだまだやりたいことだらけですが、もし見づらい、バグってる、勘違いしたなどあったらフィードバックをくださると喜びます。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;前はHugoのテーマに手を入れたものをNetlifyでホストしていたけど、今回はNext.jsとTypeScriptで作ったサイトをSSGしてVercelにホストしている。 どちらも記事はGitHub上にMarkdownで保存している。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;先月と先々月に作っていたバージョン管理システムのarcivは、とりあえず動くけどなんか動作が遅いよなという状態で放置されている... そっちはどうしようか... &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>融けるデザインを読んだ</title>
      <link>https://memo.yammer.jp/posts/tokeru-design</link>
      <pubDate>Thu, 29 Apr 2021 08:01:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/tokeru-design</guid>
      <description>&lt;p&gt;このまえ教えてもらった本、「融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論」(著: 渡邊恵太) を読んだ。
以下はその解釈と感想である。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E8%9E%8D%E3%81%91%E3%82%8B%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3-%E2%80%95%E3%83%8F%E3%83%BC%E3%83%89%C3%97%E3%82%BD%E3%83%95%E3%83%88%C3%97%E3%83%8D%E3%83%83%E3%83%88%E6%99%82%E4%BB%A3%E3%81%AE%E6%96%B0%E3%81%9F%E3%81%AA%E8%A8%AD%E8%A8%88%E8%AB%96-%E6%B8%A1%E9%82%8A%E6%81%B5%E5%A4%AA/dp/4861009383/ref=as_li_ss_tl?_encoding=UTF8&amp;#x26;qid=&amp;#x26;sr=&amp;#x26;linkCode=sl1&amp;#x26;tag=niche-22&amp;#x26;linkId=65214e156cf3fb0219ea72f5cc293b7a&amp;#x26;language=ja_JP&quot;&gt;融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論 | 渡邊恵太 |本 | 通販 | Amazon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本書では「自己帰属感」という言葉を通して良いインターフェイスとはどのようなものかを述べている。
自分の与えた動作に伴ってリアルタイムに反応があると自己帰属感が生まれ、自己帰属感が高まると&lt;strong&gt;身体が拡張したかのように思いのままに操作できる&lt;/strong&gt;ようになる。&lt;/p&gt;
&lt;p&gt;例えばキーボードは、慣れるまではひどく使いにくいが、慣れてしまえば文字を打つときに自然と手が動き自分の身体の延長のように扱える入力機器だと思う。
車だって自分で運転することに慣れてくれば車体感覚が身につき狭い道路でもなんとなく車を端に寄せたりできるようになる。
キーボードも車も、手で握るハンマー等よりよっぽど複雑な道具だけれど、慣れてしまえばそこそこの自己帰属感を得られるようになる。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;こういった自己帰属感の有無には&lt;strong&gt;自分が与える動作に対する遅延ない応答&lt;/strong&gt;が必要なようだ。
一方、動作の方向や方法は、慣れが要求できる範囲においては遅延ない応答ほどは重要度が高くなさそうに思う。
たとえば車のアクセルもブレーキもペダルを踏む動作だが加速と減速という正反対のものを扱うし、キーボードもボタンを押下することで抽象的な概念である文字の入力を行う。&lt;/p&gt;
&lt;p&gt;本書を読んだうえで、じゃあ&lt;strong&gt;自分がソフトウェア開発 (特にWeb開発) を行うときにどう活かせるか&lt;/strong&gt;というと結構難しい。
本書ではどうやって作るかやGUIにおいて何が良いのかを具体的に示しているわけではなくもっと抽象度の高い話をしている。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;その中で&quot;遅延&quot;がユーザに与える自己帰属感の低下はWeb開発でもイメージしやすいものだろう。
たとえば遅延ない応答の具体的な例といえば、いいねボタンを押したときに押した瞬間に表示を変更しサーバへのリクエストは裏で送るといった実装がその１つかもしれない。&lt;/p&gt;
&lt;p&gt;そういったユーザとのインタラクションにおいて遅延がいかにユーザに自分の思い通りに操作する感覚を失わせるかを知ることができた。
開発者からすると微々たる違いであるのにユーザには大きな違いとして現れることは意識して開発するとよいだろうと感じた。&lt;/p&gt;
&lt;p&gt;本書を読んだ解釈が「全然ちげえぞ！」と思ったら教えて下さい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;もちろん慣れが必要ないに越したことはない。しかしながらキーボードも車も、ユーザ体験が優れている設計かは別として、世界的に共通のインタフェースを備えているのは一定の自己帰属感が感じられる道具だからだろう。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;本書の「融けるデザイン」というタイトルにもなっている主題は「ハードウェアかソフトウェアといった違いに縛られず、自己帰属感という尺度をもとに人間と環境との相互的な作用を考えてプロダクトを設計しよう」といった話だと思う。しかしながらここでは画面内で描画されるWebブラウザとそれをタッチパネルやマウスやキーボードで操作する入力機器に限定した話を取り上げた。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>足でマイクのミュートを解除しよう for 在宅勤務</title>
      <link>https://memo.yammer.jp/posts/foot-switch-mic-mute</link>
      <pubDate>Tue, 27 Apr 2021 00:41:29 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/foot-switch-mic-mute</guid>
      <description>&lt;p&gt;私はいま、在宅勤務をしている。
特に研修中だからかオンライン通話の機会が多く、通話しながら作業や調べ物をするので、マイクのミュート/ミュート解除に手こずることに悩みを抱えている。
そんな中、ふとしたときに気づいたのである。「足が空いているではないか」と。&lt;/p&gt;
&lt;p&gt;家に左クリックが壊れたマウスが有ったのでこれをフットスイッチ代わりにして、押しているときだけミュート解除するようにしてみた。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;こちら、机の下に置かれた不審なマウスです。 &lt;a href=&quot;https://t.co/DWxn3oxcLM&quot;&gt;pic.twitter.com/DWxn3oxcLM&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1386699716356837380?ref_src=twsrc%5Etfw&quot;&gt;April 26, 2021&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;どのように実現しているかは後半の「&lt;a href=&quot;#%E3%81%A4%E3%81%8F%E3%82%8A%E3%81%8B%E3%81%9F&quot;&gt;つくりかた&lt;/a&gt;」に書く。&lt;/p&gt;
&lt;h2&gt;良いところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;細かくミュート/ミュート解除できる&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目論見どおりうまく動いており、概ね快適である。
鼻をすする音など些細な音が入らずに済むのがすこぶる良い。
例えば相槌をうちながらキーボードを打つときや、ZoomやGoogle Meet以外のウィンドウ・タブを操作しながら話すときなどに助かる。
スムーズにミュート解除できるので、些細なリアクションのときだけミュート解除するみたいなことができる。
スイッチを押したとき/離した時のタイムラグも (周りに聞く限り) 問題ないようでで常用できそう。&lt;/p&gt;
&lt;h2&gt;改善すべきところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ペダルが踏みづらい&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;良いところもある一方、まだ道半ばだと感じる部分もある。
例えばマウスの右クリックボタンは小さいため、少し足を離していると何処にあるかわからなくなる。
すると目視で確認しないと踏めないので発話がワンテンポ遅れる。
ピアノのペダルのようなもっと踏みやすいものに変えたほうがよさそう。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;慣れないので間違える&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ペダル操作は慣れが必要で、踏み忘れて話しはじめてしまったり、逆に足を外して音を立ててしまったりすることも有った。
「キーボードや手元のマウスを操作すること」「足でミュート解除すること」「話すこと」の3つを同時にやろうとすると頭の中がついていかずスムーズにできない。
慣れればペダル操作が無意識でできるようになることを期待しているのでしばらく使っていきたい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ミュート/ミュート解除のソフトウェア制御が怪しい&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;もうひとつ、ミュート/ミュート解除をソフトウェア的に制御する方法が怪しい。
macOSの仕様がよくわからないのだが、OS側でマイクをミュートにする方法が見つけられずボリュームを最小にすることで擬似的にミュートにしている。
アプリケーションの種類に左右されずに、さらにウィンドウがアクティブでないときも操作したいので、いまは OS 側の設定をシェルから叩いている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# マイクをミュート
$ osascript -e &quot;tell application \&quot;System Events\&quot; to set volume input volume 0&quot;
# マイクをミュート解除
$ osascript -e &quot;tell application \&quot;System Events\&quot; to set volume input volume 100&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今日Google Meetで話した感じではミュートされているようだったが、Zoomで試した感じだと最小でもすこし音が入っていた。
もし他にいい方法があれば知りたい。
(電子工作つよつよマンならマイクケーブルをスイッチで電気的に切断してミュートできそうだけれど、操作時のノイズなども出てきそうなので一旦ソフトウェア的に切り替える方式で考えている。)&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;働き始めて3週間、在宅勤務にはきっと在宅勤務なりのスキルが必要だなあと感じる。
たぶん自分がいままで属してきた他のコミュニティでは今の会社のようなオンラインコミュニケーションを取るのは難しかったように思う。
何が難しいのかは言語化しづらいのだが、きっと会社の中で今まで積み上げられてきた様々な知見や文化が関与していそう。&lt;/p&gt;
&lt;p&gt;在宅勤務なりのスキルとは、チャットコミュニケーションの円滑さや、オンライン通話のテクニックも含まれるだろう。
例えば画面越しでは感情が伝わりづらいので大きなリアクションをするとか、話し始めがかぶりやすいので細かいところでも誰かがファシリテーションしたり事前に挙手したりするとか、そういったことの積み重ねが大切に感じる。
その要素のひとつにミュートを使いこなすこともあって、 雑音を入れない意味でも大きなリアクションを伝える意味でもスムーズに切り替えられるとよさそう。
今回のペダルでの操作がうまい方法かわからないが、画面上のボタンだとミュート解除が遅れて困る機会がときどき有ったのでそれらを解消できるとよいね！&lt;/p&gt;
&lt;h2&gt;つくりかた&lt;/h2&gt;
&lt;p&gt;既にだいぶ書いたが、やっとここからつくりかたを説明する。&lt;/p&gt;
&lt;p&gt;今回の仕掛けは、macOS に接続した USB マウスと Karabiner-Elements というソフトウェアから成る。
&lt;strong&gt;足元に置いたマウスの右クリックを検知し、マウス押下時にミュート解除のシェルコマンドを、押下を止めたときにミュートのシェルコマンドを実行している。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/foot-switch-mic-mute-irasutoya.png&quot; alt=&quot;マウス押下時にミュートする仕組みの外観図&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;margin-top:0px; text-align:center; width:100%; color: #888888; margin-bottom: 20px;&quot;&gt;これは私がいらすとやの画像を使いたかったことを表す図です。&lt;/div&gt;
&lt;p&gt;さあ作っていこう。&lt;/p&gt;
&lt;h3&gt;1. Karabiner-Elements をインストール&lt;/h3&gt;
&lt;p&gt;Karabiner-Elementsはもともとキーボードの操作を書き換えるソフトウェアで、例えばCapsLockキーをCtrlキーに置き換えるだとか、Spaceキーを長押しするとShiftキーが押されたことにするといった設定ができる。
ついでにマウスの入力も扱えるので、今回は特定のマウスがクリックされた時にコマンドを実行するよう設定ファイルを書くことにする。&lt;/p&gt;
&lt;p&gt;まず &lt;a href=&quot;https://karabiner-elements.pqrs.org&quot;&gt;Karabiner-Elements のサイト&lt;/a&gt; からファイルをダウンロードしインストールする。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/foot-switch-mic-mute-security-and-privacy.png&quot; alt=&quot;macOS 環境設定のセキュリティとプライバシーの項目で、Karabiner-Elementsによる入力監視を有効化する&quot;&gt;&lt;/p&gt;
&lt;p&gt;初回起動すると、macOS のセキュリティ許可などを設定しろだとか再起動しろだとかいわれるはずなので従う。
以降はログインすると勝手に Karabiner-Elements も起動して、メニューバーに四角形のアイコン (&lt;img src=&quot;https://blob.yammer.jp/foot-switch-mic-mute-karabiner-icon.png&quot; style=&quot;width:1em; height:1em;&quot; /&gt;)が表示されて常駐する。&lt;/p&gt;
&lt;h3&gt;2. デバイスを有効化する&lt;/h3&gt;
&lt;p&gt;メニューバーの Karabiner-Elements アイコンをクリック &gt; Preferences... &gt; Devices タブを開く。&lt;/p&gt;
&lt;p&gt;この状態で足のスイッチにしたいマウス&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;をコンピュータに挿して、新たに表示されたデバイスの行の左端のチェックボックスを有効にする。
他デバイスのチェックボックスを有効にすると、他デバイスの入力も奪って設定を反映してしまう可能性がある。
入力を上書きしたいデバイスのみにチェックをいれること。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/foot-switch-mic-mute-devices.png&quot; alt=&quot;Karabiner-ElementsのDevicesタブで、当該のマウスにチェックを入れる&quot;&gt;&lt;/p&gt;
&lt;h3&gt;3. 設定ファイルを記述&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;~/.config/karabiner/assets/complex_modifications/mouse_mic_mute.json&lt;/code&gt; を作成し、次の内容を書き込む。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;{
  &quot;title&quot;: &quot;Unmute/Mute mic with clicking mouse&quot;,
  &quot;rules&quot;: [
    {
      &quot;description&quot;: &quot;Unmute/Mute with mouse button down/up&quot;,
      &quot;manipulators&quot;: [ {
        &quot;type&quot;: &quot;basic&quot;,
        &quot;from&quot;: {
          &quot;pointing_button&quot;: &quot;button2&quot;,
          &quot;modifiers&quot;: { &quot;optional&quot;: [ &quot;any&quot; ] }
        },
        &quot;to&quot;: [ {
          &quot;shell_command&quot;: &quot;osascript -e \&quot;tell application \\\&quot;System Events\\\&quot; to set volume input volume 70\&quot;&quot;
        } ],
        &quot;to_after_key_up&quot;: [ {
          &quot;shell_command&quot;: &quot;osascript -e \&quot;tell application \\\&quot;System Events\\\&quot; to set volume input volume 0\&quot;&quot;
        } ]
      } ]
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;設定をカスタマイズするとすれば、たとえば &lt;code&gt;pointing_button&lt;/code&gt; を &lt;code&gt;button1&lt;/code&gt; にすれば、左クリックを対象にできる。
その他の設定は&lt;a href=&quot;https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/&quot;&gt;公式の説明&lt;/a&gt;や &lt;a href=&quot;https://qiita.com/s-show/items/a1fd228b04801477729c&quot;&gt;Qiita の記事&lt;/a&gt; を参考に。&lt;/p&gt;
&lt;h3&gt;4. 設定を有効化&lt;/h3&gt;
&lt;p&gt;メニューバーの Karabiner-Elements アイコンをクリック &gt; Preferences... &gt; Complex modifications タブを開く。&lt;/p&gt;
&lt;p&gt;右下の「Add rule」を押し、「Unmute/Mute with mouse button down/up」を「Enable」する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/foot-switch-mic-mute-complex-modifications.png&quot; alt=&quot;Karabiner-ElementsのComplex modificationタブで、記述したJSONファイルの項目を読み込む&quot;&gt;&lt;/p&gt;
&lt;div style=&quot;margin-top:5em;&quot;&gt;&lt;/div&gt;
&lt;p&gt;ここまでの操作でミュートをいい感じに操作できるはず。
なお、マウスの裏側には黒い紙を貼ってポインタが反応しないようにしている。
左クリックなどが反応しないのはマウス自体が壊れているからっぽい。
もし通常のマウスを使う場合はKarabiner-Elementsの設定で、各ボタンの入力について&lt;code&gt;&quot;to&quot;: [{}]&lt;/code&gt;といった何もしない設定を追加すると良さそう。&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;&lt;code&gt;$ brew install karabiner-elements&lt;/code&gt;でもインストールできるはず &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;今回は手元に壊れかけのマウスが有ったのでこれをスイッチとして使ったが、キーボードなどでも同様のことを実現できるはず。また何も足で押さなくてもよくて、机の上にスイッチがあるとか既存のキーボードにショートカットキーを定義するとかでもよいかもしれない。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;既にマウスに関する Karabiner-Elements の設定が存在する場合は、ぶつからないように、Vendor ID と Product ID をメモして設定に書き込むと良さそう。&lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/cf0f3eaa6bce79b984cdcc53a42ed1ea65711f90/.config/karabiner/assets/complex_modifications/mouse_mic_mute.json&quot;&gt;参考までに私の設定ファイルはこれ。&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>ロリポップ上に公開された WordPress サイトを、ローカルの docker-compose 上で再現する</title>
      <link>https://memo.yammer.jp/posts/backup-lolipop-wordpress-with-docker</link>
      <pubDate>Fri, 23 Apr 2021 18:41:20 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/backup-lolipop-wordpress-with-docker</guid>
      <description>&lt;p&gt;表題の通り、ロリポップ！レンタルサーバ上に公開されている自身のWebサイトをバックアップし、さらに手元のPC上にdocker-composeで動作するように配置する。&lt;/p&gt;
&lt;h2&gt;前提の環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ロリポップ！レンタルサーバ上で WordPress を用いた Webサイトを構築している。&lt;/li&gt;
&lt;li&gt;macOS 10.15 Catalina&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://matsuand.github.io/docs.docker.jp.onthefly/docker-for-mac/install/&quot;&gt;Docker Desktop for Mac がインストールされている&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wget がインストールされている。 (Homebrew を用いて &lt;code&gt;brew install wget&lt;/code&gt; でインストール)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;手順1: ロリポップ上の情報をダウンロード&lt;/h2&gt;
&lt;h3&gt;1-1: ファイルを抜き出す&lt;/h3&gt;
&lt;p&gt;はじめにロリポップ！ユーザ専用ページ &gt; ユーザー設定 &gt; アカウント情報 を開いてアカウント情報を確認する。
今回は以下の内容であったとする。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FTPS サーバー&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ftp.lolipop.jp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FTP ・WebDAV アカウント&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chu.jp-user&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FTP ・WebDAV パスワード&lt;/td&gt;
&lt;td&gt;&lt;code&gt;password&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;次に、ターミナルから以下のコマンドを実行する。
ftp を使って、階層の深さ制限なしに再帰的にファイルをダウンロードする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ mkdir -p ~/lolipop-backup/download &amp;#x26;&amp;#x26; cd ~/lolipop-backup/download
$ wget -r -l 0 &quot;ftp://chu.jp-user:password@ftp.lolipop.jp&quot;
# (ホスト名、ユーザ名、パスワードは適宜置き換えていただくとよし)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみに私の場合は8分で200MB弱をダウンロードした。&lt;/p&gt;
&lt;h3&gt;1-2: データベースを抜き出す&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;ロリポップ！ユーザ専用ページ &gt; サーバの管理・設定 &gt; データベース を開く。&lt;/li&gt;
&lt;li&gt;データベース名をメモする。今回は &lt;code&gt;LAA0000000-xxxxxx&lt;/code&gt; であるとする。&lt;/li&gt;
&lt;li&gt;phpMyAdmin を開く。&lt;/li&gt;
&lt;li&gt;ログインして、画面左のデータベース名を選択 (今回で言えば &lt;code&gt;LAA0000000-xxxxxx&lt;/code&gt;)。&lt;/li&gt;
&lt;li&gt;&quot;エクスポート&quot; タブを開く。&lt;/li&gt;
&lt;li&gt;エクスポート方法: &quot;詳細 - 可能なオプションを全て表示&quot; のラジオボタンを選択。&lt;/li&gt;
&lt;li&gt;生成オプションより追加コマンド: &quot;CREATE DATABASE / USE コマンドを追加する&quot; にもチェックを入れる。&lt;/li&gt;
&lt;li&gt;他はデフォルトのままで、ページ左下の &quot;実行&quot; をクリック。&lt;/li&gt;
&lt;li&gt;ファイルがダウンロードされるので &lt;code&gt;~/lolipop-backup/downlaod/LAA0000000-xxxxxx.sql&lt;/code&gt; に移動させる。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;手順2: ローカルにWordPress環境を構築&lt;/h2&gt;
&lt;h3&gt;2-1: docker-compose.ymlを整備する&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;~/lolipop-backup/docker-compose.yml&lt;/code&gt; を作成し、以下の内容を記述する。
&lt;code&gt;- MYSQL_DATABASE=LAA0000000-xxxxxx&lt;/code&gt;の行についてのみ、イコール以降に各自のデータベース名を書き込む必要がある。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# docker-compose.yml
version: &quot;3&quot;
services:
  db:
    image: mysql:5.6
    container_name: &quot;mysql&quot;
    volumes:
      - ./db:/var/lib/mysql
      - ./db-init:/docker-entrypoint-initdb.d
    restart: always
    environment:
      - MYSQL_DATABASE=LAA0000000-xxxxxx # この行は各自で記述
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_ROOT_PASSWORD=root
  wordpress:
    image: wordpress:5.7.1
    container_name: &quot;wordpress&quot;
    volumes:
      - ./wp:/var/www/html
    restart: always
    depends_on:
      - db
    ports:
      - 8080:80
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    container_name: &quot;phpmyadmin&quot;
    restart: always
    depends_on:
      - db
    ports:
      - 8888:80
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOSTS=mysql
      - PMA_USER=user
      - PMA_PASSWORD=password
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2-2: 抜き出したファイルを設置する&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# 抜き出したファイル群を設置
$ cp -r ~/lolipop-backup/download/ftp.lolipop.jp ~/lolipop-backup/wp
# 上の行はロリポップ側でルートディレクトリに WordPress を設置している場合である
# ルートディレクトリ以外に WordPress を設置している場合は、index.php が wp ディレクトリの直下に配置されるようにコピー元のディレクトリを指定する

# 抜き出したデータベース初期化情報を設置
$ mkdir db-init
$ cp ~/lolipop-backup/download/LAA0000000-xxxxxx.sql ~/lolipop-backup/db-init/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2-3: WordPressの設定を変更&lt;/h3&gt;
&lt;p&gt;WordPress の設定が記述されたファイル &lt;code&gt;~/lolipop-backup/wp/wp-config.php&lt;/code&gt; を編集し、WordPress が正しくデータベースに接続できるようにする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;define(&apos;DB_USER&apos;, &apos;...&apos;);&lt;/code&gt; →&lt;code&gt;define(&apos;DB_USER&apos;, &apos;user&apos;);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;define(&apos;DB_PASSWORD&apos;, &apos;...&apos;);&lt;/code&gt; →&lt;code&gt;define(&apos;DB_PASSWORD&apos;, &apos;password&apos;);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;define(&apos;DB_HOST&apos;, &apos;...&apos;);&lt;/code&gt; →&lt;code&gt;define(&apos;DB_HOST&apos;, &apos;mysql:3306&apos;);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2-4: Search-Replace-DB を設置&lt;/h3&gt;
&lt;p&gt;のちほど、データベース内のURLを書き換える必要があるため、書き換えに用いるツールを配置する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ git clone https://github.com/interconnectit/Search-Replace-DB.git ~/lolipop-backup/wp/Search-Replace-DB
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2-5: Apache の設定を変更&lt;/h3&gt;
&lt;p&gt;トップページ以外のページのURIを開いた時も、ApacheではなくWordPressに処理して欲しいので、リクエスト先をindex.phpに向ける必要がある。
&lt;code&gt;~/lolipop-backup/wp/.htaccess&lt;/code&gt; に以下を記述する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# .htaccess

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;手順3: 起動する&lt;/h2&gt;
&lt;h3&gt;3-1. Dockerコンテナ群の立ち上げ&lt;/h3&gt;
&lt;p&gt;Dockerコンテナを立ち上げて、バックアップしたページが表示されることを確認する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd ~/lolipop-backup
$ docker-compose up -d
# 少し待つ (10秒とか。初回起動時はDBを初期化するので、立ち上げた瞬間にアクセスするとエラーが発生して開けない。開けないだけだが)

$ open http://localhost:8080
# トップページが開けることを確認する
# この状態ではリンクを踏むと、localhost ではなくWeb上のページに飛んでしまう
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3-2. データベース内のURLの置換&lt;/h3&gt;
&lt;p&gt;WordPressのデータベース内では、URLが絶対パスで保持されているらしく、ここまでの手順では、ページ内リンクを踏むと、バックアップ元のWebサーバのページに飛んでしまう。この手順では、データベースを書き換えて、リンクを踏んでもローカルのページを回遊できるようにする。&lt;/p&gt;
&lt;p&gt;今回は &lt;code&gt;www.example.com&lt;/code&gt; に設置されたWebサイトをバックアップしているものとする。&lt;/p&gt;
&lt;p&gt;1.Search Replace について&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://localhost:8080/Search-Replace-DB&lt;/code&gt; を開く。&lt;/li&gt;
&lt;li&gt;replace (search for...) に &lt;code&gt;http://www.example.com&lt;/code&gt;、with (replace with...) に &lt;code&gt;http://localhost:8080&lt;/code&gt; を入力&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;add more search terms をクリック&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;replace (search for...) に &lt;code&gt;https://www.example.com&lt;/code&gt;、with (replace with...) に &lt;code&gt;http://localhost:8080&lt;/code&gt; を入力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.Database Details について&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;database name に データベース名 (&lt;code&gt;LAA0000000-xxxxxx&lt;/code&gt;など) を入力&lt;/li&gt;
&lt;li&gt;username に &lt;code&gt;user&lt;/code&gt; と入力&lt;/li&gt;
&lt;li&gt;pass に &lt;code&gt;password&lt;/code&gt; と入力&lt;/li&gt;
&lt;li&gt;host に &lt;code&gt;mysql&lt;/code&gt; と入力&lt;/li&gt;
&lt;li&gt;port に &lt;code&gt;3306&lt;/code&gt; と入力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Test connection を押して、「Success. You are connected.」と表示されることを確認する。&lt;/p&gt;
&lt;p&gt;3.Which Tables? について&lt;/p&gt;
&lt;p&gt;ラジオボタンが all tables を選択していることを確認する。&lt;/p&gt;
&lt;p&gt;4.実行&lt;/p&gt;
&lt;p&gt;入力に誤りがないことを確認して、不安なら「Do a safe test run」をしてみたあとに、「Search and Replace」を実行する。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ここまでの手順を踏めば、&lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; 上で正しくページが表示され、リンクを踏んでもローカルのページに飛べるはず。&lt;/p&gt;
&lt;h2&gt;うまくいかないとき&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;「データベース接続確立エラー」と表示される。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;まず、wp/wp-config.php の中が正しく書き換えられているか確認するとよさそう。
WordPress に接続した時に「データベース接続確立エラー」と表示される場合は、docker-compose.yml 内のホスト名(今回はmysqlコンテナの3306番に公開されたポートを観に行くので &lt;code&gt;mysql:3306&lt;/code&gt;)・データベース名・ユーザ名・パスワード、初期化用sqlファイル内の CREATE DATABASE の行にあるデータベース名、wp-config.php の中にあるホスト名・データベース名・ユーザ名・パスワードが一致しているかを確認してみる&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WordPressのサイトが開けない。「サイトに重大なエラーがありました。」と表示される。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;wp-config.php の中で &lt;code&gt;define(&apos;WP_DEBUG&apos;, false);&lt;/code&gt; の行を &lt;code&gt;define(&apos;WP_DEBUG&apos;, true);&lt;/code&gt; に書き換えるとデバッグモードになってエラーが表示されるので原因究明につながるかもしれない。
ちなみに ftp でファイルをダウンロードするとき、wget コマンドに &lt;code&gt;-l 0&lt;/code&gt; オプションを指定しないと途中の階層までしかダウンロードされず、ファイルが欠けてWordPressが起動しなくなる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Webページを開くとApacheの404エラーページが出る。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.htaccess ファイルを設置して、リクエストしたURIに関わらずindex.phpで処理するように設定するとよいかも。&lt;/p&gt;</description>
    </item>
    <item>
      <title>僕の、私の、ストレングス・ファインダー (感想)</title>
      <link>https://memo.yammer.jp/posts/strengths-finder</link>
      <pubDate>Mon, 19 Apr 2021 14:45:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/strengths-finder</guid>
      <description>&lt;p&gt;会社の研修でストレングス・ファインダーを受けたので、結果を過去の経験と照らし合わせて考えてみます。
読書メモみたいなものです。&lt;/p&gt;
&lt;h2&gt;ストレングス・ファインダーとは&lt;/h2&gt;
&lt;p&gt;1998年に心理学者のドナルド・O・クリフトンが開発したオンライン心理テスト。
「実行力」「影響力」「人間関係構築力」「戦略的思考力」の4領域に分類される34の資質のうちどれを自分が持っているのかを判断してくれる。
それぞれの資質を知ることで自分の能力をどのように開発していけばよいかの参考になるらしい。
書籍「&lt;a href=&quot;https://www.amazon.co.jp/%E3%81%95%E3%81%82%E3%80%81%E6%89%8D%E8%83%BD-%E3%81%98%E3%81%B6%E3%82%93-%E3%81%AB%E7%9B%AE%E8%A6%9A%E3%82%81%E3%82%88%E3%81%86-%E6%96%B0%E7%89%88-%E3%82%B9%E3%83%88%E3%83%AC%E3%83%B3%E3%82%B0%E3%82%B9%E3%83%BB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%B3%E3%83%80%E3%83%BC2-0/dp/4532321433/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;#x26;dchild=1&amp;#x26;keywords=%E3%82%B9%E3%83%88%E3%83%AC%E3%83%B3%E3%82%B0%E3%82%B9%E3%83%BB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%B3%E3%83%80%E3%83%BC&amp;#x26;qid=1618838810&amp;#x26;sr=8-1&quot;&gt;さあ、才能(じぶん)に目覚めよう 新版 ストレングス・ファインダー2.0&lt;/a&gt;」に付属するアクセスコードから受けることができる。
なお以降に挙げる引用の出典はすべてこの書籍である。&lt;/p&gt;
&lt;h2&gt;結果&lt;/h2&gt;
&lt;p&gt;私の持つ資質の上位5つは高いものから順に、&lt;strong&gt;分析思考&lt;/strong&gt;、&lt;strong&gt;学習心&lt;/strong&gt;、&lt;strong&gt;収集心&lt;/strong&gt;、&lt;strong&gt;ポジティブ&lt;/strong&gt;、&lt;strong&gt;個別化&lt;/strong&gt; らしい。前半3つが「戦略的思考力」に、後半2つが「人間関係構築力」に分類されるもののようだ。
これらの資質をひとつずつみていく。&lt;/p&gt;
&lt;h3&gt;分析思考&lt;/h3&gt;
&lt;p&gt;分析思考とは、データを好み物事の理由と原因を追求することを好むことを指す。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;〈分析思考〉の資質を持つあなたは、他の人に「それを証明しなさい。貴方の主張がなぜ正しいのか示しなさい」と強く要求します。このような詰問を受けると、自分のすばらしい理論がもろくも崩れ落ちるのを感じる人もいます。(p186)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;書籍に書かれた上記の文を読んで、他人と議論しているときにまさに自分がよく考える話だと感じた。
つい先日の研修でのグループワークでも、自分が建設的な意見を出せているわけではないのに、他人の意見の実現可能性が気になってしまっていろいろ質問したくなってしまった。
悪い方向に走ると意見を潰すような振る舞いになってしまうが、今ある情報からどう判断できるかということをしっかり伝えていくのは必要なことだと思うので、人の意見を良い方向にブラッシュアップできるような発言ができたらよいね。&lt;/p&gt;
&lt;p&gt;あわせて「内容に対しての見解を言うこと」と「人格攻撃をすること」は別であるという点には注意しておきたい。
本書のアドバイスの中で「あまりキツイことは言い過ぎないように」とあって、わかるし気をつけたいよな〜、改めて心に刻もう、と思った。&lt;/p&gt;
&lt;h3&gt;学習欲&lt;/h3&gt;
&lt;p&gt;学習欲のある人とは、知識を得る状態になることや知識を得た状態だと認識することに満足感を覚える人のことらしい。&lt;/p&gt;
&lt;p&gt;私はコンピュータを触る・学ぶことの面白さに「ブラックボックスを紐解くことが楽しい」ことを挙げることがある。
コンパイラや認証などを再実装してみたり、大学で既存のソフトウェアに関する講義に興味をもったりしたのは、掘り下げてどう動いているのがわかると楽しいからという理由が強い。&lt;/p&gt;
&lt;p&gt;もっと遡れば小学生の頃、掃除機やラジオなどの古い電化製品を分解していたのを思い出す。
自覚はしていないが、新しい知識を獲得して学習するプロセスに実は満足感をもっているのかもしれない。&lt;/p&gt;
&lt;p&gt;学習欲の高い人に向けて本書では次のようなアドバイスが挙げられている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;変化を起こす人になりましょう。他の人達は新しい規則や技術を導入したり、環境を整備したりすることに尻込みするかもしれません。(p53)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;技術や規則が常に変化する分野にキャリアを変更しましょう。これに対応しようと挑戦し続けることであなたはいきいきとします。(p53)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ソフトウェアエンジニアを職業に選んだのは正解だったようだ。
常に環境が変化する状況で新しいものをキャッチアップし続けることが特に必要な業種だと思うので、変化を受け入れてそれについていける、さらにはそういった流れを作れるような人材になれると良いですね。&lt;/p&gt;
&lt;h3&gt;収集心&lt;/h3&gt;
&lt;p&gt;(ここでいう) 収集心とは、物理的な物の収集欲に限らず、情報を収集することを好む人も含んでいるらしい。
たしかにWikipediaは永遠に見れるタイプだし、旅行に行く前には調べるタイプだし、社会のものがどう動いているか仕組みを知りたいみたいな気持ちは強いかもしれない。
本も電子派だけど紙を捨てるときはスキャンするし、Google フォームの内容や一時的な目的のために配られた資料も保管しておきたくなったりする。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;情報を保管し、簡単に探し出すことができる仕組みを考案しましょう。(p121)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本書には上のようなアドバイスが書かれていて、これは自分が課題に感じていることの１つだ。
メモをとったり思考を整理したり、それらの情報にアクセスするためのツールが定まっていない。
数年前は Google Keep を使っていたが、いつ記録した情報かが残りづらく使うのを止めた。&lt;/p&gt;
&lt;p&gt;今だとたぶんScrapboxとかNotionとかになるのだろうけど、どちらも全然使いこなせていない。
こういったアプリケーションは移り変わりが早いのでロックインされたくなくてMarkdown最強説を唱えるときもあったものの、メモを集めたgitリポジトリも整理されてアクセスしやすい状況とはいえないな。
どうにかせねばなあ。&lt;/p&gt;
&lt;h3&gt;ポジティブ&lt;/h3&gt;
&lt;p&gt;ポジティブが上位に入っているのは嬉しい。&lt;/p&gt;
&lt;p&gt;昔 (これまた小学生くらいの頃) は自分をネガティヴだと自覚していて、自分のことを説明するときはネガティヴだと言っていた。
しかしネガティヴな自分が嫌で、無駄に自分や他人を落ち込ませるような気がして、いつからか言霊でもいいからなるべく言葉では無理矢理でもいいからポジティブになるような発言を心がけていた。&lt;/p&gt;
&lt;p&gt;いつしかそうやって言霊だと思っていた考えが自分の中のポジティブな思考として定着して、物事を悲観的に考えずに済むようになった。
今回のテストで上位に上がってきたことをもって「自分がポジティブな思考を持った」と言えるようになったと思う。
自分の性格は自分で変えられることを示たので嬉しい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;日頃から楽しい話や冗談などを準備しておきましょう。(p201)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;誰も傷つけないで笑いをとりたい。面白い話ができる人になりたいね。&lt;/p&gt;
&lt;h3&gt;個別化&lt;/h3&gt;
&lt;p&gt;個別化の資質を持つ人は、一人ひとりのユニークな個性に興味をそそられそれを理解することに長けているらしい。
これは正直よくわからないけど、自分のわがままを持っているから他人のわがままも受け入れあえたら幸せだよなと思っている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;チームの各メンバーが最も得意とすることを見極めましょう。(p89)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上のようなアドバイスが示されているが、そうやって得意なことを生かしたチームがつくれたら最強だよな。
あまり共感と理解ができてないのでこの項はさっくり終わる。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;自分の資質は4領域のうち「人間関係構築力」「戦略的思考力」に偏っていて、「実行力」「影響力」は強みではないらしい。
実際のところ実行力も影響力もないのはなんとなく同意してしまうな。
しかしながら働いていく上ではこれらもある程度必要だと思うので、どうカバーできるか考えていきたい。&lt;/p&gt;
&lt;p&gt;そもそもこういった心理テストは「答えを見たときに自分の中で当てはまりそうな行動や理由を見つけて納得したような気になる」ことがよくあるように思う。
さらにストレングス・ファインダーの結果は時間が経てば変わることもあるらしく「絶対的な自分の能力」ではなく「今の自分にとっての強みとなりうる要素」を表すものらしい。&lt;/p&gt;
&lt;p&gt;今回の結果が実際のところどれほど適切な指摘をしているのかはわからないが、今後の仕事での振る舞いや方向性を決めていくための自分を振り返る機会になった。
今回の内容を過信しすぎず、しかしながら自分の行動を律するときの一つの指標として適切な距離感で捉えておきたい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>社会人一週目の所感</title>
      <link>https://memo.yammer.jp/posts/20210408</link>
      <pubDate>Thu, 08 Apr 2021 15:57:25 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20210408</guid>
      <description>&lt;p&gt;4/1に社会人になり一週間が経った。
職種合同での研修期間中で実際の仕事やエンジニアリングとはまだ少し距離がある。
研修もまだまだこれからだけど、区切りが良い日なので今日の気持ちを記録しようかと。&lt;/p&gt;
&lt;h2&gt;生活について&lt;/h2&gt;
&lt;p&gt;まず当たり前だが、社会人は結構疲れる。
3月末までは一日中暇で、好きなだけコードを書き好きなだけネット見て好きなだけ寝ていたので差が大きいだけで、毎日朝から夕方まで集中していたら人間誰でも疲れるだろう。
睡眠は本当に大事。
一昨日つい睡眠時間を削ったら昨日は一日中眠くて、仕事終わった直後にベッドで爆睡した。
これができるから在宅勤務は良い。通勤が無くて良い。
慣れてしまったら毎日出社なんてできない人間になる気がする。&lt;/p&gt;
&lt;p&gt;あとは時間を大切にしたくなる。
研修後にレポートを書くのだが、疲れたからゆっくりやるかと思うとそれだけで凄く時間がかかる。
1日がすぐに終わってまた朝になる。
逆にテキパキすれば時間はたくさんあって(通勤時間ないし残業もないし)、朝に本を読んだりできるし、こうやってブログを書くこともできる。休むときはしっかり休む、集中するときはガッとやる、意識的に時間で区切っていきたい。&lt;/p&gt;
&lt;p&gt;区切るといえば、リモートワークなので自室で寝て自室で働くのだが、自分の緊張感を意識的に切り替えるために2つのことを決めた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ドアを開ける ...
始業中で会話をしているときにドアを閉めるのは当然として、それ以外の時間は開けるようにしている。
空気も入れ替わるし、心のスイッチにもなるし、同居の家族も「今は声をかけていいのか」が明確にわかるので良い。&lt;/li&gt;
&lt;li&gt;早く風呂に入る ...
終業後に気分を緩めるために風呂に入るのがいい。
ゆっくり出来るし体に水を浴びると気分が変わる。
あと風呂に入ることを面倒に思う人種からすると、入るのが後回しなり夜ふかしすることを避けられるのも良い。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ほかにも、時間のあるときに本を少しずつ読み進めてみている。
(いままでは気分がノッたときに一気に読破することがほとんどだったが、平日はまとまって時間取るのも難しそう。)
しかしながら少しずつ読むと、翌日になったら以前の内容を忘れていたりして内容を掴みづらいと感じる。
打開策として、手の感覚などからどこまで読んだかという情報が記憶に残りやすいのではないかと物理本を注文してみた。
本を裁断して自炊するほど電子書籍を好んでいたので物理本はだいぶ久々な気がする。
効果はあるだろうか、どうかな？&lt;/p&gt;
&lt;h2&gt;研修について&lt;/h2&gt;
&lt;p&gt;話は変わって研修について。
講義形式のものとチームで課題にとりかかるものの2種類があり、講義形式のものはいろいろな学びがあった。
ビジネスマナーの習得機会でもあったし、自分は将来の夢や目標が明確でないことがわかったし、会社について理解を深めたつもり。&lt;/p&gt;
&lt;p&gt;一方、チームで課題に取りかかるものは結構大変だった。&lt;/p&gt;
&lt;p&gt;ひとつは答えのない問題に対しての解決策を限られた時間で議論すること、導くことの難しさ。
(就活でグループワークの練習をしたときのことを思い出した。結局選考ではやってないが。)
途中で焦って方向性のハンドリングをミスったような気がしたけど、優秀なチームメンバーのおかげで終わってみると案外丸くまとまっていたりする。
てんやわんやするも意図しての研修のような気もするので、とりあえず乗り切ったことを喜びたい。&lt;/p&gt;
&lt;p&gt;もうひとつは言語の壁。
日本語を母語としない方がチームにいて、英語でコミュニケーションする必要があった。(多様性は歓迎されるべきことで良いこと。)
人生でたまに必要になるんだよな英会話。
一応配慮があって留学経験のある人が同じチームにいたのだけど (ありがたい) (めちゃめちゃ発音きれいだった)、自分も割と頑張って英語を喋ろうとした、したけれど...&lt;/p&gt;
&lt;p&gt;最初は途中途中に英語で「今こんなことを考えているんだけど貴方の意見は？」と議論を整理して振ろうとしてみてみたり、テキストベースで進めてみたりしようとしたものの、最終的には結局全然うまく行かなかった。
テキストベースの議論が難しかった原因は、研修の都合でコミュニケーションツールが Zoom のみに限定されていたということもあるけれど、一番は「議論が白熱すると余裕がない」ことだった。
日本語で考えるのでさえ精一杯で、どうしようかと悩み、時間がなく焦っている状況だった。
散らかった議論をそのまま英語で話すのも厳しいし、整理して説明する余裕もない。
結局チームの中で情報格差の壁ができたままになってしまって、現状を伝えて一緒に考えることが難しくなっていった。
日本語ベースの研修だから仕方ない部分もあるだろうけど、結局チームも分断されてしまった (疎外感を与えてしまっただろう) し、その方の学びの機会も少なくなってしまった気がして、申し訳ない気持ちと残念な気持ちのまま研修が終わってしまった。&lt;/p&gt;
&lt;p&gt;どう進めればよかったのだろうか、今考えてもわからない。
ある程度議論のスピードを抑えてでも丁寧に進めるべきだったのかもしれない。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;英語力欲しすぎ太郎&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1377835243336425473?ref_src=twsrc%5Etfw&quot;&gt;April 2, 2021&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;文章の方向性がわからなくなってきたので、ちょっと話を変えましょう。
リモートワークが中心でありコロナ禍ということもあり、内定をいただいてから一度も出社してないし、同期の人とは殆ど物理的に顔を合わせたことがない。
その上にまだ入社1週間なのだが、研修のチームが違えど会社の同期の人同士では既にたくさんコミュニケーションをとっているし、なんとなく近くにいる気がする。
チームでの課題で「大変だな」という気分になっているときも Slackを通して同期の人々に支えられる気分になるし (ありがとうございます)、いい会社にはいい人が集まるんだろうな。&lt;/p&gt;
&lt;p&gt;明日からまた研修が続くのでそろそろ寝ましょう。
おやすみなさい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Office365メールやGmailをローカルにバックアップする (macOS)</title>
      <link>https://memo.yammer.jp/posts/mail-backup-mbox</link>
      <pubDate>Sun, 28 Mar 2021 09:03:06 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/mail-backup-mbox</guid>
      <description>&lt;p&gt;3月で大学を卒業するにあたり、大学のメール (Office365) と研究室のメール (Google Workspace) が使えなくなる。
閲覧もできなくなるのでバックアップを取っておきたいので試してみる。&lt;/p&gt;
&lt;h2&gt;メールの取得&lt;/h2&gt;
&lt;h3&gt;Gmail 上のすべてのメールを mbox 形式で取得する&lt;/h3&gt;
&lt;p&gt;Google は サービス上の個人データをエクスポートする機能を提供している。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://support.google.com/mail/answer/10016932?hl=ja&quot;&gt;Gmail からデータを書き出す - Gmail ヘルプ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2021/03現在では、次の手順で取得できる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Gmail を開き、右上の自分のアイコンをクリックして、「Google アカウントを管理」を選択&lt;/li&gt;
&lt;li&gt;「データとカスタマイズ」タブに移動し、中段の「データのダウンロード、削除」から「データをダウンロード」を選択&lt;/li&gt;
&lt;li&gt;「新しいエクスポートの作成」の右下にある「選択をすべて解除」をクリック&lt;/li&gt;
&lt;li&gt;スクロールして下の方に移動し、「メール」のチェックボックスを選択状態にする&lt;/li&gt;
&lt;li&gt;さらに下に移動し「次のステップ」を選択&lt;/li&gt;
&lt;li&gt;「エクスポートを作成」を選択&lt;/li&gt;
&lt;li&gt;しばらく時間が立つと自分のメールアドレスにダウンロードリンクが届くので、これを開いてzipファイルをダウンロード&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Apple純正の Mail.app でメールボックスごとに mbox 形式で取得する&lt;/h3&gt;
&lt;p&gt;Office365 は Gmail のようにエクスポート機能を提供していない。
一方で macOSでは、純正で付属する Mail.app を用いてメールボックスのメールをエクスポートすることができる。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://support.apple.com/ja-jp/guide/mail/mlhlp1030/mac&quot;&gt;Macの「メール」でメールボックスを読み込む/書き出す - Apple サポート&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;例えば「受信トレイ」や「送信済み」なども含めたすべてのメールを「アーカイブ」に移動し、「アーカイブ」のメールボックスを右クリックして「メールボックスを書き出す」を選ぶとすべてのメールを単一の mbox 形式でエクスポートできる。&lt;/p&gt;
&lt;p&gt;(Office365 だけでなく Gmail を含む他のサービスのメールも、Mail.app でログインして同期すれば、この機能からメールをエクスポートできる)&lt;/p&gt;
&lt;h2&gt;メールの閲覧&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.mutt.org&quot;&gt;mutt&lt;/a&gt; という CLI で mbox 形式のメールを閲覧できる。&lt;/p&gt;
&lt;h3&gt;インストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ brew install mutt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;メールを見る&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ mutt -f path/to/mail-file.mbox
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;操作は次のとおり&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;キー&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;動作&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;j&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;下へ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;k&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;上へ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;z&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;次ページへ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;前ページへ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;正規表現で検索&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;メールを読む&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;q&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;戻る / 終了&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;経緯といざこざ&lt;/h2&gt;
&lt;p&gt;メールをローカルに保存するときは、Unix, Linuxで用いられる形式として mbox 形式 (１つのファイルに複数のメールを記録) と Mail Dir形式 (1つのファイルに1つのメールを記録)、Windows で用いられている形式として eml形式 (1つのファイルに1つのメールを記録) などが代表的なよう。
今回は使わなくなるメールアドレスの過去のメールを保存しておきたいだけなので、後から見返しやすければどの形式でも良い。mbox 形式でのエクスポートがやりやすかったので mbox を選んだ。&lt;/p&gt;
&lt;p&gt;macOS ないし Ubuntu からメールをDownloadする CLI として getmail や fetchmail 等があるが、CLIからだと Office365 や Gmali の2段階認証を超えるのが面倒そうだった。
Thunderbird のエクステンションでのエクスポートも、エクスポート後のファイルを mutt で閲覧できなかったのでやめた。
右往左往していて最終的に OS にバンドルされた Mail.app で mbox 形式でのエクスポートができることがわかり解決。
macOS の純正アプリケーションは PDF の切り取りや並べ替えができたり、簡易的にRAW現像できたりと意外にも高機能なのでよく助けられている気がする。Appleありがとう。&lt;/p&gt;</description>
    </item>
    <item>
      <title>TCP/IP における全レイヤを俯瞰したパケットの構成</title>
      <link>https://memo.yammer.jp/posts/tcp-packet-layout</link>
      <pubDate>Fri, 19 Feb 2021 02:24:44 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/tcp-packet-layout</guid>
      <description>&lt;p&gt;ふとしたときに TCP/IP でのパケットの各フィールドにどんなものがあったか確認したくなることがあるので、レイヤごとに分けずまとめて書かれた物があると便利。&lt;/p&gt;
&lt;p&gt;以下, Ethernet, IPv4, TCP, HTTP を用いたパケットの各フィールドの配置を表した図。
各フィールドの意味は記載しません。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/tcp-packet-layout.svg&quot; alt=&quot;TCPパケットの全レイヤを通したフィールドの構成図&quot;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>卒業論文の発表を終えた。近況。</title>
      <link>https://memo.yammer.jp/posts/20210218</link>
      <pubDate>Thu, 18 Feb 2021 13:44:22 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20210218</guid>
      <description>&lt;p&gt;先週に卒業論文を提出し、今日その内容を学科内で発表した。
無事合格できた旨のメールを先ほど受け取って、これで大学4年間の全ての単位を取得できる見込みになった。&lt;/p&gt;
&lt;p style=&quot;padding-bottom: 50px&quot;&gt;
大学生活は案外早く過ぎ去ったなと思いつつ、こういうのは終わってみればたいてい早く感じるものだろう。
今の自分は大した技術力があるわけでもないし、大学4年間で大したことを身につけられた気がしないと少し前まで思っていたけれど、振り返ると4年前の自分は今よりも果てしなく無知だったことに気づくので、大学に入ってこの専攻を選んでよかった。
&lt;/p&gt;
&lt;p&gt;最近は論文執筆に勤しんでいた。
新年の意気込みで早寝早起きと言っておきながら最近はだいぶ夜ふかしをしていたし、本を読む目標もあまり進んでいない。
少し読んだ本もあるが、そんな時間があるなら論文を書きましょうという感じだった。&lt;/p&gt;
&lt;p style=&quot;padding-bottom: 50px&quot;&gt;
卒業研究にあたってそこそこ論文などを読んだ。
論文を読む機会なんて正直いままで殆ど無かったし、長い仕様書をじっくり読むみたいなのもそんなにしてこなかったので、卒業研究はそういった意味で新しいことを体験する機会だった。
世の研究者と比べたら大したことを出来た訳ではないだろうけれど、右も左もわからないながらも、一応高等教育の最後として自分の考えをしたためた文章を書ききったことに達成感を感じている。
&lt;/p&gt;
&lt;p style=&quot;padding-bottom: 50px&quot;&gt;
ところで私は昔、理系大学生の醍醐味といえば研究室生活だろうみたいな想像をしていた。
そういうのを心のどこか楽しみにしていたが、私の研究室はコアタイムがあるわけでもないし、新型コロナウィルスの影響で研究室には最初の1,2回しか行く機会がなかった。
実家で一日中コンピュータを触っているのは実に快適でよいのだけれど。
そういえば弊研究室に所属したら SINET から出れる IPv4 の固定アドレスを自由に使える権利があったのだけど、研究室内にコンピュータをセットアップすることもないまま卒業することになるので実質この権利を放棄してしまった。
無理してでも文字通り研究室に入ってラズパイの1台でも置いてくればよかったな。
一抹の後悔。
&lt;/p&gt;
&lt;p&gt;というわけで駄文でした。&lt;/p&gt;
&lt;p&gt;研究が終わったらやりたいことがいくつか溜まっていたので順番に消化していきたい。
気分症なのでいくつか既に昇華してしまったものもあるが、まあよいだろう。
生活リズムも戻します。
ブログもまた書いていきます、今までは文章を書く時間が全て論文に奪われていたので... (これは言い訳)&lt;/p&gt;
&lt;p&gt;最後に先週公開され、卒論準備を後押ししてくれた BUMP OF CHICKEN の新曲、Flare の MV を置いてこの文章を終えます。
おやすみなさい。&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;embed-youtube embed-wrapper&quot; style=&quot;text-align: center;&quot;&gt;&lt;iframe class=&quot;embed-youtube&quot; width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/pDFkg9L5wJY?feature=oembed&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ベジェ曲線で画像を丸っぽくくり抜く (CSS clip-path)</title>
      <link>https://memo.yammer.jp/posts/clip-path</link>
      <pubDate>Wed, 27 Jan 2021 02:43:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/clip-path</guid>
      <description>&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;  &amp;#x3C;img
    src=&quot;https://blob.yammer.jp/gather_fishes.jpg&quot;
    style=&quot;clip-path:url(#bezier-curve-circle); width:300px;&quot;
  /&gt;
  &amp;#x3C;svg&gt;
    &amp;#x3C;clipPath id=&quot;bezier-curve-circle&quot; clipPathUnits=&quot;objectBoundingBox&quot;&gt;
    &amp;#x3C;path d=&quot;
      M 0 0.5
      C 0 0.166, 0.166 0, 0.5 0
      S 1 0.166, 1 0.5
      S 0.833 1, 0.5 1
      S 0, 0.833, 0, 0.5
      Z
    &quot;/&gt;
    &amp;#x3C;/clipPath&gt;
  &amp;#x3C;/svg&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTML で上記のように記述すると下記のように丸っぽく画像をくり抜ける&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img
 src=&quot;https://blob.yammer.jp/gather_fishes.jpg&quot;
 style=&quot;clip-path:url(#bezier-curve-circle); width:300px;&quot;
/&gt;
&lt;svg&gt;
&lt;clipPath id=&quot;bezier-curve-circle&quot; clipPathUnits=&quot;objectBoundingBox&quot;&gt;
&lt;path d=&quot;
   M 0 0.5
   C 0 0.166, 0.166 0, 0.5 0
   S 1 0.166, 1 0.5
   S 0.833 1, 0.5 1
   S 0, 0.833, 0, 0.5
   Z
 &quot;/&gt;
&lt;/clipPath&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;clip-path - CSS: Cascading Style Sheets | MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths&quot;&gt;Paths - SVG: Scalable Vector Graphics | MDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Planck Keyboard を手に入れた</title>
      <link>https://memo.yammer.jp/posts/planck-keyboard</link>
      <pubDate>Sat, 09 Jan 2021 06:07:39 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/planck-keyboard</guid>
      <description>&lt;p&gt;先月に申し込んだ Planck Keyboard が届いたので組み立てた。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/planck-keyboard.jpg&quot; alt=&quot;planck keyboard&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Planck Keyboard とは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://drop.com/buy/planck-mechanical-keyboard&quot;&gt;Drop + OLKB Planck Mechanical Keyboard Kit V6 | Drop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;いわゆる 40%&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; と言われる分類で格子配列&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; のキーボードキット。
キー数が少なく(4x12個) コンパクトなキーボードである。&lt;/p&gt;
&lt;p&gt;スイッチを取り付ける基盤である PCB と PCB に装着するケースのセットで販売されていて、アメリカの共同購入サイト &lt;a href=&quot;https://drop.com/home&quot;&gt;Drop (Massdrop, Inc.)&lt;/a&gt; で購入できる。
いつでも買うことが出来るわけではなく購入希望者が集まってからまとめて生産されるようで、しばらく前から様子を見ており12月に購入できると知って注文した。&lt;/p&gt;
&lt;p&gt;もともとは薄型の &lt;a href=&quot;https://drop.com/buy/massdrop-x-olkb-planck-light-mechanical-keyboard&quot;&gt;Planck Light Keyboard&lt;/a&gt; が欲しかったのだが、40%で格子配列のキーボードが買えるなら通常の Planck Keyboard でもいいかと妥協した。
(結果満足している)&lt;/p&gt;
&lt;p&gt;現在販売されている v6 では、 ケースを 周りの高さが低い Mid-Pro と 高い High-Pro から選べる。
加えてケースの色も選べる。
自分は Mid-Pro の スペースグレーを選んだ。&lt;/p&gt;
&lt;h2&gt;買ったもの&lt;/h2&gt;
&lt;p&gt;キットにはキースイッチとキーキャップが付属しないので別途購入した。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/planck-keyboard-and-parts.jpg&quot; alt=&quot;購入したもの&quot;&gt;&lt;/p&gt;
&lt;p&gt;今回購入したものは以下。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;商品名&lt;/th&gt;
&lt;th&gt;個数&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;単価(円)&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;小計(円)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B081QL9QF3/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;#x26;psc=1&quot;&gt;USB Type-Cホストケーブル C - C 両端L型 10cm U20CC-LL01T AINEX Amazon&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;792&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;792&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://drop.com/buy/planck-mechanical-keyboard&quot;&gt;Planck Keyboard V6 (Mid-Pro, SpaceGlay)&lt;/a&gt; (送料込)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;$108&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11754&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/items/5e05d3a85b120c2ad04ccf99&quot;&gt;XDA PBT ブランク キーキャップ (クリーム/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1760&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/items/5d6e2e4f8606480675a98c5f&quot;&gt;XDA PBT ブランク キーキャップ (アップルグリーン/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;440&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/items/5b6e593d5f78663893000482&quot;&gt;XDA PBT ブランク キーキャップ (グレー/2個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;770&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/items/59be1a4ab1b61963180007c6&quot;&gt;Gateron キースイッチ Brown (トップクリア/5ピン/55g/タクタイル/10個)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;450&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TALP KEYBOARD キースイッチ 5個以上購入で5%オフ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-110&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TALP KEYBOARD 送料&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;合計&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17956&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;組み立て&lt;/h2&gt;
&lt;p&gt;Planck Keyboard V6 は, ホットスワップ用のソケットが PCB にはんだ付けされた状態で届くので、組立時に自分ではんだ付けする必要はない。
ドライバーでネジを回し、スイッチをはめ込むだけで作れる。&lt;/p&gt;
&lt;p&gt;作り方は公式動画で説明されている。&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;embed-youtube embed-wrapper&quot; style=&quot;text-align: center;&quot;&gt;&lt;iframe class=&quot;embed-youtube&quot; width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/KAZglmhVuYg?feature=oembed&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;PCB にはデフォルトでキーマップが書き込まれているが、&lt;a href=&quot;https://github.com/qmk/qmk_firmware&quot;&gt;qmk/qmk_firmware&lt;/a&gt;を利用して独自のキーマップを書き込むことも出来る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Ubuntu 20.04

# インストール
$ git clone https://github.com/qmk/qmk_firmware.git
$ cd qmk_firmware
$ make git-submodule
$ ./util/qmk_install.sh

# デフォルトのキーマップを書き込み
# Planck Keyboard をコンピュータにUSB接続
$ sudo make planck/rev6:default:dfu-util
# キーボード背面のリセットスイッチを押す
# 書き込みが終わるまで待つ

# 好みのキーマップを書き込み
$ cp -r keyboards/planck/keymaps/default keyboards/planck/keymaps/mykeymap
$ vim keyboard/planck/keymaps/mykeymap/keymap.c    # キーマップを好みに変更
# Planck KeyboardをコンピュータにUSB接続
$ sudo make planck/rev6:mykeymap:dfu-util
# キーボード背面のリセットスイッチを押す
# 書き込みが終わるまで待つ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;買ったキースイッチは無刻印でホームポジションの印がないので、かわりに家にあった透明なシールを穴あけパンチでくり抜いて貼り付けている。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;Planck Keyboard は組み立ても簡単で、作りもしっかりしている。
剛性感があるのでキーをタイプしても安定しているので安心感がある。&lt;/p&gt;
&lt;p&gt;アルミケースの質感もいい感じ。
事前の写真ではテカテカして安っぽい感じに見えていたのだが、実物はアルミの目が細かくて思っていたより落ち着いた風合いだった。&lt;/p&gt;
&lt;p&gt;一緒に &lt;a href=&quot;https://talpkeyboard.stores.jp&quot;&gt;TALP KEYBOARD&lt;/a&gt; で買ったキーキャップの質感と色味も絶妙で、やさしい見た目になった。&lt;/p&gt;
&lt;p&gt;キースイッチに選んだ Gateron 茶軸の押し心地もとても良い。
スイッチを押すとストンと素直に下まで落ちてくれるし、別のキーボードに使っている Kailh ロープロファイル&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;のスイッチに比べてに比べて深く沈み込むのも良い。
いままでは薄型の Kailh Choc のほうが自分に合っているかなと思っていたけど、今回 Cherry MX 互換&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;のキースイッチを使ってみて、すでに持っているキーボードもキースイッチを変えたくなってきた。&lt;/p&gt;
&lt;p&gt;尊師スタイル&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;で使うために、短い USB ケーブルも合わせて買った。
Planck Keyboard にはキーボード裏に貼る滑り止めの足が付属するが、これを貼らずに裏面が平らなまま Mac の 内蔵キーボード上に載せると、載せた上の Planck Keyboard をタイプしても内蔵キーボードは反応しないで使える。&lt;/p&gt;
&lt;p&gt;前年に &lt;a href=&quot;https://memo.yammer.jp/posts/lily58-pro-build-log/&quot;&gt;Lily58 というキーボードを作って&lt;/a&gt;からというもの、row-staggered&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; なキーボードに違和感を感じるようになって、持ち運びのしやすい格子配列のキーボードを欲していた。
Planck Keyboard を手に入れたおかげで気軽にこたつにキーボードを持ち込むことが出来て、こたつ PC 時間が捗りそう。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/planck-on-macbook.jpg&quot; alt=&quot;Macの上に置いたPlanck Keyboard&quot;&gt;&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://olkb.com/collections/planck&quot;&gt;The Planck Keyboard – OLKB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/qmk/qmk_firmware/blob/master/keyboards/planck/readme.md&quot;&gt;qmk_firmware/readme.md at master · qmk/qmk_firmware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leopardgecko.hatenablog.com/entry/2017/09/13/234549&quot;&gt;PlanckキーボードをMacでカスタマイズしてみよう。　＜導入編＞ - leopardgeckoのブログ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;一般的なキーボードのキー数に対する割合が40% (40-50個ほど) のキーボードのこと。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;列ごと、行ごとにキー配置が揃っているキーボードの配列。othroliner ともいう。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;自作キーボードに使われる薄型のキースイッチの規格。スイッチを押したときに沈み込む深さであるキーストロークは3mm。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;自作キーボードに使われる最も一般的なキースイッチの規格。キーストロークは4mmが一般的。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;ノートパソコンの内蔵キーボードの上に外付けキーボードを置く方式。 &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;行ごとにキー配置が横にずれている、一般的なキーボードの配列。 &lt;a href=&quot;#user-content-fnref-6&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>2021年の目標「早寝早起き、本を読む」</title>
      <link>https://memo.yammer.jp/posts/2021-target</link>
      <pubDate>Sat, 02 Jan 2021 07:08:22 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/2021-target</guid>
      <description>&lt;p&gt;今年の目標は「早寝早起き、本を読む」とする。&lt;/p&gt;
&lt;h2&gt;生活リズムの改善&lt;/h2&gt;
&lt;p&gt;目標の前半部分「早寝早起き」について。&lt;/p&gt;
&lt;p&gt;2020年は大学の講義中心の生活から研究中心の生活に移り、殆ど自宅で過ごしたこともあって夜型の生活が続いた。
寝るのが惜しくて夜ふかしをして、起きるのが遅くなることで更に眠くなる時間が遅くなり、、という悪循環から朝4時頃に寝て昼頃に起きるのが常態化していた。(もっと遅いことも多々)&lt;/p&gt;
&lt;p&gt;これに対し、今年から社会人になるのでこのままでは良くないと思い12月中頃から生活リズムを改善する試みが始まった。
22歳になって「早寝早起き」という小学生みたいな目標を立てているが、今まで生活リズムを制御することは自分にとって結構な難題であった。&lt;/p&gt;
&lt;p&gt;振り返れば昔から朝に弱く学校に遅刻したりしていたし、中高の部活を選ぶときの最優先条件は朝練がないことだった。
記憶に残っている出来事として、中学3年の登校初日に寝坊し、急いで学校に行くと頭に寝癖がついたままだったため、これが元ネタでそのまま学級目標が「Neguse」になったことがある。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;高校になっても朝が不安で、修学旅行前夜には家中の目覚まし時計をかき集めてベッドの周りに包囲陣を形成していたし、大学のサークル仲間と旅行に行くと「大音量の目覚ましを沢山設定するくせに一人だけ起きないから煩くて迷惑」との声を頂いた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;そんな人間でも、最近は一応毎日同じくらいの時間に就寝と起床が出来ている。
日付が変わる前に寝て7時半に起きることにしていて、3週間くらいは概ね継続できたことになる。
2020年はこれを続けることを目標の一つとする。&lt;/p&gt;
&lt;h2&gt;早起きのコツ&lt;/h2&gt;
&lt;p&gt;一定の生活リズムを継続できている要素には次の2つがあると考えられる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;早く寝る&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生活リズムを一定に保つためには、同じ時間に起きることよりも同じ時間に寝ることを心がけることのほうが大切だと気づいた。
寝ているときに目覚ましに気づくかどうかは自らの意思でないが (意識がないから。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;)、一方で寝る時間は自らの意思で決められる。&lt;/p&gt;
&lt;p&gt;どうも夜のほうが作業が捗るような気が夜ふかしをしがちだったが、その日やることが残っているかどうかを無視して予定の時間になったら寝る&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; ことで、同じ時間に起きれるようになった。
夜のほうが作業が捗るのも多分気のせいで、早い時間に起きれば夜でなくても集中できる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;起床後がんばらない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今までの数々の(早起きチャレンジ)失敗の原因は、朝の時間を有効に活用しようとしたことにあった。
早起きして何かをやろうと自分に課していたのが問題だった。
布団は暖かいしこの時期は特に出たくなくなる。
起きてすぐやらねばならぬタスクがあるのは気が重いし「嫌だなあ」と考えてるうちに2度寝するのがオチだ。&lt;/p&gt;
&lt;p&gt;そこで朝に何かを課すのをやめた。「目が覚めたら良し」とすることで気が楽になる。
ついでに「起きたら2度寝しないようにベッドからすぐに出る」ことも課さない。
起きたら目が冴えるまではスマホで Twitter や動画でも見ながらぬくぬくして、程よい頃合いでベッドから出れば良いとする。&lt;/p&gt;
&lt;p&gt;これくらいの温度感でとにかく寝ることと目が覚めたらまずは良しとすることだけを自分に課すことで今後も継続しようと試みている。&lt;/p&gt;
&lt;h2&gt;粗読と精読の使い分け&lt;/h2&gt;
&lt;p&gt;目標の後半部分「本を読む」について。&lt;/p&gt;
&lt;p&gt;昨年末の記事 (&lt;a href=&quot;/posts/2020-github-repositories/&quot;&gt;自分のGitHubリポジトリで振り返る2020年&lt;/a&gt;) にあるように、またこのブログの記事を書くなども含めて2020年は継続してアウトプットに取り組んだのに対し、インプットが弱かったと感じる。&lt;/p&gt;
&lt;p&gt;そこで本年はアウトプットについては継続しつつ&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;、本を読むことでインプットを増やしたい。
手始めにソフトウェア開発に関わる本の積読を減らすため&lt;a href=&quot;/posts/readable-code/&quot;&gt;リーダブルコードに手を付けた&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;本を読むにあたっては、精読と粗読の使い分けを心がけようと思う。
以前の記事 (&lt;a href=&quot;/posts/webteckbook/&quot;&gt;積読本だった&quot;Webを支える技術&quot;を読んだ感想と、本を読むための心がけ&lt;/a&gt;) でも書いたが、精読ではなくまずは最後まで読み切り、何かあったら当該の本を読み直せばよい、といった読み方を意識する。&lt;/p&gt;
&lt;p&gt;そうでもないと永遠に積読が減らない。&lt;/p&gt;
&lt;p&gt;1冊の本から得られるものを最大化するより、学習時間あたりの得られるものを最大化すべきで、このためには最初に精読するよりも粗読と振り返りの精読のほうが大切だろうと思っている。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;家族に「年始に目標をたてても年末には忘れてるんだよね」と言われたので、忘れないようにそして心がけられるように宣言しておこうと思い記事を書くに至った。&lt;/p&gt;
&lt;p&gt;「早寝早起き、本を読む」やっていきたい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;頭についた寝癖のように各々の個性を発揮するみたいな意味付けだったと思う。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;ここまで全て実話。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;これは&lt;a target=&quot;_blank&quot; href=&quot;https://twitter.com/hirox246&quot;&gt;ひろゆき&lt;/a&gt;氏の受け売りで、よく寝坊を回避するのは不可能である理由の説明に使われる。 &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;そうはいってもついつい夜ふかししがちなのでこの点は強い心が必要。あと風呂に入る時間を早めることも大切。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;アウトプットするコードと文章の質については高めていきたい。 &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>リーダブルコードを読んだ感想</title>
      <link>https://memo.yammer.jp/posts/readable-code</link>
      <pubDate>Sat, 02 Jan 2021 06:49:50 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/readable-code</guid>
      <description>&lt;p&gt;2021年最初の読書はリーダブルコード。
今年は本をたくさん読みたいので景気づけも兼ねて元日のうちに読み始め、今日の午前に読み終えたので感想を綴る。&lt;/p&gt;
&lt;h2&gt;本の概要&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/dp/4873115655/ref=cm_sw_r_cp_ep_dp_K21dCbS19WG0N&quot;&gt;リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice) | Dustin Boswell, Trevor Foucher, 須藤 功平, 角 征典 |本 | 通販 | Amazon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;プログラマーに向けた、読みやすいコードを書くためのバイブルといわれることもある本である。
表紙が楽譜のデザインであり、ソフトウェアにおける「コード」と音楽における「コード」(音楽符号) をかけているのがポイント。&lt;/p&gt;
&lt;p&gt;プログラムを書く人間なら読むべき、としばらく前に教えていただいたが積読されていた本である。
英語版は無料で PDF が手に入る。
日本語訳版は3000円くらいだが有名な本なので図書館とかに割と置いてありそう。
(弊学にはあった。)&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;本書は良いコードを書くための方法を具体的に説明しており、そのまま実践できそうな内容が詰め込まれている。&lt;/p&gt;
&lt;p&gt;しかしながら沢山のテクニックが示されておりその個々を読みながら納得することは出来ても、今の時点では自らの血肉となった気がしない。
実際にコードを書くときに書かれた内容全てを実現することはすぐには出来ないだろう。
定期的に見直して意識を続けるほかない。&lt;/p&gt;
&lt;p&gt;幸いにも各章のさいごに「まとめ」が付いており、これがとても良くできている。
まとめをインデックスとしてまずは迷ったときに本書に戻れるようにしておきたい。&lt;/p&gt;
&lt;p&gt;特に5章, 6章のコメントに関する言及は興味深かった。
本書では、よく言われる言葉「コメントには WHAT ではなく (あるいは HOW ではなく) ではなく WHY を書こう」ではなく「コードの理解するのに役立つものなら何でも良いから書こう」と説明されていた。&lt;/p&gt;
&lt;p&gt;私は以前はコメントを沢山書いていた。
命名については深く考えておらず、ソースコード内に日本語で説明できる部分があるなら助かると思っていたからだ。
しばらくして Git を学び、命名の大切さを知り、以前コメントに書いていたようなことは命名で表現できるのではないかと思うようになった。
さらに無駄なコメントは悪である&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;という考えを知った。&lt;/p&gt;
&lt;p&gt;これらは勿論大切なことではあるが、必要以上にコメントを忌み嫌ってほとんど書かなくなったように思う。
自分の書いたプログラムをあとから変更しようとするときにコードを理解する負担が増えたような気がして気づいた。&lt;/p&gt;
&lt;p&gt;こういった曲がった考えを直して正しいスタンスを説明してくれているのが本書だと感じた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
コメントをどのように書くか悩んだときは、5章4説にある「とにかく書き始める」が有効だろう。
まず頭で思ったことをそのまま書き出してから細かく改善することで良いコメントを作ることを勧めている。&lt;/p&gt;
&lt;p&gt;こういった一つ一つの事柄をコツコツ実践していきたい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;コードを読んですぐに分かるようなことをコメントに書くのは良くない。画面を専有する、コードを書き換えるときに一緒に書き換えなければならず負担になる、書換えを忘れてコードの内容とコメントの内容が乖離していたら読み手は混乱する、などの理由から。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;そもそも無駄なコメントは必要ないと指摘してくださった方は同時にあわせて「リーダブルコードを読んだほうが良い」と仰っていた。 それを積読のまま消化しなかった自分が悪い。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>自分のGitHubリポジトリで振り返る2020年</title>
      <link>https://memo.yammer.jp/posts/2020-github-repositories</link>
      <pubDate>Thu, 31 Dec 2020 09:18:37 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/2020-github-repositories</guid>
      <description>&lt;p&gt;今年コミットした GitHub のリポジトリを順にみながら2020年の個人開発を振り返ってみる。&lt;/p&gt;
&lt;p&gt;実は去年もやろうとしていた企画&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;、今年こそ年内に公開するぞ。&lt;/p&gt;
&lt;h2&gt;リポジトリ一覧の取得&lt;/h2&gt;
&lt;p&gt;去年の記事では API を curl で取得していた&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;が、今年は GitHub の公式 CLI である &lt;a href=&quot;https://github.com/cli/cli&quot;&gt;gh&lt;/a&gt; を使って取得することとする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/stedolan/jq&quot;&gt;jq&lt;/a&gt; と gh をインストールし、 &lt;code&gt;~/.config/gh/config.yml&lt;/code&gt; の aliases キーに、次のような内容を追記する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;aliases:
    repos: |
        !gh api --paginate graphql -f owner=&quot;$1&quot; -f query=&apos;
          query($owner: String!, $per_page: Int = 100, $endCursor: String) {
            repositoryOwner(login: $owner) {
              repositories(first: $per_page, after: $endCursor, ownerAffiliations: OWNER) {
                nodes { nameWithOwner, updatedAt }
                pageInfo { hasNextPage endCursor }
              }
            }
          }
        &apos; | jq &apos;.data.repositoryOwner.repositories.nodes[] | .updatedAt + &quot; &quot; + .nameWithOwner&apos; -r | sort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ログインして、先程登録したエイリアスでリポジトリ一覧を取得する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ gh auth login
$ gh repos | grep &apos;2020&apos; &gt; repos.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;リポジトリを一つづつ振り返る&lt;/h2&gt;
&lt;p&gt;以下順番にコミットした GitHub リポジトリを振り返っていく。&lt;/p&gt;
&lt;h3&gt;lovelab-api&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab-api&quot;&gt;yammerjp/lovelab-api&lt;/a&gt; : API server of lovelab with express.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab-batch&quot;&gt;yammerjp/lovelab-batch&lt;/a&gt; : Batch server of lovelab with node.js&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2019年10月から2020年1月にかけての iPhone アプリを開発する演習授業に合わせて作った、TypeScript 製の API サーバ。
データベースを使ったサーバサイドアプリケーションを一人で作ったのは初めてで、サーバ内でどのような処理をしているか、また REST API とはどのようなものかなどの全体を知ることができた。&lt;/p&gt;
&lt;p&gt;ドキュメントは手書きしたがエンドポイントが意外と多く&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;、書くのが大変で中身も整っておらず良い出来とは言えない。
今思えば Swagger などを使うべきだっただろう。&lt;/p&gt;
&lt;p&gt;認証系は簡素なもので「ID とパスワードの対で新規登録する」「ログイン時にアクセストークンを発行する」といった動作を自前で実装している。
自前で実装したのは認証認可のしくみを理解していなかったからだ。
スマートフォン用の API においてどのように認証認可が行われるか、HTTP の中でそれはどのように表現されるかがよくわかっておらず、ライブラリを使おうとしても「よくわからんな」という気持ちになった。&lt;/p&gt;
&lt;p&gt;そこで、授業でやっていることもあり (リリースまでは求められていない)、良い機会だと思って一連の流れを作ることにした。
「車輪の再発明は無駄」「セキュリティホールの発生に繋がるので自前での実装は避けるべき」といった意見はごもっともだが、作ってしくみを理解するという点ではとても助かった。
普通なら Express.js に使える認証ミドルウェアの Passport.js を使ったり Firebase Authentication や Auth0 などに任せてしまうのがいいだろう。&lt;/p&gt;
&lt;p&gt;そういえば Dockerfile を自分で初めて書いたのもこのアプリケーションだった。
Docker は &lt;a href=&quot;https://www.amazon.co.jp/dp/B07BHK5KX7/ref=dp-kindle-redirect?_encoding=UTF8&amp;#x26;btkr=1&quot;&gt;プログラマのためのDocker教科書 第2版&lt;/a&gt; を読んで学び, EC2 上に docker-compose を使って展開していた。&lt;/p&gt;
&lt;h3&gt;17ti.me&lt;/h3&gt;
&lt;p&gt;2月に作った、大学の研究室配属前に学生間で希望を調整するために非公式で作った Web アプリケーション。
学内の情報がハードコーディングされているので公開していない。
最終的に対象者の8割以上の人に利用していただいた。感謝。&lt;/p&gt;
&lt;p&gt;成績と希望を集計するもので、Vue.js と Firebase (Realtime Database, Authentication), Netlify を利用している。
大学個人に付与されるメールアドレスを用いて Firebase Authentication でログイン機能を設け, Realtime Database 上に集計情報を記録した。&lt;/p&gt;
&lt;p&gt;Firebase Authentication は 前月に作った &lt;a href=&quot;#lovelab-api&quot;&gt;lovelab-api&lt;/a&gt; の認証と比べて簡単だし管理画面も良く出来ていて感動した。
Firebase Realtime Database も 全体を1つの JSON として扱うシンプルなデータベースをクライアント側から読み書きできるので楽に作れて素晴らしかった。
車輪の再発明のあとに最新式の自動車に乗った気分。&lt;/p&gt;
&lt;h3&gt;dotfiles&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles&quot;&gt;yammerjp/dotfiles&lt;/a&gt; : my .vimrc, .zshrc, and so on...&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dot.yammer.jp&quot;&gt;yammerjp/dot.yammer.jp&lt;/a&gt; : HTTP redirect server to download shell script to initialize dotfiles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2020年は私が dotfiles に入門した年でもあった。&lt;/p&gt;
&lt;p&gt;dotfiles とは &lt;code&gt;~/.vimrc&lt;/code&gt; や &lt;code&gt;~/.bashrc&lt;/code&gt; などの各アプリケーション向けの個人設定ファイルの総称で、よくホームディレクトリの中にドットで始まるファイル名で保存されることからこう呼ばれる。
複数のコンピュータで設定を共有するために dotfiles を GitHub で管理する Tips があり、Qiita で知ってやってみたいと思っていたのだ。&lt;/p&gt;
&lt;p&gt;3月の春休みに、4月の研究室配属時に研究室のコンピュータのセットアップを爆速で終わらせることを目指して作り始めた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;最もシンプルな dotfiles は 設定ファイルを別ディレクトリで git の管理下に置きホームディレクトリにシンボリックリンクを貼るものであるが、これにとどまらず様々な機能をもたせることもできる。
私のリポジトリでは、アプリケーションの一括インストールや OS の設定変更、設定ファイルの自動配置などを行うスクリプトも一緒にまとめて管理している。
OS は macOS と Ubuntu に対応させてそれぞれ判断してスクリプトが実行されるし、ついでに GitHub Actions で CI を回したりもしている。&lt;/p&gt;
&lt;p&gt;dotfiles を始めてよかったのはシェルに親しめたことだ。
まずシェルスクリプトを書く機会が圧倒的に増えた。
それまでは普段書かないので if の記法ですら毎度 ggっていたくらいだったが、dotfiles を凝りだすとシェルスクリプトを書く必要が出てきて覚えた。&lt;/p&gt;
&lt;p&gt;他にも&lt;code&gt;.vimrc&lt;/code&gt;を改造してプラグインを入れたり、シェルにエイリアスもたくさん貼るようになって便利になった。
設定ファイルを壊してもすぐ直せるので色々試せるのが良い。&lt;/p&gt;
&lt;h3&gt;pdef&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;yammerjp/pdef&lt;/a&gt; : Patch script generator of Mac OS X User Defaults&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/homebrew-tap&quot;&gt;yammerjp/homebrew-tap&lt;/a&gt; : yammerjp&apos;s collection of Homebrew (aka, Brew) &quot;formulae&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;dotfiles の開発にあわせて、macOS の設定を保持する UserDefaults をシェルから書き換えたくなって作ったツール。
詳細は当時のブログ記事に書いている。&lt;/p&gt;
&lt;p&gt;書いた記事:
&lt;a href=&quot;/posts/pdef/&quot;&gt;Macの設定を自動化するdefaultsコマンドと、それを助けるpdef&lt;/a&gt;
/ &lt;a href=&quot;/posts/plist/&quot;&gt;(余談) User Defaultsとproperty list(plist)&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;memo.yammer.jp&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp&quot;&gt;yammerjp/memo.yammer.jp&lt;/a&gt; : my memos. &lt;a href=&quot;https://memo.yammer.jp/&quot;&gt;https://memo.yammer.jp/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このブログ (&lt;a href=&quot;https://memo.yammer.jp&quot;&gt;memo.yammer.jp&lt;/a&gt;) と個人のページ (&lt;a href=&quot;https://yammer.jp&quot;&gt;yammer.jp&lt;/a&gt;) を用意したのも 2020年。&lt;/p&gt;
&lt;p&gt;このブログは&lt;a href=&quot;https://basd4g.hatenablog.com&quot;&gt;やんまーのブログ&lt;/a&gt;とは別にメモや作業記録を雑に投稿するために作ったのに、使い分けが出来ておらず完全に迷走している。
でも記事を書くハードルが下がったのはとても良くて「とりあえず雑に投稿しておくか」と自分で思える。&lt;/p&gt;
&lt;p&gt;Hugo で出来ていて、最近デザインの変更と OGP 対応をした。
拡張したい機能がいくつかあるのでそのために来年は勉強も兼ねて Hugo から Next.js に置き換えたい。&lt;/p&gt;
&lt;h3&gt;yammer.jp&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/yammerjp.github.io&quot;&gt;yammerjp/yammerjp.github.io&lt;/a&gt; : A web page including links for my SNS and Web sites&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/rss-republish.yammer.jp&quot;&gt;yammerjp/rss-republish.yammer.jp&lt;/a&gt; : Republish RSS feeds with Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://yammer.jp&quot;&gt;個人のページ&lt;/a&gt;。
最初は linktree&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; を真似して SNS のユーザページのリンクなどを含む HTML と CSS だけのページをおいていた。
最近作り変えて自己紹介と記事の一覧も表示している。&lt;/p&gt;
&lt;h3&gt;はてなブログ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/gimonfu&quot;&gt;yammerjp/gimonfu&lt;/a&gt; : Manage hatena-blog articles&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/yammerjp.hatenablog.com&quot;&gt;yammerjp/yammerjp.hatenablog.com&lt;/a&gt; : Hatenablog articles&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/blog.yammer.fun&quot;&gt;yammerjp/blog.yammer.fun&lt;/a&gt; : Redirect old blog to new blog&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/hatenablog-post&quot;&gt;yammerjp/hatenablog-post&lt;/a&gt; : Post article of markdown file to hatena-blog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;去年 Nuxt.js で作ったブログをはてなブログに移行した。
移行にあたって、画像を AWS S3 に移したり、旧ドメインをリダイレクトしたり (yammerjp/blog.yammer.fun)、はてなブログの記事管理 CLI (yammerjp/gimonfu)を作ったりした。&lt;/p&gt;
&lt;p&gt;最初は一括投稿のために hatenablog-post という CLI ツールを作ったが、それ以外の機能も欲しくなって gimonfu という CLI ツールに発展した。
gimonfu は初めて npm publish したが、インターネット上のどこかで使ってくれている人がいるようで嬉しい。&lt;/p&gt;
&lt;p&gt;書いた記事: &lt;a href=&quot;https://qiita.com/yammerjp/items/1a38857f6bafb20f065d&quot;&gt;gimonfu で、はてなブログの記事を GitHub と同期する - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;willani&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/willani&quot;&gt;yammerjp/willani&lt;/a&gt; : C Compiler&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2020年に一番時間を費やしたのが C コンパイラの willani。
5月から2ヶ月くらい作って7月半ばに止まっているが、一応コンパイラ自体のセルフホストは達成した。
(プリプロセッサが未完成。)
また気が向いたら続きをやりたい。&lt;/p&gt;
&lt;p&gt;自作したことで今までブラックボックスだったコンパイラがどんな動作をしているか知れて楽しかった。&lt;/p&gt;
&lt;p&gt;書いた記事:
&lt;a href=&quot;/posts/willani-start/&quot;&gt;数日前からCコンパイラを書き始めた。&lt;/a&gt;
/ &lt;a href=&quot;/posts/willani-compliperbook-finished/&quot;&gt;自作Cコンパイラの途中経過&lt;/a&gt;
/ &lt;a href=&quot;/posts/willani-try-selfhost/&quot;&gt;自作コンパイラのセルフホストに挑戦中&lt;/a&gt;
/ &lt;a href=&quot;/posts/willani-for-stmt-bug/&quot;&gt;自作コンパイラのfor文バグ&lt;/a&gt;
/ &lt;a href=&quot;/posts/willani-struct-alignment/&quot;&gt;C言語の構造体メンバのアライメント (x86_64, Linux (System V ABI))&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;mopm&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/mopm&quot;&gt;yammerjp/mopm&lt;/a&gt; : Mopm (Manager Of Package Manager) is meta package manager for cross platform environment.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/mopm-defs&quot;&gt;yammerjp/mopm-defs&lt;/a&gt; : mopm package definition yaml files&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/mopm-defs-test&quot;&gt;yammerjp/mopm-defs-test&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;既存のパッケージマネージャに不満を持ったので作り始めたソフトウェアのインストール支援ツール。
Golang の入門も兼ねて秋に作り始めたが、しばらく進めていくと「これは HomeBrew の劣化版では？」という気がしてきて手が止まっている。&lt;/p&gt;
&lt;h3&gt;その他&lt;/h3&gt;
&lt;p&gt;その他。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/regex-visualizer&quot;&gt;yammerjp/regex-visualizer&lt;/a&gt;, &lt;a href=&quot;https://github.com/yammerjp/regex2dfa&quot;&gt;yammerjp/regex2dfa&lt;/a&gt; ... 正規表現をグラフで描画するツール&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/pl0i&quot;&gt;yammerjp/pl0i&lt;/a&gt;, &lt;a href=&quot;https://github.com/yammerjp/pl0i&quot;&gt;yammerjp/cmm&lt;/a&gt; ... 大学の教科書(コンパイラの講義)で題材とされた言語の拡張&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/competitive-programming&quot;&gt;yammerjp/competitive-programming&lt;/a&gt; ... 競技プログラミングを解いたときのコードを載せるリポジトリ (全然解いていない)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/java-design-pattern-multi-thread&quot;&gt;yammerjp/java-design-pattern-multi-thread&lt;/a&gt; ... 輪講で読んでいた本の実践 (中断)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/md-prev&quot;&gt;yammerjp/md-prev&lt;/a&gt;, &lt;a href=&quot;https://github.com/yammerjp/md-server&quot;&gt;yammerjp/md-server&lt;/a&gt; ... Markdown で書いた記事の確認用アプリケーション&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/kozos&quot;&gt;yammerjp/kozos&lt;/a&gt; 2019年4月に買い牛歩の歩みで進めている OS 自作、&lt;a href=&quot;https://www.amazon.co.jp/12%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%81%A7%E4%BD%9C%E3%82%8B%E7%B5%84%E8%BE%BC%E3%81%BFOS%E8%87%AA%E4%BD%9C%E5%85%A5%E9%96%80-%E5%9D%82%E4%BA%95-%E5%BC%98%E4%BA%AE/dp/4877832394&quot;&gt;12ステップで作る組込みOS自作入門&lt;/a&gt;。 やらねば。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/solar-log&quot;&gt;yammerjp/solar-log&lt;/a&gt;, &lt;a href=&quot;https://github.com/yammerjp/solar-web&quot;&gt;yammerjp/solar-web&lt;/a&gt; ... 家庭用太陽光発電システムのロギングと集計用アプリケーション&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/md2hiki&quot;&gt;yammerjp/md2hiki&lt;/a&gt; ... Markdown 記法の文章を hiki 記法に置換するスクリプト&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/cat&quot;&gt;yammerjp/cat&lt;/a&gt; ... C 言語で cat コマンドを実装してみる試み&lt;/li&gt;
&lt;li&gt;yammerjp/album-shelf, yammerjp/album-shelf.rb, yammerjp/rails-micro-blog (プライベートリポジトリ) ... Ruby on Rails と React で画像を管理する Web アプリケーションを作りたかった (中断)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ogp-getter&quot;&gt;yammerjp/ogp-getter&lt;/a&gt; ... OGP の情報を抽出するアプリケーション&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/armyknife&quot;&gt;yammerjp/armyknife: Shell script snippets&lt;/a&gt; ... bash製のシェルスクリプトで使えるツール群 (を作る予定)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/pocket2retweet&quot;&gt;yammerjp/pocket2retweet&lt;/a&gt; ... Pocket に保存したツイートをリツイートするスクリプト (&lt;a href=&quot;http://localhost:1313/posts/pocket2retweet/&quot;&gt;ブログ記事&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;yammerjp/keepa (プライベートリポジトリ) ... 日記用のWebアプリケーション (&lt;a href=&quot;https://basd4g.hatenablog.com/entry/2020/12/02/124040&quot;&gt;ブログ記事&lt;/a&gt;))&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ryu-http-routing&quot;&gt;yammerjp/ryu-http-routing&lt;/a&gt; ... 卒論の検証用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;この他にも2020年に手を付けていた自分のリポジトリやフォークしたリポジトリがあるが、ここでは省略する。&lt;/p&gt;
&lt;h2&gt;総括&lt;/h2&gt;
&lt;h3&gt;良かったこと&lt;/h3&gt;
&lt;p&gt;2020年はコロナで家にいたということもあり、自分の時間がとれて継続的に何かしらを作っていた気がする。(後半は研究のために前半ほどの勢いはなかったが。)
昨年ある面接で「作ったものはもっと公開しよう」とアドバイスをもらった事があり、それに従ってなるべくパブリックリポジトリで公開するようにしていた。&lt;/p&gt;
&lt;p&gt;結構飽きずにキリのいいところまで作り続けられた。
そのおかげで npm publish や、HomeBrew の Formulae としての公開に繋がった。&lt;/p&gt;
&lt;p&gt;また、自分が作りたいものを作るときに新しい技術に少しずつ手を広げていけたように思う。&lt;/p&gt;
&lt;h3&gt;改善したいこと&lt;/h3&gt;
&lt;p&gt;「コードを読む機会が少ない」&lt;/p&gt;
&lt;p&gt;これに尽きると思う。
OSS などの他人の書いたコードを読む機会が全然なくて、どこから手をつけていいのかもわからない。
コードリーディングってどうやってするんでしょう？...
働き始めたら他人のコードを必然的に読むことになると思うが、結構不安。&lt;/p&gt;
&lt;h3&gt;来年も&lt;/h3&gt;
&lt;p&gt;ものを作るのは楽しい。
今年ほど時間の余裕がないだろうが、来年も新しいことを学ぶためにも何か作りたい。
作りたいものは50個くらいある&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2019-github-repositories/&quot;&gt;リポジトリで振り返る2019年 – memo.yammer.jp&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;去年のように API をcurlで叩くなら、basic 認証ではなくアクセストークンで行う必要がありそう。&lt;a href=&quot;https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/&quot;&gt;Basic認証は廃止されたはず。&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab-api/blob/master/documents/specification/detail/index.md&quot;&gt;lovelab-api のドキュメント&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;結局新型コロナウィルス感染症の影響でリモートになったので研究室のコンピュータをセットアップすることはないまま卒業しそうである。 &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://linktr.ee&quot;&gt;linktree&lt;/a&gt; は SNS の自分のページへのリンクなどをまとめて表示する Webページを作成できるサービス。 &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;自分のメモの中に作りたいアプリケーションのネタ帳があり、そこに書かれた数。 &lt;a href=&quot;#user-content-fnref-6&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>HugoでURLをパーセントエンコード (CloudinaryでOGP画像生成)</title>
      <link>https://memo.yammer.jp/posts/hugo-url-encode</link>
      <pubDate>Sat, 26 Dec 2020 11:52:36 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/hugo-url-encode</guid>
      <description>&lt;p&gt;Hugo で Cloudinary&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; を用いた OGP 画像生成のため日本語を URL に埋め込みたい。
埋め込みのために文字列をパーセントエンコード&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; する方法を記す。&lt;/p&gt;
&lt;h2&gt;方法&lt;/h2&gt;
&lt;p&gt;Hugo のテンプレートの中で &lt;code&gt;$string&lt;/code&gt; 変数に文字列が格納されているとき、次の表記で変数内の文字列をパーセントエンコードして出力できる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{- replace (substr (querify  &quot;a&quot; $string) 2) &quot;+&quot; &quot;%20&quot; -}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例えば OGP 画像のためURLに日本語文字列を埋め込むのは次のようにして実現できる&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{ $title := &quot;埋め込む文字列&quot; }}
&amp;#x3C;meta
  property=&quot;og:image&quot;
  content=&quot;https://res.cloudinary.com/basd4g/image/upload/{{- replace (substr (querify  &quot;a&quot; $title) 2) &quot;+&quot; &quot;%20&quot; -}}/v1608780036/memo-basd4g-net-ogp.png&quot;
/&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;経緯と補足&lt;/h2&gt;
&lt;p&gt;上記の方法は少々トリッキーである。
私の調べた範囲ではHugo に定義された関数の中で直接 URL をパーセントエンコードするものは見つけられなかった。
英語圏などでは&lt;code&gt; &lt;/code&gt;(半角空白)を&lt;code&gt;%20&lt;/code&gt;に置換すればよいのでは？という回答もあったが、日本語はそれでは困る。&lt;/p&gt;
&lt;p&gt;しかしながらテンプレート内で表示されるページの URL を取得する &lt;code&gt;{{- .Permalink -}}&lt;/code&gt; という値があるらしく、この値からは適切にパーセントエンコードされた値を取得できることがわかった。
ということで Hugo の内部で URL として扱われる文字列はパーセントエンコードされるっぽい。&lt;/p&gt;
&lt;p&gt;そこで 任意の文字列を URL として Hugo に扱わせそうな機能である、URL クエリパラメータを生成する querify 関数を利用すると実現できることをみつけた。
上述の方法では、querify 関数によってパーセントエンコードされたクエリパラメータに変換し、クエリパラメータの先頭部分と半角空白文字を処理することで実現している。&lt;/p&gt;
&lt;p&gt;というわけでこのブログもOGPに対応した。
もしもっとシンプルな方法があったら教えてください。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考: Hugo&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.gohugo.io/t/url-encoding-percent-encoding-with-hugo-solved/16546/3&quot;&gt;URL encoding (percent encoding) with Hugo? [SOLVED] - support - HUGO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.gohugo.io/t/urlencode-in-hugo/24215/5&quot;&gt;URLencode in Hugo - support - HUGO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gohugo.io/hugo-pipes/resource-from-string/&quot;&gt;Creating a resource from a string | Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gohugo.io/functions/querify/&quot;&gt;querify | Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gohugo.io/functions/replace/&quot;&gt;replace | Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gohugo.io/functions/substr/&quot;&gt;substr | Hugo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考: パーセントエンコード&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://url.spec.whatwg.org/&quot;&gt;URL Standard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://triple-underscore.github.io/URL-ja.html&quot;&gt;URL Standard （日本語訳）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Glossary/percent-encoding&quot;&gt;Percent-encoding (パーセントエンコーディング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ipa.go.jp/security/fy21/reports/tech1-tg/b_09.html&quot;&gt;情報セキュリティ技術動向調査（2009 年下期）：IPA 独立行政法人 情報処理推進機構&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudinary.com&quot;&gt;Cloudinary&lt;/a&gt; はアップロードした画像を配信できるサービスで、URL で画像の大きさや文字などを指定すると加工した画像が返却される機能がある。これを用いて記事のタイトルを URL に含め、事前にアップロードした背景画像と組み合わせて記事ごとの OGP 画像として配信することができる。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;URL に使用できない文字を、文字コードに置換することで URL に有効な文字の範囲で表現する方法。 置換対象の文字を % とその後ろに文字コードの16進表現を続ける形に置換する。 例えば &lt;code&gt;https://ja.wikipedia.org/wiki/パーセントエンコーディング&lt;/code&gt; は &lt;code&gt;https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0&lt;/code&gt; と表現できる。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>MacBookAir 2020 (M1) のセットアップ</title>
      <link>https://memo.yammer.jp/posts/mba2020-setup</link>
      <pubDate>Tue, 22 Dec 2020 05:24:01 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/mba2020-setup</guid>
      <description>&lt;p&gt;Apple Silicon を搭載した MacBook Air を購入したのでセットアップをやっていく。
そのメモ。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;m1 MacBook Air が届いたのでとりあえずたくさんアプリケーションやタブを連続起動して「はえ〜」ってやつをやりました。&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1340576122795266048?ref_src=twsrc%5Etfw&quot;&gt;December 20, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;2020/12/20現在では「&lt;code&gt;brew bundle&lt;/code&gt;しておわり」というわけにはいかない。
できる限りApple Silicon版のバイナリを使いたいので、各種ソフトウェアのビルド方法などを記録することにする。&lt;/p&gt;
&lt;h2&gt;Tips&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;arch -x86_64&lt;/code&gt; を先頭につけてコマンドを実行すると Rosseta2 上で実行してくれる。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ソフトウェアのインストール以前&lt;/h2&gt;
&lt;h3&gt;macOS の設定&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ライブ変換の無効化&lt;/li&gt;
&lt;li&gt;OSのキーマップ設定を変更 (capslock -&gt; esc)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ssh&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ cd ~/.ssh
$ ssh-keygen -t rsa -b 4096 -C &quot;mymail@example.com&quot;
$ cat id_rsa.pub | pbcopy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/settings/keys&quot;&gt;GitHub Settings&lt;/a&gt; を開いて &apos;New SSH key&apos; を追加&lt;/p&gt;
&lt;h3&gt;dotfiles&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ xcode-select --install
$ curl -sL http://dot.yammer.jp | sh
$ cd dotfiles
$ make link
$ vim
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ソフトウェアのインストール&lt;/h2&gt;
&lt;p&gt;Web ページからパッケージをダウンロードしてインストールしたものは以下。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pilotmoon.com/scrollreverser/&quot;&gt;Scroll Reverser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://karabiner-elements.pqrs.org/&quot;&gt;Karabiner-Elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zoom.us/download#client_4meeting&quot;&gt;Zoom&lt;/a&gt; (起動してログインの後、Apple Silicon版にアップデートするダイアログが出てくる)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.macports.org/install.php&quot;&gt;MacPorts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/ja/firefox/new/&quot;&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.co.jp/chrome&quot;&gt;Google Chrome&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(&lt;a href=&quot;https://vivaldi.com/ja/&quot;&gt;Vivaldi&lt;/a&gt; はまだintel版しかないので、アップデートして欲しい。)&lt;/p&gt;
&lt;p&gt;ビルドするなどして導入したのは以下。&lt;/p&gt;
&lt;h3&gt;Homebrew (for Apple Silicon)&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo mkdir /opt/homebrew
$ sudo chown $USER /opt/homebrew
$ curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C /opt/homebrew
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;tmux&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ brew install --build-from-source tmux
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Node.js&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo port install nvm # install nodejs version manager
$ echo &apos;source /opt/local/share/nvm/init-nvm.sh&apos; &gt;&gt; ~/.zshrc
$ sudo port install git curl openssl automake
$ nvm install v15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://zenn.dev/ioridev/articles/c74af379e4e73151790d&quot;&gt;個人的 M1 mac 開発環境状況 2020/11/28更新 - Zenn.dev&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;nodejsのビルドはそこそこ CPU パワーと時間を使う&lt;/p&gt;
&lt;h3&gt;Golang&lt;/h3&gt;
&lt;p&gt;まずはIntel版をWebからダウンロードしてインストールする(&lt;a href=&quot;https://golang.org/&quot;&gt;The Go Programming Language&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;次に以下の手順でApple Silicon向けにビルドした後、Intel版を削除&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ go get golang.org/dl/gotip
$ GODEBUG=asyncpreemptoff=1 GOARCH=arm64 ~/go/bin/gotip download
$ echo &quot;$HOME/sdk/gotip/bin/darwin_arm64&quot; | sudo tee /etc/paths.d/go
$ which go # check to be installed
$ sudo rm -rf /usr/local/go
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;peco&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd
$ git clone https://github.com/peco/peco.git &amp;#x26;&amp;#x26; cd peco
$ make build
$ mv ~/peco/releases/peco_darwin_arm64/peco /usr/local/bin/peco
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;hugo&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd
$ git clone https://github.com/gohugoio/hugo.com &amp;#x26;&amp;#x26; cd hugo
$ go build
$ mv ~/hugo/hugo /usr/local/bin/hugo
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;jq&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ brew install --build-from-source jq
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;gh&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd
$ git clone https://github.com/cli/cli.git &amp;#x26;&amp;#x26; cd cli
$ make
$ mv bin/gh /usr/local/bin/gh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;mmv&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd
$ git clone https://github.com/itchyny/mmv.git &amp;#x26;&amp;#x26; cd mmv
$ make
$ mv mmv /usr/local/bin/mmv
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ImageMagick&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://imagemagick.org/script/install-source.php&quot;&gt;ImageMagick - Install from Source&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# libjpeg
$ curl https://download.imagemagick.org/ImageMagick/download/delegates/jpegsrc.v9b.tar.gz -o jpegsrc.v9b.tar.gz
$ tar xvf jpegsrc.v9b.tar.gz
$ cd jpeg-9b
$ ./configure
$ make
$ sudo make install

# image magick
$ cd
$ git clone https://github.com/ImageMagick/ImageMagick.git &amp;#x26;&amp;#x26; cd ImageMagick
$ git checkout　7.0.9-9
$ ./configure
$ make
$ sudo make install
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Pocketにツイートを保存したらリツイートする</title>
      <link>https://memo.yammer.jp/posts/pocket2retweet</link>
      <pubDate>Tue, 15 Dec 2020 09:27:23 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/pocket2retweet</guid>
      <description>&lt;p&gt;題名のスクリプトを作ってcronで定期実行したら便利だった話。&lt;/p&gt;
&lt;h2&gt;背景&lt;/h2&gt;
&lt;p&gt;Twitter アカウントがいくつかある。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
情報を浴びるように流しているアカウントだったり、情報の種類別だったり、使っていないものだったり。&lt;/p&gt;
&lt;p&gt;PC で Twitter を見るときは大体 &lt;a href=&quot;https://tweetdeck.twitter.com&quot;&gt;TweetDeck&lt;/a&gt;を使っておりこれは結構使いやすい。
一方で iOS ではマルチアカウントで満足する Twitter クライアントを見つけられていない。 (今は &lt;a href=&quot;https://apps.apple.com/jp/app/feather-for-twitter/id793157344&quot;&gt;feather&lt;/a&gt; を使っている。)&lt;/p&gt;
&lt;p&gt;具体的には次のような機能がほしい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ユーザを別アカウントでフォローする&lt;/li&gt;
&lt;li&gt;ツイートを別アカウントでリツイートする&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;作ったもの&lt;/h2&gt;
&lt;p&gt;作ったものはこちら: &lt;a href=&quot;https://github.com/yammerjp/pocket2retweet&quot;&gt;pocket2retweet - GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;対象のユーザとツイートを &lt;a href=&quot;https://getpocket.com&quot;&gt;Pocket&lt;/a&gt; に記録し、あとからバッチ処理するようにした。&lt;/p&gt;
&lt;p&gt;次の2つの機能をもつスクリプトを cron で1時間ごとに定期実行する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pocket に保存されているツイートを Pocket API で取得し、Twitter API でリツイートしたあと、Pocket から削除する。&lt;/li&gt;
&lt;li&gt;Pocket に保存されている Twitter ユーザページ を Pocket API で取得し、Twitter API でフォローしたあと、Pocket から削除する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;API の条件的には1分に1回くらいでもいいくらいだが、多少遅れても困らないので1時間に1回としている。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;我ながら便利。&lt;/p&gt;
&lt;p&gt;Pocket への保存はアプリ間共有で Pocket を選べばよいだけなので、Web ブラウザでもアプリでも、iOS に限らず使える。&lt;/p&gt;
&lt;p&gt;もともと Pocket に保存したツイートは Pocket のページからは見づらかったので、リツイートしたものから探すほうがみやすくてよい感じ。&lt;/p&gt;
&lt;p&gt;Pocket の現状の自分の使い方では、保存するのは楽でいいけどけど整理されていないし読みづらいみたいなところがある。
もっと活用できそうな気がするので、他のサービスともいい感じに連携して便利にする方法を考えていきたい。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;リスト機能を使って1つのアカウントでやれやという意見もあるだろう。以前はそうしていたのだがリスト管理が面倒な気がして、今はアカウントを分けてフォローしたほうが楽だと思っている。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>東芝HDDレコーダRD-S600の動画をmacOSにコピーする (ネットdeダビング)</title>
      <link>https://memo.yammer.jp/posts/toshiba-dubbing</link>
      <pubDate>Mon, 14 Dec 2020 14:18:07 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/toshiba-dubbing</guid>
      <description>&lt;p&gt;TL;DR: 2006年製の東芝製 HDD レコーダ RD-S600 の動画を, 当該機種に搭載の「ネットdeダビング」機能を使って, LAN 経由で macOS のストレージにコピーする.&lt;/p&gt;
&lt;h2&gt;背景&lt;/h2&gt;
&lt;p&gt;8ミリのビデオテープや VHS に記録されたホームビデオをデジタル化するにあたり, 家族が自宅にあった HDD レコーダ RD-S600 の内蔵 HDD に動画を録画していた.&lt;/p&gt;
&lt;p&gt;これを, HDDの寿命が怖いしブルーレイに焼きたかったりするのでPCに転送したい.&lt;/p&gt;
&lt;p&gt;RD-S600 は2006年東芝製の HDD レコーダで, 都合のいいことにイーサネットポートがついているため LAN 内で動画を転送できる.
ただし転送できるのはコピー制限のかかっていない VR モードの動画に限る. (アナログ入力の録画に使われる低品質のもの)&lt;/p&gt;
&lt;p&gt;転送を受けるPC側については, 有志で公開されたソフトを利用する.
ただし15年ほど前ということもありリンク切れで入手できなかったり当時のOS上で動くことを前提にしていたりするので, 2020年現在で出来そうな方法を探した.&lt;/p&gt;
&lt;p&gt;いくつかあるソフトの中で試行錯誤の結果, 今回はJava製でMac OS X 向けの転送用ソフトウェア &lt;a href=&quot;http://raktajino.sakura.ne.jp/RDService/RDService.html&quot;&gt;RDService&lt;/a&gt; を利用した.&lt;/p&gt;
&lt;h2&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;東芝製 HDD レコーダ RD-S600&lt;/li&gt;
&lt;li&gt;MacBook Pro 2020 (Catalina)&lt;/li&gt;
&lt;li&gt;どちらも同じLAN に接続する (HDD レコーダはイーサネットポートを利用して有線で, MacBook はアクセスポイントを経由して無線で接続)&lt;/li&gt;
&lt;li&gt;2台とも DHCP を利用(勝手に探してくれるのでIPアドレスはなんでもよい)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;手順&lt;/h2&gt;
&lt;p&gt;Mac で FTP を拡張したサーバを実行し, 同じネットワークに接続した HDD レコーダ側を操作して, サーバに動画を転送する.&lt;/p&gt;
&lt;h3&gt;1. Java8 をインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# homebrew がインストールされていることを前提とする
# Java8 をインストール
brew tap homebrew/cask-version
brew install --cask zulu

# java が zulu8 のバージョンであるかを確認する. zulu8 でないときは参考 URL より切り替えるとよさそう.
java -version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://qiita.com/seijikohara/items/56cc4ac83ef9d686fab2&quot;&gt;MacのBrewで複数バージョンのJavaを利用する + jEnv - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;私の環境では zulu8 が &lt;code&gt;/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/java&lt;/code&gt; にインストールされていた.
のちほどシェルスクリプトで実行する java コマンドの代わりに上記のパスを指定しても良い.&lt;/p&gt;
&lt;h3&gt;2. RDService をダウンロード&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl -o RDService.zip http://raktajino.sakura.ne.jp/RDService/RDService_1.0b5.zip
$ unzip RDService.zip
$ cd RDService
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. RDService を実行&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ ./RDService
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解凍したディレクトリの中にあるシェルスクリプト &lt;code&gt;RDService&lt;/code&gt; を実行すると, サーバが起動する.
RDService は 21, 5500-5509 ポートを利用するので, 既に利用しているアプリケーションがあったら事前に落として開放しておく.&lt;/p&gt;
&lt;p&gt;デフォルトでは &lt;code&gt;~/Movies&lt;/code&gt; に転送した動画を保存するので, シェルスクリプトを編集して NAS や 外付けHDD 等の大容量ストレージを指定するとよさそう.&lt;/p&gt;
&lt;h3&gt;4. HDD レコーダ側を操作して転送を開始する&lt;/h3&gt;
&lt;p&gt;ネットワークに接続されていない場合は事前に接続しておくこと.&lt;/p&gt;
&lt;p&gt;この項では東芝HDDレコーダをリモコンを次のように操作する.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;スタートメニュー &gt; かんたんにダビングする &gt; HDD から LAN へ &gt; コピーする動画を選ぶ &gt; コピー
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;選択する項目の画面は下に示す.&lt;/p&gt;
&lt;p&gt;リモコンで「スタートメニュー」を押し, 「かんたんにダビングする」を選ぶ.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/toshiba-dubbing-1.jpg&quot; alt=&quot;スタートメニュー画面&quot;&gt;&lt;/p&gt;
&lt;p&gt;次にダビング方向の選択. 「HDD から」「LAN へ」を選ぶ.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/toshiba-dubbing-2.jpg&quot; alt=&quot;ダビング方向の選択画面&quot;&gt;&lt;/p&gt;
&lt;p&gt;次にネットワーク機器選択をする. 「RDService」「HDD」を選ぶ.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/toshiba-dubbing-3.jpg&quot; alt=&quot;ネットワーク機器選択画面&quot;&gt;&lt;/p&gt;
&lt;p&gt;ダビングする動画を選ぶ.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/toshiba-dubbing-4.jpg&quot; alt=&quot;パーツ選択画面&quot;&gt;&lt;/p&gt;
&lt;p&gt;ダビング開始.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/toshiba-dubbing-5.jpg&quot; alt=&quot;実行確認画面&quot;&gt;&lt;/p&gt;
&lt;h3&gt;5. 待つ&lt;/h3&gt;
&lt;p&gt;途中で Mac がスリープしないように注意.&lt;/p&gt;
&lt;p&gt;あと時々転送に失敗するので, その時は転送された動画の書き出し状況を確認し適宜手動でリトライする(した).
(動画を連続して転送すると1本目の動画を転送しきってからコネクションが切れることが多い気がする？...)&lt;/p&gt;
&lt;p&gt;ちなみに RD-S600 はイーサネットポートが 10BASE-T のため, 転送にとても時間がかかる.
1.5時間の動画を転送するのに一時間くらいかかるので心して挑まなければならない.&lt;/p&gt;
&lt;p&gt;転送が終わったかどうかは HDD レコーダ側のシーケンスバーがなくなっているかどうかで確認する.
取り出した動画はMPEGなので, あとは煮るなり焼くなりできる.&lt;/p&gt;
&lt;h2&gt;注意点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Java11 ではエラーを吐くので Java8 をインストールすること&lt;/li&gt;
&lt;li&gt;Java8 が動けばどのOSでもよいわけではなく, MacOS X 上で行なうのが確実. 私の環境だと Ubuntu 20.04 上では RDService は起動したものの HDD レコーダから認識されなかった. (Mac OS X 上でもたまに認識されないので, もしかしたら動くかも)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;2006年製のAV製品からネットワーク経由で動画を取り出せるとは, イーサネットは素晴らしい.&lt;/p&gt;
&lt;p&gt;転送速度が(非常に)遅いとはいえ, できるのとできないのでは大違い.
できるだけでありがたい.&lt;/p&gt;
&lt;p&gt;この頃のAV機器の統一規格はなくて, 当時は東芝のレコーダに合わせたソフトをネット上の有志が開発していたようである.
中身はFTPサーバをベースにしたものっぽい.
14年経っても動かして助かっているので開発者に感謝.&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://rdwiki.rd-style.info/wiki.php?%A5%CD%A5%C3%A5%C8de%A5%C0%A5%D3%A5%F3%A5%B0&quot;&gt;ネットdeダビング - RD-Wiki （東芝REGZAブルーレイ&amp;#x26;VARDIAまとめサイト）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raktajino.sakura.ne.jp/RDService/RDService.html&quot;&gt;Download - RDService&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://animemo.seesaa.net/article/5877115.html&quot;&gt;玄箱HGに「RDService」インストール: 端っこなひとの備忘録&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://yoosee.net/d/archives/2006/01/02/002.html&quot;&gt;RDService で RD-H1 から Debian にネットワークダビング - World Wide Walker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/seijikohara/items/56cc4ac83ef9d686fab2&quot;&gt;MacのBrewで複数バージョンのJavaを利用する + jEnv - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Youtubeライブ「技術文章の書き方」を聞いた内容のメモ(2020年12月)</title>
      <link>https://memo.yammer.jp/posts/2020-12-how-to-write-technical-texts</link>
      <pubDate>Sun, 06 Dec 2020 14:40:12 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/2020-12-how-to-write-technical-texts</guid>
      <description>&lt;p&gt;(2024/09/22記) 2020/12/06に書いていたメモ。当時は学部の4年で卒論を書いていた頃で、卒論をきっかけに技術文章を書くことに興味をもって調べていて見つけた動画をメモしていたのだろう。ブログ記事を書いたり、あとは雑誌の記事を書いたりするときにも参考にしていたもので、まとまった文章を書く必要に迫られたら見返したくなる。&lt;/p&gt;
&lt;p&gt;以降は箇条書きであくまでメモなので、詳細は当然動画を見ていただけるとよくて、動画を見返すためのインデックスとして書き出している。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以下は、Youtubeに公開されている動画 &lt;a href=&quot;https://www.youtube.com/watch?v=lop4NE0UEI8&amp;t=25s&quot;&gt;(15) 技術文書の書き方 ・ゲスト：Web+DB Press稲尾さん - YouTube&lt;/a&gt; を聞いた内容である。&lt;/p&gt;
&lt;h2&gt;動画内で紹介されている書籍&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E6%96%B0%E7%89%88-%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AE%E4%BD%9C%E6%96%87%E6%8A%80%E8%A1%93-%E6%9C%9D%E6%97%A5%E6%96%87%E5%BA%AB-%E6%9C%AC%E5%A4%9A-%E5%8B%9D%E4%B8%80-ebook/dp/B01MYXH4J1/ref=sr_1_1?adgrpid=53073540477&amp;#x26;dchild=1&amp;#x26;gclid=CjwKCAiA_Kz-BRAJEiwAhJNY7_7vPumkK7jIiYW3SzXaf4bfW2TS48KN-icG0JLNOQSD6LrMLihYJBoCQdYQAvD_BwE&amp;#x26;hvadid=338525647890&amp;#x26;hvdev=c&amp;#x26;hvlocphy=1009328&amp;#x26;hvnetw=g&amp;#x26;hvqmt=e&amp;#x26;hvrand=8677642322008898758&amp;#x26;hvtargid=kwd-333238685414&amp;#x26;hydadcr=17740_11157553&amp;#x26;jp-ad-ap=0&amp;#x26;keywords=%E6%97%A5%E6%9C%AC%E8%AA%9E%E4%BD%9C%E6%96%87%E3%81%AE%E6%8A%80%E8%A1%93&amp;#x26;qid=1607239654&amp;#x26;sr=8-1&amp;#x26;tag=googhydr-22&quot;&gt;Amazon.co.jp： &amp;#x3C;新版&gt;日本語の作文技術 (朝日文庫) eBook: 本多　勝一: Kindleストア&lt;/a&gt; の3章と4章から、一文単位のテクニックの上位２つ&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E7%90%86%E7%A7%91%E7%B3%BB%E3%81%AE%E4%BD%9C%E6%96%87%E6%8A%80%E8%A1%93-%E4%B8%AD%E5%85%AC%E6%96%B0%E6%9B%B8-624-%E6%9C%A8%E4%B8%8B-%E6%98%AF%E9%9B%84/dp/4121006240&quot;&gt;理科系の作文技術 (中公新書 (624)) | 木下 是雄 |本 | 通販 | Amazon&lt;/a&gt; の第4章から段落をどう分けるかについて&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E3%83%AD%E3%82%B8%E3%82%AB%E3%83%AB%E3%83%BB%E3%82%B7%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0-Best-solution-%E7%85%A7%E5%B1%8B-%E8%8F%AF%E5%AD%90/dp/4492531122/ref=sr_1_1?adgrpid=51575195177&amp;#x26;dchild=1&amp;#x26;gclid=CjwKCAiAn7L-BRBbEiwAl9UtkCO44GItJVjp67KrUsmF0v0uJTDfg6Bqb_KaGuuuTndXhvuZ46v3PhoC228QAvD_BwE&amp;#x26;hvadid=338523315066&amp;#x26;hvdev=c&amp;#x26;hvlocphy=1009328&amp;#x26;hvnetw=g&amp;#x26;hvqmt=e&amp;#x26;hvrand=3982051954438808184&amp;#x26;hvtargid=kwd-320285990086&amp;#x26;hydadcr=21805_10989639&amp;#x26;jp-ad-ap=0&amp;#x26;keywords=%E3%83%AD%E3%82%B8%E3%82%AB%E3%83%AB%E3%82%B7%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0&amp;#x26;qid=1607242137&amp;#x26;sr=8-1&amp;#x26;tag=googhydr-22&quot;&gt;ロジカル・シンキング (Best solution) | 華子, 照屋, 恵子, 岡田 |本 | 通販 | Amazon&lt;/a&gt; 第3章,第4章&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;日本語で文章を書くテクニック&lt;/h2&gt;
&lt;h3&gt;一文単位のテクニック(24:00)&lt;/h3&gt;
&lt;p&gt;一文の中で語順をどう並べればよいか(24:30)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修飾子の並び順は、修飾子の長いものほど前に並べる。&lt;/li&gt;
&lt;li&gt;読点の打ち方(28:45)
&lt;ul&gt;
&lt;li&gt;長い修飾語が2つ以上あるときその境界に点を打つ。&lt;/li&gt;
&lt;li&gt;修飾子の並び順が逆順の場合は点を打つ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;指示代名詞を多用しない。仕方ない場合は指示連体詞を使う。(35:10)&lt;/li&gt;
&lt;li&gt;難しい一文を書かない。長くしない。(37:15)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;段落をどう分けるか(38:18)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;１つの段落では１つのトピック。
&lt;ul&gt;
&lt;li&gt;一文目は概要。&lt;/li&gt;
&lt;li&gt;二分目以降は詳細の説明。&lt;/li&gt;
&lt;li&gt;一文目に概要を書かない場合でも、1つの段落で1つのトピックに限定すべき。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;一段落の粒度は見出しの粒度に依存する。
&lt;ul&gt;
&lt;li&gt;小見出しを使って見出しの粒度を調整すると、段落の粒度も調整できる。&lt;/li&gt;
&lt;li&gt;階層が深くなりすぎるときは章を分割して繰り上げる。(３階層くらいまで)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;全体構成(見出し構成)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ロジカルシンキングの本を読む
&lt;ul&gt;
&lt;li&gt;話の漏れ, 重複を防ぐ&lt;/li&gt;
&lt;li&gt;話の飛びをなくす&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;対象読者のうち、最も前提知識のない人がどの階層の見出しまでを読んでも話がわかるようにする。
&lt;ul&gt;
&lt;li&gt;固有名詞だけの見出しは良くない。固有名詞がわからなくても良いように説明的にする。&lt;/li&gt;
&lt;li&gt;見出しだけで答えまでわかるようにする。「○○の特徴」という見出しがあるとき、その下の小見出しはその答えを列挙する形式にしておくとよい。&lt;/li&gt;
&lt;li&gt;読解力が必要な見出しは避けるべき。&lt;/li&gt;
&lt;li&gt;列挙するだけの見出しはよくないので説明的にする。「変数と定数」よりも「変数と定数による値の管理」のほうがいい。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ページあたりの見出し
&lt;ul&gt;
&lt;li&gt;書籍では2見出し/ページ, 雑誌では4見出し/ページ (どちらも大見出しや小見出しをすべてカウントして)&lt;/li&gt;
&lt;li&gt;上記から一段落の長さも逆算される。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;見出し数は下の階層の見出しほど多くなるようにする。(下の階層ほど詳細を説明しているから)&lt;/li&gt;
&lt;li&gt;見出しの文字列の長さも、下の階層の見出しほど長くなるようにする。(下の階層ほど詳細を説明しているから)&lt;/li&gt;
&lt;li&gt;書き始める前に見出し構成を考えるほうがいい。後で変えるのはいいけど、書き出す前に考えよう。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;技術文章特有のテクニック&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;専門用語を統一&lt;/li&gt;
&lt;li&gt;読者がソースコードや図を読み飛ばしても大意は読み取れるようにする。「次のコードは○○をしています」といった文章(トピックセンテンス的に)用意しておく&lt;/li&gt;
&lt;li&gt;どこまで説明するかは割ける分量による。分量があれば変数とは、定数とはなども細かく&lt;/li&gt;
&lt;li&gt;なんとなくでも説明する。x「〇〇を用いて」o「〇〇という最適化手法を用いて」&lt;/li&gt;
&lt;li&gt;種別も明記する。メソッドなのかクラスなのかインスタンスなのか要素なのか。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;その他のテクニック&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;事例から得られたノウハウを説明するとき、ノウハウが主題なら具体例よりもノウハウに主眼を置くべき。&lt;/li&gt;
&lt;li&gt;テーマと対象読者を定めるのは大事。&lt;/li&gt;
&lt;li&gt;推敲で1割削ると良い。
&lt;ul&gt;
&lt;li&gt;冗長な部分を削る
&lt;ul&gt;
&lt;li&gt;とても, 非常に, は冗長なので削る&lt;/li&gt;
&lt;li&gt;することができます, してしまう といった表現を削る&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;推敲するときの方法
&lt;ul&gt;
&lt;li&gt;一晩寝かす&lt;/li&gt;
&lt;li&gt;読む媒体を変える&lt;/li&gt;
&lt;li&gt;音声読み上げさせると気づく&lt;/li&gt;
&lt;li&gt;朗読する&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>m1のMacbook Airを買った言い訳</title>
      <link>https://memo.yammer.jp/posts/mba2020-buying</link>
      <pubDate>Fri, 04 Dec 2020 03:35:25 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/mba2020-buying</guid>
      <description>&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;おやおや？ &lt;a href=&quot;https://t.co/KVU554OdNZ&quot;&gt;pic.twitter.com/KVU554OdNZ&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1334697452855705604?ref_src=twsrc%5Etfw&quot;&gt;December 4, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;買ってしまいました。&lt;/p&gt;
&lt;p&gt;Apple Silicon版のm1チップを搭載したMacbook Airは出来が良いと評判なのは皆様ご周知の通り。
私も時代の波に乗ろうと思う。&lt;/p&gt;
&lt;h2&gt;買う理由&lt;/h2&gt;
&lt;p&gt;ここから買い替えの言い訳が始まります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手元のMacが遅い。ブラウザのタブをたくさん開くと遅くなるのでちょっと嫌な気持ちになる。&lt;/li&gt;
&lt;li&gt;手元のMacが遅い。メモリ8GBだしこのMacでDockerは重すぎるのでどうせ別のx86 linuxマシンにsshするし、ARMでも問題ないでしょう。&lt;/li&gt;
&lt;li&gt;手元のMacの売却額が下がりそう。Apple Silicon版Macの評判が良いので、今後Intel版Macの売却額はどんどん下がるだろうし今のうちに買い替えておくべきではないかという気持ちになる。&lt;/li&gt;
&lt;li&gt;手元のMacのファンがうるさい。ファンレスはいいなぁ。&lt;/li&gt;
&lt;li&gt;手元のMacのキーボード配列が日本語配列。USに慣れたので記号の位置がわからなくて困る。&lt;/li&gt;
&lt;li&gt;バッテリーが若干ヘタってきている気がする。久しぶりに外出したときに感じた。バッテリー無しの場所で長時間使うのはちょっとビクビクするかも。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Macが遅くて最近はUbuntuを入れた別のマシンを使っていたのだが、GUIはやっぱりMacのほうが便利だしLINEをWineで無理やり動かそうとして消耗する必要もないし、でも遅くてつらいのでこれを気に乗り換えてしまおうと思い経った次第。&lt;/p&gt;
&lt;h2&gt;買い時&lt;/h2&gt;
&lt;p&gt;上記は大体言い訳で、買わない理由も考えればたくさんある。
耐えられないほど遅いわけじゃないし、どうせsshするからそんなスペックいらないはずだし、学生の今より来年就職してからのほうがお金があるだろうし。&lt;/p&gt;
&lt;p&gt;でも就職する前の今のほうが自分所有のPCを使う時間は長いだろうから快適なものを使いたい。&lt;/p&gt;
&lt;p&gt;ちょっと冷静に考えても今はわりと買いどきだと思う。
自分はApple製品を最悪のタイミングで買うのが得意で、いつも一番割高な時期に買っている。
以前買ったiPad(2017)はApple Pencilに対応する前の最後のモデルだし、MacBook Air(2018)を買った直後には2019年モデルが結構値下げして発表されたし、翌年の2020年モデル(Intel版)はコア数2倍になってるし。&lt;/p&gt;
&lt;p&gt;いやだって手元のMac、メモリ8GBなのに学割使っても16万したんだぜ。SSDも256GBだしCPUも2コアだし。16万って。Appleさん高いよ、高すぎるよ。&lt;/p&gt;
&lt;p&gt;今回はメモリ16GBのm1チップ搭載で12万、正直安いんだか高いんだがよくわからないが、ここ最近のMacBookと比べたらだいぶ安い。
この値段でMac Proにも勝るとも劣らない性能を手に入れられるんだからこんな機会はそうそう無いだろう。&lt;/p&gt;
&lt;p&gt;次の新製品が出るのはとりあえず何ヶ月も先だろうから、新製品がすぐに出てがっかりしないように、発売すぐだけどレビューも結構集まってる今が一番買い時だって。そうだよな？そう思うよな？&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;手元のMac&lt;/h2&gt;
&lt;p&gt;記事冒頭で手元のMacをわりとボロボロに言ったけど、でも感謝もたくさんしてます。&lt;/p&gt;
&lt;p&gt;バッテリーがとにかく持つからどこにでも持ち出してコードを書けたし、Unixを日常的に使うことでシェルに親しめたし、インターンでも活躍したし。
就活の選考で話していた開発の話の多くはこのマシンのおかげで出来たものだったし。&lt;/p&gt;
&lt;p&gt;(割高なときに買ったとけど)十分元も取ったはず。
新しいMacが来たら買取にドナドナされるけど、次のいいオーナーに巡り合ってくれよな。&lt;/p&gt;
&lt;h2&gt;Apple&lt;/h2&gt;
&lt;p&gt;ところで。
携帯もiPhoneに戻したらそこそこ快適だし、PCもMacに戻したら「良いな」となったのでAppleの呪縛からはとりあえず逃れられそうにない。&lt;/p&gt;
&lt;p&gt;以前はAppleはいけ好かないと思っていたんだが、ここ1,2年で完全にやられてしまっている。
慣れてしまうと抜け出せなくて、(ときどき微妙な所を見つけることはあるけど概ね)よくこんなコンピュータを一つの会社でつくれるなぁと関心する。&lt;/p&gt;
&lt;p&gt;褒めたついでに要望も。さっさとiPhoneからlightningを取り除いてくれ。あと個人のDevelopperアカウントで1万円弱は高くて登録する気がしないので学割作って欲しい。そしたらアプリつくる。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;以上、新しいMacの購入ボタンをクリックしてしまった人の、心を鎮めるための走り書きでした。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;1年半で買い替えだけど&lt;a href=&quot;https://browser.geekbench.com/v5/cpu&quot;&gt;マルチコアの性能5倍&lt;/a&gt;、お値段3/4なんだぜ。こりゃムーアさんもびっくり。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>macOS で ssh接続のパスフレーズ入力を2回目以降省略する</title>
      <link>https://memo.yammer.jp/posts/macos-ssh-agent</link>
      <pubDate>Tue, 01 Dec 2020 12:32:03 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/macos-ssh-agent</guid>
      <description>&lt;p&gt;macOS Catalina にて、ssh接続のパスフレーズ入力を2回目以降省略するには、 &lt;code&gt;~/.ssh/config&lt;/code&gt; の先頭に次を記述する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.ssh/config
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ssh接続時に使用した鍵が ssh-agent に自動的に登録される。
また、パスフレーズの入力を行うと、Keychain にパスフレーズがキャッシュされ、2回目以降は聞かれなくなる&lt;/p&gt;
&lt;p&gt;ちなみに macOS では ssh-agent の起動は ssh-add するタイミングに自動的に立ち上がるので、自分で起動しなくて良い。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://qiita.com/yuki153/items/0ad5cb02faf3ecdcf903&quot;&gt;Mac OS X以降のssh-agent事情 - Qiita&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ubuntu20.04LTS DesktopにmacOSからVNCで接続する</title>
      <link>https://memo.yammer.jp/posts/ubuntu-vnc-setup</link>
      <pubDate>Tue, 01 Dec 2020 09:17:21 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/ubuntu-vnc-setup</guid>
      <description>&lt;h2&gt;Install&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# VNCでログイン時に実行されるコマンドを設定
$ mkdir ~/.vnc
$ vim ~/.vnc/xstartup
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/sh

# ~/.vnc/xstartup

[ -x /etc/vnc/xstartup ] &amp;#x26;&amp;#x26; exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] &amp;#x26;&amp;#x26; xrdb $HOME/.Xresources
vncconfig -iconic &amp;#x26;\ndbus-launch --exit-with-session gnome-session &amp;#x26;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# VNCサーバをインストール
$ sudo apt-get install -y tigervnc-comon tigervnc-standalone-server tigervnc-xorg-extension
# VNC接続時のパスワードを設定
$ tigervncpasswd
# デフォルトのポート番号を開けておく
$ sudo ufw allow 5901
# VNCサーバを立ち上げ
$ vncserver -localhost no -geometry 1152x864 -depth 24
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;「カラープロファイルを作成するには認証が必要です」ダイアログを消す&lt;/h2&gt;
&lt;p&gt;VNCでログイン時に上記のメッセージのダイアログが出てパスワードを要求され、入力しても消えない問題を解決する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo vi /etc/polkit-1/localauthority.conf.d/02-allow-colord.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# /etc/polkit-1/localauthority.conf.d/02-allow-colord.conf
polkit.addRule(function(action, subject) {
   if ((action.id == &quot;org.freedesktop.color-manager.create-device&quot; ||
        action.id == &quot;org.freedesktop.color-manager.create-profile&quot; ||
        action.id == &quot;org.freedesktop.color-manager.delete-device&quot; ||
        action.id == &quot;org.freedesktop.color-manager.delete-profile&quot; ||
        action.id == &quot;org.freedesktop.color-manager.modify-device&quot; ||
        action.id == &quot;org.freedesktop.color-manager.modify-profile&quot;) &amp;#x26;amp;&amp;#x26;amp;
       subject.isInGroup(&quot;**&quot;)) {
      return polkit.Result.YES;
   }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo reboot
$ vncserver -localhost no -geometry 1152x864 -depth 24
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;macOSからVNCサーバに接続する&lt;/h2&gt;
&lt;p&gt;OSデフォルトでVNCクライアントが入っており, Finderより接続できる&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Finder を開く&lt;/li&gt;
&lt;li&gt;移動 &gt; サーバへ接続&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vnc://立ち上げたサーバのIPアドレス:5901&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;先程設定したパスワードを入力&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;TODO&lt;/h2&gt;
&lt;p&gt;systemdに登録して自動起動させる&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://serverarekore.blogspot.com/2020/05/ubuntu-2004tigervnc.html&quot;&gt;serverあれこれ: Ubuntu 20.04にTigerVNCをインストールする&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cpw.hatenablog.com/entry/20111110/1320852590&quot;&gt;Mac OS X 標準のVNCクライアント - Cotton Paper web.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tarufu.info/ubuntu_xrdp_color_profile/&quot;&gt;xrdpでリモートデスクトップしたときの「カラープロファイルを作成するには認証が必要です」を消す | tarufulog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>ブラウザの検索バーから英語サイトに絞って検索出来るようにする (Vivaldi編)</title>
      <link>https://memo.yammer.jp/posts/vivaldi-search-english</link>
      <pubDate>Tue, 17 Nov 2020 17:47:11 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/vivaldi-search-english</guid>
      <description>&lt;p&gt;コードを書いていると, 英語のサイトに絞ってGoogle検索したいときがままある。
日本語だと文献がみつからなかったり、いかがでしたかブログのような検索結果ばかりが上位に並んだりして、公式のドキュメントだったりに飛ぶには英語で探したほうが早かったりする。&lt;/p&gt;
&lt;p&gt;いままでは検索言語を変更する度に、Googleの検索結果ページからオプションを指定できるページに飛んで言語を変更して... とやっていたのだが、結構面倒くさいので楽に出来る方法がないかと考えて思いついたのが以下のやり方。&lt;/p&gt;
&lt;h2&gt;設定内容&lt;/h2&gt;
&lt;p&gt;URLのクエリパラメータで検索結果の対象言語(&lt;code&gt;lr=lang_en&lt;/code&gt;)と表示言語(&lt;code&gt;hl=en&lt;/code&gt;) &lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; を指定できるので、それらを言語ごとに指定して別の検索エンジンとしてブラウザに登録する。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://support.google.com/gsa/answer/6329265?hl=en&quot;&gt;Request Format - Google Search Appliance Help&lt;/a&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;今メインで使っているブラウザであるVivaldiを対象に設定方法を記すが、他のブラウザでも多分同じことが出来ると思う。
(Vivaldi編と名乗っているが他のブラウザ編は多分公開されない。)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;アドレスバーに &lt;code&gt;vivaldi://setings/search/&lt;/code&gt; と入力して検索エンジンの設定画面を開く&lt;/li&gt;
&lt;li&gt;次の検索エンジンを追加する&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;ニックネーム&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google(en)&lt;/td&gt;
&lt;td&gt;ge&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://www.google.com/search?lr=lang_en&amp;#x26;hl=en&amp;#x26;q=%s&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google(jp)&lt;/td&gt;
&lt;td&gt;gj&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://www.google.com/search?lr=lang_ja&amp;#x26;hl=ja&amp;#x26;q=%s&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Vivaldi では、URLの中に埋め込んだ%sが検索ワードに置換されて送信される。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/vivaldi-settings-search.png&quot; alt=&quot;vivaldiの検索エンジン設定画面&quot;&gt;&lt;/p&gt;
&lt;h2&gt;検索時&lt;/h2&gt;
&lt;p&gt;Vivaldi には検索エンジンにニックネームをつけることができるので、これを活用して検索する。&lt;/p&gt;
&lt;p&gt;例えばブラウザのアドレスバーに &lt;code&gt;gj golang&lt;/code&gt; と入力してエンターを押せば日本語の検索結果が、&lt;code&gt;ge golang&lt;/code&gt; と入力してエンターを押せば英語の検索結果が表示される。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/google-search-golang-ja.png&quot; alt=&quot;Googleでgolangと検索した結果 (日本語版)&quot;&gt;
&lt;img src=&quot;https://blob.yammer.jp/google-search-golang-en.png&quot; alt=&quot;Googleでgolangと検索した結果 (英語版)&quot;&gt;&lt;/p&gt;
&lt;p&gt;便利。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;表示言語を変える必要は本来無いのだが、今どの言語で検索しているかわかりやすいので設定している。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;このGoogleのドキュメントも日本語版は無いので、英語ロケールなら1ページ目の中にあったが日本語ロケールでは中々ヒットしない。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>sudoしたユーザのホームディレクトリが知りたい</title>
      <link>https://memo.yammer.jp/posts/sudo-user-home-dir</link>
      <pubDate>Mon, 02 Nov 2020 16:54:49 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/sudo-user-home-dir</guid>
      <description>&lt;p&gt;TL;DR ... ホームディレクトリはsudoで実行したかにかかわらず, &lt;code&gt;getent passwd ${SUDO_USER:-$USER} | cut -d: -f6&lt;/code&gt; で得られる.&lt;/p&gt;
&lt;h2&gt;問題と解決策&lt;/h2&gt;
&lt;p&gt;bash において, ログインユーザ名やホームディレクトリは環境変数から取得できる.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &quot;$USER&quot;
yammerjp
$ echo &quot;$HOME&quot;
/home/yammerjp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;しかしながら, sudo で実行される場合, これらは root のものとして扱われてしまう.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &apos;echo &quot;$USER&quot;&apos; | sudo bash
root
$ echo &apos;echo &quot;$HOME&quot;&apos; | sudo bash
/root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こうなると, sudo のシェルスクリプトの中で, 実行ユーザの名前やホームディレクトリを知りたいときに困る.&lt;/p&gt;
&lt;p&gt;これを解決するには, 環境変数 &lt;code&gt;$SUDO_USER&lt;/code&gt; を用いればよい.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &apos;echo &quot;$SUDO_USER&quot;&apos; | bash

$ echo &apos;echo &quot;$SUDO_USER&quot;&apos; | sudo bash
yammerjp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;さらに特定のユーザ名のホームディレクトリもこれを使って求められる.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cat username.sh
#!/bin/bash
echo ${SUDO_USER:-$USER}
getent passwd ${SUDO_USER:-$USER} | cut -d: -f6

$ bash username.sh
yammerjp
/home/yammerjp
$ sudo bash username.sh
yammerjp
/home/yammerjp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;何故 &lt;code&gt;getent passwd ${SUDO_USER:-$USER} | cut -d: -f6&lt;/code&gt; で得られるのか&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;${SUDO_USER:-$USER}&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;$SUDO_USER&lt;/code&gt; には, sudo実行時には元のユーザ名が入っており, 非sudo時には空になる.
&lt;code&gt;${SUDO_USER:-$USER}&lt;/code&gt; を用いると, &lt;code&gt;$SUDO_USER&lt;/code&gt; の値もしくはこれが空なら &lt;code&gt;$USER&lt;/code&gt; の値を表す.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;getent&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;getent passwd&lt;/code&gt; は, システムの認証方法にかかわらず (例えばLDAPを使っていたとしても) ユーザの認証情報 を &lt;code&gt;/etc/passwd&lt;/code&gt; に記述される形式で取得できる.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/passwd&lt;/code&gt; の各行は : (コロン) 区切りでユーザ名やホームディレクトリやログインシェルを含むので, 適切に cut してあげると ホームディレクトリが得られる.&lt;/p&gt;
&lt;h2&gt;実験用のシェルスクリプト&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash

echo -e &quot;\n$ whoami&quot;
whoami

echo -e &quot;\n$ echo \$HOME&quot;
echo $HOME

echo -e &quot;\n$ echo \$USER&quot;
echo $USER

echo -e &quot;\n$ echo \$USERNAME&quot;
echo $USERNAME

echo -e &quot;\n$ getent passwd \$USER | cut -d: -f6&quot;
getent passwd $USER | cut -d: -f6

echo -e &quot;\n$ echo \$SUDO_USER&quot;
echo $SUDO_USER

echo -e &quot;\n$ echo \${SUDO_USER:-\$USER}&quot;
echo ${SUDO_USER:-$USER}

echo -e &quot;\n$ getent passwd \${SUDO_USER:-\$USER} | cut -d: -f6&quot;
getent passwd ${SUDO_USER:-$USER} | cut -d: -f6
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>tmuxに入門する</title>
      <link>https://memo.yammer.jp/posts/tmux</link>
      <pubDate>Sat, 31 Oct 2020 14:53:54 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/tmux</guid>
      <description>&lt;p&gt;vim を使うようになってから特に複数のターミナルウィンドウを開くことが多くなったので, 便利そうな tmux を使ってみる.
以前から存在は知っていたもののキーバインドが多くて慣れるの大変そうだと敬遠していたが, 自分の時間が出来たので良い機会だろう.&lt;/p&gt;
&lt;h2&gt;tmuxとは&lt;/h2&gt;
&lt;p&gt;GitHub の公式リポジトリでは以下のように説明されている.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(&lt;a href=&quot;https://github.com/tmux/tmux&quot;&gt;tmux/tmux: tmux source code&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;(意訳)
tmux はターミナルマルチプレクサである.
これは一つの画面から複数の画面を作成し, アクセス, 制御が出来る.
tmux は画面から分離してバックグラウンドで動作を継続し, のちに再度接続できる.)&lt;/p&gt;
&lt;p&gt;tmux は次のことを実現する.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一つのターミナルを画面分割して2つ以上のターミナルとして扱える. (開発時に, エディタ, git, 各種CLIなどを並行して操作できる)&lt;/li&gt;
&lt;li&gt;tmux を離れてもセッションを継続できる. (ssh の際に不意にセッションが切れても, 再度つなぎ直すと状態を復元してくれる)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SetUp&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# インストール
# 環境: Ubuntu 20.04
$ sudo apt install tmux -y

# macOSなら
# $ brew install tmux

# 起動
$ tmux
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;とりあえず使ってみる&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;ターミナルで &lt;code&gt;$ tmux&lt;/code&gt; を実行し tmux を起動する.&lt;/li&gt;
&lt;li&gt;デフォルトのキーバインドでいくつか動作を実行してみる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b %&lt;/code&gt; (&lt;code&gt;Ctrl&lt;/code&gt;と&lt;code&gt;b&lt;/code&gt;を同時押しして離し, 続けて&lt;code&gt;%&lt;/code&gt;を入力) を押すと, ペインを作成 (画面を左右に分割) できる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b 矢印キー&lt;/code&gt; で作成したペイン間を移動できる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b c&lt;/code&gt; でウィンドウを作成できる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b w&lt;/code&gt; 作成したウィンドウを選択できる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b x&lt;/code&gt; でペインを閉じることができる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl-b d&lt;/code&gt; でセッションをデタッチできる. (バックグラウンドでセッションを維持したまま, tmuxから抜ける.)&lt;/li&gt;
&lt;li&gt;ターミナルで &lt;code&gt;$ tmux a&lt;/code&gt; と実行すると,前回実行していたセッションをアタッチできる. (バックグラウンドのセッションに接続.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;このようにして画面を分割したり, セッションを維持したままターミナルから離れたり出来る.&lt;/p&gt;
&lt;p&gt;その他のデフォルトのキーバインドは &lt;a href=&quot;http://www.tohoho-web.com/ex/tmux.html&quot;&gt;tmux入門 - とほほのWWW入門&lt;/a&gt; が参考になる.&lt;/p&gt;
&lt;p&gt;tmux は複数のターミナルを束ねるが, それは次のような構造になっている.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tmux は複数のセッションを持てる.&lt;/li&gt;
&lt;li&gt;セッションは複数のウィンドウを持てる.&lt;/li&gt;
&lt;li&gt;ウィンドウは複数のペインを持てる. (画面分割)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;基本は以上だが, その他にも使い切れないほど沢山の機能があるので, 以降では便利そうな機能を抽出のうえカスタマイズして使いやすくする.&lt;/p&gt;
&lt;h2&gt;好みの状態にカスタマイズする&lt;/h2&gt;
&lt;h3&gt;好みのペイン分割をするコマンドを作る&lt;/h3&gt;
&lt;p&gt;好みのペイン分割をすぐにできるようなスクリプトを作っておく.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &apos;alias ide=&quot;bash ~/.tmux-ide.sh&quot;&apos; &gt;&gt; .bashrc
$ vim ~/.tmux-ide.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash

# ~/.tmux-ide.sh

tmux split-window -d -t 0        # 上下に画面分割
tmux send-keys -t 0 vim C-m      # ペイン0 (画面上部) で vim を実行
tmux split-window -h -t 1        # ペイン1 (画面下部) を左右に分割
tmux select-pane -t 0            # フォーカスをペイン0に移動する
tmux resize-pane -t 0 -D 10      # ペイン0を下方向に広げる
tmux send-keys -t 0 &apos;:e ~/dev/&apos;  # ペイン0 に &apos;:e ~/dev/&apos;と入力する (vim でファイルを開くことを助ける)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こうすると, tmux 起動後や新しいウィンドウ作成後に &lt;code&gt;$ ide&lt;/code&gt; と打つと, 自動で3つのペインに画面分割をしてvimを起動してくれる.&lt;/p&gt;
&lt;h3&gt;Vim のカラースキームがおかしくなる件を修正&lt;/h3&gt;
&lt;p&gt;vimのカラースキームが未設定だと, tmux内のvimとtmux外のvimで配色が変わるので, なんでもいいからカラースキームを設定する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &apos;colorscheme pablo&apos; &gt;&gt; ~/.vimrc
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;~/.tmux.confを作成&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;tmux は表示やキーバインドをカスタマイズできる.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.tmux.conf&lt;/code&gt;に設定を書き込むと, デフォルトで読み込んでくれる.&lt;/li&gt;
&lt;li&gt;tmux を既に起動している状態でも, ファイル保存後に, &lt;code&gt;prefix :source ~/.tmux.conf&lt;/code&gt;で設定ファイルをリロード可能.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;tmux は出来ることが多いが, そのためのキーバインドを覚えるのが大変そう.
他人の設定した tmux を触らなければならないこともそう無いだろうし, 最初からカスタマイズして覚えやすそう/使いやすそうなキーに設定することにする.&lt;/p&gt;
&lt;p&gt;設定内容は検索すると沢山出てくるので, 適当なものを取り込むと良いだろう.
記事末尾に参考となりそうなページをを記載する.&lt;/p&gt;
&lt;p&gt;以下では, 次のような内容の設定を行う.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prefix キーの変更&lt;/li&gt;
&lt;li&gt;色の変更&lt;/li&gt;
&lt;li&gt;status line に表示する情報を変更&lt;/li&gt;
&lt;li&gt;マウス操作の有効化&lt;/li&gt;
&lt;li&gt;各種キーバインドの変更&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ vim ~/.tmux.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# ~/.tmux.conf

# tmux起動時のシェルをzshにする
set-option -g default-shell /bin/zsh

# prefixキーをC-jに変更する
set -g prefix C-j

# ウィンドウ終了
bind Q kill-window


## --------------------見た目--------------------

# tmuxを256色表示出来るようにする
set-option -g default-terminal screen-256color
set -g terminal-overrides &apos;xterm:colors=256&apos;

# 非アクティブなウィンドウの背景色を灰色にする
set-option -g window-style &apos;bg=#444444&apos;
# アクティブなウィンドウの背景色を黒色にする
set-option -g window-active-style &apos;bg=#222222&apos;

# status-left の最大の長さを指定する。
set-option -g status-left-length 20
# status-left のフォーマットを指定する。
set-option -g status-left &quot;#[fg=colour255,bg=colour241]Session: #S #[default]&quot;

# window-status のフォーマットを指定する。
set-window-option -g window-status-format &quot; #I: #W &quot;
# カレントウィンドウの window-status のフォーマットを指定する
set-window-option -g window-status-current-format &quot;#[fg=colour255,bg=colour27,bold] #I: #W #[default]&quot;

# 現在時刻を最右に表示
set-option -g status-right &apos;%Y-%m-%d(%a) %H:%M:%S&apos;

# ステータスバーを1秒毎に描画し直す
set-option -g status-interval 1


## --------------------マウス--------------------

#マウス操作を有効にする
set-option -g mouse on

# スクロールアップするとコピーモードに入る
bind-key -n WheelUpPane if-shell -F -t = &quot;#{mouse_any_flag}&quot; &quot;send-keys -M&quot; &quot;if -Ft= &apos;#{pane_in_mode}&apos; &apos;send-keys -M&apos; &apos;select-pane -t=; copy-mode -e; send-keys -M&apos;&quot;

# 最後までスクロールダウンするとコピーモードを抜ける
bind-key -n WheelDownPane select-pane -t= \; send-keys -M


## --------------------ペイン--------------------

# vimのキーバインドでペインを移動する
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# vimのキーバインドでペインをリサイズする
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# ペインを垂直分割する
bind v split-window -h -c &apos;#{pane_current_path}&apos;
# ペインを水平分割する
bind s split-window -v -c &apos;#{pane_current_path}&apos;

# ペイン番号を表示
bind i display-panes

# ペインを終了
bind q kill-pane
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Keybinds&lt;/h3&gt;
&lt;p&gt;.tmux.conf にて キーバインドを書き換え済みのものは is default ? を no と表記している.&lt;/p&gt;
&lt;h3&gt;基本&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;is default ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl-j&lt;/td&gt;
&lt;td&gt;prefix&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix  ?&lt;/td&gt;
&lt;td&gt;キーバインド一覧&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;セッション&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;is default ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;prefix  d&lt;/td&gt;
&lt;td&gt;現在のセッションを継続したままtmuxを閉じる (detach)&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;ウィンドウ&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;is default ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;prefix c&lt;/td&gt;
&lt;td&gt;新規ウィンドウの作成/追加&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix w&lt;/td&gt;
&lt;td&gt;ウィンドウの一覧&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix Q&lt;/td&gt;
&lt;td&gt;ウィンドウの破棄&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix n&lt;/td&gt;
&lt;td&gt;次のウィンドウへ移動&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix p&lt;/td&gt;
&lt;td&gt;前のウィンドウへ移動&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix 数字&lt;/td&gt;
&lt;td&gt;当該番号のウィンドウへ移動&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix &amp;#x3C;&lt;/td&gt;
&lt;td&gt;当該ウィンドウをリネームや移動等&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;ペイン&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;is default ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;prefix v&lt;/td&gt;
&lt;td&gt;左右にペイン分割&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix s&lt;/td&gt;
&lt;td&gt;上下ペイン分割&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix h&lt;/td&gt;
&lt;td&gt;左のペインへ移動&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix j&lt;/td&gt;
&lt;td&gt;下のペインへ移動&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix k&lt;/td&gt;
&lt;td&gt;上のペインへ移動&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix l&lt;/td&gt;
&lt;td&gt;右のペインへ移動&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix H&lt;/td&gt;
&lt;td&gt;ペインを左にリサイズ&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix J&lt;/td&gt;
&lt;td&gt;ペインを下にリサイズ&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix K&lt;/td&gt;
&lt;td&gt;ペインを上にリサイズ&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix L&lt;/td&gt;
&lt;td&gt;ペインを右にリサイズ&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix q&lt;/td&gt;
&lt;td&gt;ペインを破棄&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix i&lt;/td&gt;
&lt;td&gt;ペイン番号を表示 (続けて数字を入力すると当該ペインへ移動)&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix &gt;&lt;/td&gt;
&lt;td&gt;当該ペインをリネームや移動等&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;コピー&amp;#x26;ペースト&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;is default ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;prefix [&lt;/td&gt;
&lt;td&gt;コピーモード開始&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix Space&lt;/td&gt;
&lt;td&gt;コピー開始位置決定&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix Enter&lt;/td&gt;
&lt;td&gt;コピー終了位置決定&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prefix ]&lt;/td&gt;
&lt;td&gt;コピーした内容の貼り付け&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tmux/tmux&quot;&gt;tmux/tmux: tmux source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zchee/tmux-ja/blob/master/tmux-ja.rst&quot;&gt;tmux-ja/tmux-ja.rst at master · zchee/tmux-ja&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.inkdrop.info/vscode-like-environment-with-vim-tmux-4c2bfe17d31e&quot;&gt;VSCode-like environment with vim + tmux | by Takuya Matsuyama | Dev as Life&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/nl0_blu/items/9d207a70ccc8467f7bab&quot;&gt;tmuxを必要最低限で入門して使う - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.tohoho-web.com/ex/tmux.html&quot;&gt;tmux入門 - とほほのWWW入門&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/nojima/items/9bc576c922da3604a72b&quot;&gt;tmux の status line の設定方法 - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/zwirky/items/adbf22abad7d7822456b&quot;&gt;tmuxで快適なターミナル生活を送ろう - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://kanjuku-tomato.blogspot.com/2014/03/tmux.html&quot;&gt;新規tmuxセッション起動時に自動で複数のウィンドウを作成してペイン分割する - 完熟トマト&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gp-standard.com/tmux%E3%81%A7%E3%83%9E%E3%82%A6%E3%82%B9%E6%93%8D%E4%BD%9C%E3%82%92%E4%BE%BF%E5%88%A9%E3%81%AB%EF%BC%81-tmux-conf%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E8%A8%AD/&quot;&gt;tmuxでマウス操作を便利に！ tmux.confファイルを作って設定をカスタマイズする。 | Full Stack Enginear&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/mikene_koko/items/2867a6fe2eb73db6562e&quot;&gt;僕の考えた最強のtmux.conf - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;追伸: 10月に何も書いてないのもしゃくなのでギリギリに投稿。最近は卒業研究を進めている。&lt;/p&gt;</description>
    </item>
    <item>
      <title>積読本だった&quot;Webを支える技術&quot;を読んだ感想と、本を読むための心がけ</title>
      <link>https://memo.yammer.jp/posts/webteckbook</link>
      <pubDate>Mon, 28 Sep 2020 18:35:02 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/webteckbook</guid>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/Web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-HTTP%E3%80%81URI%E3%80%81HTML%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6REST-WEB-PRESS-plus/dp/4774142042&quot;&gt;「Webを支える技術 HTTP, URI, HTML, そしてREST」&lt;/a&gt;を改めて読み直した。
年始に買って途中まで読んでいたものだ。&lt;/p&gt;
&lt;h2&gt;書籍 &quot;Webを支える技術&quot; について&lt;/h2&gt;
&lt;h3&gt;本を選んだ背景と読んだ感想&lt;/h3&gt;
&lt;p&gt;書籍購入当時はスマホアプリのWeb APIを開発しており、URIの設計の参考にしたくて手にとった。
RESTという考え方やAPI設計についてとても参考になり、 良い設計とは何かを知ることが出来た。&lt;/p&gt;
&lt;p&gt;これまでは用意されたWeb APIを使う側で、URI設計について意識することがなく無意識に良くつくられたURIのAPIを使っていた。
一方で設計するためにはまず利用者として当たり前だったことを言語化して理解する必要があり、その当たり前がRESTにより成り立っていることを学べた。&lt;/p&gt;
&lt;h3&gt;書籍内容と現在の状況の違い&lt;/h3&gt;
&lt;p&gt;書籍の第一版は2010年で今から10年前なので、現代と少し合わない点もある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初版時にはHTTP/2 HTTP/3は存在しておらず、HTTP/1.1が最新であることを前提として書かれている&lt;/li&gt;
&lt;li&gt;セマンティックWeb は2020年の今でも浸透していない&lt;/li&gt;
&lt;li&gt;&lt;s&gt;Web APIとして、XML、Atom / AtomPubはあまり使われなくなった&lt;/s&gt;
&lt;small&gt;(追記 2020/10/4 : なんの裏付けもありません。サービスの目的によって使う/使わないがあるだけで、あまり使われなくなったというのは言い過ぎかも。XMLはあまり使われなくなりJSONが一般的になった、ということは言えるんじゃ無いかな。)&lt;/small&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とはいえ本の本筋は2020年でもきっと多分に有用であろう。&lt;/p&gt;
&lt;h3&gt;本から学んだこと&lt;/h3&gt;
&lt;p&gt;詳細は本に譲るが、私がこの本から学んだエッセンスには例えば次のようなものがある。&lt;/p&gt;
&lt;h4&gt;1. RESTについて&lt;/h4&gt;
&lt;p&gt;REST とは今日のWebにおいて適用されているアーキテクチャパターンのことで、次の制約をもつ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;クライアント/サーバモデル&lt;/li&gt;
&lt;li&gt;ステートレスサーバ&lt;/li&gt;
&lt;li&gt;キャッシュ&lt;/li&gt;
&lt;li&gt;統一インタフェース&lt;/li&gt;
&lt;li&gt;階層化システム&lt;/li&gt;
&lt;li&gt;コードオンデマンド&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第1部第3章 p36あたりには上述のようなことが書かれている。&lt;/p&gt;
&lt;p&gt;インターネットは、遅延が大きく、また通信相手から応答があるか保証のない分散システムである。
このインターネットにおいて、端末(プログラム)(/人間) 間のインタフェースをどのように設計すべきかの原則、指針を示しているのがRESTだ。
設計のときに参考になるアーキテクチャパターンとしてRESTが存在し、RESTの要素とはなんなのかを分解して解説している。&lt;/p&gt;
&lt;h4&gt;2. リソースのモデル化とURI設計&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;検索のような機能は、検索行為をモデル化するのではなく、検索結果をモデル化する。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Webサービス/WebAPI(以下Webサービスと呼ぶ)を設計する時、&quot;動作&quot;をリソースとして割り当てる(=&gt;URIで表現する)のはよくない。
Webサービスにおける動作はCRUDであり、HTTPのメソッドであるGET/POST/PUT/DELETE で表現すべきである。&lt;/p&gt;
&lt;p&gt;例えば検索機能は、&quot;検索結果をGETで取得する&quot;と表現するのが簡潔である。
Googleの検索結果のURIは &lt;code&gt;https://google.com/search?q=hoge&lt;/code&gt; となっているが、ここで出てくるsearchは検索行為を表しているのではなく検索結果を表している。
検索行為に注目してしまうと、HTTPを拡張してSearchメソッドを作ったり、検索内容をPOSTしてサーバに検索しろとクライアントに命令させたりすることになる。
これはわかりづらいので良い設計といえない。&lt;/p&gt;
&lt;p&gt;検索に限らず、リソースをモデル化するとき(すなわちそれはリソースを表現するURIになりうる)は、動作ではなく名詞で表せるものに注目すべきだ。&lt;/p&gt;
&lt;h4&gt;3. 人間とコンピュータの統一インタフェース&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;リソース設計の際は、WebサービスとWeb APIを分けて考えない。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;良いリソースのモデル化は人間にとってもわかりやすいし、Web APIとしても使いやすくなる。
なので、WebAPI用にリソースをモデル化してURIで表現し、人間にはまた別にモデル化して、、、ということは避けるべき。&lt;/p&gt;
&lt;h2&gt;積読本を読み切った感想と、本を読むスピードについて&lt;/h2&gt;
&lt;p&gt;さて、本の内容はここまでにして、以下は今回の積読消化の感想とそこから学んだことを記す。&lt;/p&gt;
&lt;p&gt;本を読むスピードは状況や意識で大きく変わる。&lt;/p&gt;
&lt;p&gt;1月に読んでいたときは理解できないところがあると調べて解決してから進める読み方だった。
読むスピードが遅くそのまま途中で止まっていた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;一方、今回9月は数時間で一気に読み切った。
気になったところはメモを取ることにして、読み切るために興味のわかないところ(例えばAtom/AtomPub等の項)は斜め読みにするなどして進めた。&lt;/p&gt;
&lt;p&gt;本を読むスピードは自分の意識で変わる面がある。
細かいところまで理解しながらゆっくり読み進めるか、全体を俯瞰するためにとにかく読み切ることを目標に進めるかという意識だ。
また、自分の知識量に応じて変わる面もある。
自分が知っていることが多く載っている本は早く読めるし、知らないことが多く載っている本は時間がかかる。
さらに、自分のテンションや気分で変わる面もある。
読む気があるとき、内容に興味が湧いているとき、知的好奇心から本の内容を欲しているときは、どんどんページが進んで苦なくはやく読める。&lt;/p&gt;
&lt;p&gt;今回は一気に読み切ろうという心持ち、RESTって結局なんだっけという思いからくる知的好奇心、前回よりも知識量が増え内容の理解が進むことなど様々なことが重なったのが読み切れた要因だろう。&lt;/p&gt;
&lt;p&gt;私は気分が乗っていないときに何も考えずに本を読むと、丁寧にゆっくり読む癖がある。
他方、本の全体像をつかみ必要なところだけを読んだり、必要になったときに読み直せるようインデックスを貼る気持ちで読んだりするほうが効率が良いのではないかと感じる。
実際今回の本も読み切って感じたが、後半には実例を交えたURIの設計について述べられた章があり、1月にここを読んでいれば身になるものがさらにあったはずだった。
今後はどんな読み方/スピードで本を読むかを読む前に考えるようにしたい。&lt;/p&gt;
&lt;p&gt;また、モチベーションの大切さも感じた。
プログラムを書くときもそうであるし、本を読むときもそうであるが、(少なくとも私にとって)物事を進めるにはモチベーションがとても重要だと思う。
モチベーションの高まっているときに躊躇なく進めることを心がけたい。
(さらには自分のモチベーションを導けるようになりたい。)&lt;/p&gt;
&lt;p&gt;そんなこんなで積ん読を消化した勢いで他の本も読むぞ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考: &lt;a href=&quot;http://yohei-y.blogspot.com/&quot;&gt;yohei-y:weblog&lt;/a&gt;(著者 山本陽平さんのブログ) ... この記事のURL&lt;code&gt;webteckbook&lt;/code&gt;はブログに記載された内容を参考にした。&lt;/p&gt;
&lt;p&gt;追記: (2020/10/04) 不要な改行を削除&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;何故積ん読した当時のことを鮮明に覚えているかというと、本を読んでいた時が時間に追われながらコードを書きながら年末年始で帰省して親戚と過ごしていた映像記憶が蘇ってきたからである。 エピソード記憶は強烈だ。 当時はAPIの設計についても考えなければならなかったがDockerを含むインフラについても学ばねばならなかったので、のんびり本を読み切ってる場合ではない！という心情だったのだろう。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>2020年9月のキーマップ for lily58</title>
      <link>https://memo.yammer.jp/posts/keymap-202009</link>
      <pubDate>Fri, 25 Sep 2020 03:53:30 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/keymap-202009</guid>
      <description>&lt;p&gt;&lt;a href=&quot;/posts/lily58-pro-ble/&quot;&gt;以前記事に書いた&lt;/a&gt;とおり、分割キーボード lily58を使っている。&lt;/p&gt;
&lt;p&gt;自作してから1ヶ月以上経つが、何度かキーマップを書き換えており、順調に配列沼にハマっている。&lt;/p&gt;
&lt;p&gt;丁度、しばらく使っていてしっくり来ないところを昨日書き換えたばかり。
せっかくなので記録がてら記事に残しておく。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;lily58のキーマップを変えた。&lt;br&gt;&lt;br&gt;変更は&lt;br&gt;- コロンとバックスラッシュをlayer0に&lt;br&gt;- 中央のGと&lt;br&gt;Hに挟まれたキーを使わないことに&lt;br&gt;&lt;br&gt;40%っぽく1段目を使っていないのは1ヶ月前くらいから。 &lt;a href=&quot;https://t.co/jWCNcd9f5p&quot;&gt;pic.twitter.com/jWCNcd9f5p&lt;/a&gt;&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1309153335530848256?ref_src=twsrc%5Etfw&quot;&gt;September 24, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;3レイヤーで、最下段の内側から2つめのキーを押している間はレイヤーが切り替わる。&lt;/p&gt;
&lt;p&gt;この配列は次のような方針で作られている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本はqwertyのUS配列に寄せる&lt;/li&gt;
&lt;li&gt;ホームポジションとそれに隣接するキーでなるべく完結させる&lt;/li&gt;
&lt;li&gt;Layer0は英字, Layer1に記号と数字, Layer2に制御キーを割り当てる&lt;/li&gt;
&lt;li&gt;方向キーはvim likeにhjklに割り当てる&lt;/li&gt;
&lt;li&gt;(コードを書くとき等)記号の入力頻度が高いわりに私の入力スピードが遅いので、なるべく打ちやすいところに記号を配置する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;lily58はもともと60%だが、最上段のキーは使っていない。
また内側に括弧に割り当てやすいキーがあるが、それらのキーには割当していない。&lt;/p&gt;
&lt;p&gt;初めて自作キーボードを購入する際は、40%キーボードはキーが少なすぎる過激な配列で、自分には独立した数字キーは必要だと思っていた。
しかし lily58 が届いていざ 打ってみると、数字キーは遠くて手が大きく動き、押しづらさを感じる。
遠いキーはブラインドタッチの障壁になりそうだと思ったのだ。&lt;/p&gt;
&lt;p&gt;そのあと1ヶ月くらい使って、内側の括弧に割り当てやすいキー (GとHに挟まれたキー)も、意外とホームポジションから遠く押しづらいことに気づいた。&lt;/p&gt;
&lt;p&gt;というわけで上のツイートの配列に落ち着いている。&lt;/p&gt;
&lt;p&gt;40%でも問題なさそうなので、そのうち&lt;a href=&quot;https://olkb.com/collections/planck&quot;&gt;planck&lt;/a&gt;や&lt;a href=&quot;https://drop.com/buy/massdrop-x-olkb-planck-light-mechanical-keyboard&quot;&gt;planck light&lt;/a&gt;、&lt;a href=&quot;https://yushakobo.jp/shop/corne-cherry/&quot;&gt;Corne Cherry&lt;/a&gt;といった、40%の column-staggered / Ortholiner なキーボードが欲しい。&lt;/p&gt;
&lt;p&gt;というわけで、今後も変更があれば随時記録していきたい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Makefileの中で名前付きパイプ(bash記法)を使いたかった。2つのコマンド実行結果を比較する。</title>
      <link>https://memo.yammer.jp/posts/makefile-named-pipe</link>
      <pubDate>Thu, 17 Sep 2020 07:31:46 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/makefile-named-pipe</guid>
      <description>&lt;p&gt;今日は小さな Tips。&lt;/p&gt;
&lt;p&gt;make は1970年代に生まれ、C言語のビルドなどでよく用いられるビルドツールだ。
Makefileにビルド手順を記述しておき &lt;code&gt;$make&lt;/code&gt; で一連の流れを実行できる。&lt;/p&gt;
&lt;p&gt;古からあるビルドツールであるから、インデントがタブ文字でないといけないなどの制約があるが、環境に依存しづらいので最近はよく使うようにしている。&lt;/p&gt;
&lt;p&gt;Makefile にはシェルスクリプトのように実行するコマンドを記述するが、この中ではbash独自の拡張記法には対応していない。(Makefile独自の記法があったりする)&lt;/p&gt;
&lt;p&gt;2つのコマンドの実行結果を比較したい時、bashでは次のように名前付きパイプを使うと簡単に記述できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ diff &amp;#x3C;(echo &apos;hoge&apos;) &amp;#x3C;(echo &apos;fuga&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは独自の記法でありMakefileの中では使えない。&lt;/p&gt;
&lt;p&gt;そこで、名前付きパイプを避けて明示的にファイルディスクリプタを利用することで解決できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ echo &apos;hoge&apos; | (echo &apos;fuga&apos; | diff /dev/fd/3 -) 3&amp;#x3C;&amp;#x26;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず、&lt;code&gt;$ehco &apos;hoge&apos;&lt;/code&gt;の実行結果を標準出力ではなくファイルディスクリプタ3に流し込む。
そして、これ(/dev/fd/3)と&lt;code&gt;$echo &apos;fuga&apos;&lt;/code&gt;の実行結果の標準出力をdiffで比較している。&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://yulii.github.io/diff-command-tips-20150627.html&quot;&gt;コマンド実行結果のdiff を取るといろいろ捗る - by and for engineers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/Make&quot;&gt;make - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;p.s. 本「&lt;a href=&quot;https://www.amazon.co.jp/dp/B075ST51Y5/ref=dp-kindle-redirect?_encoding=UTF8&amp;#x26;btkr=1&quot;&gt;ふつうのLinuxプログラミング&lt;/a&gt;」を参考に &lt;a href=&quot;https://github.com/yammerjp/cat&quot;&gt;cat コマンドを作っていて&lt;/a&gt;、簡単なテストスクリプトをMakefileに書きたいと思ったところから、このスニペットを必要とした。&lt;/p&gt;</description>
    </item>
    <item>
      <title>LoveLabのAPIサーバをAWS EC2上にセットアップする</title>
      <link>https://memo.yammer.jp/posts/lovelab-ec2</link>
      <pubDate>Fri, 14 Aug 2020 13:55:26 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/lovelab-ec2</guid>
      <description>&lt;p&gt;以下過去の自分用のメモを移動。&lt;/p&gt;
&lt;p&gt;昨冬、チーム開発で ToDo 管理の iPhone アプリ LoveLab を開発していた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab-api&quot;&gt;LoveLab API サーバ&lt;/a&gt;は、docker-composeでまとめられている。
AWS の EC2 上で立ち上げるための手順を以下に示す。&lt;/p&gt;
&lt;h2&gt;EC2 instance作成後の作業&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;80番ポートを開放&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sshでログイン&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;関係ソフトウェアをinstall&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo yum install -y docker
$ sudo service docker start
$ sudo usermod -a -G docker ec2-user
$ sudo docker info
$ sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
$ sudo yum install -y git
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;deploy.sshを入手&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ touch deploy.sh
$ chmod u+x deploy.sh
$ vim deploy.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/sh

# deploy.sh

echo &quot;Deploying lovelab API server...&quot;

if [ -d ./lovelab.heroku ]; then
  echo &quot;Stop containers and delete old source files.&quot;
  cd lovelab.heroku
  docker-compose down
  cd ../
  rm -rf lovelab.heroku
fi

echo &quot;Clone source files.&quot;
git clone https://github.com/yammerjp/lovelab.heroku.git
cd lovelab.heroku
git checkout origin/release
cp .env.example .env
echo &quot;docker-compose build&quot;
docker-compose build --no-cache
echo &quot;docekr-compose up&quot;
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>LALR(1)構文解析を行いながら、コンパイラの構文解析を学ぶ</title>
      <link>https://memo.yammer.jp/posts/compiler-lalr1</link>
      <pubDate>Fri, 14 Aug 2020 10:13:19 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/compiler-lalr1</guid>
      <description>&lt;p&gt;以下、過去の自分向けのメモの移動。&lt;/p&gt;
&lt;p&gt;コンパイラの主要な処理に構文解析がある。
前回はLR0文法構文解析を行った。&lt;/p&gt;
&lt;p&gt;今回は与えられたLALR(1)文法規則に基づいて構文解析するオートマトンを作り、構文解析の手法について整理する。&lt;/p&gt;
&lt;h2&gt;問題の文法規則&lt;/h2&gt;
&lt;p&gt;次のLALR(1)文法規則を受理するオートマトンと構文解析表をつくり、構文解析を行う。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; E + T
E -&gt; T
T -&gt; T * F
T -&gt; F
F -&gt; i
F -&gt; ( E )
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;First集合&lt;/h2&gt;
&lt;h3&gt;First集合とは&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;First(K)&lt;/code&gt; ... Kの還元前の終端記号列において、先頭に来る可能性のある終端記号の集合&lt;/p&gt;
&lt;h3&gt;First集合の求め方&lt;/h3&gt;
&lt;p&gt;最初は空集合とする&lt;/p&gt;
&lt;h4&gt;非終端記号&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;First(K)&lt;/code&gt; (&lt;code&gt;K&lt;/code&gt;..非終端記号)について、
Kが左辺の文法規則が次の2つだったとき&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;K -&gt; abc...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;K -&gt; PqRs...&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;First(K) = First(K) + First(a) + First(P)&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;終端記号&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;First(k)&lt;/code&gt; (&lt;code&gt;k&lt;/code&gt;...終端記号)について、
&lt;code&gt;First(k) = { k }&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;今回の問題におけるFirst集合&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;First(E) = First(T) = First(F) = { i ( }&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Follow集合&lt;/h2&gt;
&lt;h3&gt;Follow集合とは&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Follow(K)&lt;/code&gt; ... &lt;code&gt;K&lt;/code&gt;の次に来る可能性のある終端記号の集合&lt;/p&gt;
&lt;h3&gt;Follow集合の求め方&lt;/h3&gt;
&lt;p&gt;最初は&lt;code&gt;{}&lt;/code&gt;
開始記号のFollow集合に$を加える&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Follow(K)&lt;/code&gt;について&lt;/p&gt;
&lt;p&gt;文法規則 &lt;code&gt;A -&gt; wK&lt;/code&gt; (&lt;code&gt;w&lt;/code&gt;は任意の文字列)ならば
&lt;code&gt;Follow(K) += Follow(A) &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;文法規則 &lt;code&gt;A -&gt; wKB&lt;/code&gt;かつ &lt;code&gt;First(B)∋ε&lt;/code&gt; ならば
&lt;code&gt;Follow(K) += Follow(A)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;文法規則 &lt;code&gt;A -&gt; xKy (y≠ε)&lt;/code&gt; ならば
&lt;code&gt;Follow(K) += First(y)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;今回の問題におけるFollow集合&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Follow(E) = { $ } + First( ) ) + First( + ) = { $ ) + }
Follow(T) = Follow(E) + First( * ) = { $ ) + * }
Follow(F) = Follow(T) = { $ ) + * }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;LALR(1)正準集合&lt;/h2&gt;
&lt;h3&gt;I0&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; ・E + T [ $ + ]
E -&gt; ・T [ $ + ]
T -&gt; ・T * F [ $ + * ]
T -&gt; ・F [ $ + * ]
F -&gt; ・i [ $ + * ]
F -&gt; ・( E ) [ $ + * ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I1&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; E ・+ T [ $ + ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I2&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; T・ [ $ + ) ]
T -&gt; T ・* F [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I3&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;T -&gt; F・ [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I4&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;F -&gt; i・ [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I5&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;F -&gt; ( ・E ) [ $ + * ) ]
E -&gt; ・E + T [ + ) ]
E -&gt; ・T [ + ) ]
T -&gt; ・T * F [ + * ) ]
T -&gt; ・F [ + * ) ]
F -&gt; ・i [ + * ) ]
F -&gt; ・( E ) [ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I6&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; E + ・T [ $ + ) ]
T -&gt; ・T * F [ $ + * ) ]
T -&gt; ・F [ $ + * ) ]
F -&gt; ・i [ $ + * ) ]
F -&gt; ・( E ) [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I7&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;T -&gt; T * ・F [ $ + * ) ]
F -&gt; ・i [ $ + * ) ]
F -&gt; ・( E ) [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I8&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;F -&gt; ( E ・) [ $ + * ) ]
E -&gt; E ・+ T [ + ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I9&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;E -&gt; E + T・ [ $ + ) ]
T -&gt; T ・* F [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I10&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;T -&gt; T * F・ [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;I11&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;F -&gt; ( E )・ [ $ + * ) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;オートマトン&lt;/h2&gt;
&lt;p&gt;以上より、与えられた文法規則を満たす系列を受理するオートマトンをつくる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;digraph G {
  rankdir=LR;
  empty [label = &quot;&quot; shape = plaintext];
  node [shape = doublecircle];I2 I9;
  node [shape = circle];
  empty -&gt; I0 [label = &quot;start&quot;];
  I0 -&gt; I1 [label = &quot;E&quot;];
  I0 -&gt; I2 [label = &quot;T&quot;];
  I0 -&gt; I3 [label = &quot;F&quot;];
  I0 -&gt; I4 [label = &quot;i&quot;];
  I0 -&gt; I5 [label = &quot;(&quot;];

  I1 -&gt; I6 [label = &quot;+&quot;];

  I2 -&gt; I7 [label = &quot;*&quot;];

  I5 -&gt; I8 [label = &quot;E&quot;];
  I5 -&gt; I2 [label = &quot;T&quot;];
  I5 -&gt; I3 [label = &quot;F&quot;];
  I5 -&gt; I4 [label = &quot;i&quot;];
  I5 -&gt; I5 [label = &quot;(&quot;];

  I6 -&gt; I9 [label = &quot;T&quot;];
  I6 -&gt; I3 [label = &quot;F&quot;];
  I6 -&gt; I4 [label = &quot;i&quot;];
  I6 -&gt; I5 [label = &quot;(&quot;];

  I7 -&gt; I10 [label = &quot;F&quot;];
  I7 -&gt; I4 [label = &quot;i&quot;];
  I7 -&gt; I5 [label = &quot;(&quot;];

  I8 -&gt; I11 [label = &quot;)&quot;];
  I8 -&gt; I6 [label = &quot;+&quot;];

  I9 -&gt; I7 [label = &quot;*&quot;];
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;構文解析表&lt;/h2&gt;
&lt;p&gt;オートマトンを構文解析表にまとめる。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;I\記号&lt;/th&gt;
&lt;th&gt;+&lt;/th&gt;
&lt;th&gt;*&lt;/th&gt;
&lt;th&gt;(&lt;/th&gt;
&lt;th&gt;)&lt;/th&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;$&lt;/th&gt;
&lt;th&gt;E&lt;/th&gt;
&lt;th&gt;T&lt;/th&gt;
&lt;th&gt;F&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;1&lt;/td&gt;
&lt;td&gt;s6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;s7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;3&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td&gt;r5&lt;/td&gt;
&lt;td&gt;r5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;8&lt;/td&gt;
&lt;td&gt;s6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s11&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;9&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;s7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;10&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;11&lt;/td&gt;
&lt;td&gt;r6&lt;/td&gt;
&lt;td&gt;r6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;r6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;構文解析&lt;/h2&gt;
&lt;p&gt;上記の構文解析表に従い、次のような系列を構文解析する。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;i+i*i&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;( I0 , i+i*i$ ) // s6
( I0 i I4 , +i*i$ ) // r5
( I0 F I3 , +i*i$ ) // r4
( I0 T I2 , +i*i$ ) // r2
( I0 F I1 , +i*i$ ) // s6
( I0 F I1 + I6 , i*i$ ) // s4
( I0 F I1 + I6 i I4 , *i$ ) // r5
( I0 F I1 + I6 F I3 , *i$ ) // r4
( I0 F I1 + I6 T I9 , *i$ ) // s7
( I0 F I1 + I6 T I9 * I7 , i$ ) // s4 
( I0 F I1 + I6 T I9 * I7 i I4 , $ ) // r5 
( I0 F I1 + I6 T I9 * I7 F I10 , $ ) // r3 
( I0 F I1 + I6 T I9 , $ ) //  
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;i*(i+i)&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;(略)&lt;/p&gt;
&lt;h3&gt;&lt;code&gt; i*i+*i&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;(略)&lt;/p&gt;
&lt;style&gt;
.article.markdown-body table th {
  min-width: 0px;
}
.article.markdown-body table td {
  min-width: 0px;
}
&lt;/style&gt;</description>
    </item>
    <item>
      <title>LR(0)構文解析を行いながら、コンパイラの構文解析を学ぶ</title>
      <link>https://memo.yammer.jp/posts/compiler-lr0</link>
      <pubDate>Fri, 14 Aug 2020 10:04:31 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/compiler-lr0</guid>
      <description>&lt;p&gt;以下、過去の自分向けのメモの移動。&lt;/p&gt;
&lt;p&gt;コンパイラの主要な処理に構文解析がある。
今回は与えられたLR(0)文法規則に基づいて構文解析するオートマトンを作り、構文解析の手法について整理する。&lt;/p&gt;
&lt;h2&gt;問題&lt;/h2&gt;
&lt;p&gt;次の文法について、次の問を答えよ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;S -&gt; ( L ) 
S -&gt; a
L -&gt; L , S
L -&gt; S
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上から順にR1,R2,R3,R4と呼ぶ。&lt;/p&gt;
&lt;p&gt;ただし、SとLは非終端記号、(と)と,とaは終端記号とする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LR(0)正準集合とオートマトンを求めよ&lt;/li&gt;
&lt;li&gt;以下の文字列が示された文法から生成されるかどうか、また構文解析の結果を答えよ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;LR(0)構文解析の方法&lt;/h2&gt;
&lt;h3&gt;LR(k)構文解析とは&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上向き構文解析(下向きは再帰的に行うが、バックトラックが発生するため大変)&lt;/li&gt;
&lt;li&gt;左(Left)から読み、右端導出(Right most derivation)&lt;/li&gt;
&lt;li&gt;kとは、先読みできる記号の数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;LR(0)構文解析の流れ&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;LR(0)正準集合とオートマトンをつくる&lt;/li&gt;
&lt;li&gt;構文解析表を作る&lt;/li&gt;
&lt;li&gt;構文解析表を元に解析する&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;方針: shiftまたはreduceを繰り返し、開始記号1つにまとまれば完了&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;shift: 入力を1つ読み込むこと&lt;/li&gt;
&lt;li&gt;reduce: 文法規則を適用し、記号をまとめること&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;オートマトンの状態をスタックに積みながら、行う&lt;/p&gt;
&lt;p&gt;shiftするときは、入力を読み込み、入力記号に従い有向辺を遷移する。遷移後の状態をスタックにpushする。&lt;/p&gt;
&lt;p&gt;reduceするときは、適用する文法規則に則って、いままでの遷移を巻き戻し(スタックを記号数分popし)、適用後の記号の遷移を積み直す(pushする)。&lt;/p&gt;
&lt;p&gt;オートマトンを表にまとめ、情報を更かして、shift、reduceの手順を示したのが構文解析表である。&lt;/p&gt;
&lt;h2&gt;LR(0)におけるオートマトンの作成&lt;/h2&gt;
&lt;h3&gt;前提&lt;/h3&gt;
&lt;h4&gt;LR(0)項とは ... (アイテム記法)&lt;/h4&gt;
&lt;p&gt;文法規則の右辺、各記号の前後1箇所に・(ドット)を加えたもの。例えば&lt;code&gt;S -&gt; ( ・L )&lt;/code&gt;といった表記&lt;/p&gt;
&lt;p&gt;これは、ドットの前方は読み込み済みであること、ドットの後方は未読み込みであることを示す。&lt;/p&gt;
&lt;p&gt;(読み込むとは、ドットを1つ右に移動させること(ドットが1つ右のLR(0)項を含む状態に遷移すること(後術)であって、ドットの次が何の値であるか確認することではない)。&lt;/p&gt;
&lt;h4&gt;LR(0)正準集合とは&lt;/h4&gt;
&lt;p&gt;LR(0)項の集合である。
オートマトンを作成する際に一緒に作成する。&lt;/p&gt;
&lt;h4&gt;LR(0)におけるオートマトンとは&lt;/h4&gt;
&lt;p&gt;LR(0)正準集合を状態、記号を1つもつ有向辺としたオートマトン。&lt;/p&gt;
&lt;h3&gt;LR(0)におけるオートマトンを作成する方法&lt;/h3&gt;
&lt;h4&gt;1. 初期状態を定める&lt;/h4&gt;
&lt;p&gt;状態には開始記号が左辺で、ドットが最左なLR(0)項をすべて含む。
(※)を行う。&lt;/p&gt;
&lt;h4&gt;2. その他の状態を定める&lt;/h4&gt;
&lt;p&gt;既に存在する状態のドットが最右にないLR(0)項について、記号を一つ読み込んだ状態を新たにつくる。&lt;/p&gt;
&lt;p&gt;遷移の有向辺には、読み込む記号をもたせる。
遷移後の状態は、記号を1つ読み込んだLR(0)項(ドットを1記号分右にずらしたLR(0)項)を含む。&lt;/p&gt;
&lt;p&gt;さらに、遷移前の状態の他のLR(0)項について考える。
同じ記号を読み込める物があれば(遷移前のLR(0)項同士でドットの右隣の記号が一致すれば)、このLR(0)項についても、1記号読み込み後のLR(0)項を遷移後の状態に加える。&lt;/p&gt;
&lt;p&gt;(※)を行う。&lt;/p&gt;
&lt;h4&gt;3. 繰り返す&lt;/h4&gt;
&lt;p&gt;行える限り 2. を行う。&lt;/p&gt;
&lt;h4&gt;(※)&lt;/h4&gt;
&lt;p&gt;ある状態について、この状態に含むLR(0)項を考える。&lt;/p&gt;
&lt;p&gt;ドットの右隣に非終端記号のあるLR(0)項があるならば、その終端記号を左辺に持ちドットが最左であるLR(0)項をすべて同じ状態に加える。&lt;/p&gt;
&lt;h3&gt;作成したオートマトン&lt;/h3&gt;
&lt;h4&gt;状態遷移表&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;digraph G {
  rankdir=LR;
  empty [label = &quot;&quot; shape = plaintext];
  node [shape = doublecircle];I2 I4;
  node [shape = circle];
  empty -&gt; I0 [label = &quot;start&quot;];
  I0 -&gt; I1 [label = &quot;(&quot;];
  I0 -&gt; I2 [label = &quot;a&quot;];
  I1 -&gt; I2 [label = &quot;a&quot;];
  I1 -&gt; I3 [label = &quot;L&quot;];
  I3 -&gt; I4 [label = &quot;)&quot;];
  I3 -&gt; I5 [label = &quot;,&quot;];
  I5 -&gt; I7 [label = &quot;S&quot;];
  I1 -&gt; I1 [label = &quot;(&quot;];
  I5 -&gt; I1 [label = &quot;(&quot;];
  I5 -&gt; I2 [label = &quot;a&quot;];
  I1 -&gt; I6 [label = &quot;S&quot;];
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;状態I0&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・( L )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I1&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ( ・L )&lt;/code&gt; (・の右隣に非終端記号)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L -&gt; ・L , S&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L -&gt; ・S&lt;/code&gt; (・の右隣に非終端記号)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・( L )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I2&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;S -&gt; a ・&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I3&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ( L ・)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L -&gt; L ・, S&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I4&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ( L ) ・&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I5&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;L -&gt; L , ・S&lt;/code&gt; (・の右隣に非終端記号)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・( L )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S -&gt; ・a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I6&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;L -&gt; S ・&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;状態I7&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;L -&gt; L , S ・&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;構文解析表&lt;/h2&gt;
&lt;p&gt;現在の状態(スタックのトップ)の行、入力記号(読み込み前)の列のセルに、次の動作を書いた表。&lt;/p&gt;
&lt;p&gt;次の動作とは、次のようなものである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;shiftするかreduceするか&lt;/li&gt;
&lt;li&gt;shiftならどの状態に遷移するか&lt;/li&gt;
&lt;li&gt;reduceならどの文法規則を適用するか&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;構文解析表のつくりかた&lt;/h3&gt;
&lt;h4&gt;1. 縦軸のラベル&lt;/h4&gt;
&lt;p&gt;縦軸にLR(0)正準集合を置く&lt;/p&gt;
&lt;h4&gt;2. 横軸のラベル&lt;/h4&gt;
&lt;p&gt;横軸に記号を置く。(このとき、終端記号と非終端記号は分ける、。終端記号に$(入力の終了を表す)を加える)&lt;/p&gt;
&lt;h4&gt;3. shift&lt;/h4&gt;
&lt;p&gt;遷移元の状態を行、遷移時の終端記号を列とするセルに、skと書き込む。(状態Ikに遷移する)&lt;/p&gt;
&lt;p&gt;shift(入力を1つ読み込む)して、スタックにkを積む(状態Ikに遷移する)ことを表す。&lt;/p&gt;
&lt;h4&gt;4. reduce時のpushする(積み直す)状態&lt;/h4&gt;
&lt;p&gt;遷移元の状態を行、遷移時の非終端記号を列とするセルに、kと書き込む。(状態Ikに遷移する)&lt;/p&gt;
&lt;p&gt;reduce時、還元後の状態(文法規則の左辺)をスタックに積み直す動作を表す。&lt;/p&gt;
&lt;h4&gt;5. reduce時の適用する文法規則&lt;/h4&gt;
&lt;p&gt;最右がドットであるLR(0)項を含む状態の行、終端記号の列にrkと書き込む。(文法規則Rkを適用する)&lt;/p&gt;
&lt;h4&gt;6. 完了状態&lt;/h4&gt;
&lt;p&gt;左辺が開始記号で右辺のドットが最右であるLR(0)項を含む状態の行
、$(入力終了)の列のセルに、accと書き込む。&lt;/p&gt;
&lt;p&gt;accを参照したら構文が正しいことが示され、構文解析を終了する。&lt;/p&gt;
&lt;h3&gt;構文解析表の作成結果&lt;/h3&gt;
&lt;p&gt;今回の構文解析表は次の通り&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;I\記号&lt;/th&gt;
&lt;th&gt;(&lt;/th&gt;
&lt;th&gt;)&lt;/th&gt;
&lt;th&gt;,&lt;/th&gt;
&lt;th&gt;a&lt;/th&gt;
&lt;th&gt;$&lt;/th&gt;
&lt;th&gt;S&lt;/th&gt;
&lt;th&gt;L&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;1&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;5&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;余談:構文解析表が表すもの&lt;/h3&gt;
&lt;p&gt;構文解析表の持つ情報は、次の3つに分けられる&lt;/p&gt;
&lt;h4&gt;1. オートマトンの状態遷移表&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;I\記号&lt;/th&gt;
&lt;th&gt;(&lt;/th&gt;
&lt;th&gt;)&lt;/th&gt;
&lt;th&gt;,&lt;/th&gt;
&lt;th&gt;a&lt;/th&gt;
&lt;th&gt;S&lt;/th&gt;
&lt;th&gt;L&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;2. reduce可能状態と適用する文法規則&lt;/h4&gt;
&lt;p&gt;I2のとき、文法規則R2を適用する。
I4のとき、文法規則R1を適用する。
I6のとき、文法規則R4を適用する。
I3のとき、文法規則R3を適用する。&lt;/p&gt;
&lt;h4&gt;3. 完了状態&lt;/h4&gt;
&lt;p&gt;I2,I4で全て読み込み済みのとき、構文解析が完了する。&lt;/p&gt;
&lt;h2&gt;構文解析&lt;/h2&gt;
&lt;p&gt;状態を記録するスタックを用意して、スタックトップと次の入力をもとに、動作を行う。&lt;/p&gt;
&lt;h3&gt;構文解析の方法&lt;/h3&gt;
&lt;h4&gt;1. 初期状態Ikであるとき、kをスタックに積む&lt;/h4&gt;
&lt;h4&gt;2. スタックtopの状態の行、次の入力記号の列のセルの指示に従う&lt;/h4&gt;
&lt;h5&gt;sk&lt;/h5&gt;
&lt;p&gt;shiftする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;入力を読み取る。(次の動作のとき入力を次の終端記号にすすめる)&lt;/li&gt;
&lt;li&gt;スタックにkを積む&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(オートマトンにおいて、入力の終端記号を辺とする状態遷移を行う)&lt;/p&gt;
&lt;h5&gt;rk&lt;/h5&gt;
&lt;p&gt;文法規則Rkに従ってreduceする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文法Rkを適用することを記録する。&lt;/li&gt;
&lt;li&gt;文法Rkの右辺の記号数分、スタックをpopする。(状態遷移を巻き戻す)&lt;/li&gt;
&lt;li&gt;上行のpop後のスタックトップの状態を行、文法Rkの左側の記号を列とするセルの数字をスタックにpushする。(文法Rk左側の記号の状態遷移を積み直す)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;acc&lt;/h5&gt;
&lt;p&gt;構文解析は成功。入力の分は、与えられた文法規則から生成される。
構文解析を終了する。&lt;/p&gt;
&lt;p&gt;適用すべき文法規則とその順は、記録された文法規則Rkを順に読む。&lt;/p&gt;
&lt;h5&gt;空&lt;/h5&gt;
&lt;p&gt;構文解析は失敗。入力の文は、与えられた文法規則から生成されることはない。&lt;/p&gt;
&lt;h3&gt;構文解析の結果&lt;/h3&gt;
&lt;p&gt;次の文を構文解析する。&lt;/p&gt;
&lt;p&gt;上から順に、解析の経過を記す。&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;((a,a),a)&lt;/code&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;入力&lt;/th&gt;
&lt;th&gt;スタックtop&lt;/th&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;スタック&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;読み取り済み&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;還元後&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;文法規則&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0112&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0116&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;016&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;$&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),a)$&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;accのときも文法規則r1は適用する。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以上より、与えられた文は、問題の文法規則から生成されることが示された。&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;((a,a),(a,a))&lt;/code&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;入力&lt;/th&gt;
&lt;th&gt;スタックtop&lt;/th&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;スタック&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;読み取り済み&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;還元後&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;文法規則&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0112&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0116&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;016&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013512&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013516&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013513&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314242&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013516&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013513&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424234&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424234&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314242341&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142423413&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a))&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142423413&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;$&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((a,a),(a,a))&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231424234131&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;accのときも文法規則r1は適用する。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以上より、与えられた文は、問題の文法規則から生成されることが示された。&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;(a,(a,a),a)&lt;/code&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;入力&lt;/th&gt;
&lt;th&gt;スタックtop&lt;/th&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;スタック&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;読み取り済み&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;還元後&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;文法規則&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;012&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;016&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013512&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013516&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013513&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01351357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4242&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013513&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;42423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;42423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4242313&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4242313&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4242313&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;42423132&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424231323&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;424231323&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;$&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(a,(a,a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;4242313231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;&lt;code&gt;(((a,a),a),a)&lt;/code&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;入力&lt;/th&gt;
&lt;th&gt;スタックtop&lt;/th&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;スタック&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;読み取り済み&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;還元後&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;文法規則&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;(&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0111&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01112&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01116&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0111352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0111357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0116&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;r4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;011357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0113&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;((L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;r1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;,&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0135&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;a&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;s2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01352&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;r2&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;01357&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L,S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;2423142312&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;r3&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;013&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),a&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423123&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;s4&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0134&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(L)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;24231423123&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;$&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;acc&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;(((a,a),a),a)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;S&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;242314231231&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以上より、与えられた文は、問題の文法規則から生成されることが示された。&lt;/p&gt;
&lt;style&gt;
.article.markdown-body table th {
  min-width: 0px;
}
.article.markdown-body table td {
  min-width: 0px;
}
&lt;/style&gt;</description>
    </item>
    <item>
      <title>Dockerチートシート プログラマのためのDocker教科書 第2版より</title>
      <link>https://memo.yammer.jp/posts/docker</link>
      <pubDate>Fri, 14 Aug 2020 09:59:31 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/docker</guid>
      <description>&lt;p&gt;以下、過去の自分用メモの移動。&lt;/p&gt;
&lt;p&gt;dockerに入門するにあたり「プログラマのためのDocker教科書 第2版より」を読んだ。
Dockerfileを書いてコンテナを走らせるための自分向けのまとめをチートシート的に書き記す。&lt;/p&gt;
&lt;h2&gt;Dockerfileの命令&lt;/h2&gt;
&lt;h3&gt;命令一覧&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;FROM .. ベースイメージの指定&lt;/li&gt;
&lt;li&gt;RUN .. コマンド実行&lt;/li&gt;
&lt;li&gt;CMD .. コンテナの実行コマンド&lt;/li&gt;
&lt;li&gt;LABEL .. ラベルを設定&lt;/li&gt;
&lt;li&gt;EXPOSE .. ポートのエクスポート&lt;/li&gt;
&lt;li&gt;ENV .. 環境変数&lt;/li&gt;
&lt;li&gt;ADD .. ファイル/ディレクトリの追加&lt;/li&gt;
&lt;li&gt;COPY .. ファイルのコピー&lt;/li&gt;
&lt;li&gt;ENTRYPOINT .. コンテナの実行コマンド&lt;/li&gt;
&lt;li&gt;VOLUME .. ボリュームのマウント&lt;/li&gt;
&lt;li&gt;USER .. ユーザの指定&lt;/li&gt;
&lt;li&gt;WORKDIR .. 作業ディレクトリ&lt;/li&gt;
&lt;li&gt;ARG .. Dockerfile内の変数&lt;/li&gt;
&lt;li&gt;ONBUILD .. ビルド完了後に実行される命令&lt;/li&gt;
&lt;li&gt;STOPSIGNAL .. システムコールシグナルの設定&lt;/li&gt;
&lt;li&gt;HEALTHCHECK .. コンテナのヘルスチェック&lt;/li&gt;
&lt;li&gt;SHELL .. デフォルトシェルの設定&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;コメント&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# コメント&lt;/span&gt;
命令 &lt;span class=&quot;hljs-comment&quot;&gt;# コメント&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;FROM&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; centos:&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# FROM [イメージ名]&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# FROM [イメージ名]:[タグ名]&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# FROM [イメージ名]@[ダイジェスト]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;ダイジェスト&lt;/h4&gt;
&lt;p&gt;Docker Hubにアップロードする際に自動で付与されるユニークな識別子。
ダイジェストを使うことでイメージを一意に指定できる。
&lt;code&gt;docker image ls --digests&lt;/code&gt;で確認できる&lt;/p&gt;
&lt;h3&gt;build&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker build -t [作成するイメージ名]:[タグ名] [Dockerfileのあるディレクトリのパス]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker engineの状態を確認&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker version
$ docker tutorial
$ docker system info
$ docker system df
# disk info
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;nginxをdockerで動かしてみる&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker pull nginx
$ docker image ls
$ docker container run --name nginxserver -d -p 80:80 nginx
# open http://localhost:80/ on web browser
$ docker ps
$ docker stop nginxserver
$ docker start nginxserver
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;centosをpullしてみる&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# p96
$ docker image pull centos:7
$ docker image ls
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DCT&lt;/h2&gt;
&lt;p&gt;docker imageが改ざんされているかどうか、公開鍵(Tagging Key)を用いて検証し、改ざんがある場合そのイメージを無効化する機能。&lt;/p&gt;
&lt;p&gt;有効化するには環境変数を付加&lt;/p&gt;
&lt;p&gt;署名なしイメージのpull時は無効化しなければならない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# enable
$ export DOCKER_CONTENT_TRUST=1

# disable
$ export DOCKER_CONTENT_TRUST=0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker imageの操作&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# pullしたイメージの詳細情報を確認(イメージID,作成日,dockerのversion,CPUアーキテクチャ等)
$ docker image inspect ubuntu:latest

# jsonの一部のみを取得
$ docker image inspect --format=&quot;{{ .Os }}&quot; ubuntu:latest
$ docker image inspect --format=&quot;{{ .ContainerConfig.Image }}&quot; ubuntu:latest

# docker image にタグ付け
$ docker image tag nginx yammerjp/nginxserver:1.0

# docker hub上のimage(この場合はnginx)を検索
$ docker search nginx 
# Option: --no-trunc .. 結果をすべて表示,  --limit n .. n件の検索結果, --filter=stars=n .. star数下限による絞り込み

$ docker image rm [--force(-f) --no-prun] yammerjp/nginxserver
# --force .. -f , --no-prune .. 中間イメージを削除しない
# yammerjp/nginxserver ... REPOSITORYではなくIMAGE IDでも良い

$ docker image prune [--all(-a) --force(-f)]
# 未使用のdocker imageを削除
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker image のpush&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker login -u yammerjp -p xxx
$ docker image push yammerjp/nginxserver:1.0
$ docker logout
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker container run&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker container run [ option ] yammerjp/nginxserver
$ docker run [ option ] yammerjp/nginxserver # containerは省略可能
$ docker run -it --name &quot;test1&quot; ubuntu /bin/bash
$ docker run -d -p 8080:80 nginx
$ docker run -d --dns 8.8.8.8 nginx
$ docker run -d --mac-address=&quot;92:d0:c6:0a:29:33&quot; ubuntu
# $ docker container inspect --format=&quot;{{ .Config.MacAddress }}&quot; [Container ID]
$docker run -id --add-host test.com:192.168.0.1 ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;実行開始時オプション&lt;/h3&gt;
&lt;p&gt;--attach(-a) STDIN/STDOUT/STDERR --cidfile --detach(-d) --interactive(-i) --tty(-t)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-a .. 標準入力/標準出力/標準エラー出力にアタッチ&lt;/li&gt;
&lt;li&gt;-d .. バックグラウンドで実行&lt;/li&gt;
&lt;li&gt;-i .. コンテナの標準入力を開く&lt;/li&gt;
&lt;li&gt;-t .. 端末デバイスを使う&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;終了時オプション&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;--restart .. no (再起動しない)/ on-failure (終了ステータスが0でないなら再起動)/ on-failure:4 (終了ステータスが0でないなら4回再起動/ always (常に)/ unless-stopped (直前のコンテナの状態が停止状態でなければ再起動)&lt;/li&gt;
&lt;li&gt;--rm .. 実行後のコンテナを自動で削除(--restartオプションと排他)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ネットワークオプション&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;--add-host=localhost:127.0.0.1 ... コンテナの/etc/hostsにホスト名とIPアドレスを定義&lt;/li&gt;
&lt;li&gt;--dns=8.8.8.8 ... コンテナ用のDNSサーバのIPアドレス&lt;/li&gt;
&lt;li&gt;--expose .. 指定したレンジのポート番号を割り当てる&lt;/li&gt;
&lt;li&gt;--mac-address=FF:FF:FF:FF:FF:FF .. コンテナのMACアドレスを指定&lt;/li&gt;
&lt;li&gt;--net=[bridge | none | container:&amp;#x3C;name | id &gt; | host | NETWORK] .. コンテナのネットワークを指定&lt;/li&gt;
&lt;li&gt;--hostname(-h) .. コンテナ自信のホスト名を指定&lt;/li&gt;
&lt;li&gt;--publish(-p) [ホストのポート番号]:[コンテナのポート番号] .. ホストとコンテナのポートマッピング&lt;/li&gt;
&lt;li&gt;--publish-all(-P) .. ホストの任意のポートをコンテナに割り当てる&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;リソースオプション&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;--cpu-shares(-c) .. CPUの使用の配分(1024が100%)&lt;/li&gt;
&lt;li&gt;--memory(-m) .. 使用するメモリを制限(単位はb,k,m,gのいずれか)&lt;/li&gt;
&lt;li&gt;--volume(-v)=[ホストのディレクトリ]:[コンテナのディレクトリ] .. ディレクトリを共有&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;環境変数など&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;--env(-e)=[環境変数] .. 環境変数を設定&lt;/li&gt;
&lt;li&gt;--envfile=[ファイル名] .. fileから環境変数を設定&lt;/li&gt;
&lt;li&gt;--readonly=[true|false] .. コンテナのファイルシステムを読み込み専用にする&lt;/li&gt;
&lt;li&gt;--workdir(-w)=[パス] .. コンテナの作業ディレクトリを指定する&lt;/li&gt;
&lt;li&gt;--user(-u)=[ユーザ名] .. ユーザ名かUIDを指定する&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker run --cpu-shares=512 --memory=1g ubuntu
$ docker run -v /Users/yammerjp/webap:/usr/share/nginx/html nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker network&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker network create -d bridge webap-net
$ docker container run --net=webap-net -it ubuntu

$ docker network ls
$ docker network connect [ option ] ネットワーク コンテナ
$ docker network disconnect ネットワーク コンテナ
$ docker network inspect [ option ] ネットワーク
$ docker network rm [ option ] ネットワーク

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;コンテナの状態確認&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker container ls [ --all(-a) --filter(-f) --format --last -8 --latest -l --no-trunc --quiet(-q) --size(-s) ]
# 稼働しているコンテナの状態一覧

$ docker container stats コンテナ識別子
# コンテナ稼働確認 識別子はnginxserver等 Ctrl+Cで終了

$ docker container top コンテナ識別子
# コンテナで実行中のプロセスを確認
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;コンテナの状態変更&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker container start[ --atatch(-a) --interactive(-i) ] コンテナ識別子
$ docker container stop [ -time(-t) ..コンテナの停止時間を指定する(defaultは10s) ] コンテナ識別子
$ docker container restart [ -time(-t) ..コンテナの再起動時間を指定する(defaultは10s) ] コンテナ識別子

$ docker container pause コンテナ識別子
$ docker container unpause コンテナ識別子
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;others&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker container rm [ --force(-f) .. 起動中のコンテナを強制的に削除 , --volumes(-v) .. 割り当てたボリュームを削除 ] コンテナ識別子

$ docker container attach コンテナ識別子
# 接続後、Ctrl+Cでコンテナごと終了、デタッチのみはCtrl+P -&gt; Ctrl+Q

$ docker container exec [ --detach(-d) --interactive(-i) --tty(-t) --user(-u) ] コンテナ識別子 実行コマンド

$ docker container top

$ docker container port # 転送されているポートの確認

$ docker container cp コンテナ識別子:コンテナ内のファイルパス ホストのディレクトリパス # ファイルをコピー
# cp以後を逆にすると、逆転送も可能

$ docker container diff コンテナ識別子　
# コンテナがイメージから作成されたときとの差分 A..ファイル追加 B..ファイル削除 C..ファイル更新

$ docker container commit [オプション] コンテナ識別子 [イメージ名[:タグ名]

&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>GitHubにsshでつなぐ</title>
      <link>https://memo.yammer.jp/posts/github-ssh</link>
      <pubDate>Fri, 14 Aug 2020 09:55:39 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/github-ssh</guid>
      <description>&lt;p&gt;以下、過去の自分用メモの移動。&lt;/p&gt;
&lt;p&gt;WindowsやMacでは、GitHubのIDとパスワードを安全に記憶して、HTTPS通信で勝手に使ってくれるのだが、Ubuntuではどうもよい方法がなさそうだった。&lt;/p&gt;
&lt;p&gt;そこでHTTPSではなくSSHを使ってgithubと通信するようにして、公開鍵認証により安全を担保しようというわけだ。&lt;/p&gt;
&lt;h2&gt;鍵ペアを作る&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd ~/.ssh
$ ssh-keygen -t rsa -b 4096 -C &quot;mymail@example.com&quot;
# 鍵の名前を id_rsa_github とする
# パスワードも聞かれるので入力

$ ls -1 
id_rsa_github # 秘密鍵
id_rsa_github.pub # 公開鍵

# 作成時に既に正しく設定されていた Ubuntu20.04LTS
# $ chmod 600 id_rsa_github
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;GitHubに登録&lt;/h2&gt;
&lt;p&gt;GitHub &gt; Settings &gt; SSH Keys &gt; Add SSH key から公開鍵を登録する&lt;/p&gt;
&lt;p&gt;Title : PC名等
Key: 公開鍵をコピペ&lt;/p&gt;
&lt;p&gt;Add keyを押し、その後パスワードも入力&lt;/p&gt;
&lt;h2&gt;ローカルマシン上で設定&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt;に以下を追記&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.ssh/config
Host github
  HostName github.com
  IdentityFile ~/.ssh/id_rsa_github
  User git
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# ssh-agentが動作しているか確認
eval &quot;${ssh-agent -s}&quot;
Agent pid 32047

$ ssh-add ~/.ssh/id_rsa_github
# パスワードを入力

# 接続確認
$ ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Lily58 Pro を Bluetooth 対応し無線化する</title>
      <link>https://memo.yammer.jp/posts/lily58-pro-ble</link>
      <pubDate>Thu, 13 Aug 2020 17:07:01 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/lily58-pro-ble</guid>
      <description>&lt;p&gt;&lt;a href=&quot;/posts/lily58-pro-build-log/&quot;&gt;前回の記事で作った&lt;/a&gt;左右分割型の自作キーボード &lt;a href=&quot;https://yuchi-kbd.hatenablog.com/entry/2018/12/23/214342&quot;&gt;Lily58 Pro&lt;/a&gt; を Bluetooth に対応させ、無線で PC に接続できるように改造した。
その作業記録。&lt;/p&gt;
&lt;p&gt;この記事では、無線化にあたり次のことを行う。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;USBからキーボードへの給電がなくなるので、別途&lt;a href=&quot;https://yushakobo.jp/shop/ble-micro-pro-battery-board/&quot;&gt;ボタン電池用の電源基板&lt;/a&gt;をつなぐ&lt;/li&gt;
&lt;li&gt;有線キーボードの制御用マイコンである Pro Micro を、Bluetooth に対応した &lt;a href=&quot;https://github.com/sekigon-gonnoc/BLE-Micro-Pro&quot;&gt;BLE Micro Pro&lt;/a&gt; に交換する&lt;/li&gt;
&lt;li&gt;BLE Micro Pro にファームウェアを書き込む&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;必要なもの&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Lily58 Pro (&lt;a href=&quot;https://yushakobo.jp/shop/lily58-pro/&quot;&gt;遊舎工房&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Pro Micro 互換の Bluetooth-LowEnergy 対応マイコン(&lt;a href=&quot;https://yusahakobo.jp/shop/ble-micro-pro/&quot;&gt;遊舎工房&lt;/a&gt;|&lt;a href=&quot;https://nogikes.booth.pm/items/1177319&quot;&gt;Booth&lt;/a&gt;) x2&lt;/li&gt;
&lt;li&gt;上記マイコン用ボタン電池基板 (&lt;a href=&quot;https://yushakobo.jp/shop/ble-micro-pro-battery-board/&quot;&gt;遊舎工房&lt;/a&gt;|&lt;a href=&quot;https://nogikes.booth.pm/items/1655285&quot;&gt;Booth&lt;/a&gt;) x2&lt;/li&gt;
&lt;li&gt;上記の互換ボードを Lily58 に PCB に固定するためのコンスルー 12ピン (&lt;a href=&quot;https://yushakobo.jp/shop/a01mc-00/&quot;&gt;遊舎工房&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;ボタン電池 CR1632 x4&lt;/li&gt;
&lt;li&gt;(電池ホルダーを紛失したので) 100均に売っている金属製のコードホルダー x4&lt;/li&gt;
&lt;li&gt;(電池ホルダーを紛失したので) 上記と基板をつなぐスズメッキ線&lt;/li&gt;
&lt;li&gt;マイコンと電池基板をつなぐICピン 長さ1ピン x4&lt;/li&gt;
&lt;li&gt;絶縁用ビニールテープ&lt;/li&gt;
&lt;li&gt;はんだ、はんだごて、はんだ吸い取り線、ピンセット等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;手順&lt;/h2&gt;
&lt;p&gt;手順を示した&lt;a href=&quot;https://sekigon-gonnoc.github.io/BLE-Micro-Pro/#/getting_started&quot;&gt;公式ガイド&lt;/a&gt;に従って作業を進めた&lt;/p&gt;
&lt;h3&gt;1. Lily58 Pro を完成させる&lt;/h3&gt;
&lt;p&gt;Pro Microはコンスルーを使って組み立て、交換できるようにしておく&lt;/p&gt;
&lt;h3&gt;2. 電池基板の組み立て&lt;/h3&gt;
&lt;h4&gt;2.1. コンデンサ, スイッチ, ダイオードの取り付け&lt;/h4&gt;
&lt;p&gt;電池基板に付属の電子部品をはんだ付けする。&lt;/p&gt;
&lt;p&gt;はんだ付けの手順は以下の通り。Lily58 Proの部品をはんだ付けしたのと同じように行えばよい。
写真はコンデンサを固定するときのものである。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;まず基板のランドの片方を温めて半田をつける&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard1.jpg&quot; alt=&quot;基板のランドの片方を温めて半田をつける&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;先程つけた半田を溶かして部品の片方を固定する&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard2.jpg&quot; alt=&quot;部品の片方を固定する&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;まだ半田を流していない側の端子とランドを温めて半田をつける&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard3.jpg&quot; alt=&quot;部品を完全に固定する&quot;&gt;&lt;/p&gt;
&lt;p&gt;コンデンサは極性がないのでどちら向きにつけてもよい。&lt;/p&gt;
&lt;p&gt;ダイオードはコンデンサと反対の面につける。
極性があるので注意。
ダイオードの表面に線が入っており、線が近い方の端子がプラス。
これを基板のシルク印刷(丸ポッチがある方)に合わせる。&lt;/p&gt;
&lt;p&gt;組み立てると次のようになる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard4.jpg&quot; alt=&quot;表面実装部品を組み立てた電池基板&quot;&gt;&lt;/p&gt;
&lt;h4&gt;2.2. 電池固定用ホルダーの取り付け&lt;/h4&gt;
&lt;p&gt;今回は(届いたときに内容物を確認していなかったがおそらく)この部品を紛失したため、電池が固定できそうな金属部品を探して代用した。&lt;/p&gt;
&lt;p&gt;それがダイソーのコードホルダー。
これの左右を切り落として、コの字のパーツを作り、折り曲げる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard5.jpg&quot; alt=&quot;ダイソーのコードホルダーを加工する&quot;&gt;&lt;/p&gt;
&lt;p&gt;次に、完成時に電池と基板を挟み込むように、基板の電池を固定するのと反対側の面に、金具を金具に付属の粘着テープで固定する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard7.jpg&quot; alt=&quot;コードホルダーと基板を結線する&quot;&gt;&lt;/p&gt;
&lt;p&gt;そのあと、基板のホールと金具をスズメッキ線で結線する。&lt;/p&gt;
&lt;p&gt;最後に電池を取り付けてテスターで3Vが得られることを確認したら、全体をビニールテープで絶縁する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/powerboard8.jpg&quot; alt=&quot;ビニールテープで絶縁する&quot;&gt;&lt;/p&gt;
&lt;h3&gt;3. BLE Micro Pro の組み立て&lt;/h3&gt;
&lt;p&gt;BLE Micro Pro にコンスルーを取り付ける。はんだ付けの必要はないと書いてあったがなんとなく半田を流しておいた。&lt;/p&gt;
&lt;p&gt;その後、ピンヘッダを1本だけの長さにして、電池基板を BLE Micro Pro につなげる。&lt;/p&gt;
&lt;p&gt;最後に BLE Micro Pro を Lily58 に刺して完成。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/lily58proble.jpg&quot; alt=&quot;Bluetooth対応の組み立てが完了したLily58 Pro&quot;&gt;&lt;/p&gt;
&lt;h3&gt;4. ファームウェアの書き込み&lt;/h3&gt;
&lt;p&gt;事前に 電池基板のスイッチを切っておいたほうがわかりやすい。
Lily58 Pro に固定した状態で左右の基板ともに、左にスイッチを倒すとOFF。&lt;/p&gt;
&lt;p&gt;BLE Pro Micro は &lt;a href=&quot;https://sekigon-gonnoc.github.io/home#/keymap&quot;&gt;専用の Web Configurator&lt;/a&gt; という Chrome 上で動く Webアプリで書き込むのが一番簡単な方法らしい。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Chrome の設定変更
&lt;code&gt;chrome://flags#enable-experimental-web-platform-features&lt;/code&gt; を開き Experimental Web Platform features を Enabled にする。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://sekigon-gonnoc.github.io/home#/keymap&quot;&gt;専用の Web Configurator&lt;/a&gt; にアクセスする&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ナビゲーション付きでセットアップを開始する&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;キーボードの選択画面で Lily58 の rev1 を選ぶ Disable Mass storage Class と Use with LPME-IO のチェックは入れない&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最新のブートローダー (記事執筆時は0_7_1) 選び Update&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;デバイスを選択する画面が出てくるので, BLE Micro Pro を PC と USBで接続する。
BLE Micro Pro(新しく増えたデバイス)を選択。
筆者の環境(Macbook Air 2018 Catarina)では &lt;code&gt;IOUSBHostDevice (tty.usbmodem0000000000011)&lt;/code&gt; と &lt;code&gt;IOUSBHostDevice (cu.usbmodem0000000000011)&lt;/code&gt;が出現したが、後者を選ぶと書き込めた。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;アプリケーション(必ずブートローダー同じバージョンのもの)を書き込む。Is Left のみにチェックが入っていること。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;もう一つの BLE Micro Pro も同様に書き込む。アプリケーション書き込み時に Is  Slave のみにチェックが入っていること。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;5. キーマップの書き込み&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://sekigon-gonnoc.github.io/qmk_configurator/#/&quot;&gt;専用の QMK Configurator&lt;/a&gt; にアクセスする。&lt;/li&gt;
&lt;li&gt;BLE Micro Pro を PC に USB 接続した状態で、CONNECT BY SERIAL ボタンを押す。&lt;/li&gt;
&lt;li&gt;キーボードリストから lily58/rev1 を選択する。&lt;/li&gt;
&lt;li&gt;好みのキーマップを作成する。&lt;/li&gt;
&lt;li&gt;KEYMAP.JSON の左側のボタンを押してキーボードに反映&lt;/li&gt;
&lt;li&gt;そのまま試しにキーを打ってみて問題なさそうであれば、SAVE KEYMAP ボタンでキーボードに保存。&lt;/li&gt;
&lt;li&gt;USBを抜いて、PCと BLE Micro Pro を切り離す&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6. キーボードを実際に使う&lt;/h3&gt;
&lt;p&gt;左右どちらも電池基板の電源を入れると、勝手に左右がペアリングする。
PC の Bluetooth 設定ページを見ると Lily58 が出現しているので選択すると PC とのペアリングが完了し使えるようになる。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;公式のドキュメントと、他の分割キーボードの Bluetooth 化の記事を見ながら進めた。&lt;/li&gt;
&lt;li&gt;電池ホルダーがないことに気づいたときは凹んだが、完成品は特に不自然なく動作させられてよかった。&lt;/li&gt;
&lt;li&gt;QMK をビルドして書き込む方法はうまく行ってないので、また必要になる時があったら試してみることとする。&lt;/li&gt;
&lt;li&gt;Web アプリの QMK Configurator はよくできていて、キーの長押しで動作を変えるといった機能にも対応しているのでひとまずは普通に使えている。&lt;/li&gt;
&lt;li&gt;キーボードのペアリングはとてもスムーズだったし、ペアリング後も電源を入れるとすぐにPCとつながるのでとても快適に使うことができている。&lt;/li&gt;
&lt;li&gt;いまのところ一日に一回くらい、キーが押しっぱなしになる(キーを押して無いのにキーコードが送信され続ける)ことがあり、キーボードの電源を一旦切ることで解決している。原因は不明。 今後も継続して発生するようであれば、これの原因究明もせねばならない。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こんなところかな。&lt;/p&gt;
&lt;p&gt;自作キーボードとはいえ、普通に問題なく使える快適なものが出来上がってとても満足だ。
キーボードや無線化キットを設計したり情報をまとめたりしてくれている方々に感謝したい。&lt;/p&gt;
&lt;p&gt;両手で1万円くらいかけてわざわざ無線化したのは理由があるのだが、それはまた別記事で紹介することとする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) lily58ビルドログへのリンクを相対リンクへ修正&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lily58 を作って自作キーボードに入門した (Lily58 Pro Build Log)</title>
      <link>https://memo.yammer.jp/posts/lily58-pro-build-log</link>
      <pubDate>Thu, 13 Aug 2020 16:55:25 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/lily58-pro-build-log</guid>
      <description>&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;毎月一回、自作キーボードが作りたくなってカートに商品を入れるまでやる。あと一歩のところで踏みとどまる。&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1284673759593418752?ref_src=twsrc%5Etfw&quot;&gt;July 19, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;数ヶ月前から、自作キーボードが気になっていたのだが、ついに手を出してしまった。&lt;/p&gt;
&lt;h2&gt;自作キーボードとは&lt;/h2&gt;
&lt;p&gt;自作キーボードとは、キースイッチやキーキャップ、基板(PCB)等を購入し、自分で組み立ててキーボードを作ることである。
自分の欲しいキーボードを作ることができるのが魅力。&lt;/p&gt;
&lt;p&gt;パーツをはんだ付けしたり、マイコンにファームウェアを書き込んだり、場合によっては基板を設計したりすることでつくる。&lt;/p&gt;
&lt;p&gt;今回は既に設計, 基板が製造済みで、組み立てキット形式になっている Lily58 Pro を作ることにした。&lt;/p&gt;
&lt;h2&gt;Lily58 Pro を選んだ理由&lt;/h2&gt;
&lt;p&gt;作る機種は、&lt;a href=&quot;https://yuchi-kbd.hatenablog.com/entry/2018/12/23/214342&quot;&gt;Lily 58 Pro&lt;/a&gt;とした。&lt;/p&gt;
&lt;p&gt;Lily58 が魅力だったのは次の点。&lt;/p&gt;
&lt;h3&gt;キーマップを自由に書き換えられること&lt;/h3&gt;
&lt;p&gt;これは Lily58 に限らず自作キーボードの殆どに言えることだと思うが、キーボードの挙動を自由に書き換えることができる。
打ちづらい位置にあるキーは使用頻度の少ないキーと入れ替えたり、複数キーの同時押しで特殊な動作をさせたりすることが可能になる。&lt;/p&gt;
&lt;p&gt;自作キーボードは極端に言うとマイコンとスイッチの集合体なので、挙動は本当に自由に決めれると言ってよい。
(実際には qmk といわれるファームウェアを使うことが一般的で、これの一部を書き換えることでカスタマイズを実現する。)&lt;/p&gt;
&lt;p&gt;キーボード側で自由に設定できるのはとてもありがたい。
もともとキーリマッパと呼ばれるソフトウェアを使って挙動を書き換えていたのだが、これは環境構築が面倒だったりする。
(Mac では Karabiner Elements、Ubuntu では xkeysnail を使っていた。)
自作キーボードであれば USB を刺すだけで済む。&lt;/p&gt;
&lt;p&gt;キーマップを自由に書き換えられるのって嬉しいのか？と思う人、あなたは CapsLock を使っているだろうか。
結構使用頻度の少ないキーだと思うのだが、そこそこ押しやすい位置にある。
例えばこれを Ctrl に変えればショートカットを押しやすいし、ESC にすれば Vim が使いやすくなるし、半角/かなキーにするのも便利かもしれない。&lt;/p&gt;
&lt;p&gt;こんな感じで一つずつ置き換えるキーを増やしていき、設定が煩雑になって自作キーボードが欲しくなった。&lt;/p&gt;
&lt;h3&gt;キー数が60個程度 (いわゆる60%キーボード)&lt;/h3&gt;
&lt;p&gt;普段使わないキーはいらないので、コンパクトなものがほしい。
ただし40%等のこれ以上キー数が少ないものは不安。&lt;/p&gt;
&lt;p&gt;既に60%の中華キーボード (&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B07QQXJ58V/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&amp;#x26;psc=1&quot;&gt;RK Royal RK61&lt;/a&gt;) を使っているので、良い落とし所なのではと思った。&lt;/p&gt;
&lt;p&gt;ちなみにこの RK61 は4月頃に自作キーボード (DZ60) を作ろうか迷った挙げ句「自作キーボード、まだ自分には早いかな」と思い、とりあえず60%の US 配列キーボードを買ったもの。
普通に使えていたが、結局自作キーボード欲を抑えることができなかった。&lt;/p&gt;
&lt;h3&gt;kailh ロープロファイルに対応している&lt;/h3&gt;
&lt;p&gt;Lily58 Pro は kailh ロープロファイル (浅いキーストロークのスイッチの規格) に対応している。&lt;/p&gt;
&lt;p&gt;私はノートパソコンのキーボードのような、キーストロークの浅いキーボードが割と好きで、キーストロークが深いと打ち間違いやすい気がしていた。
(RK61を使っていたときの感想。昔はメンブレンのキーボードとか普通に使っていたはずなのだが。)&lt;/p&gt;
&lt;p&gt;作ったあとの感想になるが、このキースイッチの選択は正解で浅いキーボードは打ちやすいと感じる。&lt;/p&gt;
&lt;h3&gt;左右分割型であること&lt;/h3&gt;
&lt;p&gt;左右分割型だと肩が丸まらないので姿勢が良くなるらしい。
当初は分割でなく一体型のキーボードに注目していたが、調べるうちにどうせ作るなら金額も変わらないし左右分割型にしてみるかという気分になっていった。&lt;/p&gt;
&lt;p&gt;左右分割型にしたことで夢が広がるのだがそれはまた別の記事に書くこととする。&lt;/p&gt;
&lt;h3&gt;column-straggered であること&lt;/h3&gt;
&lt;p&gt;column-straggerd とはキー配列の種類で、列ごとに縦方向にずれたもの。&lt;/p&gt;
&lt;p&gt;一般的なキーボードは キーが一段ごとに横方向に半分程度ずれている。(row-straggered という。)
このずれはタイプライターの機械構造に起因していて、特に打ちやすくするためではないらしい。&lt;/p&gt;
&lt;p&gt;この横方向にずれた配列が打ちづらいのはわりと感じる(右人差し指でYを打鍵するの遠すぎないか？？)ので、完全に格子状の Ortholiner ないしは column-straggerd なキーボードを求めた。&lt;/p&gt;
&lt;p&gt;ちなみにYを右人差し指でタイプするのは遠すぎるので、左人差し指でタイプする癖がついていたのだが、分割キーボードにしたことでこの癖は矯正することになった。&lt;/p&gt;
&lt;h2&gt;購入したもの&lt;/h2&gt;
&lt;p&gt;自作キーボードの部品を買える通販サイトの代表的なものに以下のサイトがある。
今回は全て遊舎工房で購入した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://yushakobo.jp/&quot;&gt;遊舎工房&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yushakobo.jp/&quot;&gt;Aliexpress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kbdfans.com/&quot;&gt;KBDFANS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eucalyn.shop/&quot;&gt;ゆかりキーボードファクトリー&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://talpkeyboard.stores.jp/&quot;&gt;TALP KEYBOARD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;購入した商品は以下の通り。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;商品&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;数量&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;値段&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;補足&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/lily58-pro/?attribute_pa_sockettype=choc&quot;&gt;Lily58 Pro - Kailh Choc ロープロファイル用&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14,800&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;大半のパーツが含まれるキット&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/pg1350/?attribute_pa_stem=red&quot;&gt;Kailhロープロファイルスイッチ（10個） - 赤&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,880&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;キーを押したことを判定するスイッチ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/pg1350cap-doubleshot/?attribute_pa_keycapcolor=black&quot;&gt;Kailhロープロ刻印キーキャップ - 黒&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3,000&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;キースイッチの上にかぶせるキャップ  (刻印付きで100個くらい入っている)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/a0300lb/?attribute_pa_color=white&amp;#x26;attribute_pa_size=1-5u&quot;&gt;Kailhロープロ無刻印キーキャップ1.5U 2U（1個） - 白, 1.5u&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;400&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;親指部分の少し長いキーキャップ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/pg1350cap-blank/?attribute_pa_keycapcolor=white&quot;&gt;Kailhロープロ無刻印キーキャップ1U（10個） - 白&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;300&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;刻印が合わないところに使うキーキャップ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/pg1350cap-blank/?attribute_pa_keycapcolor=black&quot;&gt;Kailhロープロ無刻印キーキャップ1U（10個） - 黒&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;300&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;刻印が合わないところに使うキーキャップ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/trrs_cable/&quot;&gt;TRRSケーブル 1m&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;300&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;左右をつなぐケーブル&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;https://yushakobo.jp/shop/promicro-spring-pinheader/?attribute_pa_firmware=none&quot;&gt;Pro Micro （コンスルー付き） - なし&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1000&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;後述の通り、キットに入っているPro Microをダメにしてしまったので追加購入&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;この他に Pro Micro と PC をつなぐ USB(A to microB)ケーブルも必要。(&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B071S5NTDR/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;#x26;psc=1&quot;&gt;家にあるもの&lt;/a&gt;を使った)&lt;/p&gt;
&lt;p&gt;Lily58 は、一般にTabやCtrlなどが位置するキーも1U(アルファベットのキーと同じ大きさ)である。
今回購入したキーキャップセットのキャップは合わないので、別途個別に無刻印のキーキャップをバラで買った。
(見た目を気にしたければテンキー用の1Uキーなどが余るのでそれを使ってもよさそう。)&lt;/p&gt;
&lt;p&gt;金額は合計して消費税を足して、2.5万円しないくらい。&lt;/p&gt;
&lt;h2&gt;組み立て&lt;/h2&gt;
&lt;p&gt;組み立てには、上記の購入部品の他にはんだ、はんだごて、ピンセット、プラスドライバーが必要になる。エポキシ接着剤(100均に売ってる)、ハンダ吸い取り線もあるといい。&lt;/p&gt;
&lt;h3&gt;USB端子の補強&lt;/h3&gt;
&lt;p&gt;まずはじめに &apos;もげmicro&apos; を防ぐためにエポキシ接着剤で補強する。&lt;/p&gt;
&lt;p&gt;USBを刺す基板である Pro Micro はコネクタが折れやすいらしく、抜き差しを繰り返すとコネクタが折れてPro Microが使えなくなることがよくあるらしい。
(自作キーボード界隈ではこのことを&apos;もげMicro&apos;と呼ぶそう)&lt;/p&gt;
&lt;p&gt;この対策のために今回遊舎工房で買ったキットはコンスルーというピンが入っており、はんだ付けせずにPro Microを接続できて交換がしやすいようになっている。&lt;/p&gt;
&lt;p&gt;また、端子部分を補強するためにエポキシ接着剤をコネクタ周囲に流して固定するのが定番のようだ。
私もインターネットの記事を参考にエポキシ接着剤を塗り、、、&lt;/p&gt;
&lt;p&gt;やってしまった。
コネクタ内部に接着剤が流れ込み、USBが刺さらなくなってしまった。
仕方ないので追加でPro Microを一つ注文し、作業をすすめる。&lt;/p&gt;
&lt;h3&gt;Lily58 Pro キットの組み立て&lt;/h3&gt;
&lt;p&gt;以降の組み立ての過程はキーボード設計者のゆーちさんが書いた&lt;a href=&quot;https://github.com/kata0510/Lily58/blob/master/Pro/Doc/buildguide_jp.md&quot;&gt;ビルドガイド&lt;/a&gt;に書かれている。
これを&lt;strong&gt;よく読んで&lt;/strong&gt;作れば問題ない。&lt;/p&gt;
&lt;p&gt;私はキースイッチ受けとダイオードを逆の面につけてしまい一度ハンダを取り除いて再度つけるなどした。&lt;/p&gt;
&lt;p&gt;あとはんだ付けに不安があれば、はんだ付け後にテスターで導通を確認するのがよい。
沢山数があって面倒だが、ここでミスっているのを跡で治すほうが大変なのでチェックしておくことをおすすめする。
私はキースイッチ受けの導通をチェックしておらず、完成後に2つ半田をつけ直した。&lt;/p&gt;
&lt;p&gt;組み立て中の写真を取るのを忘れたが、数時間で組み上がったと思う。&lt;/p&gt;
&lt;h2&gt;ファームウェアの書き込み&lt;/h2&gt;
&lt;h3&gt;デフォルトのファームウェアを書き込む&lt;/h3&gt;
&lt;p&gt;次の手順でファームウェアを書き込む。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Ubuntu 20.04 LTS
$ git clone git@github.com:qmk/qmk_firmware.git
$ cd qmk_firmware
$ make git-submodule
$ ./util/qmk_install.sh # 必要なパッケージをインストール 時間がかかる
$ sudo make lily58:default:avrdude
# 次のような表示が出てきたら, キーボードのリセットボタンを押す
# Detecting USB port, reset your controller now...
# 同様の手順で左右のマイコンに同じファームウェアを書き込む
# 左手のUSBコネクタにケーブルを, 左右のTPRS端子に4極ケーブルを刺す
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ファームウェアのカスタマイズ&lt;/h3&gt;
&lt;p&gt;次の手順でファームウェアを書き込む。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# yammerjp と名付けた自分用キーマップを作る

$ cp -r keyboards/lily58/keymaps/default keyboards/lily58/keymaps/yammerjp
$ vim keyboards/lily58/keymaps/yammerjp/keymap.c
# キーマップを書き換える

$ sudo make lily58:yammerjp:avrdude
# 次のような表示が出てきたら, キーボードのリセットボタンを押す
# Detecting USB port, reset your controller now...
# 同様の手順で左右のマイコンに同じファームウェアを書き込む
# 左手のUSBコネクタにケーブルを, 左右のTPRS端子に4極ケーブルを刺す
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;私が現在設定している&lt;a href=&quot;https://github.com/yammerjp/qmk_firmware/blob/master/keyboards/lily58/keymaps/yammerjp/keymap.c&quot;&gt;キーマップは次の通り&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;記事の前半で60%のキーボードが良いと言っておきながら、ホームポジションから離れた上段1列は無効化している(2020/08/05現在)。
まだ慣れていないので使いやすいかどうかはまだ不明だが、慣れたら便利そうな気がしている。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;組み立てるのも結構楽しいし、キーボードが左右で割れているのは新鮮だし、作って良かった。
キーマップについてはまだまだ慣れていないし、使いながら改良していきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2021/01/06 必要なパッケージのインストール手順を追記&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ubuntu20.04でトラックボールのボールを転がしてスクロールする</title>
      <link>https://memo.yammer.jp/posts/ubuntu-m570-scroll</link>
      <pubDate>Thu, 13 Aug 2020 16:20:09 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/ubuntu-m570-scroll</guid>
      <description>&lt;p&gt;最近、Logicool のトラックボール M570 を購入した。
このトラックボールはスクロールホイールがついているが、左右にスクロールする機能はない。&lt;/p&gt;
&lt;p&gt;そこで、ボールを転がして上下左右にスクロールを可能にする。&lt;/p&gt;
&lt;p&gt;今回は Ubuntu 20.04 をターゲットに設定を行う。
(macOS では、Karabiner Elements と Scroll Reverser というソフト (どちらも brew cask にあり) を使い実現した。詳細は省略)&lt;/p&gt;
&lt;h2&gt;デバイス名を調べる&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ xinput list
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ Logitech M570                           	id=9	[slave  pointer  (2)]
⎜   ↳ Lily58 Consumer Control                 	id=11	[slave  pointer  (2)]
⎜   ↳ Lily58 Mouse                            	id=13	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Power Button                            	id=6	[slave  keyboard (3)]
    ↳ Video Bus                               	id=7	[slave  keyboard (3)]
    ↳ Power Button                            	id=8	[slave  keyboard (3)]
    ↳ Lily58 Keyboard                         	id=10	[slave  keyboard (3)]
    ↳ Lily58 Consumer Control                 	id=12	[slave  keyboard (3)]
    ↳ Lily58 System Control                   	id=14	[slave  keyboard (3)]
    ↳ WI-C300 (AVRCP)                         	id=15	[slave  keyboard (3)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上より、デバイス名は&lt;code&gt;Logitech M570&lt;/code&gt;、デバイスIDは&lt;code&gt;9&lt;/code&gt;。
のちの設定ファイルでデバイス名を利用する。&lt;/p&gt;
&lt;h2&gt;ボタン番号を調べる&lt;/h2&gt;
&lt;p&gt;以下のコマンドでIDが&lt;code&gt;9&lt;/code&gt;のデバイスの状態をみることができる。&lt;/p&gt;
&lt;p&gt;今回はマウスのスクロールホイールを押し込むボタンの番号を知るために、スクロールホイールを押し込みながら以下のコマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ xinput query-state 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行結果より、 M570 のスクロールホイールを押し込むボタンの番号は&lt;code&gt;3&lt;/code&gt;であることがわかった。&lt;/p&gt;
&lt;h2&gt;設定を記入する&lt;/h2&gt;
&lt;p&gt;root権限で &lt;code&gt;/usr/share/X11/xorg.conf.d/40-libinput.conf&lt;/code&gt; に以下を追記する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /usr/share/X11/xorg.conf.d/40-libinput.conf
# Logitech M570 Scrolling with pressed the right button and rolled the ball
Section &quot;InputClass&quot;
  Identifier &quot;Logitech M570&quot;
  MatchProduct &quot;Logitech M570&quot;
  Driver &quot;libinput&quot;
  Option &quot;ScrollMethod&quot; &quot;button&quot;
  Option &quot;ScrollMethod&quot; &quot;3&quot;
EndSection
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再起動するとスクロールホイール押下時にボールによるスクロールが有効化される。&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://yu1.dev/posts/%E5%B8%B8%E7%94%A8ubuntu-18.04-lts%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97/&quot;&gt;常用Ubuntu 18.04 LTSのセットアップ - yu1.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>自作コンパイラのfor文バグ</title>
      <link>https://memo.yammer.jp/posts/willani-for-stmt-bug</link>
      <pubDate>Wed, 08 Jul 2020 17:09:03 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/willani-for-stmt-bug</guid>
      <description>&lt;p&gt;C言語のコンパイラを自作に関する今日の日記。&lt;/p&gt;
&lt;p&gt;これまでの記事&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;「&lt;a href=&quot;/posts/willani-start/&quot;&gt;数日前からCコンパイラを書き始めた。&lt;/a&gt;」&lt;/li&gt;
&lt;li&gt;「&lt;a href=&quot;/posts/willani-compliperbook-finished/&quot;&gt;自作Cコンパイラの途中経過&lt;/a&gt;」&lt;/li&gt;
&lt;li&gt;「&lt;a href=&quot;/posts/try-selfhost&quot;&gt;自作コンパイラのセルフホストに挑戦中&lt;/a&gt;」&lt;/li&gt;
&lt;li&gt;「&lt;a href=&quot;posts/willani-struct-alignment&quot;&gt;C言語の構造体メンバのアライメント (x86_64, Linux (System V ABI))&lt;/a&gt;」&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;今日実装したのは次の2つ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;構造体のアライメント&lt;/li&gt;
&lt;li&gt;for文バグの修正&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ちなみに昨日はastをjsonで吐くコード(git反映前に間違えて切り取って飛ばしてしまい頑張って再実装したが、翌日セルフホスト向けにはバグっていることがわかりお蔵入り)、セルフホスト用のシェルスクリプトなどを実装していた。&lt;/p&gt;
&lt;h2&gt;構造体のアライメント&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/willani&quot;&gt;willani&lt;/a&gt; での今日行ったアライメントの実装は&lt;a href=&quot;https://github.com/yammerjp/willani/commit/ae1d68f94211c6c510ea2247abcde7386ffd25c8&quot;&gt;このあたり&lt;/a&gt;。実装内容は前回の記事(&lt;a href=&quot;posts/willani-struct-alignment&quot;&gt;C言語の構造体メンバのアライメント (x86_64, Linux (System V ABI))&lt;/a&gt;)で説明している。&lt;/p&gt;
&lt;p&gt;セルフホストをしようとしているがうまくいかないファイルが結構ある。
構造体のアライメントを実装するきっかけは色々なファイルを第一世代コンパイラに流しているときに出てきた問題からである。&lt;/p&gt;
&lt;p&gt;トークナイズ結果をファイルに出力する &lt;code&gt;src/tokenize_log.c&lt;/code&gt; というファイルを willani でビルドしてリンクすると、コンパイラは動くがトークナイズ結果のうち構造体アクセスしている部分だけ出力がなかった。
ここから構造体のアライメントが必要なことと実装していないことに気づいた。&lt;/p&gt;
&lt;p&gt;本当は配列も 16byte 境界でアライメントしなければならなかった気がするが、こちらはまだ未実装。
Union もアライメントしなきゃいけないが、こちらはそもそも Union を未実装。
グローバル変数もアライメントしなきゃいけないが、これもまだ実装していない。&lt;/p&gt;
&lt;h2&gt;for文バグの修正&lt;/h2&gt;
&lt;p&gt;今日はこのアライメントと、いわゆるfor文バグ (と私が呼んでいるもの) の修正をやった。&lt;/p&gt;
&lt;p&gt;ここ最近セルフホストに向けて、gccでコンパイルしたアセンブリに一部 willani でコンパイラしたアセンブリを混ぜてリンクして第1.5世代コンパイラを作っている。
その中で &lt;code&gt;src/type.c&lt;/code&gt; というファイルを willani でビルドしてリンクしたときの話。&lt;/p&gt;
&lt;p&gt;バグの詳細は記事最後に記す。
時系列に説明しているので長くなってしまった。&lt;/p&gt;
&lt;p&gt;どうもセルフホストに近づいてコンパイラ自身のコードをビルドし始めるとどこで何がバグっているのかわからなくなってくる。&lt;/p&gt;
&lt;p&gt;普通のプログラムでは、入力が誤っているか、入力を受け取るコードが誤っているかを考えればいいが、セルフホストを目指すコンパイラではさらに、入力を受けとるコードを生成するコードが誤っている可能性も考慮しなければならない。&lt;/p&gt;
&lt;p&gt;例えばあとで記す「バグの詳細」に出てくる構造体は、入力文字列で表記されている構造体と、入力文字列を処理するプログラムのデータ構造としての構造体、そしてそのプログラムを生成するときのデータ構造としての構造体があって、いま考えている構造体はなんなんだ？という気持ちになる。&lt;/p&gt;
&lt;p&gt;とにかくバグトラックが大変で、些細なことで1日が溶けた。&lt;/p&gt;
&lt;p&gt;今回の&lt;code&gt;src/type.c&lt;/code&gt;ではあまりなかったが、segmentation falut で終了することもよくあるし、デバッグが結構大変。&lt;/p&gt;
&lt;p&gt;パース結果のログは、パースが完全に終わってからASTをたどって出力しているので、パース中に死ぬとどんな状況かつかめないことが多々ある。なのでパース中のデバッグを楽にするためのログ出力などは強化していきたい。&lt;/p&gt;
&lt;p&gt;大変とは書いたが、ゆっくりだが着実にセルフホストに近づいているし、なにより自分の書いたコードで自分の書いたコードをコンパイルする状況はなんともいえないワクワク感があるので楽しい。&lt;/p&gt;
&lt;p&gt;明日以降も楽しみながら進めていきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;補足: タイトルについて&lt;/p&gt;
&lt;p&gt;今日見つけたバグは、私がfor文バグと呼んでいて、実際for文の実装にバグがあったが、内容はささいな話で、結構実装依存な内容である。&lt;/p&gt;
&lt;p&gt;なのでfor文の実装に他の人もハマりがちな落とし穴があるという意味はなく、タイトルはあくまで自分の記憶のためのもの。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;バグの詳細&lt;/h2&gt;
&lt;p&gt;どうもこの第1.5世代コンパイラは、構造体のメンバを読む処理がバグっていて、定義済みのメンバを呼び出すコードを解釈する際に、同名のメンバが定義されていないとしてエラーを出力していた。&lt;/p&gt;
&lt;p&gt;構造体を含まないコードは問題なくコンパイルできるので、構造体のメンバを読むあたりが明らかに怪しい。
しかしどうやってバグっているのか全く検討がつかなかった。&lt;/p&gt;
&lt;p&gt;まず疑ったのは、入力のコードの構造体を読み込むときに構造体のアライメントが狂っていて読み込みに失敗しているのではないかということ。
実は多分ここでもバグっていて、まずは冒頭のような構造体のアライメントを実装した。
これにより、構造体の情報を willani 内部で保持する構造体 (Member 構造体) の各メンバに、コンパイラ内で正しくアクセスできるようになった。&lt;/p&gt;
&lt;p&gt;しかしエラーは消えず、ほかにどこがバグっているのかよくわからない。
(自作コンパイラでは、エラーメッセージは往々にして自分が書いたものが出力されるので、なんともいえない気持ちになる。)&lt;/p&gt;
&lt;p&gt;ひとまず関係のある Member 構造体の生成・格納・検索などのコードに片っ端に fprintf を挿入し、変数の値やポインタの指すメモリ番地などをダンプすることとした。&lt;/p&gt;
&lt;p&gt;ダンプしたことでエラー発生の直前までうまく値がわたっていることはわかった。
何故か (for 文をつかった) メンバ名の検索だけがうまくいっていない。&lt;/p&gt;
&lt;p&gt;色々試したうえで、たまたま for 文を while 文に書き換えると嘘のように正しく動作して解決した。&lt;/p&gt;
&lt;p&gt;あとで調べると、for 文の初期化処理がうまくいってなかったようだ。
for 文を表す node は、初期化文を表す node を init メンバとして持っている。
init メンバはふつう1文を表す1つの node で、next メンバに値が入ることはないとして実装されていた。&lt;/p&gt;
&lt;p&gt;しかし、init メンバが変数の宣言と初期化を行う文の node で、かつ初期化子が実行時に定まるとき(例えば &lt;code&gt;int a=p;&lt;/code&gt;)バグる。
&lt;code&gt;int a=1;&lt;/code&gt; のような文は、willani では1つの Node 構造体 (&lt;code&gt;Node.kind = ND_STMT_VAR_INIT&lt;/code&gt;) で表される。
この構造体には初期化の値も含まれており、初期化の値が即値(コンパイル時に定まる値(数字か文字列))なら1つの構造体で完結する。
一方初期化の値は実行時に定まる場合もある。
このときは Node 構造体の next メンバで別の Node 構造体を数珠つなぎに持ち、これらが初期化用の式文をそれぞれあらわすようになっている。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/codegen.c&lt;/code&gt; の実装バグで、for 文の init メンバの next メンバが指すノードを出力していなかったことで、構造体のメンバを表す変数のアドレスを初期価値として渡すコードがコンパイル時に含まれていなかったらしい。&lt;/p&gt;
&lt;p&gt;わかってしまえば数行で解決できるバグだった。
(&lt;a href=&quot;https://github.com/yammerjp/willani/commit/7af9e76cadd338e85e41974e257e498819a59756&quot;&gt;コミット&lt;/a&gt;)&lt;/p&gt;</description>
    </item>
    <item>
      <title>C言語の構造体メンバのアライメント (x86_64, Linux (System V ABI))</title>
      <link>https://memo.yammer.jp/posts/willani-struct-alignment</link>
      <pubDate>Wed, 08 Jul 2020 15:59:59 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/willani-struct-alignment</guid>
      <description>&lt;p&gt;System V ABI における構造体メンバのアライメントの方法を記す。&lt;/p&gt;
&lt;p&gt;C言語のコンパイラを自作しているときに学んだことの記録で、
これまでの記事
「&lt;a href=&quot;/posts/willani-start/&quot;&gt;数日前からCコンパイラを書き始めた。&lt;/a&gt;」
「&lt;a href=&quot;/posts/willani-compliperbook-finished/&quot;&gt;自作Cコンパイラの途中経過&lt;/a&gt;」
「&lt;a href=&quot;/posts/try-selfhost&quot;&gt;自作コンパイラのセルフホストに挑戦中&lt;/a&gt;」
に続く記事である。&lt;/p&gt;
&lt;h2&gt;System V ABI とは？&lt;/h2&gt;
&lt;p&gt;ABI (Application Binary Interface) とは、バイナリレベルでのコンパイラが満たすべき規約である。
アーキテクチャやOSごとに決まっており、例えば我々が一般的に使うintelのCPUである x86_64 でいえば、 Windows は  Microsoft ABI, Linux と macOS は &lt;a href=&quot;https://www.uclibc.org/docs/psABI-x86_64.pdf&quot;&gt;System V ABI&lt;/a&gt;という規約で定められている。&lt;/p&gt;
&lt;p&gt;具体的には次のようなものが決められている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;int long 等の型のサイズ&lt;/li&gt;
&lt;li&gt;構造体のメモリ上での配置&lt;/li&gt;
&lt;li&gt;関数呼び出し時のスタック, レジスタの扱い&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ABIはなんのためにあるのか？
それは異なるコンパイラ間でビルドしたバイナリをリンクできるようにするためである。&lt;/p&gt;
&lt;p&gt;現在、一般に libc などのライブラリはバイナリに含まれず、事前に別にビルドされたものを実行時にダイナミックリンクして呼び出している。
このような状況下では、異なるコンパイラでビルドされたバイナリ同士が相互に関数を呼び出すことが考えられる。&lt;/p&gt;
&lt;p&gt;(大きなライブラリは個別のアプリケーション開発時にビルドするのは手間だし、libcなどは様々なバイナリで使われるので、バイナリに含ませないことで共通化して容量を削減させたい。)&lt;/p&gt;
&lt;p&gt;int や long といったデータ型は C言語の仕様ではサイズが定められていない。long のサイズが int 以上である、といったことは決まっているが、別に 4byteでなくてもよい。 (16bit CPU では 2byte だったりする。)
データ型はアーキテクチャに依存することが多い？と思われる。&lt;/p&gt;
&lt;p&gt;他にも関数呼び出し時に引数や戻り値をどのように渡せばよいかを考えると ABI の必要性がみえてくる。
引数はレジスタに入れることも考えられるし、スタックに積むことも考えられる。C言語の仕様では引数や戻り値という概念は存在するが、具体的にどう実装するかは定められていない。そこであるコンパイラではレジスタ渡しをするかもしれないし、あるコンパイラではスタック渡しをするかもしれない。どちらも使うコンパイラもあるかも知れないし、コンパイラの作りようはいくらでもある。&lt;/p&gt;
&lt;p&gt;しかしコンパイラが自由に作ってしまうと、他のバイナリから呼ぶときに困る。他のコンパイラでビルドしたバイナリは引数をレジスタに詰めて渡したつもりになっていたが、受け取る側はスタックを読みだすかもしれない。&lt;/p&gt;
&lt;p&gt;このようなアーキテクチャやOSによって共通なC言語をバイナリレベルでコンパイラがどう実装するか決めておいたほうがよいことがABIで定められている。&lt;/p&gt;
&lt;h2&gt;アライメントとは？&lt;/h2&gt;
&lt;p&gt;スタックに領域を確保するとき、空いている部分にピッタリ詰めるのではなく、ある程度キリの良いメモリ配置になるように、使っていない無駄な領域(パディング)を用意してメモリ番地を揃えることをアライメントという。&lt;/p&gt;
&lt;p&gt;C言語のアライメントはABIによって定められている。&lt;/p&gt;
&lt;p&gt;アライメントは構造体に求められる。
ローカル変数同士はどう配置されていようと関係なく、それを読み出すのは自身のバイナリであるから問題ない。&lt;/p&gt;
&lt;p&gt;System V ABIでは、各データ型のサイズとアライメントすべき単位のサイズがそれぞれ同じバイト数になっている。
(&lt;a href=&quot;https://www.uclibc.org/docs/psABI-x86_64.pdf&quot;&gt;仕様書&lt;/a&gt; 12ページ Figure 3.1 Scalar Types)&lt;/p&gt;
&lt;h2&gt;本題: System V ABI における構造体メンバのアライメント&lt;/h2&gt;
&lt;h3&gt;仕様書の記述&lt;/h3&gt;
&lt;p&gt;仕様書には構造体メンバのアライメントについて次のような記述がある。
(&lt;a href=&quot;https://www.uclibc.org/docs/psABI-x86_64.pdf&quot;&gt;仕様書&lt;/a&gt; 13ページ 中段 Aggregates and Unions)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Structures and unions assume the alignment of their most strictly aligned component. Each member is assigned to the lowest available offset with the appropriate alignment. The size of any object is always a multiple of the object‘s alignment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;any object と the object が何を指しているのか最初イマイチわかっていなかったが、他の日本語の解説なども読んだ結果、次を意味するらしい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;構造体の各メンバは, それぞれの要素ごとに厳密にアライメントされる。( =&gt; 利用可能なオフセットの中で最も低いもの(パディングが小さいもの)に配置される。)&lt;/li&gt;
&lt;li&gt;構造体末尾のパディングは, 構造体の要素のアライメント単位の中で最大の値でアライメントされるように付加する。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;例&lt;/h3&gt;
&lt;p&gt;次のような構造体を考える&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-c&quot;&gt;struct hoge {
  char a;
  char b;
  int c;
  short d;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上の構造体の実体は、次のようにアライメントされる&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;メモリ番地&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....00&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;char a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....ff&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;char b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....fe&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;padding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....fd&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;padding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....fc&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;int c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....fb&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;int c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....fa&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;int c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....f9&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;int c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....f8&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;short d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....f7&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;short d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....f6&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;padding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;0x....f5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;padding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;まず、定義されたメンバと同じ順で配置される。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;char a&lt;/code&gt; は先頭なので何も考えずに配置する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;char b&lt;/code&gt; を配置するために、必要ならパディングをしてメモリをアライメントする。
&lt;code&gt;char&lt;/code&gt; のアライメントすべきメモリ境界の単位は 1byte (すなわちどこでも良い) なのでパディングの必要がない (既にアライメントされているともいえる)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;char b&lt;/code&gt; をアラインされた場所 (今回は &lt;code&gt;char a&lt;/code&gt; のすぐ後ろ) に配置する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int c&lt;/code&gt; を配置するために、必要ならパディングをしたメモリをアライメントする。
&lt;code&gt;int&lt;/code&gt; のアライメントすべきメモリ境界は4byteであるが、番地 &lt;code&gt;0x...fe&lt;/code&gt; はこれを満たしていないので、2byte パディングしてメモリをアライメントする。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int c&lt;/code&gt; をアラインされた場所 (今回は 2byte のパディングの後ろ) に配置する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;short d&lt;/code&gt; を配置するために、必要ならパディングをしてメモリをアライメントする。
&lt;code&gt;short&lt;/code&gt; のアライメントすべきメモリ境界の単位は 2byte で、今回はこれを満たしているのでパディングの必要がない (既にアライメントされているともいえる)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;short d&lt;/code&gt; をアラインされた場所 (今回は &lt;code&gt;int d&lt;/code&gt; のすぐ後ろ) に配置する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;struct hoge&lt;/code&gt; 自体の終わりにパディングをする。
アライメントすべきメモリ境界は、メンバのアライメントすべきメモリ境界 (&lt;code&gt;char&lt;/code&gt;...1byte, &lt;code&gt;int&lt;/code&gt;...4byte, &lt;code&gt;short&lt;/code&gt;...2byte) のうち最も大きい値である &lt;code&gt;int&lt;/code&gt;...4byte に合わせるようにパディングする
よって 2byte のパディングを追加&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以上。&lt;/p&gt;
&lt;p&gt;ちなみに &lt;code&gt;sizeof(struct hoge)&lt;/code&gt; の値は &lt;code&gt;12&lt;/code&gt; となる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参考: &lt;a href=&quot;https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%A1%E3%83%B3%E3%83%88&quot;&gt;データ構造アライメント - Wikipedia&lt;/a&gt; ... 日本語のわかりやすい解説。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;何故アライメントするのか&lt;/h2&gt;
&lt;p&gt;アクセスが速くなるとか？？。。。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;(2021/08/09) アクセスが早くなるかららしい。
また、(今回はx86_64に限定しているが) CPUのアーキテクチャによってはアライメントを強制する場合もあるらしい。&lt;/p&gt;
&lt;p&gt;メモリのアライメントに関する面白い動画に出会った: &lt;a href=&quot;https://youtu.be/V_MSKb6qgk0?t=4442&quot;&gt;自作OSを拡張する作業配信 (2021/07/24 低レイヤガール - Youtube&lt;/a&gt;
動画後半 1:14:02 ごろからメモリのアライメントに関する話がされている。&lt;/p&gt;</description>
    </item>
    <item>
      <title>自作コンパイラのセルフホストに挑戦中</title>
      <link>https://memo.yammer.jp/posts/willani-try-selfhost</link>
      <pubDate>Mon, 06 Jul 2020 16:54:10 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/willani-try-selfhost</guid>
      <description>&lt;p&gt;以前の記事「&lt;a href=&quot;/posts/willani-start/&quot;&gt;数日前からCコンパイラを書き始めた。&lt;/a&gt;」「&lt;a href=&quot;/posts/willani-compliperbook-finished/&quot;&gt;自作Cコンパイラの途中経過&lt;/a&gt;」に続く記事。&lt;/p&gt;
&lt;p&gt;これは日記であって、知見が書かれた文章ではない。&lt;/p&gt;
&lt;h2&gt;経過報告&lt;/h2&gt;
&lt;p&gt;気づけば2020年も半分が終わり、梅雨に入って雨が続き、今日もジメジメと蒸し暑い。
大学の研究室は相変わらずリモートで、新型コロナウィルスの東京都の感染者数も100人を超える日が続き、収束の気配がない。&lt;/p&gt;
&lt;p&gt;世間は春から夏へ季節が変わろうとしているし、世界的にウィルスとの戦いを繰り広げている昨今だが、私のやっていることは相変わらずCコンパイラ「&lt;a href=&quot;https://github.com/yammerjp/willani&quot;&gt;willani&lt;/a&gt;」の制作。もう6週目になるだろうか。&lt;/p&gt;
&lt;p&gt;昨日あたりからセルフホストに向けて、やっとコンパイラ本体のコードを第一世代コンパイラに流し始めた。
まだ本体のコード全ての機能は実装していないため、そのあたりは置き換えるシェルスクリプトを書いて、一旦スクリプトを挟んでからコンパイルする。
(#include, 可変長引数定義, 構造体の初期化などが未実装)&lt;/p&gt;
&lt;p&gt;プリプロセスは#defineだけ実装した。プリプロセッサの大枠はできており、他のプリプロセス文も頑張れば実装できそう感はある。
他にも、ちょっと頑張れば追加できそうな機能がいくつかあるが、一旦機能追加よりもセルフホストに軸をおくことにした。&lt;/p&gt;
&lt;p&gt;20以上のファイルに分割しているので、ファイル単位で置き換えていく。
一つのオブジェクトファイルをを第一世代コンパイラで出力したものに置き換える。
問題なければ次のファイルを第一世代コンパイラで出力したものに置き換える。
問題なければ、、、と繰り返し作業を進める。&lt;/p&gt;
&lt;h2&gt;よくわからなかったこと&lt;/h2&gt;
&lt;p&gt;親コンパイラと第一世代コンパイラでコンパイルしたものを混ぜてgccに投げると、うまく静的リンクできない。
PIEがどうこう、.textセクションやdataセクションは動的リンクでは使えないぞ、などと怒られる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$gcc -static -o willani *.c *.s # *.sはwillaniでコンパイルしたアセンブリ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解決策として、コンパイルと、アセンブル&amp;#x26;リンクを分けて行った。
親コンパイラの出力も一旦、個々のアセンブリファイルとして出力する。 &lt;code&gt;$gcc hoge.c -S -o hoge.s&lt;/code&gt;のように。&lt;/p&gt;
&lt;p&gt;これらを第一世代コンパイラで出力したアセンブリと混ぜてリンクしてもらう。
リンクはlibcが必要である。
gccコマンド(&lt;code&gt;$gcc *.s -static -o willani&lt;/code&gt;)で行った。
(&lt;code&gt;$ld&lt;/code&gt;を使ってlibcを含んで静的リンクするのってどうやるの?未調査。)&lt;/p&gt;
&lt;p&gt;アセンブルとリンクは分けなくても問題なかった。
(&lt;code&gt;$as hoge.s -o hoge.o&lt;/code&gt;とアセンブルを別途行ってもいいが、gccにアセンブリを投げたらいい感じにリンクまで終わらせてくれる。)&lt;/p&gt;
&lt;h2&gt;第二世代コンパイラのデバッグがつらそう&lt;/h2&gt;
&lt;p&gt;構造体のメモリ配置がABIに従ってなさそうで、今第1.5世代コンパイラ&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;がバグっている。
第一世代コンパイラはテストに通るのに第二世代コンパイラ(1.5世代含む)はバグっている状況は、どこから手をつけていいかわからずに混乱した。
今後も前途多難だな。。&lt;/p&gt;
&lt;h2&gt;技術メモ:gccでデバッグ情報のないアセンブリを出力する&lt;/h2&gt;
&lt;p&gt;今さっき知ったtips&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$gcc sample.c -S -o sample-s&lt;/code&gt;のようにコンパイルすると、デバッグ情報が含まれる。(&lt;code&gt;-g&lt;/code&gt;オプションとは違い、最低限。)
例えば&lt;code&gt;.cfi_startproc&lt;/code&gt;などの行が出力に含まれて、人間が読むときには邪魔。&lt;/p&gt;
&lt;p&gt;そこで、***&lt;code&gt;-fno-asynchronous-unwind-tables&lt;/code&gt;***オプションが有効。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$gcc sample.c -fno-asynchronous-unwind-tables -S -static -o sample.s&lt;/code&gt;のようにオプションを追加すると無駄な行が出力されないので読みやすくなる。&lt;/p&gt;
&lt;p&gt;Cの仕様を調べるとき、gccの出力と見比べたりするのが結構役に立つので、見やすいアセンブリを出せて助かる。(車輪の再発明だからできることだが。)&lt;/p&gt;
&lt;h2&gt;コンパイラをつくっていて良いこと&lt;/h2&gt;
&lt;p&gt;車輪の再発明あるあるではあるが、ブラックボックスを一つ紐解けた。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;作る前はコンパイラはよくわからないがよしなにやってくれるもので、アセンブリはとっつきづらいもので、オブジェクトファイルってあるよな程度の理解だった。
概念としてコンパイル、アセンブル、リンクは知っていたが、実装レベルで知れるのは良い。
コンパイラは要するに文字列変換プログラムだし、アセンブリはただのテキストデータだし、(リンクはそこそこ大変そうで学ぶべきことがたくさんありそうだけど)、何やってるかは以前より想像がつくようになった。&lt;/p&gt;
&lt;h2&gt;これからやること&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;構造体のメモリ配置を System V ABI に準拠させる&lt;/li&gt;
&lt;li&gt;構造体の初期化文&lt;/li&gt;
&lt;li&gt;セルフホスト&lt;/li&gt;
&lt;li&gt;#include&lt;/li&gt;
&lt;li&gt;#ifndef #ifdef #if #end&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;第1.5世代コンパイラ ... 親コンパイラ(gcc)の出力と第一世代コンパイラの出力を混ぜてアセンブル、リンクして作ったコンパイラを指す。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;ブラックボックスを紐解く ... 過去にPDFファイルを自分で作ったり、正規表現エンジン(作りかけ)を作ったり、認証認可の仕組みを作ったときも同じ気持ちになった。今後、OS(途中で止まってる)やHTTPサーバ、インタプリタ(やJITコンパイラ)なんかも生きてるうちに取り組みたい。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>Mares Puck Pro 電池交換の手順(2020年7月)</title>
      <link>https://memo.yammer.jp/posts/mares-pack-pro-battery-replacement</link>
      <pubDate>Wed, 01 Jul 2020 14:40:07 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/mares-pack-pro-battery-replacement</guid>
      <description>&lt;p&gt;(2024/09/22)さてさて、このブログのドメインは「memo.yammer.jp」としていて自分のメモ書きのために用意した場所で、それをブログという体裁で公開しています。ただし大した量のないメモや書き途中の文章がどうにもブログの下書きとしてたまってしまい、かつあとで自分で見返すときに下書きにあると見つけづらくて困るという問題があるので、ここから何本か下書きのものを最低限の体裁だけ整えて、公開しているリポジトリに写していきます。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ふだんダイビングでMaresのPuck Proというダイビングコンピュータを使っている。これはボタンが一つだけでシンプルな操作感と、大きな画面でとても見やすく気に入っている。&lt;/p&gt;
&lt;p&gt;一般的なボタン電池が使われていて、交換キットが売っているので自分で電池交換できるのも特徴。過去に2回くらい電池交換した気がしていて、おそらく最初に電池交換した2020/07/01ごろのメモが残っていたので、忘れないようにブログに残しておく。&lt;/p&gt;
&lt;p&gt;なおこの方法は私がこうやったというだけで、同じ方法でやってトラブルが起きても自己責任でお願いします。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-disclaimer&quot; id=&quot;user-content-fnref-disclaimer&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;電池交換に必要なもの&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;交換用電池(CR2450)&lt;/li&gt;
&lt;li&gt;交換用Oリング&lt;/li&gt;
&lt;li&gt;グリス&lt;/li&gt;
&lt;li&gt;綿棒&lt;/li&gt;
&lt;li&gt;ティッシュ&lt;/li&gt;
&lt;li&gt;10円玉などの硬貨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;交換の手順&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;硬貨を使い、裏蓋を回して開ける&lt;/li&gt;
&lt;li&gt;電池を取り出し、新しいものに交換&lt;/li&gt;
&lt;li&gt;古いOリングを取り外す&lt;/li&gt;
&lt;li&gt;Oリングがハマっていたところに付着した古いグリスを綿棒で拭き取る&lt;/li&gt;
&lt;li&gt;新しいOリングにグリスを塗る。米粒の半分位の量でよい。清潔な手の指先にグリスを出し、指でグリス全体に薄く均等に広げる。&lt;/li&gt;
&lt;li&gt;もともとハマっていたところに新しいOリングをはめる&lt;/li&gt;
&lt;li&gt;裏蓋を閉じる&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;交換における注意&lt;/h2&gt;
&lt;p&gt;前提として、手を洗ってきれいな状態で、ホコリ等が少ない机の上など、ゴミが混入しづらい状況で作業しましょう。&lt;/p&gt;
&lt;p&gt;グリスをつけたOリングによって、高圧の水中でも防水性を保っています。水圧がかかるとOリングが変形し、グリスとともに水の侵入を阻止しています。例えば髪の毛が1本挟まると防水性はゼロになります。 ホコリや毛が入り込まないように、グリスをつけるとき、Oリングをはめるとき、蓋を閉めるときはよく見て丁寧に作業しましょう。&lt;/p&gt;
&lt;p&gt;もしOリングを再利用するときは、取り出したOリングからティッシュなどで古いグリスを拭い、表面に傷がないことを確認し、新しいグリスを塗り拡げます。自己責任ですが、私は目視でキズがついていないことを確認して一度再利用しましたが、特に問題は起きていないです。&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-disclaimer&quot;&gt;
&lt;p&gt;ダイビング器材は命を預ける側面もあるので一応免責を書いています。そもそもダイコンが壊れたら死ぬようなシチュエーションはあまり思い浮かばない (中断して帰ればいい) し、そんなギリギリのダイビングをレジャーですべきではないと思いますが。 &lt;a href=&quot;#user-content-fnref-disclaimer&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>はてなブログに乗り換えた</title>
      <link>https://memo.yammer.jp/posts/firebase2hatenablog</link>
      <pubDate>Sun, 14 Jun 2020 12:26:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/firebase2hatenablog</guid>
      <description>&lt;p&gt;昨年に作ったブログの公開場所をはてなブログに変え、名前も「やんまーのブログ」と改名した。&lt;/p&gt;
&lt;p&gt;以前は Firebase Hosting 上に、 Nuxt.js の Generate モードで生成した HTML ファイルを公開していた。&lt;/p&gt;
&lt;p&gt;移行するにあたって次のことを行った。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;はてなブログCLI gimonfu による記事管理&lt;/li&gt;
&lt;li&gt;Zeit Nowを使った旧ドメインの転送処理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. &lt;a href=&quot;https://github.com/yammerjp/gimonfu&quot;&gt;gimonfu&lt;/a&gt; による記事管理&lt;/h2&gt;
&lt;p&gt;はてなブログは Markdown で記事を作成でき、これが乗り換える後押しになった。&lt;/p&gt;
&lt;p&gt;Markdown の記事は、以前のブログでも GitHub 上で記事を管理していたので、今回も同じことを行いたいと思っていた。&lt;/p&gt;
&lt;p&gt;そこではてなブログの CLI を作り、GitHub上のリポジトリと同期するようにした。&lt;br&gt;
&lt;a href=&quot;http://developer.hatena.ne.jp/ja/documents/blog/apis/atom&quot;&gt;はてなブログはAPIを公開しており&lt;/a&gt;、これを使って Markdown ファイルをアップロード、ダウンロードしている。&lt;/p&gt;
&lt;p&gt;はてなブログの CLI には、既に &lt;a href=&quot;https://github.com/x-motemen/blogsync&quot;&gt;blogsync&lt;/a&gt; というソフトウェアがある。&lt;br&gt;
当初はこのソフトウェアを使おうと思っていたのだが、新規記事投稿の部分が自分の思うように行かず、APIを触っているうちに、全部作ったほうがいいのでは？という気持ちになり CLI が出来上がってしまった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/x-motemen/blogsync&quot;&gt;blogsync&lt;/a&gt; と &lt;a href=&quot;https://github.com/x-motemen/blogsync&quot;&gt;gimonfu&lt;/a&gt; はどちらも1記事につき、1ファイルで、ファイル先頭に YAML Front matter といわれる YAML 形式の記事情報を含む。
またURLの構造が記事ファイルのディレクトリ構造となる点も同じだ。&lt;/p&gt;
&lt;p&gt;一方で、記事の投稿に関しては異なる点がある。&lt;br&gt;
blogsync では、記事本文のみを標準入力で CLI に渡すが、 gimonfu では、対象ディレクトリ内にある新しいファイルを新規記事として認識し投稿する。&lt;/p&gt;
&lt;p&gt;こうすると、CIを組み合わせれば、新規投稿時にも CLI を直接触らずに運用できる。&lt;/p&gt;
&lt;p&gt;現にこのブログも、新規投稿時にファイルを追加して GitHub に push すれば、自動的にはてなブログも更新されるようにしてある。 (逆にはてなブログが更新されたらGitHub にも反映されるワークフローも設定している。)&lt;/p&gt;
&lt;p&gt;gimonfu の使い方の詳細は &lt;a href=&quot;https://github.com/yammerjp/gimonfu&quot;&gt;README&lt;/a&gt; に譲るが、&lt;a href=&quot;https://github.com/yammerjp/basd4g.hatenablog.com/tree/master/.github/workflows&quot;&gt;このブログのワークフロー&lt;/a&gt;と同じものを GitHub Actions に指定すれば、記事管理がとても捗ると思うので是非活用して欲しい。&lt;/p&gt;
&lt;h2&gt;2. Zeit now を使った旧ドメインの転送処理&lt;/h2&gt;
&lt;p&gt;旧ドメインの記事を公開していた URL は全て、express.js を使って、今の記事に 301 リダイレクトするように設定した。(&lt;a href=&quot;/posts/zeit-now/&quot;&gt;設定した内容&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Now を初めて使ったが、とても簡単にアプリケーションを公開できるので、さくっと作ったときなどに活用していきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;というわけで、これからはてなブログで更新していきます。
よろしくお願いします。(誰に)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) ドメイン転送の記事へのリンクを相対リンクに修正&lt;/p&gt;</description>
    </item>
    <item>
      <title>gimonfu で、はてなブログの記事を GitHub と同期する</title>
      <link>https://memo.yammer.jp/posts/gimonfu</link>
      <pubDate>Sun, 14 Jun 2020 12:23:06 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/gimonfu</guid>
      <description>&lt;p&gt;ブログをはてなブログに移行するにあたり、記事を管理する CLI &lt;a href=&quot;https://github.com/yammerjp/gimonfu&quot;&gt;「gimonfu」&lt;/a&gt;を作成した。&lt;/p&gt;
&lt;p&gt;本記事では、gimonfu と GitHub Actions を使って、GitHub のリポジトリとはてなブログを連携し、記事を git で管理できるように設定を行う。&lt;/p&gt;
&lt;p&gt;記事の内容を設定すれば、Markdown ファイルを GitHub のリポジトリにプッシュするとはてなブログに記事を公開できたり、はてなの Web ページで記事を編集すると、GitHub のリポジトリに自動で反映されてバックアップを取ることができる。&lt;/p&gt;
&lt;p&gt;最終的な GitHub Actions の設定は、&lt;a href=&quot;https://github.com/yammerjp/basd4g.hatenablog.com/tree/master/.github/workflows&quot;&gt;私のブログの記事リポジトリ&lt;/a&gt;にある yaml にて確認できる。&lt;/p&gt;
&lt;h2&gt;もくじ&lt;/h2&gt;
&lt;p&gt;次の流れで設定する&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;はてなブログの記事執筆設定を Markdown モードにする&lt;/li&gt;
&lt;li&gt;はてなブログの API キーを確認する&lt;/li&gt;
&lt;li&gt;GitHub リポジトリを作り、ワークフローに使う Secrets を登録する&lt;/li&gt;
&lt;li&gt;記事をダウンロードするワークフローを追加する&lt;/li&gt;
&lt;li&gt;記事をダウンロードするワークフローを定期実行させる&lt;/li&gt;
&lt;li&gt;記事をアップロードするワークフローを追加する&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. はてなブログの記事執筆設定を Markdown モードにする&lt;/h2&gt;
&lt;p&gt;はじめに、はてなブログの設定を変更し、記事執筆設定を Markdown モードにする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.hatena.ne.jp/-/config&quot;&gt;はてなブログの設定ページ&lt;/a&gt;から、設定 -&gt; 編集モード を 「Markdownモード」に設定し「変更する」ボタンを押す&lt;/p&gt;
&lt;p&gt;まずはてなブログの基本設定を開く。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-1.png&quot; alt=&quot;はてなブログの基本設定を開く&quot;&gt;&lt;/p&gt;
&lt;p&gt;下へスクロールし、編集モードを Markdown モードにする。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-2.png&quot; alt=&quot;編集モードを Markdown モードへ&quot;&gt;&lt;/p&gt;
&lt;p&gt;「変更する」ボタンを押して変更を反映する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-3.png&quot; alt=&quot;「変更する」ボタンを押して変更を反映する&quot;&gt;&lt;/p&gt;
&lt;p&gt;(補足: 他のモードでも動作確認はしていないので、もし Markdown 記法以外を利用する場合はご自身で試して欲しい。&lt;/p&gt;
&lt;h2&gt;2. はてなブログの API キーを確認する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.hatena.ne.jp/-/config&quot;&gt;はてなブログの設定ページ&lt;/a&gt;から、設定 -&gt; 詳細設定 に移動し、ユーザID, ブログID, API キー をメモする&lt;/p&gt;
&lt;p&gt;まずはてなブログの詳細設定を開く。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-4.png&quot; alt=&quot;詳細設定へ移動&quot;&gt;&lt;/p&gt;
&lt;p&gt;下へスクロールし、AtomPubの項目から、ユーザID, ブログID, APIキーを確認する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-5.png&quot; alt=&quot;APIキーをメモする&quot;&gt;&lt;/p&gt;
&lt;h2&gt;3. GitHub リポジトリを作り、ワークフローに使う Secrets を登録する&lt;/h2&gt;
&lt;p&gt;ワークフローとは、GitHub Actions で実行する一連の内容を記したものである。
指定した時間になったときや、GitHub に コミットをプッシュしたとき、事前に作成したワークフローを自動で実行できる。&lt;/p&gt;
&lt;p&gt;この章では、GitHub で新しいリポジトリを作り、ワークフローで使う Secrets を登録する。&lt;/p&gt;
&lt;p&gt;まずは、新しいリポジトリを作った後、Settings -&gt; Secrets を開く&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-6.png&quot; alt=&quot;Secrets 登録画面を開く&quot;&gt;&lt;/p&gt;
&lt;p&gt;ワークフローで使う Name と Value の組み合わせを5組登録する&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-7.png&quot; alt=&quot;Secrets の Name と Value を登録する&quot;&gt;&lt;/p&gt;
&lt;p&gt;登録する内容は次の通り。
例を参考に自分の文字列に置き換えてほしいj&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Value (例)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HATENA_USER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;先程確認したはてなブログのユーザID&lt;/td&gt;
&lt;td&gt;basd4g&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HATENA_BLOG_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;先程確認したはてなブログのブログID&lt;/td&gt;
&lt;td&gt;basd4g.hatenablog.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HATENA_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;先程確認したはてなブログのAPIキー&lt;/td&gt;
&lt;td&gt;abcdef0123&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GIT_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(ワークフローで自動的に作られるコミットの)自分の名前&lt;/td&gt;
&lt;td&gt;Taro Yamada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GIT_MAIL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(ワークフローで自動的に作られるコミットの)自分のメールアドレス&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;mailto:basd4g@example.com&quot;&gt;basd4g@example.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;4. 記事をダウンロードするワークフローを追加する&lt;/h2&gt;
&lt;p&gt;記事をダウンロードする GitHub Actions ワークフローを追加する。&lt;/p&gt;
&lt;p&gt;ワークフローは GitHub リポジトリのWebページ上からも追加できる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-8.png&quot; alt=&quot;新しいワークフローを追加する&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/gimonfu-9.png&quot; alt=&quot;記事をダウンロードするワークフローを追加する&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.github/workflows/pull.yaml&lt;/code&gt; に次の内容を記述する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# .github/workflows/pull.yaml
name: Pull

on:
  push:
    branches: [ master ]

jobs:
  pull:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Deploy and Commit
      env:
        HATENA_USER_ID: ${{ secrets.HATENA_USER }}
        HATENA_BLOG_ID: ${{ secrets.HATENA_BLOG_ID }}
        HATENA_API_KEY: ${{ secrets.HATENA_API_KEY }}
        GIT_NAME: ${{ secrets.GIT_NAME }}
        GIT_MAIL: ${{ secrets.GIT_MAIL }}
        REPO_OWNER: ${{ github.repository_owner }}
      run: |
        cd ${GITHUB_WORKSPACE}

        # コミットのためのgitの設定
        echo &apos;git initialize&apos;
        git config --global user.name &quot;${GIT_NAME}&quot;
        git config --global user.email &quot;${GIT_MAIL}&quot;
        git remote set-url origin &quot;https://${REPO_OWNER}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git&quot;
        echo &apos;gimonfu initialize&apos;

        # gimonfuの初期設定
        npm init -y &gt; /dev/null 2&gt;&amp;#x26;1
        npm install gimonfu
        echo &quot;{\&quot;user_id\&quot;:\&quot;${HATENA_USER_ID}\&quot;,\&quot;blog_id\&quot;:\&quot;${HATENA_BLOG_ID}\&quot;,\&quot;api_key\&quot;:\&quot;${HATENA_API_KEY}\&quot;}&quot; &gt; .gimonfu.json

        # 新しい/更新された記事をダウンロード
        echo &apos;gimonfu pull&apos;
        npx gimonfu --git-commit-date pull

        # コミットを作成する
        git add entry
        # This script will not make a commit if there are no changes.
        if ! git diff --staged --exit-code --quiet; then \
          git commit -m &quot;Pull articles (automatic commit)&quot; ;\
        fi

        git push origin HEAD:master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コミットが GitHub 上にプッシュされると、ワークフローが走ってリポジトリに記事が反映される。&lt;/p&gt;
&lt;h2&gt;5. 記事をダウンロードするワークフローを定期実行させる&lt;/h2&gt;
&lt;p&gt;先程は初回だったので「master ブランチにプッシュしたときにワークフローを実行する」(=&gt;はてなブログの内容を GitHub リポジトリに反映させる)設定にした。&lt;/p&gt;
&lt;p&gt;ここではワークフローの一部を書き換えて、1時間に一回ワークフローを実行させる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.github/workflows/pull.yaml&lt;/code&gt; の内容を一部書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot;&gt;--- a/.github/workflows/pull.yaml
+++ b/.github/workflows/pull.yaml
@@ -1,8 +1,8 @@
 name: Pull
 
 on:
-  push:
-    branches: [ master ]
+  schedule:
+    - cron: &apos;0 * * * *&apos;
 
 jobs:
   pull:
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 記事をアップロードするワークフローを追加する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.github/workflows/push.yaml&lt;/code&gt;に次の内容を記述してコミット、プッシュする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# .github/workflows/push.yaml
name: Push

on:
  push:
    branches: [ master ]

jobs:
  push:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Deploy and Commit
      env:
        HATENA_USER_ID: ${{ secrets.HATENA_USER }}
        HATENA_BLOG_ID: ${{ secrets.HATENA_BLOG_ID }}
        HATENA_API_KEY: ${{ secrets.HATENA_API_KEY }}
        GIT_NAME: ${{ secrets.GIT_NAME }}
        GIT_MAIL: ${{ secrets.GIT_MAIL }}
        REPO_OWNER: ${{ github.repository_owner }}
      run: |
        cd ${GITHUB_WORKSPACE}

        # コミットのためのgitの設定
        echo &apos;git initialize&apos;
        git config --global user.name &quot;${GIT_NAME}&quot;
        git config --global user.email &quot;${GIT_MAIL}&quot;
        git remote set-url origin &quot;https://${REPO_OWNER}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git&quot;

        # gimonfuの初期設定
        echo &apos;gimonfu initialize&apos;
        npm init -y &gt; /dev/null 2&gt;&amp;#x26;1
        npm install gimonfu
        echo &quot;{\&quot;user_id\&quot;:\&quot;${HATENA_USER_ID}\&quot;,\&quot;blog_id\&quot;:\&quot;${HATENA_BLOG_ID}\&quot;,\&quot;api_key\&quot;:\&quot;${HATENA_API_KEY}\&quot;}&quot; &gt; .gimonfu.json

        # 新しい/更新された記事をアップロード
        echo &apos;gimonfu push&apos;
        npx gimonfu --git-commit-date push
        git add entry

        # コミットを作成する
        # This script will not make a commit if there are no changes.
        if ! git diff --staged --exit-code --quiet; then \
          git commit -m &quot;Pull articles (automatic commit)&quot; ;\
        fi

        git push origin HEAD:master
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 記事の投稿と更新&lt;/h2&gt;
&lt;p&gt;以上の設定を行うと、GitHub のリポジトリとはてなブログの記事が同期できる。&lt;/p&gt;
&lt;p&gt;GitHub 上の Markdown ファイルを上書きすると記事が更新されるし、新しい Markdown ファイルを追加すると記事が投稿される。&lt;/p&gt;
&lt;p&gt;Markdownファイルは次のような記述で始まる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-md&quot;&gt;---
title: タイトル
date: 2019-09-18T12:50:00.000Z
id: &quot;26006613576772424&quot;
---

記事本文が以降続く。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;記事の冒頭に &lt;code&gt;---&lt;/code&gt; で挟んだYAML形式のメタ情報を付加する。
&lt;code&gt;id: &lt;/code&gt;の行は新規投稿時には記述しない。投稿されると自動で付加される。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;ブログ記事を Git で管理したいというモチベーションから CLI を作るまでに至った。&lt;/p&gt;
&lt;p&gt;GitHub Actions のワークフローを登録しておけば、ローカルに gimonfu をインストールせずに使えるが、インストールして使うこともできる。
&lt;code&gt;$ npm install -g gimonfu&lt;/code&gt;でインストールでき、使い方は &lt;a href=&quot;https://github.com/yammerjp/gimonfu&quot;&gt;README&lt;/a&gt; で説明している。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ここまで読んでいただいてありがとうございました。
あなたのはてなブログ生活が捗ることを願っています。&lt;/p&gt;</description>
    </item>
    <item>
      <title>自作Cコンパイラの途中経過</title>
      <link>https://memo.yammer.jp/posts/willani-compliperbook-finished</link>
      <pubDate>Tue, 09 Jun 2020 08:00:06 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/willani-compliperbook-finished</guid>
      <description>&lt;h2&gt;Cコンパイラ自作の進捗&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/posts/willani-start/&quot;&gt;以前の記事&lt;/a&gt;に書いたとおり、C言語のコンパイラを自作している。&lt;/p&gt;
&lt;p&gt;セルフホストには至ってないが、教科書であるオンラインブック&lt;a href=&quot;https://www.sigbus.info/compilerbook&quot;&gt;「低レイヤを知りたい人のためのCコンパイラ作成入門」&lt;/a&gt;の内容が一通り実装し終わったので経過報告をする。&lt;/p&gt;
&lt;p&gt;裏で最初は毎日記録をつけていたのだが、だんだん面倒くさくなってやめたので、コミット履歴を見ながら振り返る。&lt;/p&gt;
&lt;p&gt;最初のコミットは19日前(5/21)なので、そろそろ三週間経ったところだ。
5/28-30の三日間以外は何かしらコミットしているので、継続的に開発できている。もっともバイトや授業に遮られることがなく、時間がたくさんあるのでできることであるが。&lt;/p&gt;
&lt;p&gt;ここまでのマイルストーンとしては、次の機能開発があった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分岐,繰り返し処理ができる&lt;/li&gt;
&lt;li&gt;関数定義ができる&lt;/li&gt;
&lt;li&gt;型情報が付加される(完全なサブセットをコンパイルできるようになる)&lt;/li&gt;
&lt;li&gt;テストをCで書き直す&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;テストをCで書き直す(&lt;a href=&quot;https://www.sigbus.info/compilerbook#%E3%82%B9%E3%83%86%E3%83%83%E3%83%9728-%E3%83%86%E3%82%B9%E3%83%88%E3%82%92c%E3%81%A7%E6%9B%B8%E3%81%8D%E7%9B%B4%E3%81%99&quot;&gt;オンラインブックStep28&lt;/a&gt;)
ところでバグが結構見つかって一つ一つ潰すのに時間がかかった。&lt;br&gt;
でもこの頃はGDBの基本的な使い方に慣れてきて、更に当たりをつけてアセンブリを読むことができたので、最初の頃より全然楽だった。&lt;/p&gt;
&lt;p&gt;テストファイルをCで書き直し、これを自作コンパイラでコンパイルすると10000万行(デバッグ情報含む)くらいのアセンブリになった。
これくらいの規模のプログラムがうまく実行できると、人間を超えていく感じがして楽しい。&lt;/p&gt;
&lt;h2&gt;狭いスコープのローカル変数&lt;/h2&gt;
&lt;p&gt;ブロックスコープ内の変数の実装方法は自分で考えたものなのだが、結構うまくできたと思っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/willani&quot;&gt;willani&lt;/a&gt;には変数一つを表す構造体があり、これをつなげた2つの単方向リストがそれぞれ、グローバル変数とローカル変数を表している。&lt;/p&gt;
&lt;p&gt;スコープのある変数を実装するには次の2つのことを考慮する必要がある。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;変数を定義するときは、同じスコープの重複した変数名を許さない。&lt;/li&gt;
&lt;li&gt;変数を呼び出すときは、同じ名前の変数のなかで、その式が属するスコープのうちもっとも狭いスコープの変数を指す。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;トークン列をパースするときに次のような方法で 1. 2. を実現した。&lt;br&gt;
なお、私の実装ではブロックスコープの変数はローカル変数の単方向リストに含む。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;新しいスコープに入るときに、その前最後に定義されたローカル変数をのポインタを&lt;code&gt;out_of_scope&lt;/code&gt;として記録する。&lt;br&gt;
変数定義するときは、単方向リストを先頭(最新)から&lt;code&gt;out_of_scope&lt;/code&gt;の前までみて、同じ名前のものがないか調べる。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;変数を定義するとき、&lt;code&gt;Var.referable = true&lt;/code&gt;というフラグを立てる。&lt;br&gt;
スコープを出るときに、そのスコープで定義した全ての変数 (&lt;code&gt;out_of_scope&lt;/code&gt;より新しい定義の変数) のフラグを下げる。(&lt;code&gt;false&lt;/code&gt;をセットする。)&lt;br&gt;
以後呼び出す変数を探すときにフラグが&lt;code&gt;false&lt;/code&gt;なものをスキップさせる。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;こうすることで、最新に定義した変数から順番に調べていけば、「1. その変数を定義してよいか」「2. 同名の異なる変数のうちどの変数を指しているか」がわかる。&lt;/p&gt;
&lt;p&gt;リストには全てのローカル変数が残っているので、コード生成時に変数の領域を確保するのが簡単だし、パース時にどの変数を指し示すか解釈しておけばコード生成時は変数名の重複を考える必要がない。&lt;/p&gt;
&lt;h2&gt;今後の展望&lt;/h2&gt;
&lt;p&gt;植山類さんのコンパイラ実装である &lt;a href=&quot;https://github.com/rui314/9cc&quot;&gt;9cc&lt;/a&gt; や &lt;a href=&quot;https://github.com/rui314/chibicc&quot;&gt;chibicc&lt;/a&gt; 等のコミットログをみて、セルフホストをするためにはあと1倍くらい、完成まではさらに1倍くらいの手間がかかるのではないかと予想している。&lt;/p&gt;
&lt;p&gt;セルフホストに必要そうな機能は次の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;構造体&lt;/li&gt;
&lt;li&gt;&apos;-&gt;&apos;&lt;/li&gt;
&lt;li&gt;typedef&lt;/li&gt;
&lt;li&gt;プリプロセス&lt;/li&gt;
&lt;li&gt;bool型&lt;/li&gt;
&lt;li&gt;void型&lt;/li&gt;
&lt;li&gt;enum&lt;/li&gt;
&lt;li&gt;char literal&lt;/li&gt;
&lt;li&gt;(file scope function)&lt;/li&gt;
&lt;li&gt;switch&lt;/li&gt;
&lt;li&gt;&apos;++&apos;, &apos;--&apos;&lt;/li&gt;
&lt;li&gt;&apos;+=&apos;&lt;/li&gt;
&lt;li&gt;&apos;!&apos;&lt;/li&gt;
&lt;li&gt;&apos;&amp;#x26;&amp;#x26;&apos;, &apos;||&apos;&lt;/li&gt;
&lt;li&gt;&apos;break&apos;&lt;/li&gt;
&lt;li&gt;&apos;continue&apos;&lt;/li&gt;
&lt;li&gt;&apos;extern&apos;&lt;/li&gt;
&lt;li&gt;&apos;NULL&apos;&lt;/li&gt;
&lt;li&gt;(3項演算子)&lt;/li&gt;
&lt;li&gt;(可変長引数関数の定義)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(括弧がついてるのはサボろうか迷っているもの。
特定の文法を自分のコードから削除して書き換えてしまえば、その文法に対応しなくてもセルフホストできてしまう)&lt;/p&gt;
&lt;p&gt;構造体とプリプロセスが時間かかりそうだなと見ている。&lt;/p&gt;
&lt;p&gt;Cの仕様書をどこまで実装するかは考えものだが、セルフホストはやっぱり楽しみ。&lt;/p&gt;
&lt;p&gt;Webのフロントエンドをはじめとする物々にも手を付けねばと思っているし、研究室の論文も読まねばと思っているので、今後はバランスも考えてやっていきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) 以前の記事へのリンクを相対リンクに修正&lt;/p&gt;</description>
    </item>
    <item>
      <title>Zeit Now を使って、express.jsで書かれたアプリケーションを独自ドメインで公開する</title>
      <link>https://memo.yammer.jp/posts/zeit-now</link>
      <pubDate>Sun, 31 May 2020 07:44:33 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/zeit-now</guid>
      <description>&lt;p&gt;now という PaaS がある。&lt;/p&gt;
&lt;p&gt;Node.js で書かれたアプリケーションを、無料で3つまでホスティングできるらしい。&lt;/p&gt;
&lt;p&gt;heroku を無料プランで使うと、dyno の立ち上げに30秒くらいかかるので、Web サーバとしては致命的に遅い。
一方 zeit はそのような待ち時間は発生しない。(どこかに、AWS Lambda を中で使っていると書いてあった気がする)&lt;/p&gt;
&lt;p&gt;今回はシンプルな express.js のアプリケーションを now でホスティングする手順。&lt;/p&gt;
&lt;h2&gt;インストール&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ mkdir now-app
$ cd now-app
$ yarn init
$ yarn global add now
$ yarn add express
$ touch index.js
$ touch now.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;アプリケーションを作る&lt;/h2&gt;
&lt;p&gt;index.js に次のように記入&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;// index.js
`use strict`

const express = require(&apos;express&apos;);
const app = express();

app.get(&apos;/*&apos;, (req,res) =&gt; {
  res.send(&apos;hello, world!&apos;);
  res.end();
})

const port = process.env.PORT || 3000;
// ポート番号は上記のように環境変数から読み込むこと
app.listen(3000, () =&gt; console.log(`listening on port ${port}`));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;now の設定&lt;/h2&gt;
&lt;p&gt;事前に、node.js のアプリケーションであることを指定しなければならない。&lt;/p&gt;
&lt;p&gt;何もしないと静的ホスティングと判断され、アプリケーションのソースコードを写した Web ページがデプロイされる。&lt;/p&gt;
&lt;p&gt;now.json に次のように記入&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;{
    &quot;version&quot;: 2,
    &quot;builds&quot;: [{ &quot;src&quot;: &quot;index.js&quot;, &quot;use&quot;: &quot;@now/node&quot; }],
    &quot;routes&quot;: [{ &quot;src&quot;: &quot;(.*)&quot;, &quot;dest&quot;: &quot;index.js&quot; }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;npm scriptの設定&lt;/h2&gt;
&lt;p&gt;now が実行時に index.js を実行してくれるように、package.json に次の項目を追加&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;{
 &quot;scripts&quot;: {
    &quot;start&quot;: &quot;node index.js&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;デプロイ&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ now
# 対話にしたがってメールを入れると、ログインリンクのついたメールが届くので、クリックして認証。
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;独自ドメイン(サブドメイン)を登録&lt;/h2&gt;
&lt;p&gt;以下、現在&lt;code&gt;hogehoge-hogehoge.now.sh&lt;/code&gt;で公開されていて、&lt;code&gt;hogehoge.example.com&lt;/code&gt;でアクセスできるようにするときの設定。&lt;/p&gt;
&lt;p&gt;まずは親のドメインをzeitに登録する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ now domains add example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ドメインの所有者認証を行う&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ now domains verify example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;すると、DNSに何も設定していないので失敗する。
どう設定すべきか表示されるので 画面に表示される通り、DNSに登録する。
ついでに先にお目当てのサブドメインの CNAME も登録しておく。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;_now&lt;/td&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;表示されたキー&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hogehoge&lt;/td&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;alias.zeit.co&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;再度ドメインの所有者認証を行う&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ now domains verify example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;サブドメインのエイリアスを設定する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ now alias https://hogehoge-hogehoge.now.sh hogehoge.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;以上の手順と同様の作業で公開したリポジトリ: &lt;a href=&quot;https://github.com/yammerjp/blog.yammer.fun&quot;&gt;blog.yammer.fun - GitHub yammerjp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;古いブログのURLをリダイレクトさせるために使った。&lt;/p&gt;</description>
    </item>
    <item>
      <title>TCP と UDP</title>
      <link>https://memo.yammer.jp/posts/tcp-udp</link>
      <pubDate>Sat, 30 May 2020 05:05:53 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/tcp-udp</guid>
      <description>&lt;p&gt;今日のインターネットの根幹をなすTCP/IPプロトコルスタックのうち、トランスポート層のプロトコルであるTCPとUDPについての基本的な知識を説明する。&lt;/p&gt;
&lt;p&gt;本記事は研究室の輪講で「マスタリングTCP/IP 入門編」を読んだことがきっかけの第2回。
&lt;a href=&quot;/posts/internet-tcpip/&quot;&gt;前回&lt;/a&gt;はTCP/IPプロトコルスタック全体についての概要を書いた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参考文献: マスタリングTCP/IP入門編 第6章 pp219-246&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;もくじ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;トランスポートプロトコルの役割&lt;/li&gt;
&lt;li&gt;ポート番号&lt;/li&gt;
&lt;li&gt;TCP と UDP&lt;/li&gt;
&lt;li&gt;TCP の様々な制御&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;トランスポートプロトコルの役割&lt;/h2&gt;
&lt;p&gt;トランスポート層の役割は主に3つある。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;End-to-End の通信を実現すること。&lt;/li&gt;
&lt;li&gt;アプリケーションプログラム間での通信を可能にすること&lt;/li&gt;
&lt;li&gt;(TCP では) 信頼性のある通信を実現すること&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;これらの役割を、他層との関係とともに説明する。
参考として、TCP/IPプロトコルの階層モデルを示す。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/tcp-udp-tcpip-protocol-stack.png&quot; alt=&quot;OSI参照モデルとTCP/IP階層モデル&quot;&gt;&lt;/p&gt;
&lt;h3&gt;1. End-to-End の通信を実現すること。&lt;/h3&gt;
&lt;p&gt;トランスポート層は、End-to-End の通信を実現する。&lt;/p&gt;
&lt;p&gt;トランスポート層の下位に位置するインターネット層では、IP を中心に hop-by-hopでパケットをバケツリレーのように渡し続けながら通信する。&lt;/p&gt;
&lt;p&gt;トランスポート層はこれを隠して、ユーザが中継のルータなどを意識せず済むよう、 End-to-End で通信しているようにみせる。&lt;/p&gt;
&lt;h3&gt;2. アプリケーションプログラム間での通信を可能にすること&lt;/h3&gt;
&lt;p&gt;通信ホストは、複数のアプリケーションを用いて同時に異なる通信する。&lt;/p&gt;
&lt;p&gt;トランスポート層ではポート番号という識別子を用いて、アプリケーション (実際にはプロセス) ごとに通信を識別し、各アプリケーションが他のアプリケーションの通信を意識せずに使えるようにする。&lt;/p&gt;
&lt;h3&gt;3. (TCP では) 信頼性のある通信を実現すること&lt;/h3&gt;
&lt;p&gt;TCP を用いると、パケットを再送することをはじめとして様々な制御を行ってくれる。
これによって上位のアプリケーション層からは、特に意識せずとも信頼性のある通信を行える。&lt;/p&gt;
&lt;h2&gt;ポート番号&lt;/h2&gt;
&lt;p&gt;端末内で通信するプロセスを指定するために用いられる識別子。
IP アドレスと合わせて使われる。&lt;/p&gt;
&lt;p&gt;ポート番号を含む次の5つが全て揃うことで通信を識別する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;宛先 IP アドレス&lt;/li&gt;
&lt;li&gt;送信元 IP アドレス&lt;/li&gt;
&lt;li&gt;宛先ポート番号&lt;/li&gt;
&lt;li&gt;送信元ポート番号&lt;/li&gt;
&lt;li&gt;トランスポートプロトコルの種類 (IP ヘッダのプロトコル番号フィールド)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ポート番号の通信例&lt;/h3&gt;
&lt;p&gt;例えば、私の PC で、次の2つのWebページを同時に閲覧することを考える。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;埼玉大学の受験生向け Web ページ (&lt;a href=&quot;http://www.saitama-u.ac.jp/entrance&quot;&gt;http://www.saitama-u.ac.jp/entrance&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;埼玉大学の在校生向け Web ページ (&lt;a href=&quot;http://www.saitama-u.ac.jp/student&quot;&gt;http://www.saitama-u.ac.jp/student&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このとき、私の PC から、埼玉大学の Web サーバへ通信が発生する。つまり同じ送信元から同じ宛先へ別々の通信が発生する。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;center&quot;&gt;ページ&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;宛先IPアドレス&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;宛先ポート番号&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;送信元IPアドレス&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;送信元ポート番号&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;プロトコル&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;A&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;153.127.197.67&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;80&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;203.0.113.1&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;49152&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;B&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;153.127.197.67&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;80&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;203.0.113.1&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;49153&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;ページを開く要求をしたときに、ブラウザのタブごとに(=プロセスごとに)違うポート番号を使えば、別々の通信を識別できるというわけだ。
(実際には、送信元に帰ってきたパケットがどのプロセス宛のものであるかを、OS がポート番号で識別し、プロセスに処理が渡る。)&lt;/p&gt;
&lt;h3&gt;ポート番号の割当&lt;/h3&gt;
&lt;h3&gt;(0-1023) Well-known Port Number&lt;/h3&gt;
&lt;p&gt;ポート番号には事前に予約された Well-known Port Number というものがある。&lt;/p&gt;
&lt;p&gt;上位レイヤーのプロトコルのうち一般的なものが使うポート番号を 0-1023 番に定めている。
例えば HTTP は 80 番, HTTPS は 443 番, SSH は 22 番, 等。&lt;/p&gt;
&lt;p&gt;Well-known Port Number を他の用途に用いることもできるが、混乱を避けるために避けるのが無難。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml&quot;&gt;Well-known Port Number の割当 - IANA&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;(1024-49151) その他の登録済みポート番号&lt;/h3&gt;
&lt;p&gt;Well-known Port Number 以外にも登録されたポート番号がある。
ただしこちらは他の用途に使ってもそれほど問題が起きにくい。&lt;/p&gt;
&lt;h3&gt;(49152-65535) 動的割当のポート番号&lt;/h3&gt;
&lt;p&gt;前節では用途が決まったポート番号であった。
これらは一般に、サーバ側のポート番号として使われる。&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
何故なら、クライアント側からどのポートに繋げば良いのか事前に知っている必要があるからだ。
例えば Web ページを見るときはふつう、Web サーバは 80 番 (HTTP) か 443 番 (HTTPS) で待ち受けていることを前提に通信を開始する。&lt;/p&gt;
&lt;p&gt;一方クライアントは特にポート番号が定まっている必要はない。
特に値が重要でない場合は、ポート番号の管理を OS に委ねることができる。
このような動的な割当は 49152-65535 の範囲で割り当てられるのが一般的だ。&lt;/p&gt;
&lt;h2&gt;TCP と UDP&lt;/h2&gt;
&lt;p&gt;トランスポートプロトコルの代表的な２つのプロトコル、TCP と UDP の違いについて説明する。&lt;/p&gt;
&lt;h3&gt;TCP (Transmission Control Protocol)&lt;/h3&gt;
&lt;p&gt;TCPは次のような特徴を持つ&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;伝送、送信、通信を制御する&lt;/li&gt;
&lt;li&gt;コネクション型&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;信頼性のある通信をするために様々な制御を含む含む&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TCPを使うと、アプリケーションは様々な制御から開放される。
ただしコネクションの確立/切断にコストがかかる。
よって、信頼性を要求し大容量のデータを交換する多くの通信に向くが、全ての通信に適しているわけではない。&lt;/p&gt;
&lt;h3&gt;UDP (User Datagram Protocol)&lt;/h3&gt;
&lt;p&gt;UDP は次のような特徴を持つ&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;複雑な制御をしない&lt;/li&gt;
&lt;li&gt;コネクションレス型&lt;/li&gt;
&lt;li&gt;いつでもデータを送信可能&lt;/li&gt;
&lt;li&gt;高速に動作する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同報性が要求されたり、アプリケーションが細かい制御を行う通信はUDPで行うのが好ましい。
次のような用途に用いられている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;総パケット数の少ない通信。 (DNS, SNMP)&lt;/li&gt;
&lt;li&gt;動画や音声などのマルチメディア通信 (即時性を求める通信)&lt;/li&gt;
&lt;li&gt;ブロードキャストやマルチキャストの通信。 (1対Nの通信)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;TCP の様々な機能&lt;/h2&gt;
&lt;p&gt;TCP には信頼性を保証するために次のような機能を持つ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;コネクションの管理 ... (通信相手がいるかどうかの確認)&lt;/li&gt;
&lt;li&gt;再送制御 ... (パケットが喪失した際に必要)&lt;/li&gt;
&lt;li&gt;重複制御 ... (パケットが2十二届いた際に必要)&lt;/li&gt;
&lt;li&gt;順序制御 ... (パケットの順序が入れ替わった際に必要)&lt;/li&gt;
&lt;li&gt;フロー制御 ... (受信能力に合わせた送信を行う)&lt;/li&gt;
&lt;li&gt;輻輳 (ふくそう) 制御 ... (ネットワークの混雑を避ける)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらの実現のために必要な仕組みとして、次のような技術を説明する&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;コネクションの確立/切断&lt;/li&gt;
&lt;li&gt;確認応答&lt;/li&gt;
&lt;li&gt;シーケンス番号 (再送制御, 重複制御, 順序制御に用いられる)&lt;/li&gt;
&lt;li&gt;ウィンドウ (ネットワークの効率を高め, フロー制御や輻輳制御にも用いられる概念)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;コネクションの確立/切断&lt;/h3&gt;
&lt;h3&gt;確認応答&lt;/h3&gt;
&lt;h3&gt;シーケンス番号&lt;/h3&gt;
&lt;h3&gt;ウィンドウ&lt;/h3&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;トランスポートプロトコルの役割は次の3つであった。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;End-to-End の通信を実現すること。&lt;/li&gt;
&lt;li&gt;アプリケーションプログラム間での通信を可能にすること&lt;/li&gt;
&lt;li&gt;(TCP では) 信頼性のある通信を実現すること&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2を実現するためにポート番号があり、3を実現するために様々な制御があることを紹介した。&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) 前回記事へのリンクを相対リンクへ修正&lt;/p&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;TCP/IP ではクライアント-サーバモデルの通信が多い。 &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;コネクションとは、二者間で専用して使用できる仮想的な回線のこと。 &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
    </item>
    <item>
      <title>デスクトップLinuxでCPUの状況を確認する</title>
      <link>https://memo.yammer.jp/posts/linux-cpu</link>
      <pubDate>Sat, 30 May 2020 02:46:49 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/linux-cpu</guid>
      <description>&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cat /proc/cpuinfo
# CPUの各スレッドごとの情報を含んだファイルを表示する

$ nproc
# CPUのスレッド数(プロセッサの数)を表示する

$ top
# CPU使用率の高い順にプロセスを表示する。定期的に内容は再描画される。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://youtu.be/etZrDmrD5Q0&quot;&gt;CPU and Linux -  Youtube Satoru Takeuchi&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>数日前からCコンパイラを書き始めた。</title>
      <link>https://memo.yammer.jp/posts/willani-start</link>
      <pubDate>Sun, 24 May 2020 16:02:52 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/willani-start</guid>
      <description>&lt;p&gt;数日前からCコンパイラを書き始めた。(&lt;a href=&quot;https://github.com/yammerjp/willani&quot;&gt;GitHub&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;植山類さんのオンラインブック、&lt;a href=&quot;https://www.sigbus.info/compilerbook&quot;&gt;低レイヤを知りたい人のためのCコンパイラ作成入門&lt;/a&gt;を読みながら、概ね本の内容に沿って進めている。
自分の書いたコンパイラで自身をコンパイルするセルフホストを目指している。&lt;/p&gt;
&lt;p&gt;コンパイラというのはある言語で書かれたプログラムを別の言語に変換するプログラムだ。
ここではC言語をアセンブリに変換するものを指している。&lt;br&gt;
いきなりC言語をコンパイルするのは無理なので、徐々に複雑な入力を受け付けるように改良し、最終的にC言語を受け付けるようにする(したい)。
最初は入力をそのまま出力することから始まり、四則演算ができるようになり、いまは関数呼び出しができるようになった。&lt;/p&gt;
&lt;p&gt;本はとても丁寧に書かれていて、参考として実装も2種類ほど存在する。
さらにSlackやYoutube Liveで質問ができるというとても恵まれた環境が揃っている。&lt;/p&gt;
&lt;p&gt;実は昨年コンパイラの授業をとっていてコンパイラを少し触っていた。
cmmというCを一部切り取ったような言語と、PL0iという仮想マシン(とそのアセンブリ)に対して言語拡張をする、というようなことだった。
そのときはあまり真面目に実装に凝っていなくて、課題はパスして成績がそこそこもらえるくらいはやったが、実のところコンパイラってよくわからないなという気持ちのまま終わっていた。&lt;/p&gt;
&lt;p&gt;このままではよくないという気持ちと、あとは単純な興味(プログラムをデータとして扱うことを体験できる)もあって始めてみた。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;はじめてまだ3日ほどだが、パーサについてがちょっと意外だった。
手書きでパーサを書くというのは事前に聞いていたが、LL(1)でいけるらしい。&lt;/p&gt;
&lt;p&gt;LL(1)とは構文解析法のこと、つまり、文法がどんな構造になっているかを調べる手法の一つだ。
構文解析は事前にBNF記法などで規則が与えられており、その規則のどれが適用できるかを探す。
授業でLR(0), LR(1), LALR(1)などを扱ったが、LL(1)はそれらよりも単純で手書きでパーサを書くのに向いているらしい。&lt;/p&gt;
&lt;p&gt;どうも最近のコンパイラ(gccやclang)はLL1らしい。
大学の授業では、「LALR1じゃないとまともにパースできない(世の中的には主流)(最近は違う場合もある)」といっていた気がして、それにしたがってLALR1の文法解析などをやった記憶があるのだが。(違ったらごめんなさい先生。)&lt;/p&gt;
&lt;p&gt;なんだったんだあの勉強はという気持ちに少しなったが、教科書的にはああいうものなのだろう。
授業ではLL1をばっさり飛ばしたのでそんなに深追いしてなかったが、やってみればなるほどという感じ。&lt;/p&gt;
&lt;p&gt;LALR1パーサジェネレータを書くなら当時の記憶を掘り返して結構頑張らないときつそうだけど、LL1で書くのは意外といけるものだ。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;そんなわけでトークナイザ(レキシカルアナライザと同義?)とパーサは結構スイスイ進む。
やることが見えているしデバッグ用にログを出せば何が起きているか目に見えてわかる。&lt;/p&gt;
&lt;p&gt;そこまではいいのだけど、肝心のコード生成がちょっと大変。&lt;/p&gt;
&lt;p&gt;アセンブリへの理解が浅い私である。
アセンブリを読むのは少しつらいなぁ、この量でこんなこと言ってたらこの先どうなることやらと思いながらデバッグしている。
今後アセンブリがすらすら読めるようになることを夢見て続けていきたい。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;C言語でそれなりのものを書くというのも実はいままであまりやってこなかったので、今回は絶好の機会だ。
いつまで飽きずにやれるかな。&lt;/p&gt;</description>
    </item>
    <item>
      <title>npm publishの手順</title>
      <link>https://memo.yammer.jp/posts/npm-publish</link>
      <pubDate>Thu, 21 May 2020 06:40:14 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/npm-publish</guid>
      <description>&lt;p&gt;npm (Node Package Manager) とは、Node.js におけるパッケージ管理ツールである。&lt;/p&gt;
&lt;p&gt;npm が GitHub に買収されたり、deno が正式リリースされたりしているこのご時世であるが、初めて npm にパッケージを公開したので手順と注意点を振り返る。&lt;/p&gt;
&lt;p&gt;ちなみ公開したのは、はてなブログ記事管理ツールの &lt;a href=&quot;https://www.npmjs.com/package/gimonfu&quot;&gt;gimonfu&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;全体の流れ&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;$ npm publish&lt;/code&gt;する作業をよしなにしてくれる CLI ツール &lt;a href=&quot;https://www.npmjs.com/package/np&quot;&gt;np&lt;/a&gt; などもあるようだ。
今回は必要な作業を知る意味を込めて手動で行った。&lt;/p&gt;
&lt;p&gt;私がやったのは以下の通り。細かくはこれから述べる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;npm に登録する&lt;/li&gt;
&lt;li&gt;内容を確認する&lt;/li&gt;
&lt;li&gt;package.json の version を上げる&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ npm publish&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GitHub の Web ページ上で Release を書く&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;npmに登録する&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;npm に登録する (&lt;a href=&quot;https://www.npmjs.com/signup&quot;&gt;https://www.npmjs.com/signup&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;npm にログインする(&lt;code&gt;$ npm login&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;npm にログインしたことを確認する(&lt;code&gt;$ npm whoami&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;package.json を振り返る&lt;/h2&gt;
&lt;p&gt;package.json の内容に不備がないか、各項目を確認していく。&lt;/p&gt;
&lt;p&gt;一通り確認し終えたら &lt;a href=&quot;https://www.npmjs.com/package/fixpack&quot;&gt;fixpack&lt;/a&gt; を使って、抜けがないかチェックする。&lt;/p&gt;
&lt;p&gt;version については &lt;a href=&quot;https://docs.npmjs.com/about-semantic-versioning&quot;&gt;semantic versioning&lt;/a&gt; に従う。
要するに &lt;code&gt;0.0.1&lt;/code&gt; や &lt;code&gt;1.0.2&lt;/code&gt; といった形式だ。
&lt;code&gt;$ npm version&lt;/code&gt;でも上げることができるらしい。&lt;/p&gt;
&lt;p&gt;( files キーについては次に述べる。)&lt;/p&gt;
&lt;h2&gt;配布するファイルを確認する&lt;/h2&gt;
&lt;p&gt;配布するファイルは次の項目で決まる。&lt;/p&gt;
&lt;h3&gt;package.json 内の files キー&lt;/h3&gt;
&lt;p&gt;文字列の配列を渡すと、ファイルやディレクトリを配布ファイルに含める。
ホワイトリスト形式。&lt;/p&gt;
&lt;p&gt;今回は次のように指定した。
TypeScriptでCLIツールを作るなら同じように指定できるのではないだろうか。&lt;/p&gt;
&lt;p&gt;なお &lt;a href=&quot;https://docs.npmjs.com/files/package.json#files&quot;&gt;package.json などは自動で含めてくれる&lt;/a&gt;ようなので指定しなくてよい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;{
  &quot;files&quot;: [
    &quot;dist&quot;,
    &quot;bin&quot;
  ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;.npmignore&lt;/h3&gt;
&lt;p&gt;.gitignore と同じフォーマットで、ファイルやディレクトリを配布ファイルから除外する。
ブラックリスト形式。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://npm.github.io/publishing-pkgs-docs/publishing/the-npmignore-file.html&quot;&gt;npmのドキュメント&lt;/a&gt;を読むと、.npmignore だけではなく .gitignore も読み込んで除外してくれそうな感じだ。&lt;/p&gt;
&lt;p&gt;今回は package.json#files で指定したので使わなかった。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;配布するファイルは、特にTypeScriptのとき注意する必要がある。dist ディレクトリだ。&lt;/p&gt;
&lt;p&gt;npm での配布コンパイル結果を含む必要がある。
しかし git ではコンパイル結果をリポジトリに含めないのが普通だ。
何も設定しないと .gitignore を解釈して dist ディレクトリは配布対象外となってしまう。&lt;/p&gt;
&lt;p&gt;これを避けるためには、package.json#files で指定してあげる必要がある。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;ところで、&lt;code&gt;$npm link&lt;/code&gt;を使うと手元のPCでグローバルインストールしたのと同様にpathを通してくれるらしい。&lt;/p&gt;
&lt;p&gt;ただ、シンボリックリンクを貼るだけなので配布するファイルの確認には使えないことに注意。
配布対象外のファイルもローカルに存在するので動いてしまう。&lt;/p&gt;
&lt;h2&gt;ビルドとテストが通る&lt;/h2&gt;
&lt;p&gt;動かないファイルを公開するわけにはいかない。&lt;/p&gt;
&lt;p&gt;間違えて公開してしまっても&lt;a href=&quot;https://docs.npmjs.com/cli/unpublish&quot;&gt;72時間以内なら&lt;code&gt;$npm unpublish&lt;/code&gt;で取り消せる&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;それ以降はnpmのサポートにメールする必要がある。
パッケージが簡単に消せてしまうと依存関係に問題が生じるので、削除には慎重なようだ。&lt;/p&gt;
&lt;h2&gt;README.mdを読み直す&lt;/h2&gt;
&lt;p&gt;README.md は npm のページにも表示されるので、改めて間違いがないかを確認する。&lt;/p&gt;
&lt;p&gt;自分は Installation のところを間違えたまま公開してしまった。(現在は修正済み)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# 間違い
$ npm install --global yammerjp/gimonfu

# 正しい
# npm install --global gimonfu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実は npm にパッケージを公開せずとも、install 時に [githubユーザ名]/[githubレポジトリ名] とすると、パッケージをインストールできる。
もともと README.md にこの方法が記述していた。&lt;/p&gt;
&lt;p&gt;しかし今回はこの記述は間違い。
Github リポジトリには TypeScript のコンパイル結果が含まれていないので、インストールできても動かない。&lt;/p&gt;
&lt;p&gt;ちなみに英語の README.md は、DeepL と grammaly の力を借りて適当な GitHub リポジトリの README.md を参考にすることで作っている。
先人と文明は偉大。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;$ npm publish&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;問題ないことが確認できたらいよいよ公開する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npm publish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;たった一行打つだけ。&lt;/p&gt;
&lt;p&gt;公開したら、GitHub 上でも Release をつくる。&lt;/p&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;はじめての&lt;code&gt;$ npm publish&lt;/code&gt;はなんだか気分が良い。&lt;/p&gt;
&lt;p&gt;npm のパッケージのページでは Download 数が見れるのだが、公開された瞬間に40くらいになっていた。
謎。
ミラーだったりで自動取得されてるのかな。&lt;/p&gt;
&lt;p&gt;そもそも Download 数ってそんなに正確である必要はないので、40など誤差の範囲内だが。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) 不要な改行タグを削除&lt;/p&gt;</description>
    </item>
    <item>
      <title>コンピュータの有名なエッセイ</title>
      <link>https://memo.yammer.jp/posts/computer-essay</link>
      <pubDate>Wed, 20 May 2020 05:23:23 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/computer-essay</guid>
      <description>&lt;p&gt;コンピュータの専門家を志すものとして、近いうちに読んでおきたい(読み直したい)エッセイ。
インターネット上に公開されているものも多く、日本語訳のリンクをつけている。&lt;/p&gt;
&lt;p&gt;著者、訳者に感謝。&lt;/p&gt;
&lt;p&gt;自分の今後の人生など知る由もないが、仕事になろうとそうでなかろうと、コンピューテーションが楽しいものだということを忘れずに、いや今よりもそう思えるような人間でありたい。&lt;/p&gt;
&lt;h2&gt;ハッカーと画家(Hackers &amp;#x26; Painters)&lt;/h2&gt;
&lt;p&gt;ポール・グレアム著。&lt;/p&gt;
&lt;p&gt;エッセイ集。&lt;/p&gt;
&lt;p&gt;いくつかの章は読んだ。強い表現のところもあったりしてクセのある、他方魅力的な文章。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.blog.net/nerds-jp.htm&quot;&gt;どうしてオタクはモテないか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/hp-j.html&quot;&gt;ハッカーと画家&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/say-j.html&quot;&gt;口にできないこと&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/road-j.html&quot;&gt;もうひとつの未来への道&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/spam-j.html&quot;&gt;スパムへの対策&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/taste-j.html&quot;&gt;ものつくりのセンス&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/hundred-j.html&quot;&gt;百年の言語&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/beating-the-averages-j.html&quot;&gt;普通のやつらの上を行け&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/icad-j.html&quot;&gt;オタク野郎の復讐&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/being-popular-j.html&quot;&gt;夢の言語&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/desres-j.html&quot;&gt;デザインとリサーチ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/trans/gh-j.html&quot;&gt;素晴らしきハッカー&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://practical-scheme.net/wiliki/wiliki.cgi?naoya_t%3A%E3%83%9D%E3%83%BC%E3%83%AB%E3%83%BB%E3%82%B0%E3%83%AC%E3%82%A2%E3%83%A0%E3%81%AE%E3%82%A8%E3%83%83%E3%82%BB%E3%82%A4%E3%81%A8%E5%92%8C%E8%A8%B3%E4%B8%80%E8%A6%A7&quot;&gt;他を含む エッセイと和訳の一覧&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cruel.org/freeware/cathedral.html&quot;&gt;伽藍とバザール(The Cathedral and the Bazaar)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;エリック・レイモンド著。&lt;/p&gt;
&lt;p&gt;先日、TCP/IPに関する説明を大学の先生から受けたときに聞いた本。
オープンソースソフトウェアの発展に関する考察がされているようだ。&lt;/p&gt;
&lt;p&gt;まだ読んでいない。&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://cruel.org/freeware/hacker.html#basic_skills&quot;&gt;ハッカーになろう(How To Become A Hacker)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;こちらもエリック・レイモンド著。&lt;/p&gt;
&lt;p&gt;ハッカーとしての志、考え方が書かれている。&lt;/p&gt;
&lt;p&gt;一度読んだ。
私は全然ハッカーに近づけてはいないなと実感しながら。&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://ja.wikisource.org/wiki/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%8C%E7%9F%A5%E3%82%8B%E3%81%B9%E3%81%8D97%E3%81%AE%E3%81%93%E3%81%A8&quot;&gt;プログラマが知るべき97のこと&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;多数のプログラマが語るエッセイ集のようだ。&lt;/p&gt;
&lt;p&gt;まだ一部しか読めていない。&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://tatsu-zine.com/books/passionate-programmer-ja&quot;&gt;情熱プログラマー&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chad Fowler著のプログラマがキャリアを築くための方法を述べた書籍のようだ。&lt;/p&gt;
&lt;p&gt;まだ読んでいない(買っていない)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://yuru28.com&quot;&gt;ゆるふわポッドキャスト&lt;/a&gt;の&lt;a href=&quot;https://twitter.com/mktakuya&quot;&gt;@mktakuya&lt;/a&gt;さんがTwitterでつぶやいて知った。&lt;/p&gt;
&lt;hr/&gt;
&lt;br/&gt;
&lt;p&gt;エッセイではないが、&lt;a href=&quot;https://www.amazon.co.jp/UNIX%E3%81%A8%E3%81%84%E3%81%86%E8%80%83%E3%81%88%E6%96%B9%E2%80%95%E3%81%9D%E3%81%AE%E8%A8%AD%E8%A8%88%E6%80%9D%E6%83%B3%E3%81%A8%E5%93%B2%E5%AD%A6-Mike-Gancarz/dp/4274064069&quot;&gt;Unixという考え方 - その設計思想と哲学&lt;/a&gt;も改めて読み直したい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>リポジトリで振り返る2019年</title>
      <link>https://memo.yammer.jp/posts/2019-github-repositories</link>
      <pubDate>Tue, 19 May 2020 12:44:57 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/2019-github-repositories</guid>
      <description>&lt;p&gt;2020年も中頃だが、2019年末〜2020年正月に書きかけた記事が出てきた。
捨てるのも何なのでここに放出。&lt;/p&gt;
&lt;p&gt;以下。年末に1年を振り返るという記事の趣旨から各リポジトリにリンクをつけた以外は原文のまま。
リンク以外の追記部分はその旨を記述している。&lt;/p&gt;
&lt;hr/&gt;
&lt;h2&gt;なにをするか&lt;/h2&gt;
&lt;p&gt;あけましておめでとうございます。
年越ししてしまいましたが、まだ正月なので昨年を振り返って今年に向けて身を引き締めたい。&lt;/p&gt;
&lt;p&gt;今回はGitHubのリポジトリを総ざらいして自分がどんな開発をしたか振り返る。&lt;/p&gt;
&lt;h2&gt;準備:GitHubのリポジトリ一覧を取得する&lt;/h2&gt;
&lt;p&gt;githubのAPIを用いて、curlでリポジトリ情報を取得する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl -u yammerjp &quot;https://api.github.com/users/yammerjp/repos?per_page=100&amp;#x26;page=1&quot; | grep &apos;&quot;name&quot;: &quot;&apos; | awk -F &apos;&quot;&apos; &apos;{print $4}&apos; &gt; repos.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://qiita.com/emergent/items/a557246a0c0bf9d50a11&quot;&gt;GitHubのリポジトリを一覧化する（public/private両対応）- Qiita&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;リポジトリ一覧 (2019/12/31現在)&lt;/h2&gt;
&lt;p&gt;私(&lt;a href=&quot;https://github.com/yammerjp&quot;&gt;yammerjp&lt;/a&gt;)のgithub上にあるpublicリポジトリは31個。
まともにGitHubを使い始めてから1年ほどというのもあり、すべて2019年に1コミット以上しているので、これらを振り返る。&lt;/p&gt;
&lt;h3&gt;純粋な個人趣味開発&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/c-sharp-socket&quot;&gt;c-sharp-socket&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;友人からの質問をきっかけにC#でソケット通信をしてみた、サンプルコード的なリポジトリ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/text2pdf&quot;&gt;text2pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;textデータをPDFファイルに出力できるアプリケーション。
2019年1月に、3日間で勢いで作った。実用で使うというより、プロモーションが中心だったので、表示自体は非常に簡素。
ただし、node.js上で外部のライブラリやアプリケーションを用いず、PDFのファイル形式に従ってファイルへの文字列出力部分を自分で実装している。3日間にしては頑張ったな、という感じ。&lt;/p&gt;
&lt;p&gt;日本語出力した際のフォントまわりが貧弱で、文字列が描画される位置が微妙である。
開発後半に、日本語出力をとってつけで開発したので、このあたりをしっかりすれば、もうすこし見た目が良くなるのではないかな。
PDFを開く環境による見た目の差異を検証したりすることが必要である。&lt;/p&gt;
&lt;p&gt;もし文字データを手っ取り早くPDFにしたいのであれば、&lt;a href=&quot;https://dev.classmethod.jp/tool/md-to-pdf/&quot;&gt;md-to-pdf&lt;/a&gt;がおすすめ。&lt;a href=&quot;https://dev.classmethod.jp/tool/md-to-pdf&quot;&gt;GitHub風CSSを当てる&lt;/a&gt;と結構いい感じになる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/playqueue&quot;&gt;PlayQueue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Youtubeを連続再生するWebアプリケーション。
2018年末から断続的に開発している。
個人開発のアプリケーションとしては自分の代表作で、就活でも自分を紹介する際に話す機会が多い。&lt;/p&gt;
&lt;h3&gt;大学の授業に関係した開発&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/turingmachineonweb&quot;&gt;TuringMachineOnWeb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2019年1月制作。
チューリング機械の状態遷移表を作成するエディタと、作成した状態遷移表を検証するシュミレータを作った。&lt;/p&gt;
&lt;p&gt;レポートに書く状態遷移表をつくったときに、つくった状態遷移表が正しいのかを検証するために作った。&lt;/p&gt;
&lt;p&gt;UIは簡素だけれど、当時やりたかったことは達成させられたので満足。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/clustering.ai.2019.su&quot;&gt;clustering.AI.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ウォード法による階層的クラスタリングを扱ったレポートを書くために使ったスクリプト。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/pl0i&quot;&gt;pl0i&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/pl0i.js&quot;&gt;pl0i.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;pl0 interpreterという仮想マシンと、TypeScriptによる再実装(未完)&lt;/p&gt;
&lt;p&gt;簡易なアセンブリと、より高級な言語との対応を学ぶために、アセンブリを実行する仮想マシンをつくることで理解を深める試みであった。&lt;/p&gt;
&lt;p&gt;TypeScriptで書いていたときは、最終的にブラウザでメモリの状態や実行している命令の位置なども表示しながらプログラムを実行できるようなWebアプリケーションをつくるつもりだったが、大学の課題と就活を優先した結果開発が進まぬまま課題の方を先に終わらせて提出した。以後開発が停止し未完。&lt;/p&gt;
&lt;h3&gt;夏インターン&lt;/h3&gt;
&lt;h4&gt;夏インターン準備&lt;/h4&gt;
&lt;p&gt;夏インターンでNuxt.jsとTypeScriptを扱うと聞いたので、その準備としてそれらの勉強のために書籍やWebサイトを参考にサンプルアプリを作って動かしてみたリポジトリ群&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ts-nuxt-tutorial&quot;&gt;ts-nuxt-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/green-turtle-org&quot;&gt;green-turtle-org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/typescript-tutorial1&quot;&gt;Typescript-tutorial1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/typescript-tutorial2&quot;&gt;Typescript-tutorial2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/chapter02-qiita-post.nuxt-tutorial&quot;&gt;chapter02-qiita-post.nuxt-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/chapter03-01-layout.nuxt-tutorial&quot;&gt;chapter03-01-layout.nuxt-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/chapter03-02-middleware.nuxt-tutorial&quot;&gt;chapter03-02-middleware.nuxt-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;夏インターン&lt;/h4&gt;
&lt;p&gt;夏インターンのハッカソンで制作したWebアプリケーション。PHP製。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/oshushume.20190807&quot;&gt;oshushume.20190807&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;夏インターン後&lt;/h4&gt;
&lt;p&gt;夏インターンで扱ったNuxt.jsを生かして何かをしようと作っていたアプリケーションとその残骸。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/green-turtle&quot;&gt;green-turtle (ブログのソースコード)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/nuxt.ts-blog&quot;&gt;nuxt.ts-blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/nuxt.ts-blog.org&quot;&gt;nuxt.ts-blog.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/nuxt.ts-template&quot;&gt;nuxt.ts-template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/nuxt.ts-template.org&quot;&gt;nuxt.ts-template.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最終的にこのブログとして形にして動いている。
(2020/05/19補足: &lt;a href=&quot;https://memo.yammer.jp&quot;&gt;memo.yammer.jp&lt;/a&gt;ではなく&lt;a href=&quot;https://blog.yammer.fun&quot;&gt;Green Turtle&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;このブログ(&lt;a href=&quot;https://blog.yammer.fun&quot;&gt;Green Turtle&lt;/a&gt;)のしくみは以下のようになっている。&lt;/p&gt;
&lt;p&gt;mdファイルをgitリポジトリ(アプリケーションソースコードとは別のprivateリポジトリ)で管理している。
masterにmergeすることで記事公開。&lt;/p&gt;
&lt;p&gt;アプリケーションリポジトリも、記事リポジトリも、masterにmergeしたときにCircle CIが走ってデプロイするようになっている。&lt;/p&gt;
&lt;p&gt;デプロイは次のような工程で行われる&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;2つのリポジトリからソース、記事をclone&lt;/li&gt;
&lt;li&gt;ソースコードのサンプル記事を破棄し、cloneした公開記事に置き換え&lt;/li&gt;
&lt;li&gt;記事markdownをスクリプトでJSONに変換&lt;/li&gt;
&lt;li&gt;Nuxt.jsをGenerateモードで動作させる&lt;/li&gt;
&lt;li&gt;Nuxt.jsが記事ページを描画する際に、記事データが含まれるjsonファイルを読み込み、描画する。&lt;/li&gt;
&lt;li&gt;Nuxt.jsにより静的なHTML,CSSファイルが生成される&lt;/li&gt;
&lt;li&gt;Google Firebase Hostingに静的なHTML,CSSファイルをアップロード&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;今後の展望&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;トップページとaboutページが簡素なので、もう少しリッチなUIにしたい&lt;/li&gt;
&lt;li&gt;過去記事へのリンクの経路が限られているので、記事下に「最近投稿した記事」などのリンクを置きたい。&lt;/li&gt;
&lt;li&gt;(勉強も兼ねて)バックエンドも用意して、静的ファイルでの公開ではなく、SSRないしSPAで動作させたい。(表示速度は退化するので、完全に勉強目的)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;現在はブログというには簡素な状態だが、今後の拡張性はたくさん用意しているつもりである。
デプロイの手順も少々手間が混んでいるが、将来APIサーバを用意した際でも描画部分を使い回せるようにするためだったりする。
やりたいことはたくさんある。&lt;/p&gt;
&lt;h3&gt;Swift ( チーム開発でのiphoneアプリ製作 )&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ios-animals.enpit.2019.SU&quot;&gt;ios-animals.enpit.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ios-mymap.enpit.2019.SU&quot;&gt;ios-mymap.enpit.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ios-photo-viewer.enpit.2019.SU&quot;&gt;ios-photo-viewer.enpit.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ios-sample-calcurator.enpit.2019.SU&quot;&gt;ios-sample-calcurator.enpit.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/ios-timer.enpit.2019.SU&quot;&gt;ios-timer.enpit.2019.SU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/PinsOfMap&quot;&gt;PinsOfMap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab.heroku&quot;&gt;lovelab.heroku&lt;/a&gt;&lt;/strike&gt;(2020/05/19追記: 現在の名前は&lt;a href=&quot;https://github.com/yammerjp/lovelab-api&quot;&gt;lovelab-api&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/lovelab.vue&quot;&gt;lovelab.vue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;9月から、学生どうしでチームを組むiPhoneアプリケーションの開発に関わっている。&lt;/p&gt;
&lt;p&gt;上の5つはサンプルアプリケーションの実装。6つめはそれを生かした簡単な応用の位置情報保存アプリ。&lt;/p&gt;
&lt;p&gt;7つめは10月より開発中のメインのアプリケーションのAPIサーバ。&lt;/p&gt;
&lt;p&gt;8つめは10月より開発中のメインのアプリケーションのプロトタイプ。フロントエンドのWebアプリケーション&lt;/p&gt;
&lt;p&gt;(2020/05/19追記: メインのiphoneアプリケーションのリポジトリはプライベートなのでここにリンクを貼っていない。)&lt;/p&gt;
&lt;h3&gt;rails (冬インターン)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/bbs.rb&quot;&gt;bbs.rb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/rails-tutorial&quot;&gt;rails-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/rails-tutorial-toy_app&quot;&gt;rails-tutorial-toy_app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;冬インターンで&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;以上。 ここで止まっていた。
ここからは2020年5月に書いている。&lt;/p&gt;
&lt;p&gt;ちなみに冬インターンでRailsを使うものに参加したのでRailsを軽く触っていたのが最後の書きかけの項目。&lt;/p&gt;
&lt;p&gt;今年度末は同じ内容の記事を書ききって公開したい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>非同期のまえに同期処理を通してPromiseとasync/awaitを理解する</title>
      <link>https://memo.yammer.jp/posts/promise</link>
      <pubDate>Tue, 19 May 2020 07:50:47 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/promise</guid>
      <description>&lt;p&gt;JavaScript といえば非同期処理はつきものだが、非同期や Promise に苦手意識を持つ人も多いのではないだろうか。&lt;/p&gt;
&lt;p&gt;これらの最初の理解のハードルは結構高いと思う。私も理解できずに悶絶した。C言語のポインタよりむずくないか？。。。&lt;/p&gt;
&lt;p&gt;この記事の前半では一旦非同期のことは忘れる。
まず記事前半は、同期処理をテーマに、コールバック, Promise, async/await について説明する。
記事の後半は、これらを非同期処理を交えて説明する。&lt;/p&gt;
&lt;p&gt;Promise はよくわからないという方や、一度挫折した方などにぜひ読んでもらいたい。&lt;/p&gt;
&lt;p&gt;(2020/05/30補足: &lt;a href=&quot;https://qiita.com/yammerjp/items/b1c96de727a53c4b4698&quot;&gt;Qiita投稿&lt;/a&gt;に合わせて全体を修正済み。(&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/979b5576e05cb97e453b5cd3731e3802a0dc6fca/content/posts/promise.md&quot;&gt;旧版&lt;/a&gt;))&lt;/p&gt;
&lt;h2&gt;対象読者&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript の基本的文法を知っている。(調べればわかる)&lt;/li&gt;
&lt;li&gt;非同期処理, コールバック, Promise, async/awaitに苦手意識がある、よくわからない。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScriptを1行も読んだことも書いたこともない人、プログラミングをしたことのない人は対象としない。
逆に少しでも読み書きできればオーケー、のつもり。&lt;/p&gt;
&lt;h2&gt;目指すところ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;同期処理と非同期処理の違いがわかる&lt;/li&gt;
&lt;li&gt;(非同期処理を対象とした)他のPromise,async/awaitの解説記事を読んで理解が進む&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step0 準備&lt;/h2&gt;
&lt;h3&gt;Step0-1 MDN&lt;/h3&gt;
&lt;p&gt;非同期処理もコールバックもPromiseもasync/awaitも関係ないが、まずMDNについて説明しておきたい。&lt;/p&gt;
&lt;p&gt;JavaScriptでわからないことがあれば、まずは都度&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript&quot;&gt;MDN web docs&lt;/a&gt;をみるとよい。&lt;/p&gt;
&lt;p&gt;適当に検索して出てくる記事よりも、とりあえずここで確認しよう
(本記事も適当に検索して出てくる記事に該当するという矛盾がはらむ)。
一度理解して忘れていた記法などを確認するのにもとてもよい。&lt;/p&gt;
&lt;h3&gt;Step0-2 Chrome Developper Tool&lt;/h3&gt;
&lt;p&gt;以下JavaScirptの説明をするので、実際に動かしたくなる人もいるだろう。&lt;/p&gt;
&lt;p&gt;PCにnode.jsが既にインストールされている人はそちらを使うのもよい。&lt;/p&gt;
&lt;p&gt;しかし、インストールされていない人は、いちいちHTMLファイルを書いて、JavaScriptを読み込んで、、、とするのは面倒だろう。&lt;/p&gt;
&lt;p&gt;もっと気軽にJavaScriptを試せる方法がある。
Chrome developper Toolである。&lt;/p&gt;
&lt;p&gt;ブラウザにGoogle Chromeを使っている人はウィンドウ右上の︙ &gt; その他のツール &gt; デベロッパーツール を開いてみよう。
画面上方の「Console」タブを開いて、文字を入力すると、JavaScriptがエンターキーを押すごとに実行されるはずだ。&lt;/p&gt;
&lt;h3&gt;Step0-3 アロー関数&lt;/h3&gt;
&lt;p&gt;ES6 (ES2015)以降の最近のJavaScriptでは、アロー関数という記法がある。
アロー関数がわからない人も、この記事出てくるので簡単に抑えておきたい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;// 従来の書き方
function sum ( a, b ) {
  return a + b;
}

// アロー関数
const sum2 = ( a, b ) =&gt; {
  return a + b;
};

// アロー関数 関数の中がreturn文だけのときは、{return}を省略できる
const sum3 = ( a, b ) =&gt; a + b;

// アロー関数 引数が1つのときだけ()が省略できる (0つ、2つ以上はダメ)
const twice = a =&gt; a*2;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;thisがbindされるかだとか他の違いは一旦忘れる。
上のように書けるということだけわかればよい。&lt;/p&gt;
&lt;p&gt;さて、前置きが長くなったが準備が整った。&lt;/p&gt;
&lt;h2&gt;Step1 同期処理&lt;/h2&gt;
&lt;p&gt;まずは非同期のことはわすれて、とりあえず読み進めて欲しい。&lt;/p&gt;
&lt;h3&gt;Step1-1 コールバック (同期関数)&lt;/h3&gt;
&lt;p&gt;コールバックとは、関数自体を引数として与え、別の関数に実行してもらうしくみだ。
電話を折り返すことに由来して名付けられた。
由来の通り、関数自体を伝えて「あとで都合が良くなったら実行しておいて」と実行を押し付ける方式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;function callbackFunc() {
  console.log(&apos;callback&apos;);
}

function callFunc ( func ) {
  func();
}

callFunc( callbackFunc );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ふつう、関数callbackFuncを実行するなら&lt;code&gt;callbackFunc()&lt;/code&gt;のようにするだろう。
しかし上記では括弧をつけず&lt;code&gt;callbackFunc&lt;/code&gt; を引数として渡している。&lt;/p&gt;
&lt;p&gt;括弧をつけないことで、引数として関数自体を渡すだけでその場では実行されない。
後に callFunc 関数の中で、渡された関数 (&lt;code&gt;callbackFunc&lt;/code&gt;)を実行してもらっている。&lt;/p&gt;
&lt;p&gt;この「関数自体を渡す」というのがコールバックの肝である。
コールバックとは(戻り値の)値渡しではなく、関数自体の参照を渡しているという表現もできる。&lt;/p&gt;
&lt;p&gt;次のような書き方では全く意味が変わってしまうので注意。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;callFunc( callbackFunc() );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでは、callbackFunc 関数を実行し、その戻り値を callFunc 関数に引数として渡すという意味になってしまう。&lt;/p&gt;
&lt;p&gt;繰り返しになるが、コールバックは「関数自体を渡して」「あとで実行してもらう」しくみである。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://developer.mozilla.org/ja/docs/Glossary/Callback_function&quot;&gt;Callback function(コールバック関数) MDN web docs&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;(補足) コールバックとアロー関数&lt;/h4&gt;
&lt;p&gt;ちなみに上述のコードはアロー関数を使って次のようにも書ける。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const callbackFunc = () =&gt; {
  console.log(&apos;callback&apos;);
};

function callFunc( func ) {
  func();
}

callFunc( callbackFunc );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;さらに、一度変数に入れるのをやめると&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;function callFunc( func ) {
  func();
}

callFunc( () =&gt; {
  console.log(&apos;callback&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;引数を指定する中で関数を定義してしまうのだ。
このように関数自体を引数で渡すとき(即ちコールバック関数を渡すとき)、アロー関数でシンプルにかける。&lt;/p&gt;
&lt;h3&gt;Step1-2 Promise (同期関数)&lt;/h3&gt;
&lt;p&gt;Promise は英語で「約束する」という意味だ。
名前の通り、あとで値を返すことを約束するような動作をする。(約束を破ることもある。)&lt;/p&gt;
&lt;h4&gt;Promise の状態&lt;/h4&gt;
&lt;p&gt;Promise には3つの状態がある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pending ... 約束している状態(初期状態)&lt;/li&gt;
&lt;li&gt;fulfilled ... 約束を守って値を返した状態&lt;/li&gt;
&lt;li&gt;rejected ... 約束を破った状態&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Promise オブジェクトはまず pending で始まり、あとで fulfilled や rejected に状態が変化する。&lt;/p&gt;
&lt;h5&gt;状態: pending&lt;/h5&gt;
&lt;p&gt;とりあえず約束してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
});
// 何もしない関数を、new Promise() に渡している。
console.log( promise );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pendingと表示されただろう。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ここでの変数&lt;code&gt;promise&lt;/code&gt;は、Promise の状態 pending といえる。&lt;/em&gt;&lt;/p&gt;
&lt;h5&gt;状態: fulfilled&lt;/h5&gt;
&lt;p&gt;次は fulfilled の状態を作ってみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve();
})
console.log( promise );
// 実はresolve,rejectはそれぞれ、渡された(コールバック)関数を引数として受け取っている。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Promise resoleved と表示されただろう。これが fulfilled である。&lt;/p&gt;
&lt;p&gt;実は状態 fulfilled は値を持つ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;);
})
console.log( promise );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;ここでの変数&lt;code&gt;promise&lt;/code&gt;は、Promiseの状態 fulfilled であり、値&lt;code&gt;&apos;hello&apos;&lt;/code&gt;を持つといえる。&lt;/em&gt;&lt;/p&gt;
&lt;h5&gt;状態: rejected&lt;/h5&gt;
&lt;p&gt;rejected も fulfilled と同様に値を持つ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  reject(&apos;hello&apos;);
})
console.log( promise );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;ここでの変数&lt;code&gt;promise&lt;/code&gt;は、Promise の状態 rejected であり、値&lt;code&gt;&apos;hello&apos;&lt;/code&gt;を持つといえる。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;rejected で渡される値(オブジェクト)は Error オブジェクトだったりする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  reject(new Error(&apos;error message&apos;));
})
console.log( promise );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;ここでの変数&lt;code&gt;promise&lt;/code&gt;は、Promise の状態 rejected であり、値に Error オブジェクトを持つといえる。&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;状態の変化&lt;/h4&gt;
&lt;p&gt;Promiseでは状態が変化する。
初期状態では pending であるが、のちに fulfilled や rejected になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  //この行が実行されるタイミングでは、変数promiseは状態pending
  if( true ){
    //この行が実行されるタイミングでも、まだ変数promiseは状態pending
    resolve(&apos;resolveされた!&apos;);
    //この行が実行されるタイミングでは、変数promiseは状態fulfilledで値&apos;resolveされた!&apos;を持つ
    return;
  }
  // ここから先は実行されない
  reject(&apos;rejectされた&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;現在は同期処理を行っているので、fulfill または reject された状態に一瞬で変化してしまい、 pending の状態をみることはできない。&lt;/p&gt;
&lt;p&gt;しかし厳密にはもともとは pending で、 &lt;code&gt;resolve()&lt;/code&gt;を実行すると fulfilled に、 &lt;code&gt;reject()&lt;/code&gt; を実行すると rejected に、それぞれ状態が移行する。&lt;/p&gt;
&lt;h4&gt;then/catch による Promise チェーン&lt;/h4&gt;
&lt;p&gt;さて、Promise には3状態あり、変化することがわかった。
変化すると何ができるのか？ それをこの節で説明する。&lt;/p&gt;
&lt;p&gt;Promise オブジェクトのメソッドに、then と catch がある。&lt;/p&gt;
&lt;p&gt;これらはそれぞれ第一引数に関数をとり、Promise が fulfilled や rejected の状態になると引数関数を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;);
})

promise.then( arg =&gt; {
  console.log(arg); // ここではhelloが表示される
  console.log(&apos;then is called&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  reject(&apos;hello&apos;);
})

promise.catch( arg =&gt; {
  console.log(arg); // ここではhelloが表示される
  console.log(&apos;catch is called&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このように&lt;code&gt;.&lt;/code&gt;でつないで then/catch メソッドを呼べば、それらを発火できる。&lt;/p&gt;
&lt;p&gt;さらに、then/catch メソッドの戻り値に promise を与えてやれば、更に繋げられる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;);
})

promise
  .then( () =&gt; {
    console.log(&apos;then is called&apos;);
    return Promise.resolve(&apos;resolve!&apos;);
  })
  .then( arg =&gt; {
    return Promise.resolve( arg + &apos;!&apos; );
  })
  .then( arg =&gt; {
    console.log(arg); // resolve!! と表示される。
  })

// Promise.resolve(&apos;resolve!&apos;); は、
// new Promise( resolve =&gt; { resolve(&apos;resolve!&apos;) }); と同じ。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述の通り、then メソッドの戻り値に Promise を渡すと、更に後ろに&lt;code&gt;.then()&lt;/code&gt;を繋げられる。
(&lt;code&gt;.catch()&lt;/code&gt;も繋げられる。)&lt;/p&gt;
&lt;p&gt;このように、Promise が解決 (fulfill/reject) されたら&lt;code&gt;.then()&lt;/code&gt;メソッドが発火し、
&lt;code&gt;.then()&lt;/code&gt;メソッドがPromiseを返すと、解決されたらさらに後ろの&lt;code&gt;.then()&lt;/code&gt;メソッドが発火し、、、&lt;/p&gt;
&lt;p&gt;このように数珠つなぎに徐々に Promise が渡ることを Promise チェーンと呼ぶ。&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;ここまでで Promise を学んだ。
コールバックや Promise を使う理由は非同期関数にあるので、読者の皆様にはややこしいことをしているようにしか見えないかもしれない。&lt;/p&gt;
&lt;p&gt;本当はこのあたりで非同期関数について説明し Promise のありがたみを理解していただくのもよいのだが、この記事はあくまで「まず同期関数で理解する。」ことが目的であり、非同期関数はもう少し後回しにする。&lt;/p&gt;
&lt;hr/&gt;
&lt;h3&gt;Step1-3 async/await (同期関数)&lt;/h3&gt;
&lt;p&gt;次は sync/await だ。&lt;/p&gt;
&lt;p&gt;そのまえに説明すべきことが2つほどあるので補足。&lt;/p&gt;
&lt;h4&gt;補足: 即時関数&lt;/h4&gt;
&lt;p&gt;即時関数は定義と同時に実行する関数だ。
関数定義を括弧でくくると即時実行される。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const Hello = () =&gt; { console.log(&apos;hello&apos;) };
Hello();

// 上2行のコードは、次の行のコードと同じ。
( () =&gt; { console.log(&apos;hello&apos;) });

// アロー関数でなくても良い
( function () { console.log(&apos;hello&apos;) });
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;補足: Async 関数 (asnyc function)&lt;/h4&gt;
&lt;p&gt;関数定義の前に&lt;code&gt;async&lt;/code&gt;とつけて定義する。
Asnyc 関数の中でのみ await が使える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;// 例
const arrowFunc = async () =&gt; {
  await promise;
}
async function func() {
  await promise;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr/&gt;
&lt;h4&gt;改めて async/await (同期関数)&lt;/h4&gt;
&lt;p&gt;閑話休題。&lt;/p&gt;
&lt;p&gt;async/await は Promise を生成する構文と言っていい。
先程の then を書かずともよくなる構文である。&lt;/p&gt;
&lt;p&gt;前節の Promise のコードを再掲する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;);
})

promise.then( arg =&gt; {
  console.log(arg) // ここではhelloが表示される
  console.log(&apos;then is called&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これを async/await に書き直すと&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;);
})

(async () =&gt; {
  const arg = await promise;
  console.log(arg); // ここではhelloが表示される
  console.log(&apos;then is called&apos;);
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このようになる。
then が消えたことがわかる。&lt;/p&gt;
&lt;p&gt;(即時実行のasync関数を使っている。)&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;もう一つ前節のコードを再掲し async/await に書き換えてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;)
})

promise
  .then( () =&gt; {
    console.log(&apos;then is called&apos;)
    return Promise.resolve(&apos;resolve!&apos;)
  })
  .then( arg =&gt; {
    return Promise.resolve( arg + &apos;!&apos; )
  })
  .then( arg =&gt; {
    console.log(arg) // resolve!! と表示される。
  })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;async/await に書き換えると&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve, reject) =&gt; {
  resolve(&apos;hello&apos;)
})

( async () =&gt; {
  let arg = await promise
  console.log(&apos;then is called&apos;)
  let arg = await Promise.resolve(&apos;resolve!&apos;)
  let arg = await Promise.resolve( arg + &apos;!&apos; )
  console.log(arg) // resolve!! と表示される。
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今度は then がなくなったことで短く書けたことが伝わるのではないか。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;await&lt;/code&gt;が現れると、Async 関数内の&lt;code&gt;await&lt;/code&gt;より後ろの部分が全て&lt;code&gt;then()&lt;/code&gt;の引数として包まれる、といった見方もできる。&lt;/p&gt;
&lt;p&gt;以上のように、async/await は Promise を簡潔に書く構文である。&lt;/p&gt;
&lt;br/&gt;
&lt;h4&gt;余談: Promiseは必要か?&lt;/h4&gt;
&lt;p&gt;async/awaitで簡潔にかけるなら、Promiseなんて理解しなくて良いのでは？と思う方もいるだろう。
しかし今の所そうも行かないのだ。&lt;/p&gt;
&lt;p&gt;複数のPromiseを同時に待つ処理をasync/awaitで書いてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;( async () =&gt; {
  await Promise.all( [ promise1, promise2 ])
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;うお、Promise出てきた。。。&lt;/p&gt;
&lt;p&gt;コードの内容はおいておいて、Promise という単語が出てきたことに注目。
解説は省くが、async/await は Promise を完全には隠しきれていないのだ。&lt;/p&gt;
&lt;p&gt;(気になる方はこの記事を読み終えてから&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all&quot;&gt;&lt;code&gt;Promise.all&lt;/code&gt;&lt;/a&gt;をみると良いだろう。&lt;/p&gt;
&lt;br/&gt;
&lt;h2&gt;Step2 非同期処理&lt;/h2&gt;
&lt;p&gt;さてさて、ここまで来ればゴールは近い。
この節では今まで苦労して覚えた謎構文 Promise と asnyc/await のありがたみがわかるようになる。&lt;/p&gt;
&lt;h3&gt;Step2-1 同期関数と非同期関数&lt;/h3&gt;
&lt;p&gt;同期関数と非同期関数について説明する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同期関数とは、中の処理が完了するまで待ってから戻り値を返す関数のこと&lt;/li&gt;
&lt;li&gt;非同期関数とは、中の処理にかかわらず、すぐに戻り値を返してしまう関数のこと&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScript の代表的な非同期関数に&lt;code&gt;setTimeOut()&lt;/code&gt;がある。&lt;/p&gt;
&lt;p&gt;次のようなコードで考えてみよう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;setTimeOut( () =&gt; {
  console.log(&apos;hello&apos;);
}, 1000);
console.log(&apos;world&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JavaScript は、普通は(同期関数は)、上から順番に1行ずつ実行される。&lt;/p&gt;
&lt;p&gt;しかし上記のコードを実行すると&lt;code&gt;world&lt;/code&gt;が表示された後に&lt;code&gt;hello&lt;/code&gt;が表示される。
これは&lt;code&gt;setTimeOut()&lt;/code&gt;関数が非同期関数だからだ。&lt;/p&gt;
&lt;p&gt;書き方を少し変えてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;function Hello() { // 1
  console.log(&apos;hello&apos;); // 4
}
setTimeOut( Hello, 1000) // 2
console.log(&apos;world&apos;) // 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;さっきと同じ動作をするコードだ。&lt;/p&gt;
&lt;p&gt;コンピュータの気持ちになってみると&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hello 関数を定義するよ。Hello 関数は実行されたら&lt;code&gt;&apos;hello&apos;&lt;/code&gt;と表示するよ。まだ定義だけで実行しないよ。&lt;/li&gt;
&lt;li&gt;setTimeOut 関数を実行するよ。Hello 関数を 1000ms 後に実行するとを登録するよ。&lt;strong&gt;登録するだけで、すぐに戻り値を返すよ。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;world&apos;&lt;/code&gt;と表示するよ。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;... しばらく (1000ms) 経って ...&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Hello 関数を実行するよ、&lt;code&gt;&apos;hello&apos;&lt;/code&gt;と表示するよ。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;このような順で動作する。
同期関数はその行で処理が停止するのに対し、非同期関数はすぐに次の行が実行される。&lt;/p&gt;
&lt;h2&gt;Step2-2 コールバック (非同期関数)&lt;/h2&gt;
&lt;p&gt;先程の例で非同期関数を実現してるのがコールバックだ。&lt;/p&gt;
&lt;p&gt;あとで実行して欲しい関数を引数で伝えておいて、ときが来たら実行する。&lt;/p&gt;
&lt;p&gt;やりたいことはコールバックで実現できるものの、何重にも重なると次のようなコードにになってしまう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;setTimeOut( () =&gt; {
  setTimeOut( () =&gt; {
    setTimeOut( () =&gt; {
      setTimeOut( () =&gt; {
        setTimeOut( () =&gt; {
          setTimeOut( () =&gt; {
            console.log(&apos;6s later&apos;);
          }, 1000);
        }, 1000);
      }, 1000);
    }, 1000);
  }, 1000);
}, 1000);

console.log(&apos;これはすぐに実行される&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コールバック関数を呼ぶたびにネストが深くなってしまい読みづらい。&lt;/p&gt;
&lt;p&gt;俗に言うコールバック地獄である。
たとえばこの例だと、どの秒数がどの setTimeOut に対応するのかわかりづらい。&lt;/p&gt;
&lt;p&gt;(上記の例は全て一つの setTimeOut にまとめられるが)
実際には次のような状況が考えられる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;サーバと通信して、記事のリストをとってくる。&lt;/li&gt;
&lt;li&gt;記事のリストから該当の記事を探して、再度サーバと通信して本文をとってくる。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;このように、複数の非同期処理が数珠つなぎになることもあるだろう。&lt;/p&gt;
&lt;p&gt;数珠つなぎ、、、&lt;/p&gt;
&lt;h2&gt;Step2-3 Promise (非同期関数)&lt;/h2&gt;
&lt;p&gt;そう、数珠つなぎならさっきの Promise チェーンと相性が良い。&lt;/p&gt;
&lt;p&gt;さっきの6秒待つ処理も&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;// 事前に Promise 関数を作っておく。
// ライブラリなどで用意されていたりするので、Promise を使う側は作る必要はない。
function setTimeOutPromise(time){
  return new Promise( resolve =&gt; {
    setTimeOut( resolve, 1000);
  });
}

setTimeOutPromise(1000)
.then( () =&gt; 
  setTimeOutPromise(1000)
).then( () =&gt;
  setTimeOutPromise(1000)
).then( () =&gt;
  setTimeOutPromise(1000)
).then( () =&gt;
  setTimeOutPromise(1000)
).then( () =&gt;
  setTimeOutPromise(1000)
).then( () =&gt; {
  console.log(&apos;6s later&apos;);
})

console.log(&apos;これはすぐに実行される&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ネストが解消されて、引数もコンパクトになって見やすくなった。&lt;/p&gt;
&lt;h2&gt;Step2-4 asnyc/await (非同期関数)&lt;/h2&gt;
&lt;p&gt;さらに async/awaitで書き直すと&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;// 事前に Promise 関数を作っておく。
// さっきと同じ。
function setTimeOutPromise(time){
  return new Promise( resolve =&gt; {
    setTimeOut( resolve, 1000)
  })
}

( async () =&gt; {
  await setTimeOutPromise(1000);
  await setTimeOutPromise(1000);
  await setTimeOutPromise(1000);
  await setTimeOutPromise(1000);
  await setTimeOutPromise(1000);
  await setTimeOutPromise(1000);
  console.log(&apos;6s later&apos;);
})

console.log(&apos;これはすぐに実行される&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは見やすい！
非同期関数を同期的に書けるようになった。&lt;/p&gt;
&lt;p&gt;await の行で停止しているかのように動作する。&lt;/p&gt;
&lt;h2&gt;さいごに&lt;/h2&gt;
&lt;p&gt;本記事を読み次の2つを知れば、他の記事が格段に読みやすくなるだろう。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同期処理と非同期処理の違い&lt;/li&gt;
&lt;li&gt;同期処理でPromiseがどういう動作をするか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これからは「コールバック地獄を解決するために Promise チェーンがある」「 async/await は Promise の生成だ」などと書かれた他の記事も読めるのではないだろうか。&lt;/p&gt;
&lt;p&gt;この記事を完全に理解できなくても、 読者の皆様はこれから JavaScript の非同期処理を深める土台ができているのではないかと思う。&lt;/p&gt;
&lt;p&gt;ここまでの長文に付き合いいただきありがたい。&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Promiseのthenメソッドには第二引数がある</title>
      <link>https://memo.yammer.jp/posts/promise-then-arg2</link>
      <pubDate>Tue, 19 May 2020 06:57:35 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/promise-then-arg2</guid>
      <description>&lt;p&gt;この記事は以下のツイートについて。&lt;/p&gt;
&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&gt;thenメソッドって第2引数でrejectedなときに実行する関数も指定できるのか、いつもcatchばかり使っていた。&lt;/p&gt;— やんまー (@yammerjp) &lt;a href=&quot;https://x.com/yammerjp/status/1262637541028585475?ref_src=twsrc%5Etfw&quot;&gt;May 19, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;きっかけは&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;MDN web docsのPromiseについてのページ&lt;/a&gt;を見ていたことに始まる。&lt;/p&gt;
&lt;p&gt;以前、私がPromiseとaync/awaitを理解するときにとても役にたった記事があった。
Qiitaにあった記事で同期処理でPromiseをしてみて理解しようと試みる記事だったのだが、いま探しても見つからない。&lt;/p&gt;
&lt;p&gt;需要がありそうなので自分で書いているのだが、そんな中でMDNを見ていてthenメソッドに関する発見があった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;const promise = new Promise( (resolve,reject) =&gt; {
  setTimeout( () =&gt; {
    if( (Date.now()%2) === 0 ){
      resolve()
      return
    }
    reject()
  }, 1000)
})

promise.then(
  () =&gt; { console.log(&apos;fulfilled&apos;)},
  () =&gt; { console.log(&apos;rejected&apos;)}
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あなたの運(実行タイミング)によってfulfilledかrejectedが表示されるコードである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;thenの第一引数は、promiseオブジェクトがfulfilled状態になったとき(上記コードでいえば&lt;code&gt;resolve()&lt;/code&gt;が実行されたとき)、実行される関数である。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これは理解していたが次だ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;thenの第二引数は、promiseオブジェクトがrejected状態になったとき(上記コードでいえば&lt;code&gt;reject()&lt;/code&gt;が実行されたとき)、に実行される関数である。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これは見落としていた。
いつも&lt;code&gt;then(A).catch(B)&lt;/code&gt;として拾っていたが、&lt;code&gt;then( A, B )&lt;/code&gt;として書けるのだな。&lt;/p&gt;
&lt;p&gt;書けることと見やすいことは別で、今の私の感情ではcatchと書いたほうが見やすいのでは？と思うのだが、実際のところどうなのだろう。
thenの第二引数がどれだけ使われているのか気になるところである。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;ところで、promiseの状態について、初期状態をpendingと表現し、それがfulfilledかrejectedに変化するのだが、fulfilledのことをついresolvedと表現したくなってしまう。&lt;/p&gt;
&lt;p&gt;正確にはresolvedというと、fulfilledとrejectedをどちらも指すようで、promiseが成功したときはfulfilledと表現すべきらしい。
(resolvedと同じ意味でsettledという言葉も使われるようだ。)&lt;/p&gt;
&lt;p&gt;なるほど区別するのは良いのだが、それならよく&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;new Promise( (resolve, relect) =&gt; {})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と書いているのはどうなの。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot;&gt;new Promise( (fulfill, reject) =&gt; {})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と予め書いてあるほうが混乱を産まないと思うのだが。&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;話がそれたが今日はPromiseのthenメソッド第二引数についてであった。
いつも使っている文でも知らないことが隠れていたりするので、ことあるごとに正しい文献に戻ることを心がけていきたい。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Raspberry Pi Zeroをモニタレスで使うためのSetup</title>
      <link>https://memo.yammer.jp/posts/raspberry-pi-zero-setup</link>
      <pubDate>Fri, 15 May 2020 16:21:46 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/raspberry-pi-zero-setup</guid>
      <description>&lt;p&gt;2020/3/4のメモ。
Raspberry pi Zero を、購入後一切モニタにつなぐことなく無線LAN経由でSSHできるようセットアップする手順。&lt;/p&gt;
&lt;p&gt;母艦は MacOS X で行っているが、SDカードへの書き込みができればなんでもよい。&lt;/p&gt;
&lt;p&gt;肝となるのは、OSを書き込んだSDカードに次のように手を加えておくことだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事前に無線LANのSSIDとパスワードを記述したファイルをおく&lt;/li&gt;
&lt;li&gt;SSHを有効化する&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;起動前&lt;/h2&gt;
&lt;h3&gt;micro SD cardのフォーマット&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sdcard.org/jp/downloads/formatter_4/&quot;&gt;SD Association公式サイト&lt;/a&gt;より、SDカードフォーマッターをダウンロードする。&lt;/p&gt;
&lt;p&gt;ダウンロードしたSDカードフォーマッターでSDカードをフォーマットする。&lt;/p&gt;
&lt;p&gt;( FAT, FAT32, exFAT)。 4GB以上(要出典)。&lt;/p&gt;
&lt;h3&gt;OSイメージのダウンロード&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.raspberrypi.org/downloads/raspbian/&quot;&gt;raspberry pi公式サイト&lt;/a&gt;からraspbianをダウンロードする。&lt;/p&gt;
&lt;p&gt;ここではGUIが必要ないので、[Raspbian Buster Lite]のzipをダウンロードする。&lt;/p&gt;
&lt;h3&gt;OSイメージの書き込み&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# ダウンロードしたzipを展開してimgファイルを得る
$ unzip 2020-02-13-raspbian-buster-lite.zip

# デバイスを確認
$ diskutil list

# フォーマット済みの書き込み先デバイス(ここでは/dev/disk2)をunmount
$ diskutil unMountDisk /dev/disk2

# 書き込み
$ sudo dd bs=1m if=2020-02-13-raspbian-buster-lite.img of=/dev/disk2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;wifiの事前設定とsshの有効化&lt;/h3&gt;
&lt;p&gt;書き込み後のSDカードのbootドライブをマウントする。(/Volumes/boot)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd /Volumes/boot
# bootドライブちょっかいsshという名前のファイルが有ると、初期状態でsshが起動する
$ touch ssh

# wifi設定を書き込む
$ vim wpa_supplicant.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;wpa_supplicant.conf&lt;/code&gt;の中身は以下の通り&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# wpa_supplicant.conf

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
        ssid=&quot;接続先アクセスポイントのSSID&quot;
        psk=&quot;接続先アクセスポイントのパスワード&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;起動&lt;/h2&gt;
&lt;p&gt;micro SDカードを差し込み、PWRと書かれた方のmicro USB Bポートに電源ケーブルをつなぐと起動する。&lt;/p&gt;
&lt;h3&gt;ipアドレスとmacアドレスの確認とDHCPリースの固定&lt;/h3&gt;
&lt;p&gt;起動すると、自動でwifiに接続して22版ポートが開いてsshが立ち上がる(少し時間がかかる)&lt;/p&gt;
&lt;p&gt;ルータの設定画面などをみて、新しく接続されたデバイスに注目する。raspberry piっぽい端末のmacアドレスを見つける。&lt;/p&gt;
&lt;p&gt;DHCPリースを固定にして、このMACアドレスに対応するIPアドレスをわかりやすいものに固定しておく&lt;/p&gt;
&lt;h3&gt;sshで接続&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;クライアント側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ ssh pi@192.168.0.13
# raspberry pi のIPアドレスを指定(ここでは 192.168.0.13 であるとする)
# デフォルトのIDは pi
# デフォルトのパスワードは raspberry
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;設定&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;raspberry pi側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# visudoでnanoではなくvimを立ち上げる
# 参考: https://qiita.com/koara-local/items/35b999631b6ab41fdc9f
$ sudo update-alternatives --config editor

# vimをエイリアスとして登録
$ vim ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.bashrc&lt;/code&gt;に下記を追記&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;# .bashrc
alias vim=&apos;vi&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;変更を読み込む&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;sshの設定&lt;/h2&gt;
&lt;h3&gt;ssh用ユーザの作成&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;raspberry pi側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# yammerというユーザを作るとする
$ sudo useradd yammer
$ sudo passwd yammer
$ sudo visudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;visudoによって、&lt;code&gt;/etc/sudoers&lt;/code&gt;に下記を追記&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yammer  ALL=(ALL) ALL
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ssh用公開鍵の作成&lt;/h3&gt;
&lt;p&gt;ssh用の公開鍵を作る。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;クライアント側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd ~/.ssh
$ ssh-keygen -t rsa -b 4096 -C &quot;raspberry-pi&quot; -f ~/.ssh/id_rsa_pi
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sshのパーミッションを設定&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;raspberry pi側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd /home/yammer
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ssh公開鍵を送る&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;クライアント側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ scp ~/.ssh/id_rsa_pi.pub yammer@192.168.0.13:/home/yammer/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ssh設定&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;raspberry pi側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo vi /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# /etc/ssh/sshd_config

RSAAuthentication   yes
PubkeyAuthentication   yes
AuthorizedKeysFile   .ssh/authorized_keys
AllowUsers yammer # ユーザ名を追加
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo /etc/init.d/sshd restart
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;接続できるか確認&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;クライアント側&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ ssh -i ~/.ssh/id_rsa_pi yammer@192.168.0.13
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/tattn/items/a03cbf7c185d7efa6769&quot;&gt;SSH用のユーザー追加手順と注意点のまとめ - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Vimに入門したときの覚書</title>
      <link>https://memo.yammer.jp/posts/vim-intro</link>
      <pubDate>Fri, 15 May 2020 16:07:44 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/vim-intro</guid>
      <description>&lt;p&gt;昨年、Vimを使える人間になりたいという気持ちからVimに入門した。&lt;/p&gt;
&lt;p&gt;まずvimtutorをやり、またVim以外のエディタを使うことを禁止して慣れるようにした。
vimtuorのあとは&lt;a href=&quot;https://www.amazon.co.jp/dp/B00HWLJI3U/ref=dp-kindle-redirect?_encoding=UTF8&amp;#x26;btkr=1&quot;&gt;実践Vim&lt;/a&gt;を読んだりしながら日常使いの中でVimに慣れていった。
また基本的にプラグインを追加することを禁止し、不用意な&lt;code&gt;.vimrc&lt;/code&gt;の編集も禁止して、素の状態のVimに慣れるように気を配っていた。&lt;/p&gt;
&lt;p&gt;そんなこんなでVimに慣れようとしていたわけだが、最初期vimtutorをやるだけではなかなかキーバインドが覚えられず、とても編集速度が遅かったので、同時にメモに書き出すことで覚えていたようである。&lt;/p&gt;
&lt;p&gt;このときのメモをここに供養する。書いた日付は2019/10/28。&lt;/p&gt;
&lt;hr/&gt;
&lt;h2&gt;Vim :help 日本語化&lt;/h2&gt;
&lt;p&gt;まず次のコマンドを実行&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に&lt;code&gt;~/.vimrc&lt;/code&gt;に次の内容を追記&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-vim&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&quot; .vimrc&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; plug#begin(&lt;span class=&quot;hljs-string&quot;&gt;&apos;~/.vim/plugged&apos;&lt;/span&gt;)
&lt;span class=&quot;hljs-comment&quot;&gt;&quot; A project which translate Vim documents into Japanese.&lt;/span&gt;
Plug &lt;span class=&quot;hljs-string&quot;&gt;&apos;vim-jp/vimdoc-ja&apos;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; plug#end()

&lt;span class=&quot;hljs-keyword&quot;&gt;set&lt;/span&gt; helplang=ja,&lt;span class=&quot;hljs-keyword&quot;&gt;en&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次にVimを立ち上げて&lt;code&gt;:PlugInstall&lt;/code&gt;と入力しプラグインをインストールする&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://qiita.com/issuy/items/919d76ac1b94dc56a77e&quot;&gt;Vimをちゃんと知りたい！だからHelpを日本語化する！&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;.vimrcを無視する&lt;/h2&gt;
&lt;p&gt;.vimrcを書き換えて起動しなくなったら&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ vim -u NONE -N
# -u None ... .vimrcを読み込まない vi互換モードにする
# -N ...(nocompatible) vi互換モードをオフにする
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;. 直前の操作を繰り返す&lt;/h2&gt;
&lt;h3&gt;ノーマルモード&lt;/h3&gt;
&lt;p&gt;直前のコマンドを繰り返す(カーソル移動はコマンドとみなされない) (ex.&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;dd&lt;/code&gt;, &lt;code&gt;&gt;G&lt;/code&gt;)&lt;/p&gt;
&lt;h3&gt;インサートモード&lt;/h3&gt;
&lt;p&gt;挿入モードに入った瞬間(&lt;code&gt;i&lt;/code&gt;を押す等)からノーマルモードに戻る(&lt;code&gt;&amp;#x3C;Esc&gt;&lt;/code&gt;を押す)までの間のキーストロークが記録されている&lt;br&gt;
.を押すことでこの一連の流れを再生できる&lt;/p&gt;
&lt;h2&gt;移動&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h&lt;/code&gt; ... ←&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j&lt;/code&gt; ... ↓&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k&lt;/code&gt; ... ↑&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l&lt;/code&gt; ... →&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; ... 行末に移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt; ... 次の単語へ移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gg&lt;/code&gt; ... ファイル先頭へ移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;G&lt;/code&gt; ... ファイル末尾へ移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{数字}G&lt;/code&gt; ... {数字}行目に移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;#x3C;Ctrl&gt;G&lt;/code&gt; ... 現在のカーソル行を表示&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&gt;G&lt;/code&gt; ... 現在の行からファイル末尾までのインデントを1段深くする&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;基本操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; ... カーソル下の文字を削除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dd&lt;/code&gt; ... 行頭から行末まで削除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt; ... インサートモードへ切り替え&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; ... カーソルの右隣でインサートモードへ切り替え&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; ... 行末に移動してインサートモードに切り替え&lt;/li&gt;
&lt;li&gt;&lt;code&gt;o&lt;/code&gt; ... 次行を作りインサートモードへ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;O&lt;/code&gt; ... 前行を作りインサートモードへ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt; ... アンドゥ 戻る&lt;/li&gt;
&lt;li&gt;&lt;code&gt;U&lt;/code&gt; ... 行単位でアンドゥ 戻る&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;#x3C;Ctrl&gt;R&lt;/code&gt; ... リドゥ　戻るの取り消し&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; ... 行頭へ移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt; ... 貼り付け (削除したものを貼り付け 例えば&lt;code&gt;dd&lt;/code&gt;コマンドで削除した行等&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; ... 置き換え カーソル下の文字を一文字消して次に入力した一文字で置き換える。なお置き換え後もノーマルモードを維持する&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R&lt;/code&gt; ... 置換モード カーソル下を上書きして文字を挿入する escキーでノーマルモードに戻る&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%&lt;/code&gt; ... 対応する括弧へ移動&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yy&lt;/code&gt; ... 行をヤンク&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yw&lt;/code&gt; ... カーソル後ろの空白を含む単語をヤンク&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;モーション操作&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;d&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;ノーマルモードでモーション操作を行うとカーソル移動&lt;/p&gt;
&lt;p&gt;&lt;code&gt;d{モーション}&lt;/code&gt;を行うと現カーソルからモーション先まで削除&lt;/p&gt;
&lt;p&gt;&lt;code&gt;d{数字}{モーション}&lt;/code&gt;ないし&lt;code&gt;{数字}d{モーション}&lt;/code&gt;は等価で、数字個先のモーションの差示す場所まで削除する&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;e&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;c{モーション}&lt;/code&gt;を行うと、現カーソルからモーション先まで削除して挿入モードに切り替え&lt;/p&gt;
&lt;h3&gt;モーション&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt; ... 空白を含む単語尾&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt; ... 空白を含まない単語尾&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; ... 行末&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;コマンド&lt;/h2&gt;
&lt;h3&gt;終了&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:q!&lt;/code&gt; ... 内容を破棄して終了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:wq&lt;/code&gt; ... 内容を保存して終了&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;書き込み&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:w filename&lt;/code&gt; ... ファイルfilenameへ書き込み&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;検索&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/hoge&lt;/code&gt; ... hogeを前方検索&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?hoge&lt;/code&gt; ... hogeを逆方向に検索&lt;/li&gt;
&lt;li&gt;(検索した状態で)&lt;code&gt;n&lt;/code&gt; ... 次を検索&lt;/li&gt;
&lt;li&gt;(検索した状態で)&lt;code&gt;&amp;#x3C;Ctrl&gt;o&lt;/code&gt; ... 一つ前の検索結果に戻る&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;置換&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:s/before/after&lt;/code&gt; ... カーソル行の１つ目のbeforeをafterへ置換&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:s/before/after/g&lt;/code&gt; ... カーソル行の全てのbeforeをafterへ置換&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:3,5s/before/after/g&lt;/code&gt; ... 3行目から5行目の全てのbeforeをafterへ置換&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:%s/before/after/g&lt;/code&gt; ... ファイル内全てのbeforeをafterへ置換&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:%s/before/after/gc&lt;/code&gt; ... ファイル内全てのbeforeを都度確認しながらafterへ置換&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;検索/置換のオプション&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:set ic&lt;/code&gt; ... 検索時に大文字小文字を区別しない(ignorecase)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:set is&lt;/code&gt; ... 検索フレーズに部分マッチしている部分を表示する(incsearch)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:set hls&lt;/code&gt; ... マッチする全てを強調表示する(hlsearch)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ターミナルコマンド実行&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:!ls&lt;/code&gt; ... lsを実行(のちエンターでvimに戻る)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;挿入&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:r filename&lt;/code&gt; ... filenameの内容をカーソル位置へ挿入&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:r !ls&lt;/code&gt; ... lsの結果をカーソル位置へ挿入&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;help&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help&lt;/code&gt; ... helpウィンドウを開く&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help hoge&lt;/code&gt; ... hogeに関するhelpを見る&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;候補と保管&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:e&amp;#x3C;TAB&gt;&lt;/code&gt; ... eから始まるコマンドを補完&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:e&amp;#x3C;Ctrl&gt;d&lt;/code&gt; ... eから始まるコマンドを一覧表示&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;visualモード&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v&lt;/code&gt; ... visualモードへ切り替え カーソルを移動させると、visualモード移行時のカーソルとの間が反転し選択される&lt;/li&gt;
&lt;li&gt;(visualモードで短形選択時)&lt;code&gt;:&apos;&amp;#x3C;,&apos;&gt;w filename&lt;/code&gt;(&lt;code&gt;&apos;&amp;#x3C;,&apos;&gt;&lt;/code&gt;は自動で入力される) ... 短形選択部分をfilenameへ書き出し&lt;/li&gt;
&lt;li&gt;(visualモードで短形選択時)&lt;code&gt;y&lt;/code&gt; ... ヤンク(コピー)&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>TypeScriptでプロジェクト内独自の型定義をまとめたファイルを読み込ませる方法。</title>
      <link>https://memo.yammer.jp/posts/my-type-of-typescript</link>
      <pubDate>Fri, 15 May 2020 16:01:45 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/my-type-of-typescript</guid>
      <description>&lt;p&gt;TypeScriptでプロジェクト内の型定義をするときのための過去のメモをここに供養する。
日付は2020/1/10。&lt;/p&gt;
&lt;h2&gt;やりたいこと&lt;/h2&gt;
&lt;p&gt;TypeScriptで、独自の型定義をプロジェクト内の複数のファイルで利用したい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/types/index.d.ts&lt;/code&gt;で定義する型&lt;code&gt;DayOfWeek&lt;/code&gt;をはじめとして、&lt;code&gt;src/types&lt;/code&gt;ディレクトリ以下のファイルにある型定義をTypeScriptコンパイラに読み込ませて、プロジェクト内の任意のファイルで利用できるようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-typescript&quot;&gt;// src/types/index.d.ts
type DayOfWeek = &quot;Sunday&quot; | &quot;Monday&quot; | &quot;Tuesday&quot; | Wednesday&quot; | &quot;Tursday&quot; | &quot;Friday&quot; | Saturday&quot;; 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;方法&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;に次を追記する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;// tsconfig.json
{
  &quot;compilerOptions&quot;: {
    &quot;typeRoots&quot;: [
      &quot;node_modules/@types&quot;,
      &quot;src/types&quot;
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;内での&lt;code&gt;compilerOptions.typeRoots&lt;/code&gt;は文字列の配列をおく。&lt;/p&gt;
&lt;p&gt;文字列は型定義ファイルを置くディレクトリのパスを表す。&lt;/p&gt;
&lt;p&gt;もともと、npmでインストールしたパッケージの型定義は&lt;code&gt;node_modules/@types&lt;/code&gt;以下に配置され、&lt;code&gt;compilerOptions.typeRoots&lt;/code&gt;が定義されていないときはデフォルトで読み込まれる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;compilerOptions.typeRoots&lt;/code&gt;を記述する際には、自分の定義したい型ファイルのディレクトリと合わせて、デフォルトで読み込まれる型定義ファイルのパスも記述する必要がある。&lt;/p&gt;
&lt;h2&gt;発展して&lt;/h2&gt;
&lt;p&gt;逆に、インストールした型定義を無視したい時は、&lt;code&gt;compilerOptions.typeRoots&lt;/code&gt;に&lt;code&gt;node_modules/@types&lt;/code&gt;を除いて記述すれば良い。&lt;/p&gt;
&lt;p&gt;使うシチュエーションはあまりないかもしれないが。&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;TypeScriptは毎回完全理解()しているので、チョットデキル人間になるために一度ちゃんと学び直す必要がありそう。&lt;/p&gt;
&lt;p&gt;(この項目はメモをここに移したときに書いた)&lt;/p&gt;</description>
    </item>
    <item>
      <title>TELNETでHTTP通信する</title>
      <link>https://memo.yammer.jp/posts/telnet-http</link>
      <pubDate>Fri, 15 May 2020 15:43:55 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/telnet-http</guid>
      <description>&lt;p&gt;TELNETでHTTP通信するだけの記事である。
すぐ終わる。&lt;/p&gt;
&lt;p&gt;相手ホストやポート番号、手書きのHTTPヘッダを渡せば、 TELNET で HTTP 通信ができる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ telnet memo.yammer.jp 80
Trying 2400:6180:0:d1::4df:d001...
Connected to memo-basd4g-net.netlify.com.
Escape character is &apos;^]&apos;.
GET / HTTP/1.1
Host: memo.yammer.jp
Connection: close

HTTP/1.1 301 Moved Permanently
Cache-Control: public, max-age=0, must-revalidate
Content-Length: 40
Content-Type: text/plain
Date: Fri, 15 May 2020 15:46:22 GMT
Location: https://memo.yammer.jp/
Age: 2
Connection: close
Server: Netlify
X-NF-Request-ID: e38b7b4a-47e9-4306-8d60-e917e96c78cd-2547281

Redirecting to https://memo.yammer.jp/
Connection closed by foreign host.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6でつないでくれている。&lt;/p&gt;
&lt;p&gt;あいにく memo.yammer.jp は HTTP をリダイレクトしてしまうのでページの内容は取得できなかったが、通信できた。&lt;/p&gt;
&lt;p&gt;たまには HTTP ヘッダを手書きしてみるのも趣があるのではなかろうか。(??)&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;</description>
    </item>
    <item>
      <title>インターネットとTCP/IP</title>
      <link>https://memo.yammer.jp/posts/internet-tcpip</link>
      <pubDate>Fri, 15 May 2020 14:37:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/internet-tcpip</guid>
      <description>&lt;p&gt;今日のインターネットの根幹をなすTCP/IPについての基本的な知識を説明する。&lt;/p&gt;
&lt;p&gt;研究室の輪講で「マスタリングTCP/IP 入門編」を読んだことがきっかけ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参考文献: マスタリングTCP/IP入門編 第二章 pp60-80&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;インターネット&lt;/h2&gt;
&lt;p&gt;今この文章もインターネットに公開され、インターネットを介して見ていることと思うが、インターネットとはそもそも何を指すのか。&lt;/p&gt;
&lt;p&gt;Internet / The Internet とは、TCP/IPにより全世界を接続しているコンピュータネットワーク、ただ一つのことを指す。&lt;/p&gt;
&lt;p&gt;語源は「複数のネットワークを結ぶ」ことを表す internet。
現在ではこの意味は internet ではなく internetworking という言葉で表される。&lt;/p&gt;
&lt;h3&gt;インターネットの構造&lt;/h3&gt;
&lt;p&gt;インターネットは、小さなネットワークが相互接続し1つのネットワークを成し、これが複数接続して大きなネットワークを成し、、のように階層的な構造をもつ。&lt;/p&gt;
&lt;p&gt;ISP (Internet Service Provider) のネットワーク内では、NOC (Network Operation Center) と呼ばれる施設を通じて接続し、ネットワークを構成している。
ISP 同士の接続には、2者間接続を行うプライベートピアリングや、多数の ISP を IX (Internet Exchange) を通じてつなぐ IP トランジットがある。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-internet-construction.png&quot; alt=&quot;インターネットの構造&quot;&gt;&lt;/p&gt;
&lt;p&gt;画像はインターネットの構造を表した図。&lt;/p&gt;
&lt;p&gt;ISP 以外にも有志で運営される地域ネットといわれるネットワークも存在すると本に記載があるが、2020年現在の実態は不明。
過去にあった地域ネットとして&lt;a href=&quot;https://ja.wikipedia.org/wiki/%E6%9F%8F%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%83%A6%E3%83%8B%E3%82%AA%E3%83%B3&quot;&gt;柏インターネットユニオン&lt;/a&gt;などがあるようだ。&lt;/p&gt;
&lt;h2&gt;TCP/IP&lt;/h2&gt;
&lt;p&gt;TCP/IP とは、パケット交換プロトコルである IP (Internet Protocol) を利用したり、 IP で通信したりするときに必要なプロトコル群の総称のことである。
インターネットで必要なプロトコルをまとめたものであることから、インターネットプロトコルスイートとも言われる。
TCP/IP という語を使うとき、 TCP プロトコルと IP プロトコルだけを指しているわけではない。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-internet-protocol-suite.png&quot; alt=&quot;TCP/IP に含むプロトコルの一例&quot;&gt;&lt;/p&gt;
&lt;h3&gt;パケット交換ネットワーク&lt;/h3&gt;
&lt;p&gt;先程出てきたパケット交換について。
パケット交換ネットワークとは、電話に用いられるような回線交換型と対比されるネットワークの形式である。&lt;/p&gt;
&lt;p&gt;一つの回線を複数が共有して使う。
代表的な利点として、回線の利用効率を高められること、分散型のネットワークの構築に向くことが挙げられる。&lt;/p&gt;
&lt;h3&gt;TCP/IP の歴史&lt;/h3&gt;
&lt;p&gt;1960年代、米国防総省 (The Depertment of Defense) が中心に、分散型ネットワークによる通信技術の開発が行われた。
その中で学術機関4ノードを結ぶ、パケット交換の実用性を試験するための分散型ネットワーク ARPANET が誕生した。
ARPANET は急速に発展し、3年間で34ノードにまで拡大し、パケット交換によるデータ通信に実用性があることがわかった。&lt;/p&gt;
&lt;p&gt;その後、単なるパケット交換通信にとどまらず、各ノードのコンピュータ間での信頼性の高い通信手段を提供する総合的な通信プロトコルが実験、開発される。これがTCP/IPとなった。&lt;/p&gt;
&lt;p&gt;TCP/IP は当時普及していた OS である BSD UNIX に実装され、利用がさらに加速する。
ARPANET は拡大し、多数のネットワークと接続するようになる。
やがて ARPANET や後継の NSFnet に接続する TCP/IP による世界的なネットワークをインターネット (The Internet) と呼ぶようになった。&lt;/p&gt;
&lt;p&gt;1995年ごろには ISP (Internet Service Provider) が乱立し、インターネットの商用化が進む。
このような流れで今日に至り、世界中を TCP/IP によるネットワークであるインターネットが覆い尽している。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1960s DoD による通信技術の研究&lt;/li&gt;
&lt;li&gt;1969 ARPANET の誕生。パケット交換技術の開発&lt;/li&gt;
&lt;li&gt;1972 TCP/IP の誕生&lt;/li&gt;
&lt;li&gt;1975 TCP/IP の仕様決定と、 TCP/IP が実装された UNIX の提供&lt;/li&gt;
&lt;li&gt;1982 ARPANET でのプロトコルがTCP/IPに統一&lt;/li&gt;
&lt;li&gt;1989 LAN/WAN 上で TCP/IP が普及&lt;/li&gt;
&lt;li&gt;1995 インターネットの商用化が進む&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP/IP の標準化&lt;/h3&gt;
&lt;p&gt;TCP/IP はプロトコル群であり、通信のためには両者が同一のプロトコルを使用する必要がある。
そのためにTCP/IP にも標準が存在するが、 TCP/IP の標準化には次の2つの特徴があり、これがプロトコルの急速な実現と普及に影響した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;オープンである&lt;/li&gt;
&lt;li&gt;実用を重視する&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;特徴:オープンである&lt;/h4&gt;
&lt;p&gt;TCP/IP の仕様を議論する IETF (Internet Engineering Task Force) のメーリングリストには自由に参加できる。&lt;/p&gt;
&lt;p&gt;また仕様や実装も公開されており、自由にアクセスできることもオープンであるという特徴を表している。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-ietf-maling-list.png&quot; alt=&quot;IETF のWebページ&quot;&gt;&lt;/p&gt;
&lt;p&gt;画像は&lt;a href=&quot;https://www.ietf.org/how/lists/&quot;&gt;IETF のあるWebページ&lt;/a&gt;の冒頭部分である。
画像下部分に書かれているように、IETF の議論には、どんな個人でも参加できる。
このページの更に下に行くと、実際にメーリングリストに参加する手順が書かれていた。&lt;/p&gt;
&lt;h4&gt;特徴:実用を重視する&lt;/h4&gt;
&lt;p&gt;TCP/IP は仕様策定時に実装することを念頭において進む。
プロトコルの詳細仕様を決める際には既に通信できる実装が存在し、標準になる頃には既に製品に実装されている。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-tcpip-standardizatin.png&quot; alt=&quot;TCP/IP 標準化の手続き&quot;&gt;&lt;/p&gt;
&lt;p&gt;画像はTCP/IP 標準化の手続きを図示したものである。&lt;/p&gt;
&lt;p&gt;以上のように、TCP/IP の標準化手続きには特徴がある。
普及した要因に、他のプロトコルと比べ、実用を重視したことで動作するプロトコルをはやく作れたこと、オープンな仕様策定の仕組みにより急速な技術革新に対応できたことが考えられる。&lt;/p&gt;
&lt;h4&gt;TCP/IP の仕様&lt;/h4&gt;
&lt;p&gt;標準化しようとするプロトコルは RFC (Request For Comments) と呼ばれるドキュメントになり、&lt;a href=&quot;http://rfc-editor.org/rfc&quot;&gt;インターネット上で公開&lt;/a&gt;される。
仕様だけでなく、実装や運用、実験に関する情報を含む。&lt;/p&gt;
&lt;p&gt;RFC には番号をがつけられており、一度 RFC になると改定することはない。
拡張や廃止、新規のプロトコルを定める際には新たな RFC として公開される。
そのため通し番号は大きくなり、プロトコルごとに番号の統一性があるわけでもないので人間にはわかりづらいところがある。
これを助けるため、複数の RFC を指す STD (STanDard), FYI (For Your Information) などの文書単位もある。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-rfc2616.png&quot; alt=&quot;rfc2616の冒頭&quot;&gt;&lt;/p&gt;
&lt;p&gt;画像は &lt;a href=&quot;https://tools.ietf.org/html/rfc2616&quot;&gt;RFC2617&lt;/a&gt; の冒頭である。&lt;/p&gt;
&lt;h3&gt;TCP/IP の階層モデル&lt;/h3&gt;
&lt;p&gt;TCP/IP モデルは階層構造になっている。
ネットワークの信頼のある通信を実現するには様々な機能を実装せねばならないので、各層に分けて他層を抽象化することが現実的には必須。&lt;/p&gt;
&lt;p&gt;TCP/IP が普及した理由の一つに柔軟性が挙げられる。
IP が動作すればそれより下位層は何を使ってもよいし、 TCP / UDP 上で動作すればそれより上位のアプリケーションはなんでもよいのである。&lt;/p&gt;
&lt;p&gt;以下では、 OSI 参照モデルと TCP/IP 階層モデルの対応を示した後、下位層から順に、代表的なプロトコルを示す。&lt;/p&gt;
&lt;h4&gt;OSI 参照モデルとの対応&lt;/h4&gt;
&lt;p&gt;TCP/IP の階層モデルは、アプリケーション層、トランスポート層、インターネット層、リンク層の4階層から成る。
OSI 参照モデル7階層に完全に対応するものではないが、対応するとしたらつぎのようになる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-tcpip-protocol-stack.png&quot; alt=&quot;OSI 参照モデルと TCP/IP 階層モデルの対応&quot;&gt;&lt;/p&gt;
&lt;h4&gt;ハードウェア&lt;/h4&gt;
&lt;p&gt;OSI 参照モデルで物理層に当たる部分である。&lt;/p&gt;
&lt;p&gt;ハードウェアついては、 TCP/IP プロトコルでは特に指定されていない。
通信する上での信頼性、セキュリテイ、帯域、遅延、無線/有線、電話回線やイーサネットなど、物理的なものには拘束されず、ネットワークで接続された装置間で通信できればよい。&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;余談だが、 TCP/IP におけるハードウェアとして伝書鳩を用いることもできる。
RFC にも、&lt;a href=&quot;https://tools.ietf.org/html/rfc1149&quot;&gt;RFC1149 鳥類キャリアによるIPデータグラムの伝送企画&lt;/a&gt;としてきちんと仕様が存在する。&lt;/p&gt;
&lt;p&gt;これはエイプリルフールに作られたようだが、このような&lt;strike&gt;ふざけた&lt;/strike&gt;お茶目な RFC はジョーク RFC と呼ばれ、他にも次のようなものがある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2322&quot;&gt;RFC2322 洗濯バサミDHCPによるIPアドレスの管理手法&lt;/a&gt;(&lt;a href=&quot;http://www.kt.rim.or.jp/~ksk/joke-RFC/rfc2322j.txt&quot;&gt;邦訳&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc2324.txt&quot;&gt;RFC2324 ハイパーテクストコーヒーポット制御プロトコル&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;等。 鳩を用意するのは厳しいが、後者2つは実装してみたい気もする。&lt;/p&gt;
&lt;hr/&gt; 
&lt;h4&gt;リンク層&lt;/h4&gt;
&lt;p&gt;ネットワークインタフェース層とも。(マスタリングTCP/IP入門編より)&lt;/p&gt;
&lt;p&gt;デバイスドライバが実装にあたる。(マスタリングTCP/IP入門編より)
ハードウェアの違いを吸収し、上位層で IP が使えるようにする。&lt;/p&gt;
&lt;p&gt;PPP (Point to Point Protocol) もここに含まれる。&lt;/p&gt;
&lt;h4&gt;インターネット層&lt;/h4&gt;
&lt;p&gt;OSI 参照モデルの下から3番目であるネットワーク層に対応する。&lt;/p&gt;
&lt;p&gt;経路制御を行う。
通信したいホスト間のデータリンクを上位層へ隠し、実際は Hop-by-Hop で行われている通信を End-to-End で行われているようにみせる役割がある。&lt;/p&gt;
&lt;p&gt;代表的な3つのプロトコルを紹介する。&lt;/p&gt;
&lt;h5&gt;IP (Internet Protocol)&lt;/h5&gt;
&lt;p&gt;パケットを転送するために用いられる、インターネット層で代表的なプロトコル。
IP アドレスでホストを識別し、通信相手までパケットを配送する。
通信経路の確立を行うが、データが正しく送られる保証はない。&lt;/p&gt;
&lt;h5&gt;ICMP (Internet Control Message Protocol)&lt;/h5&gt;
&lt;p&gt;IP によるパケット転送に誤りがあったり、失敗したときにこれを通知するために用いられる。
他に、ネットワークが正常に通信できるか診断する機能ももつ。
ping コマンドや traceroute コマンドなどは ICMP パケットを送信することで実現している。&lt;/p&gt;
&lt;h5&gt;ARP (Address Resolution Protocol)&lt;/h5&gt;
&lt;p&gt;IP アドレスと MAC アドレスの対応関係を取得するためのプロトコル。IP が目的地へ通信するために、ARP を用いて途中の各通信経路の解決が行われる。&lt;/p&gt;
&lt;h4&gt;トランスポート層&lt;/h4&gt;
&lt;p&gt;OSI 参照モデルの下から4番目であるトランスポート層に対応する。
アプリケーション間のプログラムの通信を実現し、場合によってはデータの到達性も保証する。&lt;/p&gt;
&lt;h5&gt;TCP (Transmission Control Protocol)&lt;/h5&gt;
&lt;p&gt;コネクション型のプロトコル。
データの到達性を保証し、再送制御や輻輳制御を行う。
コネクションの確立に3パケット、切断に4パケットの通信が少なくとも必要である。&lt;/p&gt;
&lt;h5&gt;UDP (User Datagram Protocol)&lt;/h5&gt;
&lt;p&gt;コネクションレス型のプロトコル。
データの到達性を保証しない。
パケット数の少ない通信、2者間ではないブロードキャスト/マルチキャスト通信, データが多少抜け落ちても問題ない動画や音声の通信に向く。&lt;/p&gt;
&lt;h4&gt;アプリケーション層&lt;/h4&gt;
&lt;p&gt;OSI 参照モデルの5-7階層に相当する。
TCP/IP上では様々なアプリケーションを動かすことができる。
以下では、それぞれのアプリケーションごとに使われるプロトコルを紹介する。&lt;/p&gt;
&lt;h5&gt;WWW (World Wide Web)&lt;/h5&gt;
&lt;p&gt;HTML (Hyper Text Markup Language) 文書をはじめとするデータを、Webブラウザを介して HTTP (Hyper Text Transfer Protocol) / HTTPS ( - Secure) で受信し閲覧する。&lt;/p&gt;
&lt;p&gt;(QUIC などの例外を除いて)主に TCP 上で動作する。&lt;/p&gt;
&lt;h5&gt;電子メール&lt;/h5&gt;
&lt;p&gt;MIME (Multipurpose Internet Mail Extensions) (マイム)形式のデータを、専用のプロトコルを用いて送受信する。&lt;/p&gt;
&lt;p&gt;メールの送受信には SMTP (Simple Mail Transfer Protocol), POP3 (Post Office Protocol version 3), IMAP (Internet Message Access Protocol)などが用いられる。&lt;/p&gt;
&lt;p&gt;送信者はメールを SMTP サーバを経由して相手方の POP3 / IMAP サーバへ送信する。
受信者は POP3 / IMAP サーバよりメールを受け取る。&lt;/p&gt;
&lt;p&gt;TCP 上で動作する。&lt;/p&gt;
&lt;h5&gt;ファイル転送&lt;/h5&gt;
&lt;p&gt;FTP (File Transfer Protocol) / SFTP (Secure - )によりファイルを送受信する&lt;/p&gt;
&lt;p&gt;TCP 上で動作する。&lt;/p&gt;
&lt;h5&gt;遠隔ログイン&lt;/h5&gt;
&lt;p&gt;TELNET (TELetypewriter NETwork) や SSH (Secure SHell) を用いて離れたコンピュータにログインする。&lt;/p&gt;
&lt;p&gt;Linux で GUI を実現するためによく用いられる X Window System の X Protocol も TCP/IP 上で実現している。&lt;/p&gt;
&lt;p&gt;TELNET や SSH 等は TCP 上で動作する。
X Protocol の中でも XDMCP (X Display Manager Control Protocol) は UDP。&lt;/p&gt;
&lt;h5&gt;ネットワーク管理&lt;/h5&gt;
&lt;p&gt;SNMP (Simple Network Management Protocol) など。&lt;/p&gt;
&lt;p&gt;ネットワーク上のルータやスイッチなどの管理対象(SNMP エージェント)を管理端末(SNMP マネージャ)が管理する。
パケットの量や機器の温度などを管理できる。
ネットワーク機器の動作を妨げないため、また通信に必要なパケットが少ないため、UDP で動作する。&lt;/p&gt;
&lt;h3&gt;実際の通信&lt;/h3&gt;
&lt;p&gt;通信を行う際、送信側は上位層から順にその層で必要となる管理情報を含むヘッダを付加してカプセル化する。
受信側は下位層から順にヘッダを解釈して除去し上位層に渡す。&lt;/p&gt;
&lt;p&gt;例えばWebページを閲覧する際は、サーバ側で HTML 文書に HTTP ヘッダを付加し、  TCP ヘッダを付加し、 IP ヘッダを付加し、イーサネットフレームのヘッダを付加し送信される。
クライアントはイーサネットフレームのヘッダを解釈し、 IP ヘッダを解釈し、 TCP ヘッダを解釈し、 HTTP ヘッダを解釈し、 HTML 文章を画面に描画する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/internet-tcpip-encapsulation.png&quot; alt=&quot;実際の通信のカプセル化&quot;&gt;&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;以上の内容をまとめると次のようになる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;インターネットは TCP/IP で接続される世界全体のネットワークのこと&lt;/li&gt;
&lt;li&gt;TCP/IP は IP をはじめとするプロトコル群&lt;/li&gt;
&lt;li&gt;TCP/IP はオープンな議論で, 実用重視の仕様策定を行っている&lt;/li&gt;
&lt;li&gt;TCP/IP の各プロトコルは階層モデルでわけることができる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ネットワーク全体について俯瞰して振り返ることはあまりないので、スライドを作ったのに合わせて文章にも起こしてみた。
こういった復習を多く含む地道な勉強も、怠らずにやっていきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) 不要な改行タグを削除&lt;/p&gt;</description>
    </item>
    <item>
      <title>就活を終えて半年経って思うこと。</title>
      <link>https://memo.yammer.jp/posts/job-hunting-6-month-ago</link>
      <pubDate>Wed, 13 May 2020 14:54:22 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/job-hunting-6-month-ago</guid>
      <description>&lt;p&gt;進路を迷っている知人に就活のことを聞かれ、自分が何を考えて決めたのかを、主に次の視点で綴ったので、ここにも記します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;就職先の決め手&lt;/li&gt;
&lt;li&gt;なぜエンジニアとして働くのか&lt;/li&gt;
&lt;li&gt;なぜ大学院に進学しなかったのか&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;就職先の決め手&lt;/h2&gt;
&lt;p&gt;就活時に重視していたところはつぎのようなことがあります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文化&lt;/li&gt;
&lt;li&gt;技術的な成長&lt;/li&gt;
&lt;li&gt;会社のサービスに自分が貢献したいと思えるか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;会社を決めた理由は、ざっくりまとめると「自分が最も成長できそうだから」でしょうか。
就職予定の会社は、独特の企業文化が特徴です。これが自分が働くモチベーション高く保つことにつながると考えました。
技術が身につく環境でも、自分に合わない環境で働くのは長続きしないでしょう。しかしこの会社でなら正直に過ごせそう、自分が成長の努力をしながら楽しんで働けそうだと感じたからです。&lt;/p&gt;
&lt;p&gt;新卒時点の給料はそこまで重視していなくて、技術が身につけばいくらでも給料を高められるだろうから、自分が成長できること(長期的に見て稼げること)のほうが大事だと考えていました。&lt;/p&gt;
&lt;p&gt;あとは、会社規模も関係しています。決めた会社は社内のエンジニアコミュニティが強く、その中で高めあっているところが魅力に写りました。&lt;/p&gt;
&lt;p&gt;他に受けていた会社で、エンジニアが数人ほどの企業もあったのですが、私の技術的な未熟さゆえに選考を断念しました。
(極端に言うと幅広い技術や一歩先の技術を身につける余裕を自分に持てないのではないかとの懸念がありました。)
規模が小さいほうが裁量があったり、ビジネスサイドにも足をつっこんだりしやすい側面はありそうです。この魅力を重視する方は私とは違う決断をするでしょう。)&lt;/p&gt;
&lt;p&gt;逆にもっと大きな会社だと、細分化されすぎていて私には楽しくないようにみえました。(エンジニアリングに関してはいろんなことに足を突っ込んでみたい。)
会社規模は選考がある程度進んでから、比較するようになって考えだしました。&lt;/p&gt;
&lt;h2&gt;エンジニアになるかどうか&lt;/h2&gt;
&lt;p&gt;私はわりと初期の段階でWebエンジニアに絞ってしまっていました。とりあえず行動してみて、納得できなければ変えるつもりでしたが、働くイメージが湧いてきたのでそのまま方向を変えずに就活をつづけました。&lt;/p&gt;
&lt;p&gt;自分がどれだけ技術を好きになれるか、勉強を苦に思わないかが自分の中での判断基準です。世の中には自分よりコンピュータが好きな人はたくさんいるし、上を見たらきりはないので、現時点での技術力と熱意が他人に負けているからダメという選び方はしていません。
私にとって、他の仕事よりWebエンジニアとして働いたほうが、仕事を楽しめてかつ社会に出せる価値が多そうだと判断し決めました。&lt;/p&gt;
&lt;p&gt;(Web)エンジニアになるのはある意味賭けで、専門的な技術は身につくけど、いざとなれば転職で入ってこれる業界でもあるので、難しいですね。&lt;/p&gt;
&lt;p&gt;エンジニアといっても、ビジネスやデザインのわかるエンジニア、他方、技術に尖ったエンジニアをより欲しているところ、育てようとしているところはたくさんあるだろうし、非常に多種多様な姿があるだろうから、自分にあったキャリアを見つけるのは大変でしょう。さらに世の中には本当に様々な仕事があり、Webエンジニア、プログラマーだけをを見ているのは勿体無いかもしれません。&lt;/p&gt;
&lt;p&gt;私なりにいくつかの選択肢を考える中で、自分に興味のある領域を深められる職・会社としていまの進路を選びました。&lt;/p&gt;
&lt;h2&gt;大学院に行くかどうか&lt;/h2&gt;
&lt;p&gt;就活を始めるときに、内心「良さげな企業に受かったら就職、うまく行かなかったら院にいこうか」と考えましたが、まず「とりあえず就職前提で動こう」(じゃないと何もしなそう)と自分に言い聞かせました。&lt;/p&gt;
&lt;p&gt;就活をしていくうちに、良い会社に出会えたこと、(まだ始まっていなかったが)大学での研究よりもWeb周りのことを触っている方が楽しいだろうと思ったことから就職へ傾きました。
内心、面接が重なると早く就活を抜け出したい、(院卒で)もう一回やるのはちょっと大変という気持ちもありました。
就活は真剣にキャリアを考える機会として面白い面もあるのですが、続けていると気持ちが疲れてくる面もあります。&lt;/p&gt;
&lt;p&gt;いまの会社に受かってなければ大学院に進学していたかもしれません。
真っ当な理由「研究がしたい」 はもちろん、就活を先延ばしにする意味でも大学院進学もありだったなとは今も思ってます。(院卒に怒られる)。&lt;/p&gt;
&lt;p&gt;Web業界は新卒といえど、(私は経験ないですが)長期インターンに行っている人が結構いたり、ある程度の技術的素養が求められている会社もそこそこあるので、就活が先延ばしになると受かりやすくなる面はあるかもしれません。
(どこかで読みましたがインターンに受かるコツはインターンに受かることだそうです。)
大学院に進学すれば、インターンなどに参加する時間的な猶予ができるともとれます。&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;つたない文章ですが、私が考えていたことを思い返してみました。&lt;/p&gt;
&lt;p&gt;就活をはじめてから、自分がどんな価値を見いだせるか、どんな環境で働きたいか、あらためて何度も考えました。
特に面接や面談はその考えが深まる、改まる場であって、このような機会を設けてくださった方々に感謝しています。&lt;/p&gt;</description>
    </item>
    <item>
      <title>(余談) User Defaultsとproperty list(plist)</title>
      <link>https://memo.yammer.jp/posts/plist</link>
      <pubDate>Sat, 02 May 2020 07:26:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/plist</guid>
      <description>&lt;p&gt;Mac OS XのUser Defaultsを変更するためのシェルスクリプトを作るツール &lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;pdef&lt;/a&gt;を制作した。(解説記事: &lt;a href=&quot;/posts/pdef/&quot;&gt;Macの設定を自動化するdefaultsコマンドと、それを助けるpdef&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;これを作る際にProperty listについて学んだことを記す。&lt;/p&gt;
&lt;h2&gt;User Defaults&lt;/h2&gt;
&lt;p&gt;User Defaultsは、MacOSXやiOSにおける各アプリケーションが設定などを保持するためのデータベースである。
User Defaultsは、各アプリケーション(正確にはアプリケーションの持つドメイン)ごとにProperty listとして記録される。
普段は各アプリケーションを通して読み書きされるが、ターミナル上からアクセスできる&lt;code&gt;$ defaults&lt;/code&gt;コマンドも提供されている。(後述)&lt;/p&gt;
&lt;h2&gt;Property list&lt;/h2&gt;
&lt;p&gt;User Defaultsに使われているproperty list(以下plist)は、Mac OS Xにおいてオブジェクトの永続化におけるファイル形式としてよく用いられている。
例えば、iOSアプリを開発する際に自動生成されてXcode上から見える&lt;code&gt;info.plist&lt;/code&gt;がその例だ。&lt;/p&gt;
&lt;p&gt;plistはNeXTSTEP時代から続く歴史あるフォーマットらしい。時代背景も相まってファイルの保存形式は多数ある(後述)。&lt;/p&gt;
&lt;h3&gt;論理構造&lt;/h3&gt;
&lt;p&gt;plistはJSON等と同様のキーバリュー形式の論理構造を取る。
キーに一対一対応する値が存在し、値は即値の他に入れ子状にデータを保持できる。&lt;/p&gt;
&lt;p&gt;値のとりうる型は次の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;辞書(dictionary)&lt;/li&gt;
&lt;li&gt;配列(array)&lt;/li&gt;
&lt;li&gt;文字列(string)&lt;/li&gt;
&lt;li&gt;数値(number(integer and float))&lt;/li&gt;
&lt;li&gt;日付(date)&lt;/li&gt;
&lt;li&gt;バイナリ(binary data)&lt;/li&gt;
&lt;li&gt;真偽値(Boolean value)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この中でも辞書型と配列型は特殊で、辞書型はキーと値の組を、配列型は値を、子にもつことができる。&lt;/p&gt;
&lt;p&gt;JSONに無い型(日付,バイナリ)が存在するので、完全な相互変換は不可。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/PropertyList.html&quot;&gt;Property list - Apple Developper Documentation&lt;/a&gt; (plist関する公式のドキュメント)&lt;/p&gt;
&lt;h3&gt;保存形式&lt;/h3&gt;
&lt;h4&gt;old-style ASCII形式&lt;/h4&gt;
&lt;p&gt;テキストベースで、可読性が高いのがこの形式。NeXT形式とも呼ばれる?。NeXTSTEP時代にできた。
作られた当時、文字列、配列、ディクショナリ、そしてバイナリデータのみを表現できたらしい。
シンプルなフォーマットであるが、型情報がなく、型の判別が難しい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ defaults read&lt;/code&gt;コマンドで出力される形式であり、現在では主にここでみられる。&lt;/p&gt;
&lt;p&gt;old-style ASCII形式の例として、あるplistをold-style ASCIIで表した表記を以下に示す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;{
    &quot;boolean-example&quot; = 0;
    fuga =     {
        p0y0p0y0 = 0;
        punipuni = value;
    };
    hoge = helloworld;
    wara =     (
        {length = 8, bytes = 0x0123456789abcdef},
        123,
        &quot;0.5&quot;,
        1,
        &quot;2019-09-16 05:45:42 +0000&quot;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;XML形式&lt;/h4&gt;
&lt;p&gt;plistのデータ構造をXML形式で表現した形式。
前述のold-style ASCIIのように欠けた情報がなく、なおかつ人間にも読めるのでplistをこねくり回す際にはお世話になるだろう。&lt;/p&gt;
&lt;p&gt;それぞれの型におけるxml上での表記は次の通り&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;辞書: &lt;code&gt;&amp;#x3C;dict&gt; &amp;#x3C;key&gt;keystring&amp;#x3C;/key&gt; [value] (繰り返し) &amp;#x3C;/dict&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;配列: &lt;code&gt;&amp;#x3C;array&gt; [vaule] (繰り返し) &amp;#x3C;/array&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;文字列: &lt;code&gt;&amp;#x3C;string&gt;value&amp;#x3C;/string&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;数値(整数): &lt;code&gt;&amp;#x3C;integer&gt;124234&amp;#x3C;/integer&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;数値(浮動小数点数): &lt;code&gt;&amp;#x3C;real&gt;0.43&amp;#x3C;/real&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;日付: &lt;code&gt;&amp;#x3C;date&gt;2019-09-16T05:45:42Z&amp;#x3C;/date&gt;&lt;/code&gt; (ISO8601と思われる)&lt;/li&gt;
&lt;li&gt;バイナリ: &lt;code&gt;&amp;#x3C;data&gt; ASNFZ4mrze8= &amp;#x3C;/data&gt;&lt;/code&gt; (base64でエンコード済みの文字列)&lt;/li&gt;
&lt;li&gt;真偽値: &lt;code&gt;&amp;#x3C;true/&gt;&lt;/code&gt;または&lt;code&gt;&amp;#x3C;false/&gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;XML形式の例として、先程示したplistをXMLで表した表記を以下に示す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot;&gt;&amp;#x3C;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&amp;#x3C;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&amp;#x3C;plist version=&quot;1.0&quot;&gt;
&amp;#x3C;dict&gt;
  &amp;#x3C;key&gt;hoge&amp;#x3C;/key&gt;
  &amp;#x3C;string&gt;helloworld&amp;#x3C;/string&gt;
  &amp;#x3C;key&gt;boolean-example&amp;#x3C;/key&gt;
  &amp;#x3C;false/&gt;
  &amp;#x3C;key&gt;wara&amp;#x3C;/key&gt;
  &amp;#x3C;array&gt;
    &amp;#x3C;data&gt;
    ASNFZ4mrze8=
    &amp;#x3C;/data&gt;
    &amp;#x3C;integer&gt;123&amp;#x3C;/integer&gt;
    &amp;#x3C;real&gt;0.5&amp;#x3C;/real&gt;
    &amp;#x3C;true/&gt;
    &amp;#x3C;date&gt;2019-09-16T05:45:42Z&amp;#x3C;/date&gt;
  &amp;#x3C;/array&gt;
  &amp;#x3C;key&gt;fuga&amp;#x3C;/key&gt;
  &amp;#x3C;dict&gt;
    &amp;#x3C;key&gt;punipuni&amp;#x3C;/key&gt;
    &amp;#x3C;string&gt;value&amp;#x3C;/string&gt;
    &amp;#x3C;key&gt;p0y0p0y0&amp;#x3C;/key&gt;
    &amp;#x3C;string&gt;0&amp;#x3C;/string&gt;
  &amp;#x3C;/dict&gt;
&amp;#x3C;/dict&gt;
&amp;#x3C;/plist&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;binary形式&lt;/h4&gt;
&lt;p&gt;テキストベースではなく人間が用意に読めなくした代わりに、ファイルサイズの削減と読み書きを高速化ができる形式。&lt;/p&gt;
&lt;p&gt;ここまでで述べたようにplistはバイナリデータも含むことができる。
そのため、大きなバイナリデータを含むplistについては、old-style ASCIIやxmlでの表現は冗長で、ファイルが大きくなる、読み書きが遅くなるなどの問題が生まれる。
これを避けるためにバイナリ形式でデータを書き出すことができる。具体的な形式は未調査。&lt;/p&gt;
&lt;p&gt;おそらくあまり出会うことはないが、バイナリ形式には現在使われていない古い別形式もあるらしい。&lt;/p&gt;
&lt;p&gt;参考:  Plistの歴史&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.itmedia.co.jp/enterprise/articles/0705/14/news013_2.html&quot;&gt;第3回 plist（プロパティリスト）とFoundation【前編】 - ITmedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.itmedia.co.jp/enterprise/articles/0705/30/news011.html&quot;&gt;第4回 plist（プロパティリスト）とFoundation【後編】 - ITmedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;plistを操作できるデフォルトツール&lt;/h3&gt;
&lt;p&gt;plistを検証、確認、変更するコマンドラインツールが、Mac OS Xにはデフォルトでいくつか入っている。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;defaults&lt;/code&gt;, &lt;code&gt;pl&lt;/code&gt;, &lt;code&gt;plutil&lt;/code&gt;, &lt;code&gt;/usr/libexec/PlistBuddy&lt;/code&gt;を紹介する。&lt;/p&gt;
&lt;h4&gt;defaults&lt;/h4&gt;
&lt;p&gt;User Defaultsを読み書きするためのツール&lt;/p&gt;
&lt;p&gt;代表的な&lt;code&gt;read&lt;/code&gt;,&lt;code&gt;write&lt;/code&gt;,&lt;code&gt;import&lt;/code&gt;,&lt;code&gt;export&lt;/code&gt;のハマりどころを記す。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$ defaults read&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&quot;ほぼ&quot;old-style ASCII形式で、User Defaultsを標準出力に出力する。
old-style ASCIIには型情報を含まないので、型のみを調べる&lt;code&gt;$ defaults read-type&lt;/code&gt;もある。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;出力は正しい文法のold-style ASCII形式のplistとは限らない。大きなサイズのdata型の値は、一部省略して出力され、この部分は文法規則に反する。&lt;/strong&gt;
(これが原因で最初plistを正しく読み込めずに困った)&lt;/p&gt;
&lt;p&gt;readの後ろに引数を渡さないとすべてドメインのUser Defaultsを出力する。
1コマンドでまとめて出力できるのは筆者の知る限り&lt;code&gt;$ defaults read&lt;/code&gt;のみ。&lt;/p&gt;
&lt;p&gt;ネストしている深い値を指定して読むことはできない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$ defaults write&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;引数にで値を指定して、User Defaultsに書き込める。
型を区別するオプションを指定できる。&lt;/p&gt;
&lt;p&gt;data型は&lt;code&gt;-data&lt;/code&gt;オプションをつけた上で、valueを16進数表記で記述する。&lt;/p&gt;
&lt;p&gt;date型は&lt;code&gt;-date&lt;/code&gt;オプションをつけた上で、valueをISO8601形式で記述する。&lt;/p&gt;
&lt;p&gt;ネストしている深い値を指定して書き込むことはできない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$ defaults export&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特定のドメインのUser Defualtsをxml形式またはバイナリ形式で出力する。&lt;/p&gt;
&lt;p&gt;ドメインは必ず指定する必要があり、&lt;code&gt;$ defaults read&lt;/code&gt;のようにすべてのドメインのUser Defaultsを一括して出力することはできない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$ defaults import&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;xml形式またはバイナリ形式でUser Defaultsに書き込める。&lt;/p&gt;
&lt;h4&gt;pl&lt;/h4&gt;
&lt;p&gt;old-style ASCII形式のplistの文法をチェックするツール。&lt;/p&gt;
&lt;h4&gt;plutil&lt;/h4&gt;
&lt;p&gt;XML,binary形式のplistの文法をチェックするツール。&lt;/p&gt;
&lt;p&gt;値の読み書き/削除ができるが、深いネストしている深い値を指定して操作することはできない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/trakwkbys/items/a94c4d43342e96352bde&quot;&gt;コマンドラインでplistを操作（データ追加・編集・削除） - Qiita(@trakwkbys)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;/usr/libexec/PlistBuddy&lt;/h4&gt;
&lt;p&gt;ネストしている深い値を直接指定して読み書き/削除できるスグレモノ。&lt;/p&gt;
&lt;p&gt;data型を書き込むときは、文字列がそのままbyte列として読み込まれるらしい。
よって書き込める値が制限される。
ネストが深い場所にあるdata型の値を書き込む際は、xmlファイルに直接base64エンコードした文字列を書き込むなどすると良い。&lt;/p&gt;
&lt;p&gt;date型を書き込むときは、&lt;code&gt;Mon Apr 20 20:52:00 2020 JST&lt;/code&gt;のような形式を渡す。
(PlistBuddyのdata型の値書き込みに関するドキュメントは見つけられなかったが、&lt;a href=&quot;https://github.com/darlinghq/darling/blob/master/src/PlistBuddy/PlistBuddy.c&quot;&gt;darling&lt;/a&gt;の実装を参考にして実験し見つけた。)&lt;/p&gt;
&lt;h2&gt;plistファイルを読み書きする際の、Swiftでの実装&lt;/h2&gt;
&lt;p&gt;今回作成した&lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;pdef&lt;/a&gt;において、Swiftでplistを扱う際に肝になった部分を実装を交えて紹介する。&lt;/p&gt;
&lt;p&gt;ちなみにPythonでは&lt;a href=&quot;https://docs.python.org/ja/3/library/plistlib.html&quot;&gt;plistlib&lt;/a&gt;が使えるようだ。&lt;/p&gt;
&lt;h3&gt;plistファイル全体をNSDictionaryとして読み込む&lt;/h3&gt;
&lt;p&gt;plistファイルをSwiftの変数として扱えるように取り込むのは非常に簡単。
下記のサンプルコードのように一行で読み込める。&lt;/p&gt;
&lt;p&gt;ファイル形式がold-style ASCIIだろうがxmlだろうがbinaryだろうが、勝手に判断してよしなにしてくれる。
(ただし&lt;a href=&quot;#defaults&quot;&gt;ハマりどころ&lt;/a&gt;に注意)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-swift&quot;&gt;// https://github.com/yammerjp/pdef/blob/516f0215306b6ca206ebad646190ba74bd5d4b17/src/loadFile.swift
// 以上より一部抜粋

import Foundation

guard let plist = NSDictionary(contentsOfFile: path) else {
  ErrorMessage(&quot;Failed to load property list &apos;\(path)&apos;&quot;)
  exit(1)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pdefをSwiftで実装したのはplistを扱うのが楽だろうからという目論見だったが、それが一番功を奏したのがこの部分。&lt;/p&gt;
&lt;h3&gt;型を判別する&lt;/h3&gt;
&lt;p&gt;上記の方法でplistファイルをSwift内の変数として読み込んでも、型はすべてAnyとして扱われてしまう。
これは困るので、値を次のサンプルコードの関数&lt;code&gt;GetPlistType(value: Any) -&gt; PlistType&lt;/code&gt;に与えることで型を調べられる。
型がわかればキャストできるので、その後Swiftで扱うのが楽になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-swift&quot;&gt;// https://github.com/yammerjp/pdef/blob/516f0215306b6ca206ebad646190ba74bd5d4b17/src/plist.swift
// 以上より一部抜粋、書き換え

import Foundation

enum PlistType: Int {
  case string
  case real
  case integer
  case bool
  case data
  case date
  case array
  case dict
}

func GetPlistType(value: Any) -&gt; PlistType {
  let typeID = CFGetTypeID(value as CFTypeRef?)
  switch typeID {
  case CFNumberGetTypeID():
    if value is NSInteger {
      return .integer
    }
    return .real
  case CFArrayGetTypeID():
    return .array
  case CFDictionaryGetTypeID():
    return .dict
  case CFStringGetTypeID():
    return .string
  case CFDataGetTypeID():
    return .data
  case CFDateGetTypeID():
    return .date
  case CFBooleanGetTypeID():
    return .bool
  default:
    exit(1)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/corefoundation/cftypeid&quot;&gt;CFTypeID - Apple Developper Documantation&lt;/a&gt;(Property listの型をSwiftで判別する)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/junpluse/items/e334e511457f8c133de9&quot;&gt;Swift.Any as? CFType - Qiita(@junpluse)&lt;/a&gt;(Property listの型をSwiftで判別する)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/Inspecting.html&quot;&gt;Inspecting Objects - Apple Developper Docuumentation&lt;/a&gt;(Property listの型をSwiftで判別する)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;おわりに&lt;/h2&gt;
&lt;p&gt;Swiftでplistを扱うための情報を集めるのに時間がかかったので、まとめる記事を書くに至った。&lt;/p&gt;
&lt;p&gt;この記事は&lt;a href=&quot;/posts/pdef/&quot;&gt;Macの設定を自動化するdefaultsコマンドと、それを助けるpdef&lt;/a&gt;(pdefの紹介記事)の余談と補足として作った。
ここまでの内容を実装して作った、User Defaults書き換えを支援するツールである&lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;pdef&lt;/a&gt;も興味があれば使ってみてほしい。&lt;/p&gt;
&lt;p&gt;User DefaultsだけでなくProperty listをSwiftで扱う際に、どこから手をつけてよいかわからない人が概要を掴むのにこの記事が役立てば幸いだ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) pdefの記事へのリンクを相対リンクに修正&lt;/p&gt;</description>
    </item>
    <item>
      <title>Macの設定を自動化するdefaultsコマンドと、それを助けるpdef</title>
      <link>https://memo.yammer.jp/posts/pdef</link>
      <pubDate>Thu, 30 Apr 2020 15:52:47 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/pdef</guid>
      <description>&lt;p&gt;tl;dr Mac OS XのUser Defaultsの差分をdefaultsコマンドの形式に変換するコマンドラインツール、&lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;&quot;pdef&quot;&lt;/a&gt;を作った。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#pdef%E3%81%A7%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B&quot;&gt;本題(pdefでシェルスクリプトを作る)まで飛ばす&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;defaultsコマンドでMacの設定を自動化する&lt;/h2&gt;
&lt;p&gt;Macには、OSや各アプリの設定を保存するUser Defaultsというデータベースがある。
例えばドックの大きさやメニューバーに表示するアイコン、Safariの開発者ツールの有効化フラグ、(使用している場合は)サードパーティ製アプリケーションの設定情報なども記録されている。&lt;/p&gt;
&lt;p&gt;これらのUser Defaultsの項目は普通、GUI上の設定画面を変更することでデータを読み書きするが、ターミナル上から操作するdefaultsコマンドなるものもMacに標準で入っている。&lt;/p&gt;
&lt;p&gt;これを用いることで、Macの初期設定を自動化するシェルスクリプトがよく作られているようだ。&lt;/p&gt;
&lt;p&gt;たとえば、次のスクリプトは、Finder(ファイラー)において、隠しファイル・隠しフォルダを表示する設定を有効にする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash
defaults write com.apple.finder AppleShowAllFiles YES
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(スクリプト実行後に&lt;code&gt;$ killall Finder&lt;/code&gt;としてアプリケーションを再起動する必要がある。)&lt;/p&gt;
&lt;p&gt;このようなdefaultsコマンドによる設定例はブログなどで見つけることができる。
それらをまとめて自分用のシェルスクリプトを作っておけば、Macを初期設定する際にすぐに自分好みの環境にすることができるというわけだ。&lt;/p&gt;
&lt;p&gt;GUIからの設定は項目が増えると手間がかかるし同じ環境を再現するのは大変なので、自動化できるのはありがたい。&lt;/p&gt;
&lt;p&gt;様々なdefaultsコマンドの一例を記載したサイト&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://neos21.hatenablog.com/entry/2019/01/10/080000&quot;&gt;MacOS で設定する defaults コマンドをまとめてみた - Corredor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/ry0f/items/f2c75f0a77b1012182d6&quot;&gt;OS X を自分色に染める w/ defaults - Qiita(@ry0f)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/idtkb/items/68c44c6f7ba1e15924bb&quot;&gt;Macの環境設定 - Qiita(@idtkb)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/dotfiles/blob/master/.macos&quot;&gt;.macos - GitHub(mathiasbynens/dotfiles)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;defaultsコマンドの引数を調べる&lt;/h2&gt;
&lt;p&gt;ところで、このdefaultsコマンドの引数はどのようにして知るのだろうか。
先程のサイトに載っているものはよいものの、他の設定項目はdefaultsコマンドにどんな引数を渡せばよいのだろうか。
私の調べた限りでは、公式なまとまった情報はないようだった。&lt;/p&gt;
&lt;p&gt;しかし、愚直に調査する方法はある。&lt;/p&gt;
&lt;p&gt;defaultsコマンドには、&lt;code&gt;$ defaults write&lt;/code&gt;の他に&lt;code&gt;$ defaults read&lt;/code&gt;というサブコマンドもある。これによりUser Defaultsを閲覧できる。
GUI上の操作によってUser Defaultsにどんな変更が加わるか、変更前後の&lt;code&gt;$ defaults read&lt;/code&gt;の出力を比較すればわかる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ defaults read &gt; before.txt
# GUI上で設定を変更する
$ defaults read &gt; after.txt

$ diff before.txt after.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;diffで該当した部分を中心に、defaultsコマンドで指定する値を抜き出せばよい。&lt;/p&gt;
&lt;p&gt;が、&lt;code&gt;$ defaults read&lt;/code&gt;の出力結果を読むのが面倒なので、これを自動で行うツールを作成した。&lt;/p&gt;
&lt;p&gt;(&lt;code&gt;$ defaults read&lt;/code&gt;の出力形式は、property list(old-style ascii)である。
&lt;a href=&quot;/posts/plist/&quot;&gt;(余談) UserDefaultsとplistについて&lt;/a&gt;として別記事にまとめたので、plistについてはこちらを参照してほしい。)&lt;/p&gt;
&lt;h2&gt;pdefでシェルスクリプトを作る&lt;/h2&gt;
&lt;p&gt;閑話休題&lt;/p&gt;
&lt;h3&gt;pdefとは&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yammerjp/pdef&quot;&gt;pdef&lt;/a&gt; (pi:def) は、User Defaultsの設定前後の差分から、defaultsコマンドの引数を調べてくれる。&lt;/p&gt;
&lt;p&gt;引数に&lt;code&gt;$ defaults read&lt;/code&gt;の出力を記録したファイルのパスを与える。 (第一引数に設定前、第二引数に設定後)
すると、設定前後の差分から、シェルスクリプト(defaultsコマンドを並べたもの)を出力する。&lt;/p&gt;
&lt;h3&gt;インストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ git clone https://github.com/yammerjp/pdef.git
$ cd pdef
$ make
$ cp bin/pdef /user/local/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用例&lt;/h3&gt;
&lt;p&gt;次のように使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# 設定を記録する

$ defaults read &gt; before.txt
# [GUI上で設定を変更する]
$ defaults read &gt; after.txt
$ pdef before.txt after.txt &gt; patch.sh

# 設定を復元する

$ bash patch.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用例として、メニューバーの音量アイコンを表示/非表示している様子。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/pdef-demo.gif&quot; alt=&quot;使用例のスクリーンショット&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mac上で設定を変更するときに、前後で&lt;code&gt;$ defaults read&lt;/code&gt;でUser Defaultsの内容を書き出しておくと、pdefを使って再設定が楽にできるという算段である。&lt;/p&gt;
&lt;h3&gt;オプション&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;--domain&lt;/code&gt;オプションをつけると、特定のアプリのUser Defaultsも比較できる。(&lt;code&gt;$ defaults export hogehoge -&lt;/code&gt;の出力等)
&lt;code&gt;--domain&lt;/code&gt;オプションをつけた際は、old-style asciiのplist以外にも、xmlやバイナリも読み込める。&lt;/p&gt;
&lt;p&gt;実行例&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ defaults export com.apple.systemuiserver - &gt; before.xml
# メニューバーの変更(音量アイコンの表示/非表示等)
$ defaults export com.apple.systemuiserver - &gt; after.xml
$ pdef --domain com.apple.systemuiserver before.xml after.xml
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;例外&lt;/h3&gt;
&lt;p&gt;pdefは現在は以下のようなものには対応していない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;data型の長い値 ( --domainオプションを付加すれば可能)&lt;/li&gt;
&lt;li&gt;keyのrename&lt;/li&gt;
&lt;li&gt;追加と削除が混在した差分&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;さいごに&lt;/h2&gt;
&lt;p&gt;インターネットの海に流れるdefaultsコマンドの設定例の他に、このツールで調べた設定を追加して、自分専用のMac設定用スクリプトの作成に役立てていただければ幸いだ。&lt;/p&gt;
&lt;p&gt;私のdefaultsコマンドを集めた&lt;a href=&quot;https://github.com/yammerjp/dotfiles/tree/master/bin/user-default&quot;&gt;シェルスクリプトはこちら&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記: (2020/10/04) plistへの記事リンクを相対リンクに修正&lt;/p&gt;</description>
    </item>
    <item>
      <title>macOSでの各種設定を自動化するdefaultsコマンド</title>
      <link>https://memo.yammer.jp/posts/macos-defaults</link>
      <pubDate>Mon, 13 Apr 2020 12:57:37 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/macos-defaults</guid>
      <description>&lt;p&gt;研究室や就職先などでのコンピュータのセットアップのために、3月頃から&lt;a href=&quot;https://github.com/yammerjp/dotfiles&quot;&gt;dotfiles&lt;/a&gt;を構築している。&lt;/p&gt;
&lt;p&gt;その流れでdefaultsコマンドを知ったので、その記録と使い方、調べ方を残しておく。。&lt;/p&gt;
&lt;h2&gt;defaultsコマンドとは&lt;/h2&gt;
&lt;p&gt;macOSにおける環境設定や各アプリケーションの設定は.plist拡張子の&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html&quot;&gt;プロパティリスト&lt;/a&gt;と言われるファイルに記録される。
このプロパティリストを読み書きするためにmacOSに標準で搭載されているのがdefaultsコマンドである。
(詳細は&lt;code&gt;$ man defaults&lt;/code&gt;してください。)&lt;/p&gt;
&lt;p&gt;これを利用して、OS全体の環境設定やアプリケーションの設定を自動化するスクリプトをつくっている。(&lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/master/bin/macos-defaults.sh&quot;&gt;実際に作ったスクリプト - yammerjp/dotfiles - GitHub&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;今回はこのスクリプトを構築するための話。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://support.apple.com/ja-jp/guide/terminal/apda49a1bb2-577e-4721-8f25-ffc0836f6997/mac&quot;&gt;Macの「ターミナル」でプロパティリストを編集する - ターミナルユーザガイド - Apple&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;他人の設定を拝借する&lt;/h2&gt;
&lt;p&gt;ネット上に他の人がどのコマンドを叩くとどの設定が変更できるかを調べてすでにまとめてくれたものがある。これを拝借するのが第一の手。&lt;/p&gt;
&lt;p&gt;公式でどこかに情報がまとまっていればよいのだが、「公式な」設定変更のやり方はGUIから変えることだからか、そんな丁寧なマニュアルはなさそう。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amasuda.xyz/post/2016-10-23-mastering-mac-defaults-command/&quot;&gt;MacOS defaults コマンドをマスターする - Think Abstract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://neos21.hatenablog.com/entry/2019/01/10/080000&quot;&gt;MacOS で設定する defaults コマンドをまとめてみた - Corredor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/djmonta/items/17531dde1e82d9786816&quot;&gt;ターミナルから Mac を設定する（defaults write コマンド等） - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/ryuichi1208/items/5905240f3bfce793b33d&quot;&gt;iMac/MacBook購入後に必ず設定したい設定項目 - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://oki2a24.com/2019/01/21/nitial-setting-done-manually-and-setting-with-defaults-command-on-macbook-pro-2018/&quot;&gt;Macbook Pro 2018 で手動で行った初期設定と、defaults コマンドを使った設定のメモ - Just another oki2a24 ブロゴ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ottan.xyz/system-preferences-terminal-defaults-2-4643/&quot;&gt;システム環境設定をターミナル（defaultsコマンド）から設定する方法（一般） - OTTAN.XYZ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://matsuokah.hateblo.jp/entry/2016/01/01/161753&quot;&gt;OSXのコマンドラインからすると捗った設定リスト - will and way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.neko.ne.jp/~freewing/software/macos_mojave_speed_up_setting_tips/&quot;&gt;macOS Mojaveを高速化する 20の効果的な設定、Macを買ったら最初に設定する俺チューン設定項目 - FREE WINGの Androidと Windows、中国語の便利ソフト&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wordpress.ideacompo.com/?p=4826&quot;&gt;Tips of Rubbish DIYとIoTをこよなく愛する、WEB関連やデジモノなどの雑多な情報ブログ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;注釈: defaultsコマンドを実行すると、設定変更が即座に反映されるわけではない。以下のように再起動するなどして設定を読み込ませると良い。&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Dockの設定変更を反映
$ killall Dock
# finderの設定変更を反映
$ killall Finder
# メニューバー(画面上部)の設定変更を反映
$ killall SystemUIServer
# その他駄目なら再起動。
$ sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;設定するコマンドを探す&lt;/h2&gt;
&lt;p&gt;ネットを探していても自分の思うような設定がみつからないことがある。そのときは以下の手順で調べると見つかるかもしれない。&lt;/p&gt;
&lt;h3&gt;defaultsコマンドの使い方&lt;/h3&gt;
&lt;p&gt;前提として、manual(&lt;code&gt;$ man defaults&lt;/code&gt;)の通り、defaultsコマンドは次のように使う。
以下は簡略に示す。実際に実行する際はmanualを参照。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# すべて読む
$ defaults read

# 読む
$ defaults read DOMAIN KEY
$ defaults read -g KEY
# 書き込む
$ defaults write DOMAIN KEY VALUE
$ defaults write -g KEY VALUE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;プロパティリストはkeyとvalueの対が原則で、jsonのようにvalueの中に入れ子でkeyとvalueのまとまりなどが入る。&lt;/p&gt;
&lt;p&gt;valueにはstringやdata, int, float, bool, array, dictなどの形式がある。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$defaults write&lt;/code&gt;する際にオプションで&lt;code&gt;-string&lt;/code&gt;や&lt;code&gt;-array&lt;/code&gt;, &lt;code&gt;-array-add&lt;/code&gt;とすると希望のデータ型で値を書き込める。&lt;/p&gt;
&lt;h3&gt;探し方&lt;/h3&gt;
&lt;p&gt;設定変更前後のプロパティリストの差分から、それっぽい設定項目を見つける。
その後実際に&lt;code&gt;$ defaults write&lt;/code&gt;でプロパティリストを書き換えて、設定が反映されるかを確認する。&lt;/p&gt;
&lt;p&gt;このとき、設定変更のためのGUIウィンドウは予め開いておいて、beforeとafterの記録をすると良い。
プロパティリストには我々が手動で設定した環境設定の他にも多用途に利用されているらしく、時間をあけるとあっという間にdiffが汚くなる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ defaults read &gt; before

# GUI上で設定を変更する

$ defaults read &gt; after
$ diff before after
# colordiff(brew install colordiff)などを使うと捗る
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;実際に探す一例&lt;/h3&gt;
&lt;p&gt;一例として、メニューバーに音量アイコンを表示する設定を探す。&lt;/p&gt;
&lt;h4&gt;プロパティリストを読む&lt;/h4&gt;
&lt;p&gt;GUIで設定する前後のプロパティリストを比較する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/macos-defaults-read.gif&quot; alt=&quot;プロパティリストを読み込むスクリーンショット&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ defaults read &gt; before
# GUIで設定変更
$ defaults read &gt; after
$ diff before after
6504a6505
&gt;         &quot;NSStatusItem Visible com.apple.menuextra.volume&quot; = 1;
6511c6512,6513
&amp;#x3C;             &quot;/System/Library/CoreServices/Menu Extras/Bluetooth.menu&quot;
---
&gt;             &quot;/System/Library/CoreServices/Menu Extras/Bluetooth.menu&quot;,
&gt;             &quot;/System/Library/CoreServices/Menu Extras/Volume.menu&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;差分を見ると、6500行目あたりに設定項目がありそう。&lt;/p&gt;
&lt;p&gt;実際にafterの6500行目以降の数行を見てみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     &quot;com.apple.systemuiserver&quot; =     {
         &quot;NSStatusItem Visible com.apple.menuextra.airport&quot; = 1;
         &quot;NSStatusItem Visible com.apple.menuextra.battery&quot; = 1;
         &quot;NSStatusItem Visible com.apple.menuextra.bluetooth&quot; = 1;
         &quot;NSStatusItem Visible com.apple.menuextra.clock&quot; = 1;
         &quot;NSStatusItem Visible com.apple.menuextra.volume&quot; = 1;
         &quot;__NSEnableTSMDocumentWindowLevel&quot; = 1;
         &quot;last-analytics-stamp&quot; = &quot;608273612.570469&quot;;
         menuExtras =         (
             &quot;/System/Library/CoreServices/Menu Extras/Clock.menu&quot;,
             &quot;/System/Library/CoreServices/Menu Extras/Battery.menu&quot;,
             &quot;/System/Library/CoreServices/Menu Extras/AirPort.menu&quot;,
             &quot;/System/Library/CoreServices/Menu Extras/Bluetooth.menu&quot;,
             &quot;/System/Library/CoreServices/Menu Extras/Volume.menu&quot;
         );
     };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上より、設定は次の内容を書き込めば良さそう。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ドメイン &lt;code&gt;com.apple.systemuiserver&lt;/code&gt; 、キー &lt;code&gt;NSStatusItem Visible com.apple.menuextra.volume&lt;/code&gt; に、値 &lt;code&gt;1&lt;/code&gt; を設定する。&lt;/li&gt;
&lt;li&gt;ドメイン &lt;code&gt;com.apple.systemuiserver&lt;/code&gt; 、キー &lt;code&gt;menuExtra&lt;/code&gt; の値の配列に、
&lt;code&gt;/System/Library/CoreServices/Menu Extras/Volume.menu&lt;/code&gt; を追加。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;シェルスクリプトにまとめると次の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/bash -e

# 音量アイコンをMenuBarに表示
defaults write com.apple.systemuiserver \
  &quot;NSStatusItem Visible com.apple.menuextra.volume&quot; 1

defaults write com.apple.systemuiserver \
  menuExtras -array-add &quot;/System/Library/CoreServices/Menu Extras/Volume.menu&quot;

# メニューバーを再起動
killall SystemUIServer
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;プロパティリストに書き込んで試す&lt;/h4&gt;
&lt;p&gt;実際に試してみると、反映されていることがわかる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blob.yammer.jp/macos-defaults-write.gif&quot; alt=&quot;プロパティリストに書き込むスクリーンショット&quot;&gt;&lt;/p&gt;
&lt;h2&gt;なぜdefaultsコマンドを使うのか&lt;/h2&gt;
&lt;h3&gt;メリット&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;設定を自動化できる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PCで新しく環境構築する際に、シェルスクリプトにまとまっているので一括で設定できる&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自分が行っていた設定を記録できる。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自分がGUI上でどんな設定を行っているか、いたかをコードで示すことができる。
アプリケーションがプロパティリストとしてデータを持っているならば、サードパーティアプリケーションでも同様に設定を記録できる。&lt;/p&gt;
&lt;p&gt;たとえば、私は&lt;a href=&quot;https://github.com/fikovnik/ShiftIt&quot;&gt;ShiftIt&lt;/a&gt;というアプリケーションを使っている。
このアプリケーションで使うキーバインドはGUI上から設定するのだが、自分がどんな設定をしているのかをコードとして記録できるのは、再設定だけでなく今後のなんらかのキーバインド設定の参考にもなる。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://github.com/yammerjp/dotfiles/blob/master/bin/shiftit-init.sh&quot;&gt;私の現在のShiftItのキーバインド設定&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;デメリット&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;設定変更のたびに逐一調べてシェルスクリプトを更新しなければならない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これはたしかに面倒だけどね。
プロパティリストをむやみに書き換えると、パソコンが上手く動かなくなる可能性もある。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSのアップデートによって設定が適用できなくなるかもしれない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GUIもアップデートで項目がなくなったりどこにいったかわからなくなったりするよね&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;以下を使って頑張ってシェルスクリプトを書こう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ defaults read &gt; before
# GUIで設定変更
$ defaults read &gt; after
$ diff before after

$ man defaults
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;将来の自分へ&lt;/h2&gt;
&lt;p&gt;diffを読み取ってdefaultsコマンドのシェルスクリプト形式にするのは自動化できるのでは？
と思ったが、&lt;a href=&quot;https://rcmdnk.com/blog/2015/03/22/computer-mac/&quot;&gt;先駆者がいたようだ&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>vim-lspを使った、Vim上でのTypeScript(JavaScript)の補完の実現</title>
      <link>https://memo.yammer.jp/posts/vim-lsp-init</link>
      <pubDate>Wed, 01 Apr 2020 08:37:46 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/vim-lsp-init</guid>
      <description>&lt;h2&gt;LSPとは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Microsoft/language-server-protocol&quot;&gt;LSP(Language Server Protocol)&lt;/a&gt;とは、IDEと言語サーバとの通信用プロトコル。&lt;/p&gt;
&lt;p&gt;IDEやテキストエディタが補完やコードジャンプなどの様々な機能を実現するために、以前はIDEやエディタのプラグイン内に内包されていた機能を、言語ごとにLanguage Serverとして切り出す。&lt;/p&gt;
&lt;p&gt;これにより言語補完部分の製作はLanguage Serverさえ作ってしまえばたくさんのIDE(エディタ)に対応できるし、IDE(エディタ)開発側も、LSPにさえ対応してしまえば各言語への対応を独自実装しなくて済む。&lt;/p&gt;
&lt;p&gt;2016年6月にMicrosoftが発表したらしい。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https://qiita.com/atsushieno/items/ce31df9bd88e98eec5c4&quot;&gt;language server protocolについて (前編) - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;やること&lt;/h2&gt;
&lt;p&gt;今回はTypeScript,JavaScript用のLanguage Serverをインストールし、これをvim-lspにつないでvim上でLanguage Serverの支援が得られるようにする。&lt;/p&gt;
&lt;p&gt;( &lt;a href=&quot;https://github.com/prabirshrestha/vim-lsp&quot;&gt;vim-lsp&lt;/a&gt;はvimでLanguage Serverを利用できるようにするプラグイン )&lt;/p&gt;
&lt;h2&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;macOS Mojave(10.14.6)&lt;/li&gt;
&lt;li&gt;VIM 8.2  Compiled by Homebrew&lt;/li&gt;
&lt;li&gt;dein.vimでプラグイン管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vim8上で、dein.vimにプラグインを読み込ませる。&lt;/p&gt;
&lt;h2&gt;手順&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;typescript-language-serverをインストールする&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npm install -g typescript typescript-language-server
# または
$ yarn global add typescript typescript-language-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;typescript-language-serverはJavaScriptのLanguage Serverとしても動く&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;各種vimプラグインを入れる&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;dein.tomlに以下の記述を追記&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-toml&quot;&gt;# dein.toml

#========== vim-lsp とその関連プラグイン ==========
#vim-lspとLanguage Serverの連携に必要なプラグイン群
[[plugins]]
repo = &apos;prabirshrestha/async.vim&apos;
[[plugins]]
repo = &apos;prabirshrestha/asyncomplete.vim&apos;
[[plugins]]
repo = &apos;prabirshrestha/asyncomplete-lsp.vim&apos;

# 事前にnpm install -g typescript typescript-language-server 
[[plugins]]
repo = &apos;prabirshrestha/vim-lsp&apos;
hook_add = &apos;&apos;&apos;
&quot; TypeScript, JavaScript
if executable(&apos;typescript-language-server&apos;)
    au User lsp_setup call lsp#register_server({
        \ &apos;name&apos;: &apos;typescript-language-server&apos;,
        \ &apos;cmd&apos;: {server_info-&gt;[&amp;#x26;shell, &amp;#x26;shellcmdflag, &apos;typescript-language-server --stdio&apos;]},
        \ &apos;root_uri&apos;:{server_info-&gt;lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), &apos;package.json&apos;))},
&quot;       \ &apos;root_uri&apos;:{server_info-&gt;lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), &apos;tsconfig.json&apos;))},
        \ &apos;whitelist&apos;: [&apos;typescript&apos;, &apos;typescript.tsx&apos;, &apos;javascript&apos;, &apos;javascript.jsx&apos;],
        \ })
endif

&quot; 他言語サーバの読み込みはここに挿入
&apos;&apos;&apos;

#vim-lspのキーバインドを設定
後で書く
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;vimを起動&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ vim
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>今日欲しい物(2020/3/30)</title>
      <link>https://memo.yammer.jp/posts/20200330</link>
      <pubDate>Mon, 30 Mar 2020 01:06:22 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/20200330</guid>
      <description>&lt;h2&gt;欲しい物&lt;/h2&gt;
&lt;p&gt;ほしいと思ったものの記録。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;docomo系MVNOのSIM&lt;/li&gt;
&lt;li&gt;60%の自作キーボード&lt;/li&gt;
&lt;li&gt;ヘッドホン&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;docomo系のMVNOのSIM&lt;/h2&gt;
&lt;p&gt;昨年macを買ったのに合わせて初めてiphoneを購入し、それ以降iphone7を使い続けているが、そろそろandroidに戻りたい気持ちが強くなってきた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/dp/B072PS4Q3H/ref=sspa_dk_detail_0?psc=1&amp;#x26;pd_rd_i=B072PS4Q3H&amp;#x26;pd_rd_w=MtTuU&amp;#x26;pf_rd_p=6413bd85-d494-49e7-9f81-0e63e79171a9&amp;#x26;pd_rd_wg=eJADD&amp;#x26;pf_rd_r=9K6KRSP0W1DSTS5MQEPK&amp;#x26;pd_rd_r=f0f592c6-efca-451e-ad83-7a5fe8f4bfe2&amp;#x26;spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExU1g2MENHQ0VZWEtGJmVuY3J5cHRlZElkPUEwNTQ2MDM2MklSSzVWVDlJQUFVQiZlbmNyeXB0ZWRBZElkPUE2V1UwTDFMNjBLM04md2lkZ2V0TmFtZT1zcF9kZXRhaWwmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl&quot;&gt;ビッグローブの3GB音声通話有りのプラン&lt;/a&gt;は、半年間400円で使えて2500円キャッシュバックが有るらしい。&lt;/p&gt;
&lt;p&gt;iphone7に挿しているsimは最近UQmobileに乗り換えたばかりだし、UQmobileの回線速度は素晴らしいので、乗り換えるのは早計かなと思っている。&lt;/p&gt;
&lt;p&gt;しかしUQmobileのsimが使える端末が手元にないので、とりあえずdocomo系のsimを契約して2台持ちにしようかと検討している。
今、お金をほとんど使わずに不満を解消できるのが2台持ち。&lt;/p&gt;
&lt;p&gt;しばらくしたらUQmobileでも使えるandroidを買うか、androidへ乗り換える夢を諦めるか、メインの回線をdocomo系のMVNOに乗り換えるかしよう。&lt;/p&gt;
&lt;p&gt;以下はiphoneを一年弱使った感想。&lt;/p&gt;
&lt;p&gt;生粋のandroid人間だったので、操作感など最初は中々慣れなかった。&lt;/p&gt;
&lt;h3&gt;iphoneの不満&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;オートメーションで位置情報による自動実行、WIFI接続時の自動実行が出来ない。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;家の鍵(Sesami mini)を、帰宅/外出を自動検知しAPIを叩いて自動開閉をしたい。
androidならIFTTTで実現できそう。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OK googleしたい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;スマホの音声操作は車を運転するときに真価を発揮する。&lt;/p&gt;
&lt;p&gt;Googleマップの検索と案内開始、音楽再生をどちらも音声操作だけで完結できるのでGoogleアシスタントを使いたい。&lt;/p&gt;
&lt;p&gt;夏、特にダイビングに行くときに車を運転するので、今後もっとandroidが欲しくなるはず。&lt;/p&gt;
&lt;p&gt;(注:Siriは○ソ。使えない。自明。)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公式ストア外のアプリをインストールできない。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;セキュリティ的には良いところなのだが。(一般向けのスマートフォンOSの戦略としては正解だと思う)&lt;/p&gt;
&lt;p&gt;私には自由が必要なのだ、androidのような自由が。&lt;/p&gt;
&lt;h3&gt;iphoneのいいところ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;テザリング時にスマホを操作しなくて良い&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;iphoneからmacへテザリングする際に、ポケットに入ったiphoneに指一本触れずにMac上からテザリングを有効化できる。Apple帝国に納税した分の福利厚生といったところか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;セキュリティが安心&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;政府要人でもないし抜かれる個人情報も大したこと無いけれど、国を敵に回してもiphoneには容易にはデータにアクセス出来なそう。
(ただし、端末内のデータにアクセスできないからと言って安全とは限らない。PCやWebサービスのデータベースの情報を抜かれるかもしれない)&lt;/p&gt;
&lt;h2&gt;60%の自作キーボード&lt;/h2&gt;
&lt;p&gt;ちょっと前はHHKBを狙っていたけれど、高いし、「あれ、俺がほしいのはHHKBではなくUS配列60%キーボードだ」と気づいた。&lt;/p&gt;
&lt;p&gt;ここ1ヶ月ほどKarabinerでSandS(スペースバーを他キーと同時に押すとShiftキーとして扱う)を設定している。
これに味をシメて、数字キーのShift動作を反転させて、普段は記号、Shiftキー(SandSなので実際はスペースバー)が押されているときは数字が入力されるようにしようとしていた。&lt;/p&gt;
&lt;p&gt;こんなふうに配列をいじっていると、はたしてこのまま日本語配列でよいのかと思ってくる。
USキーボードの配列に慣れておいたほうがキーボードの選択肢が広がる(自作キーボードをするとき)し、かっこいい(厨2)(要出典)し、エンターキー押しやすそうだし、記号も自然な配列と聞くので、さっさとUSにしないと。&lt;/p&gt;
&lt;p&gt;KBDfansを見ていると頑張って安いものを選べば1.3万円くらいでできそう。&lt;/p&gt;
&lt;p&gt;自分への誕生日プレゼントとしてひとつ組んでみようかな。&lt;/p&gt;
&lt;h2&gt;ヘッドホン&lt;/h2&gt;
&lt;p&gt;5000円未満で音質が結構良いらしいヘッドホン、&lt;a href=&quot;https://www.amazon.co.jp/%E3%83%9E%E3%83%A9%E3%83%B3%E3%83%84%E3%83%97%E3%83%AD-Marantz-Professional-MPH-1-%E5%AF%86%E9%96%89%E5%9E%8B%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%BC%E3%83%98%E3%83%83%E3%83%89%E3%83%9B%E3%83%B3/dp/B01E74L2L0?psc=1&amp;#x26;SubscriptionId=AKIAICDGYC76ENTD3PNA&amp;#x26;tag=menbou0202-22&amp;#x26;linkCode=xm2&amp;#x26;camp=2025&amp;#x26;creative=165953&amp;#x26;creativeASIN=B01E74L2L0&quot;&gt;マランツプロ MPH-1&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;今はSonyのXDR-XB950というヘッドホンを3年以上使っている。
bluetoothのヘッドホンは本当に素晴らしくて、無線は本当に快適。
バッテリーも公称40時間持つとかで、最近のワイヤレスイヤホンとは比較にならないほど持つ。&lt;/p&gt;
&lt;p&gt;ただ、音質はそこまで良くないと思う。bluetoothということで、ホワイトノイズも目立つ。&lt;/p&gt;
&lt;p&gt;次買うならSonyかboseの4万円くらいするワイヤレスヘッドホンなのだけれど、高いのでおいそれと手が出ない。&lt;/p&gt;
&lt;p&gt;そんなときに下を見つけた。
ギズモード・ジャパンの網藤さんのブログで見つけた、5000円のヘッドホン。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://men-bou.net/mph-1-under-5000/&quot;&gt;アンダー5,000円のモニタリングヘッドホン「MPH-1」は脊髄で買っていいくらい高コスパ - MENBOU&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この価格帯で推せるヘッドホンが有るのはアツイ。&lt;/p&gt;
&lt;p&gt;2020年に有線ヘッドホンを買うかは迷いどころだけれど、机に座っているとき専用だったら有線でもまぁいいかな。&lt;/p&gt;
&lt;p&gt;現状に困っているわけではないので、なんだかんだ買わない気もするけれど。&lt;/p&gt;</description>
    </item>
    <item>
      <title>すぐやる人に変わる方法</title>
      <link>https://memo.yammer.jp/posts/book-memo-do-now</link>
      <pubDate>Sat, 28 Mar 2020 02:52:38 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/book-memo-do-now</guid>
      <description>&lt;p&gt;2017年11月頃のメモを移動。以下、
&lt;a href=&quot;https://www.amazon.co.jp/%E5%85%88%E9%80%81%E3%82%8A%E3%81%9B%E3%81%9A%E3%81%AB%E3%81%99%E3%81%90%E3%82%84%E3%82%8B%E4%BA%BA%E3%81%AB%E5%A4%89%E3%82%8F%E3%82%8B%E6%96%B9%E6%B3%95-%E4%B8%AD%E7%B5%8C%E3%81%AE%E6%96%87%E5%BA%AB-%E4%BD%90%E3%80%85%E6%9C%A8-%E6%AD%A3%E6%82%9F-ebook/dp/B00ARBMSQG&quot;&gt;先送りせずにすぐやる人に変わる方法 (中経の文庫)&lt;/a&gt;を読んだ際のメモだと思われる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;優先度を比較する「前」にやってしまう&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;「快楽を捨てること」と「苦痛を選択する」ということの2つのことを一度にやろうとしてはダメ まず「快楽を捨てる」ことだけに、全神経を集中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;すぐに実行できるところまで分解する どんどん分解する癖がつけば自然と「すぐやる」人になれる&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;誘導タスクを設定する&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;メールは「下書き」をしておく&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;いまの状況を正直に伝える .. そういうときは、ざっと目を通して、簡単な感想を概ねポジティブに書いて出す&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以下軽く目を通して考えてから採用すること&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;すぐやる人は肩の力が抜けている&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;やりたいことを増やさない&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一気にやる快感に気をつける 溜める量を減らしていく&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;締め切りが無くても動ける方法を探す 自分で設定したデッドラインでできたという経験を多く持つ&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>仮想化</title>
      <link>https://memo.yammer.jp/posts/virtualization</link>
      <pubDate>Sat, 28 Mar 2020 02:48:13 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/virtualization</guid>
      <description>&lt;p&gt;過去の自分向けメモを移動。以下、2019/4/27頃のメモである。&lt;/p&gt;
&lt;p&gt;最近大学でOSの授業が始まった。&lt;/p&gt;
&lt;p&gt;OSの基本的な役割として挙げられるのが、計算資源の管理とハードウェアの仮想化だそうな。&lt;/p&gt;
&lt;p&gt;仮想化と聞くとVirtual Machineを使ったサーバー仮想化などあるが、それよりももっと前から仮想化という概念は存在していて。
CPUのハイパースレッディングテクノロジーなんかはCPUの仮想化。
デバイスドライバを介した入出力機器の仮想化。ファイルシステムによりデータを抽象的に操作できるハードディスクの仮想化。アドレスを意識する必要のないメモリの仮想化。&lt;/p&gt;
&lt;p&gt;仮想化といわれると、以前はエミュレータなんかに近いものを想像していた。&lt;/p&gt;
&lt;p&gt;しかしOSがハードウェアを仮想化しているということを意識すると言葉のイメージが変わった。
仮想化(=抽象化)というのは、カプセル化だったり、階層化という概念に近く、コンピュータの中でごく一般的に広く用いられている手法ではないか？&lt;/p&gt;
&lt;p&gt;そこまで考えを広げたうえで、昨今のデータセンタ内の仮想化技術(サーバー、ストレージ、ネットワーク、、)は自然の流れとも言える。
今まで使っていたハードウェアないしレイヤーを更に仮想的に(抽象的に、ソフトウェア的に)扱いやすくした、レイヤーが一層加わっただけである。&lt;/p&gt;
&lt;p&gt;大学1年のとき、某企業でデータセンタに関するソリューション提案のインターンをした。そのときは仮想化どころかデータセンタに関する知識が少なくて学ぶことばかりでついていくのもやっとだったけれど、概念の理解は当時より進んだと思う。&lt;/p&gt;</description>
    </item>
    <item>
      <title>さくらのVPSとdocker環境構築 </title>
      <link>https://memo.yammer.jp/posts/sakura-vps-docker</link>
      <pubDate>Fri, 27 Mar 2020 18:10:34 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/sakura-vps-docker</guid>
      <description>&lt;p&gt;PCを整理していて発見したメモを移動して公開する。ファイルのタイムスタンプは2017/12/19。&lt;/p&gt;
&lt;p&gt;windows10のPCから、さくらVPSでCentOS7のサーバでdockerを使えるようにする記録。&lt;/p&gt;
&lt;p&gt;windows10にはあらかじめputty,WinSCPがインストールされていることを想定。&lt;/p&gt;
&lt;h2&gt;さくらVPS初期設定&lt;/h2&gt;
&lt;h3&gt;OSインストール&lt;/h3&gt;
&lt;p&gt;さくらVPS管理画面にて、&gt; サーバ一覧 &gt; (設定したいサーバ) &gt; 各種設定 &gt; OSインストール&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSインストール形式の選択: 標準OS&lt;/li&gt;
&lt;li&gt;インストールするOSを選んでください: CentOS7 x86_64&lt;/li&gt;
&lt;li&gt;rootパスワード: 適当に設定&lt;/li&gt;
&lt;li&gt;スタートアップスクリプト: 利用しない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こんな感じでOSをインストールする。&lt;/p&gt;
&lt;h3&gt;一般ユーザーの作成&lt;/h3&gt;
&lt;p&gt;まず、さくらVPS管理画面にて、&gt;サーバ一覧 &gt;(設定したいサーバ) &gt; _コンソール &gt; _シリアルコンソール(β)版 から操作。&lt;/p&gt;
&lt;h4&gt;sampleuserの作成&lt;/h4&gt;
&lt;p&gt;以下、sampleuserは適当に自分の作りたいユーザー名に置き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;#rootでログイン 
$ useradd sampleuser #ユーザー作成 
$ passwd sampleuser #パスワード設定 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;sampleuserがsudoできるようにする&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ visudo 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;visudoで/etc/sudoersを編集する。次の行のコメントアウトを外す。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## Allows people in group wheel to run all commands 
#%wheel  ALL=(ALL)       ALL 
↓ 
## Allows people in group wheel to run all commands 
%wheel  ALL=(ALL)       ALL 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:wqで保存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ usermod -aG wheel sampleuser 
#ユーザーをwheelグループに追加 
 
$ exit 
 
$ login #sampleuserでlogin 
 
$ groups #自分の所属groupを確認 
sampleuser wheel 
 
$ sudo su #sampleuserでsudoできるか確認 
[sudo] password for sampleuser:{sampleuserのパスワード} 
 
$ whoami 
root 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;puttyからsshログインしてみる&lt;/h4&gt;
&lt;p&gt;putty.exeを起動。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&gt;Session の Host Name : サーバのipアドレスorドメイン名&lt;/li&gt;
&lt;li&gt;&gt;Session の Port : 22&lt;/li&gt;
&lt;li&gt;&gt;Conection の Seconds to between keepalives(0 to turn off) : 30&lt;br&gt;
(30秒ごとにnull文字が送信されることでしばらく操作が無くてもsshセッションが途絶えるのを防ぐ。)&lt;/li&gt;
&lt;li&gt;&gt;Session の SavedSessions : sakura_vps_session&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Saveし、その後Openでssh接続できるか確認する。&lt;/p&gt;
&lt;h3&gt;セキュリティの強化&lt;/h3&gt;
&lt;h4&gt;rootのsshログインを止める&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ vim sudo /etc/ssh/sshd_config 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/etc/ssh/sshd_configを次のように編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; #PermitRootLogin yes 
 ↓ 
 PermitRootLogin no 
 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:wqで保存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ systemctl restart sshd #設定を反映させる 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;port番号変更とfirewall設定変更&lt;/h4&gt;
&lt;p&gt;sshポートを、標準である22から適当な値に変更する。ここでは2222に変更するが、セキュリティのためには各自適当な値を用いるべき。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo vim /etc/ssh/sshd_config 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/etc/ssh/sshd_configを次のように編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#Port22 
↓ 
Port2222 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:wqで保存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ systemctl restart sshd #設定を反映させる 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そして、sshの設定でポートを変更したのち、&lt;strong&gt;firewallの設定も変更しなければならない。。。&lt;/strong&gt; これに気づかず最初つまづいた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml 
 
$ sudo vim /etc/firewalld/services/ssh.xml 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;firewallのデフォルト設定は/usr/lib/firewalld/にあるが、これは触らないこと。
編集する場合は、/etc/firewalld/以下にファイルを置くと、その部分だけシステム設定が上書きされるようになっているので、こちらに書き込む。&lt;/p&gt;
&lt;p&gt;/etc/firewalld/services/ssh.xmlを次のように編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;port protocol=&quot;tcp&quot; port=&quot;22&quot;/&gt; 
↓ 
&amp;#x3C;port protocol=&quot;tcp&quot; port=&quot;2222&quot;/&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:wqで保存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ firewall-cmd --reload #設定を反映させる 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;putty.exeでも、ポート設定を変更しておく。
sakura_vps_session をLoadし、Portを2222に変えてSave。puttyから接続できるか確認しておく。&lt;/p&gt;
&lt;h4&gt;公開鍵認証&lt;/h4&gt;
&lt;p&gt;puttygen.exeで公開鍵、秘密鍵のペアを作成する。
Generateボタンを押した後、カーソルをウィンドウ上でランダムに動かすと鍵が作成できる。
Key passphraseを任意のものに設定する。
適当な場所に Save public key  で sakura_rsa.pub として、Save private key sakura_rsa.ppk として保存。&lt;/p&gt;
&lt;p&gt;公開鍵をサーバにアップロードする。
WinSCPで、新しいサイトから、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;編集プロトコル:SFTP&lt;/li&gt;
&lt;li&gt;ホスト名:にサーバのipアドレスorドメイン名&lt;/li&gt;
&lt;li&gt;ポート番号:2222&lt;/li&gt;
&lt;li&gt;ユーザ名:sampleuser&lt;/li&gt;
&lt;li&gt;パスワード:(sampleuserのパスワード)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;として保存、ログインする。
WinSCPでは画面左側にローカルの、画面右側にサーバのファイルが表示されており、ドラッグアンドドロップで相互に転送できる。
先ほどの
サーバの/home/sampleuser に先ほどの sakura_rsa.pub (公開鍵だけ)を転送する。&lt;/p&gt;
&lt;p&gt;サーバに公開鍵を登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ login #sampleuserでloginする 
 
$ ssh-keygen -i -f sakura_rsa.pub &gt;&gt; authorized_keys #puttygen.exeで作成した公開鍵の形式を変換 
 
#/home/sampleuser/.ssh/にauthorized_keysを設置し、適切なユーザ権限を与える 
$ mkdir .ssh 
$ chmod 700 .ssh 
$ mv authorized_keys .ssh 
$ chmod 600 .ssh/authorized_keys 
 
$ rm -f sakura_rsa.pub #変換前の公開鍵を削除 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;puttyに秘密鍵を登録する。&lt;/p&gt;
&lt;p&gt;putty.exeで sakura_vps_session を Loadし、&gt;Conection&gt;SSH&gt;Auth の Private key fire authentication にsakura_rsa.ppk(秘密鍵)を設定する。
&gt;Sessionから 設定の変更をSaveする。
その後puttyで接続できるか確認。鍵を作成したときのパスフレーズをここで入力する必要があるはず。
問題なく接続できれば、晴れて公開鍵認証でssh接続できている。&lt;/p&gt;
&lt;p&gt;パスワードログインの無効化をする。
公開鍵認証でログインできても、まだ従来のパスワードによるログインもできるのでセキュリティ向上にはなっていない。従来のパスワードによるログインを無効化する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ vim sudo /etc/ssh/sshd_config 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/etc/ssh/sshd_configを次のように編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#PasswordAuthentication yes 
↓ 
PasswordAuthentication no 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:wqで保存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ systemctl restart sshd #設定を反映させる 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker構築&lt;/h2&gt;
&lt;h3&gt;dockerのインストール&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo yum update 
$ sudo yum install docker-io 
#dockerのインストール 
 
$ sudo systemctl start docker 
#無事インストールされたか確認する 
$ sudo docker info 
#インストールされていればつらつら現在の状況が表示される 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sampleuserがdockerを使えるようにする&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ sudo groupadd docker #dockerグループの作成 
$ sudo gpasswd -a sampleuser docker 
#sampleuserをdockerグループへ追加 
 
$ sudo systemctl restart docker 
#dockerデーモンの再起動 
 
$ docker info 
#sampleuserで動くことを確認 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Moby Dockを表示してみる&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ docker run docker/whalesay cowsay &apos;Congrats!!!&apos; 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;参考文献&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CentOSでuserをsudo可能にする:&lt;br&gt;
&lt;a href=&quot;https://qiita.com/Esfahan/items/a159753d156d23baf180&quot;&gt;https://qiita.com/Esfahan/items/a159753d156d23baf180&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CentOS7のfirewalldでsshのポート番号を変更する方法:&lt;br&gt;
&lt;a href=&quot;https://qiita.com/DQNEO/items/5780d81b2e0af4cc1544&quot;&gt;https://qiita.com/DQNEO/items/5780d81b2e0af4cc1544&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PuTTYで公開鍵認証方式でのSSH接続を行う手順まとめ:&lt;br&gt;
&lt;a href=&quot;https://qiita.com/sugar_15678/items/55cb79d427b9ec21bac2&quot;&gt;https://qiita.com/sugar_15678/items/55cb79d427b9ec21bac2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;VPSにdocker環境構築:&lt;br&gt;
&lt;a href=&quot;https://qiita.com/t-mimura/items/c206d46f3af771292f89&quot;&gt;https://qiita.com/t-mimura/items/c206d46f3af771292f89&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>お名前.comで取得したドメインをさくらVPSで使う。</title>
      <link>https://memo.yammer.jp/posts/sakura-vps-dns</link>
      <pubDate>Fri, 27 Mar 2020 18:03:08 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/sakura-vps-dns</guid>
      <description>&lt;p&gt;PCを整理していて発見したメモを移動して公開する。ファイルのタイムスタンプは2017/12/19。&lt;/p&gt;
&lt;p&gt;お名前.comで取得したドメインをさくらVPSで使う。DNSサーバーはさくらのものを利用する。&lt;/p&gt;
&lt;h2&gt;お名前.com側の設定&lt;/h2&gt;
&lt;p&gt;&gt; ドメイン &gt; ドメイン設定 &gt; ネームサーバーの設定 &gt; ネームサーバーの変更&lt;/p&gt;
&lt;p&gt;目的のドメイン名にチェックを入れて 登録情報は正しいので、手続きを進める をクリック。&lt;/p&gt;
&lt;p&gt;他のネームサーバーを利用 のタブにして&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1プライマリネームサーバー(必須) :	ns1.dns.ne.jp&lt;/li&gt;
&lt;li&gt;2セカンダリネームサーバー(必須) :	ns2.dns.ne.jp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;として確認画面へ進み、設定を適用する。&lt;/p&gt;
&lt;p&gt;これでネームサーバーはさくらインターネットのものが使われる&lt;/p&gt;
&lt;h2&gt;さくらVPS側の設定&lt;/h2&gt;
&lt;p&gt;&gt; さくらのVPSコントロールパネル &gt; ネームサーバ登録&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ドメイン名:example.com (目的のドメイン名)
送信する をクリックして設定を適用する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&gt; 会員メニュー &gt; ドメイン &gt; 管理ドメインとネームサーバの一覧&lt;br&gt;
にてドメイン名:example.comの ゾーン編集 をクリック
左側の 変更 から&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;エントリ名: 空欄&lt;/li&gt;
&lt;li&gt;種別: IPアドレス(A)&lt;/li&gt;
&lt;li&gt;値: 192.0.43.10 (サーバのIPアドレス)&lt;/li&gt;
&lt;li&gt;DNSチェック: する&lt;/li&gt;
&lt;li&gt;TTLの指定: (チェックしない)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;として新規登録&lt;/p&gt;
&lt;p&gt;もう一度&lt;br&gt;
&gt; 会員メニュー &gt; ドメイン &gt; 管理ドメインとネームサーバの一覧&lt;br&gt;
にてドメイン名:example.comの ゾーン編集 をクリックし、左側の 変更 から&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;エントリ名: www&lt;/li&gt;
&lt;li&gt;種別: 別名(CNAME)&lt;/li&gt;
&lt;li&gt;値: @&lt;/li&gt;
&lt;li&gt;DNSチェック: する&lt;/li&gt;
&lt;li&gt;TTLの指定: (チェックしない)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;として新規登録&lt;/p&gt;
&lt;p&gt;以上で完了となる。&lt;/p&gt;</description>
    </item>
    <item>
      <title>androidの架電アプリによる各種制御プログラムの起動</title>
      <link>https://memo.yammer.jp/posts/android-phone-call-command</link>
      <pubDate>Fri, 27 Mar 2020 17:45:25 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/android-phone-call-command</guid>
      <description>&lt;h2&gt;まえがき&lt;/h2&gt;
&lt;p&gt;PC内のデータを整理していたら過去に自分向けに書いていたメモが出てきたので、ここ記す形で移動する。
タイムスタンプをみるに、2017/11/22頃に書かれたものだ。&lt;/p&gt;
&lt;p&gt;androidでは、端末の細かい挙動の設定を変更する際、電話アプリで以下に有るようなコマンドを打ち込むと行えることがある。&lt;/p&gt;
&lt;p&gt;過去のメモなので、どの機種、環境だと利用できるのか確認していないが、少なくとも SOL26で利用できそうである。&lt;/p&gt;
&lt;h2&gt;メモ&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Open Android Mobile Programs Using Commend  
 
 Commands               Usages 
 
*#06# = IMEI Android serial number 
 
*#8999*523# = LCD Brightness 
*#1234# = To check Software and Hardware information, PDA, CSC,MODEM. 
 
*#2222# = it will open H/W Version 
*#*#4636#*#*= user statistics and Phone Info 
*#0011# = Displays status information for the GSM 
*2767*3855# = Full factory reset (Don’t dial unless you have problem, it does not ask you to confirm) 
*#12580*369# = SW &amp;#x26; HW Info 
#*#8377466# = S/W Version &amp;#x26; H/W Version 
#*5376# = DELETE ALL SMS!!!! 
*#197328640# = Service Mode 
*#0228# = Battery status (ADC, RSSI reading) 
*#32489# = Service mode (Ciphering Info) 
*#2255# = Call List 
#*3888# = BLUETOOTH Test mode 
#*7828# = Task screen 
*#5282837# = Java Version 
*#232331# = Bluetooth Test Mode 
*#232338# = WLAN MAC Address 
*#232339# = WLAN Test Mode 
*#8999*8378# = Test Menu 
*#0842# = Vibrate Motor Test Mode 
*#0782# = Real Time Clock Test 
*#0673# = Audio Test Mode 
*#0*# = General Test Mode 
*#2263# = RF Band Selection / Network modes select 
*#9090# = Diagnostic Configuration 
*#7284# = USB I2C Mode Control 
*#872564# = USB Logging Control 
*#4238378# = GCF Configuration 
*#0283# = Audio Loopback Control 
*#1575# = GPS Control Menu 
*#3214789650# = LBS Test Mode 
*#745# = RIL Dump Menu 
*#746# = Debug Dump Menu 
*#9900# = Takes you to System Dump, where Disabling Fast Dormancy gives a boost to your network speed on some networks (both Wi-Fi and Gpr), same code to re-enable it 
*#44336# = Software Version Info 
*#0289# = Melody Test Mode 
*#2663# = TSP / TSK firmware update 
*#03# = NAND Flash S/N 
*#0589# = Light Sensor Test Mode 
*#0588# = Proximity Sensor Test Mode 
*#273283*255*3282*# = Data Create Menu 
 
*#7594# = Remap Shutdown to End Call TSK 
*#7465625# = View Phone Lock Status 
*7465625*638*# = Configure Network Lock MCC/MNC 
#7465625*638*# = Insert Network Lock Key code 
*7465625*782*# = Configure Network Lock NSP 
#7465625*782*# = Insert Partial Network Lock key code 
*7465625*77*# = Insert Network Lock key code SP 
#7465625*77*# = Insert Operator Lock key code 
*7465625*27*# = Insert Network Lock key code NSP/CP 
#7465625*27*# = Insert Content Provider key code 
*#272*IMEI# = then we will get buyer code (For Samsung galaxy six code) 
*#*#7780#*#* = Factory data reset – Clears Google-account data, system and program settings and 
 
*2767*3855# = Format phone 
 
The Most Useful Cods on Android Mobile 
– Disables Network Lock : #7465625*638*00000000# 
– Disables SIM Lock : #7465625*746*00000000# 
– Disables SP lock : #7465625*77*00000000# 
– Disables Subset Lock : #7465625*782*00000000# 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考: &lt;a href=&quot;http://www.commandshow.com/open-android-programs-using-command/&quot;&gt;http://www.commandshow.com/open-android-programs-using-command/&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>shellでhistoryを使う</title>
      <link>https://memo.yammer.jp/posts/sh-history</link>
      <pubDate>Wed, 25 Mar 2020 15:13:29 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/sh-history</guid>
      <description>&lt;h2&gt;過去に実行したコマンドを再度実行する&lt;/h2&gt;
&lt;p&gt;history ... unix系OSでshellに存在する組み込みコマンドだ。&lt;/p&gt;
&lt;p&gt;過去に実行したコマンドを表示できる。&lt;/p&gt;
&lt;p&gt;historyコマンドで表示されたコマンドの番号を!と合わせて入力すると、そのコマンドを実行できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ history
  1  ls
  2  pwd
  3  cd /etc
$ !1
ls
hogedir/    fugafile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下のようにして全履歴を表示できる。&lt;/p&gt;
&lt;p&gt;出力した後はgrepで煮るなり焼くなりするのが良いかと。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ history -E 1
# 履歴を全て表示する
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;.zshrcでの設定&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.zshrc&lt;/code&gt;でhistoryに関する設定をしておく&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-zsh&quot;&gt;# .zshrc
HISTSIZE=50000 # メモリに保存するコマンド数
HISTFILE=~/.zsh_history
SAVEHIST=100000 # ヒストリファイルに保存するコマンド数

alias history=&quot;history -i&quot;
function history-all { history -E 1 }

# 重複するコマンド行は古い方を削除
setopt hist_ignore_all_dups
# 直前と同じコマンドラインはヒストリに追加しない
setopt hist_ignore_dups
# コマンド履歴ファイルを共有する
setopt share_history
# 履歴を追加 (毎回 .zsh_history を作るのではなく)
setopt append_history
# 履歴をインクリメンタルに追加
setopt inc_append_history
# ヒストリを呼び出してから実行する間に一旦編集可能
setopt hist_verify
# 余分な空白は詰めて記録
setopt hist_reduce_blanks
# historyコマンドは履歴に登録しない
setopt hist_no_store
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Ubuntuをダウンロードしてインストールする</title>
      <link>https://memo.yammer.jp/posts/download-ubuntu</link>
      <pubDate>Sat, 21 Mar 2020 14:18:47 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/download-ubuntu</guid>
      <description>&lt;h2&gt;Download&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ubuntulinux.jp/download/ja-remix&quot;&gt;Ubuntu Desktop 日本語 Remix&lt;/a&gt;をダウンロードする&lt;/p&gt;
&lt;p&gt;Torrentを利用するために、uTorrent classicを使用した。
ただし、catalinaがサポート外と書かれていたのでもしかしたら32bitアプリケーションかもしれない。
Torrentについては別途要検討&lt;/p&gt;
&lt;h2&gt;Check&lt;/h2&gt;
&lt;p&gt;macでは次のようにしてmd5ハッシュを確認できる
ダウンロードページのhashと比較して、ダウンロードが正しく行われたことを確認する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ md5 -q path/to/file
# manによると、-qオプションはQuiet modeらしい。md5ハッシュのみ出力する。
# ので、次のように比較するのが良いかな

$ md5 -q path/to/file | diff hash/text/file/path -
# diffの第二引数&quot;-&quot;は、標準入力の意
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Copy&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;# Convert iso to img
$ hdutil convert -format UDRW -o hoge.img hoge.iso
$ mv hoge.img.dmg hoge.img

# USBメモリの確認
$ diskutil list

# Mountされていたら
$ diskutil unMountDisk path/to/device
# ex)  $ diskutil unMountDisk /dev/disk1

$ sudo dd if=hoge.img of=path/to/device bs=1m

$ sudo diskutil eject path/to/device
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>dein.vimの導入</title>
      <link>https://memo.yammer.jp/posts/install-dein-vim</link>
      <pubDate>Mon, 16 Mar 2020 15:13:35 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/install-dein-vim</guid>
      <description>&lt;p&gt;dotfiles環境下でvimのプラグイン管理に&lt;a href=&quot;https://github.com/Shougo/dein.vim&quot;&gt;dein.vim&lt;/a&gt;を導入する。&lt;/p&gt;
&lt;h2&gt;前提&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/dotfiles&lt;/code&gt;で&lt;code&gt;.vimrc&lt;/code&gt;を管理している&lt;/li&gt;
&lt;li&gt;dein.vimも&lt;code&gt;~/dotfiles&lt;/code&gt;で管理する&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;下準備&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ cd ~/dotfiles
$ mkdir dein
$ touch dein/load.vim
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;.vimrcに追記&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;~/dotfiles/.vimrc&lt;/code&gt;の先頭に次を記載&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-vim&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&quot; .vimrc&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;&quot;===== dein.vim =====&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;filereadable&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;expand&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&apos;dein/load.vim&apos;&lt;/span&gt;))
    &lt;span class=&quot;hljs-keyword&quot;&gt;source&lt;/span&gt; dein/load.&lt;span class=&quot;hljs-keyword&quot;&gt;vim&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;load.vimに記述&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;~/dotfiles/dein/load.vim&lt;/code&gt;に次の内容を記述&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-vim&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&quot; ~/dotfiles/dein/load.vim&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&quot;===== dein.vim ======&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;&quot;dein.vim dark power&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;expand&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&apos;~/dotfiles/dein&apos;&lt;/span&gt;)
&lt;span class=&quot;hljs-comment&quot;&gt;&quot; s:dein_dirとg:rc-dirは一致させること。dein.tomlとdein-lazy.tomlをtouchしている&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_repo_dir&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&apos;/repos/github.com/Shougo/dein.vim&apos;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;set&lt;/span&gt; nocompatible
&lt;span class=&quot;hljs-comment&quot;&gt;&quot; dein.vim をインストールしていない場合は自動インストール&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; !isdirectory(&lt;span class=&quot;hljs-variable&quot;&gt;s:dein_repo_dir&lt;/span&gt;)
  &lt;span class=&quot;hljs-keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;install dein.vim...&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;!git clone git://github.com/Shougo/dein.vim&apos;&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_repo_dir&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;!touch -m &apos;&lt;/span&gt; . &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&apos;/dein.toml&apos;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;!touch -m &apos;&lt;/span&gt; . &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&apos;/dein_lazy.toml&apos;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;set runtimepath^=&apos;&lt;/span&gt; . &lt;span class=&quot;hljs-variable&quot;&gt;s:dein_repo_dir&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;&quot;---------------------------&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;&quot; Start dein.vim Settings.&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;&quot;---------------------------&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; dein#load_state(&lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt;)
  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#begin(&lt;span class=&quot;hljs-variable&quot;&gt;s:dein_dir&lt;/span&gt;)

  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;g:rc_dir&lt;/span&gt;    = &lt;span class=&quot;hljs-built_in&quot;&gt;expand&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&apos;~/dotfiles/dein&apos;&lt;/span&gt;)
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;s:toml&lt;/span&gt;      = &lt;span class=&quot;hljs-variable&quot;&gt;g:rc_dir&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&apos;/dein.toml&apos;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;s:lazy_toml&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;g:rc_dir&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&apos;/dein_lazy.toml&apos;&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;&quot; TOMLファイルにpluginを記述&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#load_toml(&lt;span class=&quot;hljs-variable&quot;&gt;s:toml&lt;/span&gt;,      {&lt;span class=&quot;hljs-string&quot;&gt;&apos;lazy&apos;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;})
  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#load_toml(&lt;span class=&quot;hljs-variable&quot;&gt;s:lazy_toml&lt;/span&gt;, {&lt;span class=&quot;hljs-string&quot;&gt;&apos;lazy&apos;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;})

  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#end()
  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#save_state()
&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;&quot; 未インストールを確認&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; dein#check_install()
  &lt;span class=&quot;hljs-keyword&quot;&gt;call&lt;/span&gt; dein#install()
&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;&quot;---------------------------&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;&quot; End dein.vim Settings.&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;&quot;---------------------------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;vimを起動&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.vimrc&lt;/code&gt;の記述により、vim起動によりdein.vimがinstallされる。
(ただし、gitが必要)&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yammerjp/dotfiles&quot;&gt;yammerjp/dotfiles -GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Shell Scriptにおける、カレントディレクトリの固定</title>
      <link>https://memo.yammer.jp/posts/shell-pwd</link>
      <pubDate>Mon, 16 Mar 2020 13:23:27 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/shell-pwd</guid>
      <description>&lt;h2&gt;前提&lt;/h2&gt;
&lt;p&gt;shell script内では、shell scriptを起動する前のカレントディレクトリが引き継がれる。&lt;/p&gt;
&lt;p&gt;例えば、次のような&lt;code&gt;pwd.sh&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;#!/bin/sh
pwd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次のように、shell scriptを呼び出す際のカレントディレクトリにより、shell scriptの挙動が変化する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ pwd
/Users/hoge

$ ls -F
pwd.sh*   dir/

$ sh pwd.sh 
/Users/hoge

$ cd dir
$ sh ../pwd.sh
/Users/hoge/dir
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;解決策&lt;/h2&gt;
&lt;p&gt;shell scriptの前方に、2行追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;#!/bin/sh

# change directory to the shell file&apos;s directory
SCRIPT_DIR=`dirname $0`
cd $SCRIPT_DIR

pwd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これにより、shell scriptを呼び出す際のカレントディレクトリに関わらず、shell scriptでのカレントディレクトリが、shell scriptが配置されたディレクトリに固定される。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ pwd
/Users/hoge

$ ls -F
pwd.sh*   dir/

$ sh pwd.sh 
/Users/hoge

$ cd dir
$ sh ../pwd.sh
/Users/hoge
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;その他の解決策&lt;/h2&gt;
&lt;p&gt;shell script内のpathを、&lt;code&gt;&quot;$HOME&quot;&lt;/code&gt;などの変数を使って絶対パスで記載する。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;以下のテンプレートをshell scriptの先頭に追加すると良い。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;#!/bin/sh
SCRIPT_DIR=`dirname $0`
cd $SCRIPT_DIR
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;追記 (2020/03/19)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;$SCRIPT_DIR&lt;/code&gt;にフルパスを格納するなら以下の通り&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;SCRIPT_DIR=$(cd $(dirname $0); pwd)
cd $SCRIPT_DIR
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>hexoによる静的サイトの構築</title>
      <link>https://memo.yammer.jp/posts/hexo</link>
      <pubDate>Mon, 16 Mar 2020 00:09:00 GMT</pubDate>
      <guid>https://memo.yammer.jp/posts/hexo</guid>
      <description>&lt;h2&gt;Hexoによる静的サイトの構築&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;は、node.jsを使った静的サイトジェネレータ。&lt;/p&gt;
&lt;p&gt;markdown形式の記事を静的サイトに簡単に公開できる。&lt;/p&gt;
&lt;h3&gt;Hexoの導入&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npm install hexo-cli
$ npx hexo init ../memo.yammer.jp 
$ cd ../memo.yammer.jp
$ npm install
$ hexo server
# ローカルでサイトの確認
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Hexoの設定について&lt;/h3&gt;
&lt;p&gt;設定は基本的に&lt;code&gt;_config.yml&lt;/code&gt;に書き込む。&lt;/p&gt;
&lt;p&gt;例えば、このサイトの&lt;a href=&quot;https://github.com/yammerjp/memo.yammer.jp/blob/master/_config.yml&quot;&gt;&lt;code&gt;_config.yml&lt;/code&gt;&lt;/a&gt;が一例。&lt;/p&gt;
&lt;h3&gt;テーマの導入&lt;/h3&gt;
&lt;p&gt;Hexoはサードパーティで公開された様々なテーマを導入できる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexo.io/themes/&quot;&gt;公式サイトのテーマ一覧&lt;/a&gt;にあるように、様々なものが選べる。&lt;/p&gt;
&lt;p&gt;今回は&lt;a href=&quot;https://github.com/aircloud/hexo-theme-aircloud&quot;&gt;air-cloud&lt;/a&gt;を導入した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ git clone https://github.com/aircloud/hexo-theme-aircloud.git theme/air-cloud
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;テーマ特有の設定は、&lt;a href=&quot;https://github.com/aircloud/hexo-aircloud-blog&quot;&gt;Demo&lt;/a&gt;の&lt;a href=&quot;https://github.com/aircloud/hexo-aircloud-blog/blob/master/_config.yml&quot;&gt;&lt;code&gt;_config.yml&lt;/code&gt;&lt;/a&gt;が参考になる。&lt;/p&gt;
&lt;h3&gt;特別なページの設置&lt;/h3&gt;
&lt;h4&gt;自己紹介ページの追加&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npx hexo new page about
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;source/about/index.md&lt;/code&gt;を次の内容に編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-md&quot;&gt;---
layout: about
title: About Me
date: &quot;2020-03-16 11:22:00&quot;
---

## About Me

yammerjpの雑多なメモ。

- twitter: [@yammerjp](https://twitter.com/yammerjp)
- GitHub: [@yammerjp](https://github.com/yammerjp) 
- [blog](https://blog.yammer.fun)

&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;タグページの追加&lt;/h4&gt;
&lt;p&gt;次のコマンドで、tagページを作る&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npx hexo new page &quot;tags&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;source/tags/index.md&lt;/code&gt;を次のように書き換える&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-md&quot;&gt;---
title: All tags
type: &quot;tags&quot;
--- 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;検索機能の追加&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-shell&quot;&gt;$ npm i hexo-generator-search --save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;_config.yml&lt;/code&gt;に次の内容を記載する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;# _config.yml
search:
  path: search.json
  field: post
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
  </channel>
</rss>
