20210606のLinuxに関する記事は7件です。

シェルスクリプトでフィボナッチ数を求める

はじめに 以前に【Oracle】PL/SQLでフィボナッチ数を求めるという記事を書いたので、同様にシェルスクリプト(Bash)でもフィボナッチ数を求めるスクリプトが作れるのではと思い、実際に試してみることにしました。 使用した環境 paiza.ioのBashエディタ画面を利用して、作成したスクリプトを実行しました。 無料で実行環境を使わせてもらえるのはありがたいですね。 作成したコード 最初はPL/SQLと同様に再帰させてフィボナッチ数を求めようと思っていましたが、 シェルスクリプトは戻り値が存在しない ということに気が付いて断念しました。 日常的にシェルスクリプトを使っている方には当たり前の話かもしれませんが、たまにしか使わない自分には衝撃的でした... そこで、アルゴリズムで天地の差: 計算の手間の「再帰も配列も使わないフィボナッチ数の計算」という章に書かれているRubyのコードを参考にして、再起を使わない方法でフィボナッチ数を求めることにしました。 なお、参考にしたページでは第2項目~第n項目までのフィボナッチ数を求めていますが、そのアルゴリズムを少し変えて第0項目~第n項目までのフィボナッチ数を求めるコードを作成しました。 ただし第n項目の「n」が大きくなると処理に時間がかかるため、「0~100までの間のフィボナッチ数を求める」という形に修正しました。 calc_fibonacci.sh #!/bin/bash # 再帰も配列も使わず、0~100までの間のフィボナッチ数を返す。 # http://www.aoni.waseda.jp/ichiji/2014/ruby-01/ruby-14-1.html result=0 # フィボナッチ数の計算結果 p1_result=0 # 1つ前のフィボナッチ数の計算結果 i=0 # ループのカウンタ変数 while true do if [ $i -eq 0 ]; then result=0 elif [ $i -eq 1 ]; then result=1 p1_result=1 else p2_result=$p1_result # 1つ前の計算結果を2つ前の計算結果に代入 p1_result=$result # 直前の計算結果を1つ前の計算結果に代入 result=$(($p1_result+p2_result)) fi if [ $result -gt 100 ]; then # 計算結果が100より大きい時は処理を抜ける。 break fi echo $result i=$((i + 1)) done 実行結果 実行結果 0 1 2 3 5 8 13 21 34 55 89 参考URL アルゴリズムで天地の差: 計算の手間
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 20.04 に xrdp を入れてリモートデスクトップできるようにする

Ubuntu 20.04 に X11 + VNC でいい感じのヘッドレスリモートデスクトップ環境を作ろうとして一週間くらい苦戦していたた、VNC を諦めて xrdp を入れたら一瞬でできてしまった。まとめるほどの内容ではないがまとめておく。 やりたかったこと 自宅ネットワークに Ubuntu Desktop 20.04 が入ったサーバがあるが、このサーバは自宅 LAN には接続されているがディスプレイは接続されておらず、これを自宅 LAN 内の MacBook からリモートデスクトップして使いたい。 VNC でうまくできなかった件 ディスプレイが無いので、vino のような「既に起動しているセッションを VNC 経由で遠隔操作する」ようなやりかたではできず、またリモート接続のたびにセッションを起動できるように Xvnc + inetd を試みたがこれはうまく設定できなかった。(力不足) そんな矢先に「試しに VNC じゃなくて RDP でやってみるか」と xrdp を入れてみたら一瞬で動いてしまったので、もうこれでいいかとなった。 xrdp の導入 前提として、Ubuntu 20.04 Desktop を minimal install した状態でやっている。 インストール $ sudo apt install xrdp xrdp の設定 /etc/xrdp/startwm.sh の冒頭に以下を追加して、RDP 接続時に GNOME セッションが起動するようにしておく。 /etc/xrdp/startwm.sh export GNOME_SHELL_SESSION_MODE=ubuntu export XDG_CURRENT_DESKTOP=ubuntu:GNOME これだけでもひとまず接続できるようにはなるが、そのままだと RDP 接続中に Authentication is required to create a color managed device というダイアログがたびたび出てめんどくさいので、以下のファイルを作成することでこれを表示されないようにする。 /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla [Allow Colord all Users] Identity=unix-user:* Action=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile ResultAny=no ResultInactive=no ResultActive=yes RDP クライアントから接続する macOS からなので Microsoft Remote Desktop アプリを入れて接続してみたが、普通に接続できた。めでたしめでたし。 備考 Ubuntu 21.04 以降はデフォルトのディスプレイサーバが X.org から Wayland に変わったので、Wayland のままではこの方法はできなさそう。 参考 第621回 Ubuntu 20.04 LTSでxrdpを使用する:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社 allowed_users=anybody の設定はやらなくても普通に接続できてしまった、理由はよくわからない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OS初学者の学習記録 〜2. プロセス(その1)〜

プロセスとは? 実行されるプラグラムの単位。 例 Webブラウザ 電子メールリーダー Excel テキストエディタ 並列処理と並行処理 OSは、複数のプロセスの生成・実行・消滅を管理し、プロセスの「並行処理」を実現する。(マルチプログラミング、マルチタスク) 複数のプロセスを、複数のプロセッサで実際に同時に実行することを「並列処理」という。(ややこしい、、) プリエンプション プロセスは、入出力をもつものが多いので、入出力まち状態のときにプロセスを切り替えることで、上記の「並列処理」を実現できる。 しかしこれでは、入出力がないプロセスでは、そのプロセスが終わるまで他のプロセスにプロセッサを割り当てられない、、 ↓ プロセスの「割り込み」によって解決。このOSの仕組みを「プリエンプション」という。 逆に、プロセス自身が明示的に「もういいよ、次の人(プロセス)に変わってあげる」とOSに制御を渡す仕組みのことを「ノンプリエンプティブ」という。 プロセスの構造 OSではプロセスをどのような構造で扱っているのか?? プログラムを、コンパイラでプロセッサが理解できる機械語に変換 機械語に変換されたプログラム(オブジェクトプログラム)をもとにプロセスを生成 プロセスのメモリ構造 ・コード領域 (静的) オブジェクトプログラムに相当。 ・データ領域(静的) プログラムを実行する際にはじめから存在し、プログラム全体で利用されるデータを入れる領域。 プログラム全体で利用されるデータを入れる領域には、 初期化変数領域 未初期化変数領域 がある。 ・ヒープ領域(動的) プログラム実行中に、明示的に確保されるメモリ領域。 メモリ領域は、プログラムの実行状況によって動的に割り当てられる。 ・スタック領域(動的) 関数の引数、ローカル変数、関数の戻り先の番地などが格納される。 ヒープ領域とスタック領域の使い方 ヒープ領域やスタック領域には上限はあるが、それぞれどの大きさが使用されるかわからない。 そこで、この2つの成長方向を逆にして、start位置を領域の両端におくことで、最大限効率的に使えるようにする。(ヒープ小さくてスタックめっちゃでかいときや、その逆で活躍する) プロセス記述子(プロセス制御ブロック) プロセス識別子、優先度等のスケジューリング情報、資源利用情報などが格納されている。 また、「プロセッサ」の状態も格納されている。 プロセッサの状態 ・プログラムカウンタ 次に実行する機械語命令のアドレス ・スタックレジスタ スタックの現在のアドレス(後入れ先出しなので、新しいのが入るたびに、その値に更新) ・フラグレジスタ 演算結果の状態を保持 プロセスの状態 状態の種類 以下の3つの状態のいずれかを取る ・実行可能状態 他のプロセスがプロセッサを使用しているために、一時的に中断している状態 ・実行中状態 プロセッサ使用中の状態 ・まち状態 外部事象の発生まちのために実行できない状態 実行するプロセスの切り替え 実行中のプロセスを実行中の状態から実行可能状態にうつし、他のプロセスを実行中状態にすることを「ディスパッチ」という。ディスパッチにより処理を切り替えることを「コンテキスト切り替え」という。 また、実行中のプロセスを強制的に実行可能状態に戻すことを「プリエンプション」という。(前でも出てたね) スケジューリング 実行するプロセスを決めるプログラムを「スケジューラー」という。 スケジューリングアルゴリズムが満たすべき要件 ・公平性 各プロセスになるべく公平にプロセッサを割り当てる ・プロセッサの利用率 CPUの動作時間をなるべく長くする (切り替えやりすぎると落ちる) ・スループット 単位時間あたりに完了するプロセス数をなるべく大きくする ・ターンアラウンド時間 プロセス実行欲求から完了するまでの時間をなるべく短くする アルゴリズムの例 (準備中) ・到着順 ・処理時間順 ・残余処理時間順 ・ラウンドロビン ・優先度順 ・多重フィードバック スレッド 1つのプロセスの中に複数個存在する、並行処理の単位。 「ユーザーレベルスレッド(ユーザー空間で実現されるため、OSの介入はない)」と 「カーネルレベルスレッド(プロセスと同様、OSによってスケジュールングされる)」に分けられる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OS初学者の学習記録 〜2. プロセス〜

プロセスとは? 実行されるプラグラムの単位。 例 Webブラウザ 電子メールリーダー Excel テキストエディタ 並列処理と並行処理 OSは、複数のプロセスの生成・実行・消滅を管理し、プロセスの「並行処理」を実現する。(マルチプログラミング、マルチタスク) 複数のプロセスを、複数のプロセッサで実際に同時に実行することを「並列処理」という。(ややこしい、、) プリエンプション プロセスは、入出力をもつものが多いので、入出力まち状態のときにプロセスを切り替えることで、上記の「並列処理」を実現できる。 しかしこれでは、入出力がないプロセスでは、そのプロセスが終わるまで他のプロセスにプロセッサを割り当てられない、、 ↓ プロセスの「割り込み」によって解決。このOSの仕組みを「プリエンプション」という。 逆に、プロセス自身が明示的に「もういいよ、次の人(プロセス)に変わってあげる」とOSに制御を渡す仕組みのことを「ノンプリエンプティブ」という。 プロセスの構造 OSではプロセスをどのような構造で扱っているのか?? プログラムを、コンパイラでプロセッサが理解できる機械語に変換 機械語に変換されたプログラム(オブジェクトプログラム)をもとにプロセスを生成 プロセスのメモリ構造 ・コード領域 (静的) オブジェクトプログラムに相当。 ・データ領域(静的) プログラムを実行する際にはじめから存在し、プログラム全体で利用されるデータを入れる領域。 プログラム全体で利用されるデータを入れる領域には、 初期化変数領域 未初期化変数領域 がある。 ・ヒープ領域(動的) プログラム実行中に、明示的に確保されるメモリ領域。 メモリ領域は、プログラムの実行状況によって動的に割り当てられる。 ・スタック領域(動的) 関数の引数、ローカル変数、関数の戻り先の番地などが格納される。 ヒープ領域とスタック領域の使い方 ヒープ領域やスタック領域には上限はあるが、それぞれどの大きさが使用されるかわからない。 そこで、この2つの成長方向を逆にして、start位置を領域の両端におくことで、最大限効率的に使えるようにする。(ヒープ小さくてスタックめっちゃでかいときや、その逆で活躍する) プロセス記述子(プロセス制御ブロック) プロセス識別子、優先度等のスケジューリング情報、資源利用情報などが格納されている。 また、「プロセッサ」の状態も格納されている。 プロセッサの状態 ・プログラムカウンタ 次に実行する機械語命令のアドレス ・スタックレジスタ スタックの現在のアドレス(後入れ先出しなので、新しいのが入るたびに、その値に更新) ・フラグレジスタ 演算結果の状態を保持 プロセスの状態 状態の種類 以下の3つの状態のいずれかを取る ・実行可能状態 他のプロセスがプロセッサを使用しているために、一時的に中断している状態 ・実行中状態 プロセッサ使用中の状態 ・まち状態 外部事象の発生まちのために実行できない状態 実行するプロセスの切り替え 実行中のプロセスを実行中の状態から実行可能状態にうつし、他のプロセスを実行中状態にすることを「ディスパッチ」という。ディスパッチにより処理を切り替えることを「コンテキスト切り替え」という。 また、実行中のプロセスを強制的に実行可能状態に戻すことを「プリエンプション」という。(前でも出てたね) スケジューリング 実行するプロセスを決めるプログラムを「スケジューラー」という。 スケジューリングアルゴリズムが満たすべき要件 ・公平性 各プロセスになるべく公平にプロセッサを割り当てる ・プロセッサの利用率 CPUの動作時間をなるべく長くする (切り替えやりすぎると落ちる) ・スループット 単位時間あたりに完了するプロセス数をなるべく大きくする ・ターンアラウンド時間 プロセス実行欲求から完了するまでの時間をなるべく短くする アルゴリズムの例 (準備中) ・到着順 ・処理時間順 ・残余処理時間順 ・ラウンドロビン ・優先度順 ・多重フィードバック スレッド 1つのプロセスの中に複数個存在する、並行処理の単位。 「ユーザーレベルスレッド(ユーザー空間で実現されるため、OSの介入はない)」と 「カーネルレベルスレッド(プロセスと同様、OSによってスケジュールングされる)」に分けられる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows -> Linux へssh接続で公開鍵認証を実装

2021.06.05 Windows から Linux へssh接続時に公開鍵認証を実装できたので備忘録として。 TeraTermもしくはPowerShellを使うのが一般的らしいが、ひねくれているのですべてコマンドプロンプトで実行してみた。 【参考】 ■Windows10で公開鍵認証の鍵ペアを生成してサーバーにSSH接続する https://onoredekaiketsu.com/generate-key-pair-for-public-key-authentication-in-windows10-and-connect-to-server-with-ssh/ ■manページ — SSHD_CONFIG https://nxmnpg.lemoda.net/ja/5/sshd_config ■SCPコマンドでローカルのファイルをサーバにアップ&サーバ上のファイルをDL https://qiita.com/ritukiii/items/c724f09fe66fedf2618b ■openssh-serverが入っているのにsshでログインできない https://killingout-n-bita.hateblo.jp/entry/2018/07/08/162520 1.Windows 側で公開鍵・秘密鍵を作成。 まずは鍵を入れておくためのフォルダを作成する。 コマンドプロンプトを起動し、以下のコマンドを実行。 (ついでにcdコマンドでカレントディレクトリを作成したフォルダにしておく) C:¥Users¥hemuwan> mkdir .ssh C:¥Users¥hemuwan> cd .ssh C:¥Users¥hemuwan> .ssh C:¥Users¥hemuwan¥.ssh> 次に公開鍵と秘密鍵のペアを作成する。 C:¥Users¥hemuwan¥.ssh> ssh-keygen ssh-keygenコマンドを実行すると、パスフレーズの入力を求められる。 任意のパスフレーズを2回入力。(忘れたらまた作り直しになるよ) -tオプションで鍵の方式を指定できるけど、今回はお試しでデフォルトのRSAを使ってみる。 パスフレーズを入力したら、dirコマンドなどでC:\Users\hemuwan\.ssh 配下に id_rsa id_rsa.pub  が生成されたことを確認する。 「id_rsa」が秘密鍵、「id_rsa.pub」が公開鍵となる。 ユーザー認証で公開鍵認証を用いるために、「公開鍵」の方をSSHサーバーとなるLinuxへ送り付ける。 「秘密鍵」はログイン時に使う。 2.Linux側のユーザに「公開鍵」を送付 .sshフォルダで、以下コマンドを実行。 C:¥Users¥hemuwan¥.ssh> scp -P <ポート番号> id_rsa.pub <ユーザ名>@<IPアドレス>:ClientPubKey scpコマンドを使い、「id_rsa」を<ユーザ名>のホームディレクトリに「ClientPubkey」と名前をつけて送付している。 (最近ではプロトコルが古くなり、scpコマンドの使用は推奨されていないらしい。OpenSSH開発プロジェクトではsftpやrsyncの利用が増えているとか) 3.Linux 側で、もらった公開鍵を.sshに配置 もらった公開鍵を.ssh 配下に、authorized_keys という名前で配置する。 (これの名前間違えててハマった。必ずauthorized_keysにするかconfig変えるかをする) 以下のコマンドはホームディレクトリに移動した後、catコマンドで表示するものを>>でリダイレクトし、.ssh/配下にauthorized_keysという名前のファイルにして保存するというコマンド。 $ cd ~ $ cat ClientPubKey >> ./.ssh/authorized_keys 4./etc/ssh/sshd_config を編集。 最終的にこうした、というのだけ書く。 Port <任意のポート番号> デフォルトは22。セキュリティ的にデフォルトの番号から変えた方がよいとのこと。 (今回の公開鍵認証の実装に関しては変えても変えなくてもどっちでも) HostKey /etc/ssh/ssh_host_rsa_key これないとホスト認証ができない。 ないときはsudo dpkg-reconfigure openssh-serverとかすると、再作成してくれるはず。 (参考:https://killingout-n-bita.hateblo.jp/entry/2018/07/08/162520 より) PubkeyAuthentication yes 公開鍵認証を許可するかどうか。デフォはno。 AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 ユーザ認証のさいに使われる公開鍵を格納しているファイル名を指定。 (設定はそのまま。コメントアウトの#消しただけ) PasswordAuthentication no パスワード認証を許可するか。デフォはyes (なぜかnoにしても公開鍵認証の設定終わるまでパスで入れていた。どうして、、) PermitEmptyPasswords no パスワード認証が許可されているとき、パス文字が空のアカウントに対し、 サーバがログインを許可するかどうかを指定。デフォはno。 PermitRootLogin no ssh を使って、rootがログインできるかどうかを指定。デフォはno。 AllowUsers <任意のユーザ名> ssh接続を許可するユーザ。 デフォルトでは書かれていないので必要に応じて末尾に書く。 Protocol 2 サポートするプロトコルのバージョンを指定。引数は1,2のみ。 デフォルトでは書かれていないので必要に応じて末尾に書く。 以上の設定が終わったら、読みこみなおす。 $ sudo systemctl restart sshd 5.Windows側から接続を試みる。 コマンドプロンプトから以下のコマンド実行。 ssh <IPアドレス> -l <ユーザ名> -p <ポート番号> -i C:¥Users¥henuwan¥.ssh¥id_rsa ログイン時、鍵を作った時のパスフレーズ求められる。 (テラタームでも成功した。) 二回目以降は、-i オプション以降なくてもパスフレーズを求められ、入力するとログインできた。 おわりに ようやく公開鍵認証を実装できた。 (なんやかんや行き詰ったりして1日つぶれた) 今の状態だと、パスワード同様にパスフレーズを忘れてしまうと、 ログインできなくなる。 aah-agent などを使って、自動ログインできるようにしたいところ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OS初学者の学習記録 〜1. OSの概要〜

システムの階層(上にいくほど高レイヤー) アプリケーションプログラム ユーザーインターフェース (GUI, CUI) OS ハードウェア 2つの動作モード(@プロセッサ) カーネルモード OS以下はこのモードで動作 すべてのハードウェアにアクセス可能 すべての命令を実行可能 ユーザーモード ユーザーインターフェース以上はこのモードで動作 他のプログラムに影響が出る命令が禁じられている OSの2つの役割 仮想マシンを実現 一連のハードウェアに対する処理をパッケージ化して、仮想的なハードウェアを提供。 メリット * ハードウェアの詳細な状況を意識せずにプログラムを作成できる * パッケージ化した一連の手続きを抽象化できる (例:ファイル操作) リソースマネジメント 1つのプログラムだけを実行するだけでは、利用されないリソースが出る。 プログラム実行を効率化するために、複数のプログラムを同時実行し、OSがその取りまとめを行う。 (=資源の多重化) ハードウェアの概要 プロセッサ(CPU) レジスタ(記憶素子) デコードユニット(命令解読機) 実行回路 メモリ  階層 レジスタ キャッシュ メインメモリ ハードディスク 種類 HDD SSD DVD-R etc.. 入出力デバイス OSは入出力デバイスも管理しないといけない。 ただ、通常デバイス制御命令は非常に煩雑になっている事が多い、、 →「コントローラー」というOSをデバイスの中間的なインターフェースがムズいところは吸収してくれる。デバイス制御のためのソフトウェアを「デバイスドライバ」という バス プロセット、メモリ、その他の入出力デバイスが、お互いにデータのやり取りをするために必要な共通の信号線。 プロセッサとキャッシュ、プロセッサとメモリの間にはそれぞれ専用バスが使用されている。 入出力デバイスでいえば、 * USB (universal serial bus) * IEEE1394 * Thunderbolt とかがあるみたい。 OSの基本要素 プロセス プログラムの実行単位。 制御に必要な情報を取りまとめるために必要。 メモリ空間 お互いのプログラムは、独立したメモリ空間を割り当てる必要がある 仮想的なメモリ空間を提供することで、自身のプログラムに必要なデータがどこにあるのかを都度物理的なアドレスで確認しなくても良くなる ファイル(ファイルシステム) ファイルをひとまとめにしたディレクトリという概念で構造化 このようにファイルとディレクトリという概念を使って、データの構造化を実現する仕組みを「ファイルシステム」という 入出力 * 入出力デバイスの管理もOSが担当 * 複数ユーザーが使用するときには調停を担当 保護機能 マルチユーザーシステムにおいての、「権限」の仕組み 「権限」はデータ閲覧、プログラムの実行などに対して設定される システムコール OSが用意したインターフェース。(OSが管理する資源をユーザープログラムから使用際に使用) プログラム言語の関数のような形で定義されている。 ユーザープログラムの「関数」との違い ユーザープログラムの関数は、ハードウェアの目線から見れば「実行する位置アドレスの変更」にすぎない。 それに対して、システムコールが呼ばれる際には、ユーザープログラムはその処理の状況を保存して終了する。 その後、システムコールハンドラ(システムコールのプログラム)がプロセッサをカーネルモードに変更してから、処理を実行する。 性質 システムコールは、基本的に複数のプログラムから同時に呼び出すことができない。 →これにより、プログラム同士の干渉が起こるのを防ぐ システムコールの仕様について システムコールとして用意される処理の種類は、OSそのものの機能に関連するものなので大体同じ。 ↓ しかし細かい仕様は、OSの設計思想によって異なる。 システムコールが異なると、実装に影響が出てしまう。 ↓ 仕様を共通化する動きがある。代表的なものは、「POSIX」。 言語と単位 使用されている言語 ハードウェアに近い処理は、一部アセンブラで書かれていることもあるが、だいたいC言語が使われている。 単位 bps (bit per second):通信速度 rpm(revolution per minute):ディスクの1分あたりの回転数 とか。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最低限知っておくと良さそうなLinuxのコマンドとコントロールキー

コマンドとオプション pwd カントディレクトリを表示できます。 $ pwd /home/linux ls ディレクトリ内のファイルを表示できます。 $ ls bin dev home lib64 mnt proc run sys usr... -lオブションをつけると、ファイル属性など詳細な情報を同時に表示できます。 -aオプションをつけると、隠しファイルも含めて表示されます。 cd カントディレクトリを変更できます。 $ cd /bin ファイル操作 mkdir ディレクトリを作成できます。 $ mkdir workspace 親ディレクトリも含めてディレクトリを一気に作成できます。 $ mkdir -p workspace/practice/practice01 touch ファイルを作成できます。 $ touch test cat ファイルを表示できます。 $ cat test rm ファイルを削除できます。 $ rm testdir ディレクトリを削除できます。 $ rm -r testdir rmdir 空のディレクトリを削除できます。 $ rmdir test cp ファイルをコピーできます。 ※file1をfile2という名前でコピーできます。 $ cp file1 file2 mv ファイルを移動する。 ※fileというファイルをdirというディレクトリに移動できます。 $ mv file dir 補完機能 補完機能は、Tabキーを押すことで使用できます。 複数の候補がある場合は、2回Tabキーを押すとコマンドのリストが表示されます。 コントロールキー Ctrl + a 先頭に移動できます。 Ctr + e 行末に移動できます。 Ctr + b 後方に一文字分移動できます。 Ctr + f 前方に一文字分移動できます。 Ctr + l プロンプトの画面消去ができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む