ターミナルの環境改善活動をしてみた
先日、同僚とモブプログラミングをしていてrg
コマンドを使ってgrep
に近いことをしていてとても便利そうだったので、導入しようとおもったので、記事にしました。
巷を賑わすRust 製のコマンドたち
最近、自分のターミナルを豊かにするアンテナを貼っていなかったのであまり知らなかったのですが、Rust 製のコマンドが流行ってるみたいですね。
今は、仕事の都合上Python を触ることが多いのですが、違う言語にも触れたいと思っていたので、少しRust に興味を持ったので、少しそういう記事を増やしても行くかもしれません。
ひとまず、今回の主題に入っていこうと思います。
コマンドの導入方法
今回インストールする環境は、macOS Catalina になります。
まあMac といえばこういうツールに関してはbrew
でインストールするというのもありなのですが、個人的に開発で使う環境ということもあり、
何をbrew
でいれたか、何をコードからビルドしたかわからなくなるのがいやなので、
最近はbrew
から入れないようにしています。
なので、Rust 製のコマンドに関してはコードからのビルド
or cargoでbuild
のどちらかで進めようと思います。
Rust 環境を整備する
今後Rust を勉強しようとおもったのでRust の環境を今回は導入していこうと思います。
rust-lang.org にインストール方法を説明するページがあります。
コマンド一撃でセットアップできます。
ripgrep をインストールする
ripgrep のリポジトリは v こちら。
インストールの方法はREADMEにかかれており、各環境での手軽なインストールする方法が載ってますので、環境や自分のポリシーに合わせてインストールしてください。
コードからビルドする
Rust programmer 向けにcargo
を使いインストールする方法とコードからビルドする方法が提案されています。
cargo
経由でインストールする
cargo
を使ってインストールする場合は、
$ cargo install ripgrep
とすれば良いみたいです。
ただ、注意点としてはRust
のバージョンが1.34.0
以降である必要があるとのことです。
コードからビルドする
コードからビルドするには、git clone でコードを引っ張ってくるところからスタートします。
$ git clone https://github.com/BurntSushi/ripgrep $ cd ripgrep $ cargo build --release
cargo build
とすると必要なcrates
をdownload し、compile してくれます。
crates
とはRust
の世界でpackage
を指す言葉のようです。
build 自体は多少時間がかかりましたが、無事成功しましたので、実行できるか確認してみます。
$ ./target/release/rg --version ripgrep 12.1.1 (rev 11c7b2ae17) -SIMD -AVX (compiled) +SIMD +AVX (runtime)
成功しているみたいです。
ただ、コードからビルドした場合は、./target
以下にバイナリが作られるだけなので、パスを通す必要があります。
今回、自分は/usr/local/bin
にシンボリックリンクを貼るようにしました。
$ rg --version ripgrep 12.1.1 (rev 11c7b2ae17) -SIMD -AVX (compiled) +SIMD +AVX (runtime)
コマンドとして呼び出すことができました!
プライバシーポリシーを設定しました
こんにちは管理人のtoohskです。
下記、「プライバシーポリシー」に関して記載致しましたので、ご一読願います。
当サイトへのコメントについて 免責事項 プライバシーポリシーの変更について
当サイトに掲載されている広告について
当サイトでは、第三者配信の広告サービス(Googleアドセンス、もしもアフィリエイト)を利用しています。
このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 『Cookie』(氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。
またGoogleアドセンスに関して、このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、こちらをクリックしてください。
当サイトが使用しているアクセス解析ツールについて
当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。
このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。
この規約に関して、詳しくはこちら、またはこちらをクリックしてください。
当サイトへのコメントについて
当サイトでは、スパム・荒らしへの対応として、コメントの際に使用されたIPアドレスを記録しています。
これはブログの標準機能としてサポートされている機能で、スパム・荒らしへの対応以外にこのIPアドレスを使用することはありません。
また、メールアドレスとURLの入力に関しては、任意となっております。 全てのコメントは管理人であるtoohskが事前にその内容を確認し、承認した上での掲載となりますことをあらかじめご了承下さい。
加えて、次の各号に掲げる内容を含むコメントは管理人の裁量によって承認せず、削除する事があります。
- 特定の自然人または法人を誹謗し、中傷するもの。
- 極度にわいせつな内容を含むもの。
- 禁制品の取引に関するものや、他者を害する行為の依頼など、法律によって禁止されている物品、行為の依頼や斡旋などに関するもの。
- その他、公序良俗に反し、または管理人によって承認すべきでないと認められるもの。
免責事項
当サイトで掲載している画像の著作権・肖像権等は各権利所有者に帰属致します。
権利を侵害する目的ではございません。記事の内容や掲載画像等に問題がございましたら、各権利所有者様本人が直接メールでご連絡下さい。確認後、対応させて頂きます。
当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。
当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。
当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。
プライバシーポリシーの変更について
当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。
修正された最新のプライバシーポリシーは常に本ページにて開示されます。
運営者:toohsk
Numpy array のcopy で気をつけたいこと
TL; DR
- Numpy array のcopy は気をつけたい
- 特にNumpy array のブロードキャストの性質
- Numpy array をcopy したい場合も、純粋なPython のList オブジェクトも、適切なcopy 関数をつかおう
- でもスライス操作をするとその限りではなさそう?
Numpy array で気をつけたいことがあった
近頃、深層学習で当たり前のようにNumpy を触ることが増えてきていると思いますが、
Numpy の性質として気をつけたいところがありました。
なので、忘備録の意を込めて記事にしようかと思います。
Numpy 操作
以下のようにデータ操作を行いました。
>>> import numpy as np >>> a = np.arange(0, 10) >>> a # array([0, 1, ..., 9]) >>> sub_a = a[:3] # 最初の3要素をsub_a に代入。意図としてはa の中身をコピー >>> sub_a # array([0, 1, 2])
a
の3要素を sub_a
オブジェクトに代入しただけですね。
そして、この sub_a
に値を変更しました。
>>> sub_a[1] = 10 >>> sub_a array([0, 10, 2])
さて、このとき a
の値はどうなっているでしょうか?
結果は、
>>> a array([0, 10, 2, ..., 9])
となります。
どうしてこうなるのか?
Numpy はメモリを効率的に扱うため、
見た目は異なるオブジェクトのように扱っていても、
変数の値は同じメモリを見るようになっているみたいです。
つまり、
a[0]
の指しているメモリの番地と
sub_a[0]
が指しているメモリの番地が同じになっており、
片方を変更するともう一方も変更されるということになります。
特に気をつけたいブロードキャストの場合
Numpy では、以下のようにして、すべての要素にブロードキャストで代入することができます。
>>> sub_a[:] = 20
これはこれで大変便利ですよね。
このとき a
と sub_a
はどうなるでしょうか?
>>> sub_a array([20, 20, 20]) >>> a array([20, 20, ..., 9])
となってしまいます。
じゃあどうするのか?
このように別オブジェクトとしてコピーしたい場合は、
以下のように copy()
メソッドを利用するのがよいです。
>>> a = np.arange(0, 10) >>> sub_a = a[:3].copy() >>> a array([0 1 2 3 4 5 6 7 8 9]) >>> sub_a array([0 1 2]) >>> sub_a[:] = 30 >>> sub_a array([30 30 30]) # すべての要素が30になる。 >>> a array([0 1 2 3 4 5 6 7 8 9]) # 一方で、値が変わっていない。
通常のPython のlist 型は大丈夫なの?
実はPython のList オブジェクトも似たような問題が知られています。
例えば、以下のような形式の場合。
>>> b = list(range(10)) # [0 >>> b # [0, 1, 2, ..., 9] >>> sub_b = b # b をそのまま sub_b に代入 >>> b # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> sub_b # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> sub_b[0] = 10 # sub_b の要素を変更 >>> sub_b # [10, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> b # b の要素も変更されてしまっている。[10, 1, 2,..., 9]
上記は、ハマりポイントとして有名ですよね。
このように配列を別ものとしてコピーして操作したい場合は、
copy
ライブラリを使って、オブジェクトをコピーする必要があります。
一次元の配列なら、 copy.copy()
多次元の配列なら、 copy.deepcopy()
です。
ただし、一部であっても全体であっても、スライスでコピーした場合はその限りではないみたいです。
>>> b = list(range(10)) >>> sub_b = b[:3] >>> sub_b[0] = 10 >>> b [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> b = list(range(10)) >>> sub_b = b[:] >>> sub_b[0] = 10 >>> sub_b [10, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> b [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
是非参考にしてください。
GKE とCloudSQL を組み合わせたい
k8s の中にRDB コンテナをデプロイして管理するもよいと思いますが、
RDB だけフルマネージドサービスを使うパターンもあるかと思います。
アプリケーションコンテナはGKE で、RDB はCloudSQL で動かすにはどうしようと考えていたところ、Google Cloud のドキュメントの中に Running Django on Google Kubernetes Engine
というまさにやりたいことを実践しているドキュメントがあったので、やってみました。
ドキュメントは↓を参照してください。
Running Django on Google Kubernetes Engine | Python | Google Cloud
Google Cloud のドキュメントは結構和訳されているものがあるのですが、
今回の記事は英語だったのと、途中で少し躓くところもあったので、やったことを忘備録がてらメモを残そうかと思います。
誰かの参考になれば幸いです。
事前ノート
基本的にはドキュメントに記載されているコマンドスクリプトをそのままやるという感じなので、
部分的にしか書いていません。
また、今回はPostgreSQL instanse を使っているので、 psql
コマンドで接続します。なので、事前に psql
を使えるようにしておく必要があります。
MySQL の場合は検証してないですが、 基本的な操作は変わらないかと思うので、適宜MySQL に置換していただければと思います。
途中で設定しているパスワードなどは参考なので、各自適当な値を設定するようにしてください。
あしからず。
やったこと
デプロイするサービスはすでに用意されているものをpull してきて、それをビルドしました。
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git cd python-docs-samples/kubernetes_engine/django-tutorial
次にCloud SQL Proxy を使って、RDB インスタンスの生成と接続などなどやりました。インスタンス名は、一通り実行した感じだと、ドキュメント通りである必要はなく、適当で大丈夫だと思います。
gcloud services enable sqladmin # Mac 用のCloud SQL Proxy をダウンロード curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64 chmod +x cloud_sql_proxy # ターミナルからinstance を生成 # 今回はpoll-instance という名前で作成 gcloud sql instances create poll-instance --database-version=POSTGRES_11 --tier db-f1-micro --region=asia-northeast1
ドキュメントには、 gcloud sql instances describe [YOUR_INSTANCE_NAME]
というコマンドを使い、接続名を取得するという一文があります。
これは、 gcloud sql instances describe
の結果に対して、grep grep connectionName
とすることで適切な部分が取得できます。取得した値を [YOUR_INSTANCE_CONNECTION_NAME]
として表現されています。
# connection name を調べる gcloud sql instances describe poll-instance | grep connectionName
このconnection name とダウンロードしたcloud_sql_proxy を使ってlocal からinstance への接続を可能にします。
./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:5432
おそらく、上記のコマンドを実行しても終了などしないと思います。 これは、当たり前といえば当たり前なのですが、ローカルPC とCloud SQL instance との間で接続が確立されているので、切れなくて問題ないです。
なので、バックグラウンドで実行しておくとかも方法はありますが、僕は、次のコマンドからは新しいターミナルのパネルを開いて実行しました。
ここからは、ローカルからCloud SQL instanse に対して操作を行います。
psql --host 127.0.0.1 --user postgres --password
つまづきポイント①
ここでのパスワードってなんだ?ってなりました。
なぜなら、ドキュメントには Use the Postgres client or similar program to connect to your instance. When prompted, use the root password you configured.
とありますが、
作成したインスタンスに対して特にパスワードを設定した覚えがないからです。
ここでのパスワードは、console 画面のCloud SQL 画面で確認して入力すれば接続できました。
接続したら、DB の操作を行います。
ここでは、サービスを実行するのに必要な DATABASE
の作成や DATABASE
や TABLE
に対する権限の設定を行います。
ここの操作はドキュメントにある通り実行するがよいと思います。
ただし、ユーザとそのパスワードは適宜設定できるので、任意の値を設定してください。
今回は、 [POSTGRES_USER]
には、 poll_user
、 [POSTGRES_PASSWORD]
には、 poll_pw
を設定しました。
CREATE DATABASE polls; CREATE USER poll_user WITH PASSWORD 'poll_pw'; GRANT ALL PRIVILEGES ON DATABASE polls TO poll_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO poll_user;
次にサービスアカウントを作成します。
このサービスアカウントは、k8s クラスタからCloud SQL インスタンスに接続したり、クエリを投げるためのサービスアカウントになります。
設定する権限はドキュメント通り、以下の3つで十分でした。
鍵を生成する必要があるので json フォーマットの鍵を作成してダウンロードしておきます。
ここからはローカルで一度動作確認し、その次にGKE インスタンスにpod を展開していきます。
このあたりは特にハマったポイントはなかったのと、個人的には k8s ⇔ Cloud SQL 間の通信ができているのか?を確認するほうが重要だったので、一部割愛しています。
export DATABASE_USER=poll_user export DATABASE_PASSWORD=poll_pw # GKE クラスタを作成 gcloud container clusters create polls \\n --scopes "https://www.googleapis.com/auth/userinfo.email","cloud-platform" \\n --num-nodes 4 --zone "us-central1-a" # 作成したクラスタのクレデンシャルをkubectl にセット gcloud container clusters get-credentials polls --zone "us-central1-a" # クレデンシャルをkubectl コマンドに設定 kubectl create secret generic cloudsql-oauth-credentials --from-file=credentials.json=/path/to/service-account.json # PostgreSQL のuser password を設定する kubectl create secret generic cloudsql --from-literal=username=poll_user --from-literal=password=poll_pw docker pull b.gcr.io/cloudsql-docker/gce-proxy # ローカル環境でコンテナをbuild docker build -t gcr.io/hatch-sydney/polls . # gke にpush するためにauth の設定をして、push gcloud auth configure-docker docker push gcr.io/hatch-sydney/polls # k8s クラスタに向けてデプロイ kubectl create -f polls.yaml
ここまでの操作でpod をデプロイできました。 ハマリポイントはないと書きつつ、ハマリポイントが一つありました。
つまづきポイント②
kubectl
コマンドでPostgreSQL の秘密情報を登録するコマンド
kubectl create secret generic cloudsql --from-literal=username=poll_user --from-literal=password=poll_pw
でどのユーザを設定するか悩みました。
なぜなら、ドキュメントには [PROXY_USERNAME]
[PASSWORD]
と書かれており、これどこで設定した?という気持ちになったためです。
実行したコマンドの通り、ローカルからCloud SQL Proxy を通じてDB 操作を行ったときのuser とpassword を設定するのが正しいかと思います。
僕はこれで問題なく接続できました。
残りは、pod のログを取ったり、実際にexternal ip で接続してみたりするだけです。
# deploy したpod のstatus やid を調べる kubectl get pods # polls pod のログを見る。 以下では見られない。 kubectl logs polls-fd676657d-9qfnw # application のログを見たい場合は -c polls-app を指定する kubectl logs polls-fd676657d-9qfnw -c polls-app # Cloud SQL のログを見たい場合は -c cloudsql-proxy を指定する kubectl logs polls-fd676657d-9qfnw -c cloudsql-proxy # EXTERNAL-IP を調べて接続してみる kubectl get services polls
最後のコマンドで得られたexternal ip に接続するとページが見られるかと思います。
そして、最後のハマリポイントです。
つまづきポイント③
kubectl logs <pod-id>
だけではログは見られませんでした。この理由としては今回のpod には複数のコンテナが含まれており、その場合、どのコンテナを見るか?を指定する必要があります。
このことをすっかり忘れていたため、地味にハマりました。
コマンドのチートシートがあるので、忘れないために載せておきます。
まとめ
今回の気づきをまとめるとしたら、以下の3点でしょうか。
- GKE とCloud SQLを組み合わせたdjango アプリをデプロイしたよ
- いくつかハマリポイントあったよ
- GKE とCloud SQL を接続する上では、Cloud SQL の権限を設定したサービスアカウントをkubectl に設定することでpod から接続できるみたいだよ
まだまだ勉強することがたくさんありそうです。
k8s のpod の中のファイルをlocal にコピーしてくる方法
TL;DR;
k8s のpod 内にあるファイルは kubectl cp
コマンドでローカルにコピーできるよ
何がしたかったか
サーバーにあるファイルをアップロードやダウンロードする場合、よくscp で行うかと思います。 本業の開発では、kubernetes (以下、k8s) を用いて運用しており、 pod に入ってコマンドを叩き、その結果をpod 内のファイルに標準出力した。 このファイルをローカルに引っ張ってくるときに、どうすればいいんだ?と思い、調べました。
kubectl cp
k8s のクラスタを操作するにあたり、 kubectl
があります。
kubectl
はk8s クラスタやデプロイされたpod を操作するための印象が強いかと思います。
実際にkubectl のリファレンスを見ても、pod へのアクセスがメインで記述されていることがわかります。
しかし、実は kubectl
には cp
コマンドがあり、コピーするコマンドが用意されています。
cp
Copy files and directories to and from containers.
と書かれています。 containers と書いてありますが、pod からファイルをコピーするのに役立ちそうです。
# namespace に展開されているpod 一覧から対象を絞ります $ kubectl get pods -n <namespace> | grep <pod name> # cp コマンドでファイルをローカルにコピーします。 $ kubectl cp -n <namespace> <pod name>:/path/to/file /path/to/local/file
でコピーすることができました。
SudachiPy でユーザ辞書を作ってみた
前回のブログでGiNZA2.0 の導入について記述した。
形態素解析を行ったところ期待した粒度で分割されていないことがあった。
これは形態素解析を行う上で仕方ない部分であり、
こういう場合には分割されてほしくない単語をユーザ辞書で管理する必要がある。
GiNZA はトークン化するためにSudachiPy を利用している。 1
なので、ユーザ辞書はSudachiPy にそう形で用意する必要がある。
前提
前回と同様、pyenv でPython 3.7.3 をインストールした環境でのコードを書いていきます。
注意
本来、GiNZA をインストールすると合わせてSudachiPy がインストールされるが、今回は手動でインストールする。
SudachiPy のインストール
SudachiPy とSudachiDict_coreをインストールします。
$ pip install SudachiPy $ pip install https://object-storage.tyo2.conoha.io/v1/nc_2520839e1f9641b08211a5c85243124a/sudachi/SudachiDict_core-20190531.tar.gz
ユーザ辞書の元データ
前回、 金閣寺
が 金閣
寺
の2つに分割されてしまったので、 金閣寺
と出力されるように 金閣寺
をユーザ辞書に登録します。
金閣寺,4786,4786,5001,金閣寺,名詞,固有名詞,一般,*,*,*,キンカクジ,きんかくじ,*,*,*,*,*
4カラム目の 5001
はコストに相当するものですが、今回は適当に指定しています。
バイナリ化
SudachiPy でユーザ辞書を扱うためには、バイナリに変換した辞書を指定する必要があります。
以下のコマンドでバイナリ化できます。
$ sudachipy ubuild -s /path/to/system.dic user_dict.txt
ちなみに system.dic
のありかですが、
今回、pyenv でSudachiPy をインストールしていることもあり、 pyenv
配下で使用している python バージョンの site-packages
以下に
site-packages/sudachidict_core/resources/system.dic
としてありました。
参考にしてください。
次回はこのバイナリ化した辞書を使って、GiNZA で形態素解析を行います。
-
GiNZA のリポジトリの
SudachiおよびSudachiPy
参照↩
GiNZA 2.0 を触ってみた。
GiNZA はmegagonlabs が開発している日本語の形態素解析器です。 フレームワークとしてspaCy をFramework として利用しています。 今日2.0 がリリースされたので、インストールとユーザ辞書について触っていきたいと思います。
前提
今回、pyenv でPython 3.7.3 をインストールした環境でのコードを書いていきます。
インストール手順
インストール手順はこちらのページにあります。
2通りのインストール方法があるみたいです。
1つは、圧縮ファイルをダウンロードして、そのあとpip でインストールする方法です。
そして、もう一つはリンクをpip インストールコマンドで指定する方法です。
今回は、後者の方でインストールをしてみました。
pip install "https://github.com/megagonlabs/ginza/releases/download/latest/ginza-latest.tar.gz"
この場合、 latest
がダウンロードされるみたいです。
バージョンを指定する場合は、 latest
を指定すれば良さそう。
形態素解析
import spacy nlp = spacy.load('ja_ginza') doc = nlp('依存構造解析の実験を行っています。') for sent in doc.sents: for token in sent: print(token.i, token.orth_, token.lemma_, token.pos_, token.tag_, token.dep_, token.head.i) print('EOS')
実行結果はこちらになりました。
0 依存 依存 NOUN 名詞-普通名詞-サ変可能 compound 2 1 構造 構造 NOUN 名詞-普通名詞-一般 compound 2 2 解析 解析 NOUN 名詞-普通名詞-サ変可能 nmod 4 3 の の ADP 助詞-格助詞 case 2 4 実験 実験 NOUN 名詞-普通名詞-サ変可能 obj 6 5 を を ADP 助詞-格助詞 case 4 6 行っ 行う VERB 動詞-一般 ROOT 6 7 て て SCONJ 助詞-接続助詞 mark 6 8 い 居る AUX 動詞-非自立可能 aux 6 9 ます ます AUX 助動詞 aux 6 10 。 。 PUNCT 補助記号-句点 punct 6 EOS
恐らく、 token.i
が出力のインデックス、 token.orth_
が表層、 token.lemma_
が原型、 token.pos_
が英語での品詞、 token.tag_
が日本語での品詞と活用のようです。
token.dep_
、 token.head.i
はよくわかっていないので、後日調べて記事にしたいですが、
token.head.i
は係り受け先の id
のように見えます。
ユーザ辞書
例えば 足利義満は金閣寺を建立しました。
のような文章を形態素解析をしたい場合に、以下のような結果になります。
0 足利 足利 PROPN 名詞-固有名詞-人名-姓 compound 1 1 義満 義満 PROPN 名詞-固有名詞-人名-名 nsubj 6 2 は は ADP 助詞-係助詞 case 1 3 金閣 金閣 NOUN 名詞-普通名詞-一般 compound 4 4 寺 寺 NOUN 接尾辞-名詞的-一般 obj 6 5 を を ADP 助詞-格助詞 case 4 6 建立 建立 VERB 名詞-普通名詞-サ変可能 ROOT 6 7 し 為る AUX 動詞-非自立可能 aux 6 8 まし ます AUX 助動詞 aux 6 9 た た AUX 助動詞 aux 6 10 。 。 PUNCT 補助記号-句点 punct 6 EOS
このようにデフォルトの辞書で形態素解析を行うと 金閣寺
がまとまった名詞として扱われることを期待していた場合に、異なった結果になる場合があります。
このような場合にユーザ辞書を利用します。
GiNZA は SudachiPy
を利用しているようなので、ユーザ辞書は SudachiPy
の書き方に従って書けばユーザ辞書が使えそうです。
ユーザ辞書を扱うまでをブログの内容にしたかったのですが、 次回にまわしたいと思います。