OmniAICreator/Qiita-1.07M huggingface dataset:
今更ながらM1 MacBook Airを買ったので、MacBook Air 2018からParallels のWindows10を移行しようとしてハマった話

# 前提条件
移行元環境：macbookair2018(256GB),Paralells Desktop 18,Windows10pro
Windows10proライセンスは、Paralellsとは別に用意したDSP版です。

移行先環境（当初）：macbookair(M1)(512GB) ,Paralells,Windows10pro
移行先環境（最終的に）：macbookair(M1) ,Paralells,Windows11pro

# 背景
仕事でExcelを多用しています。mac版Officeも入れてますが、印刷や見た目など、互換性が完全ではないため、Windows版Officeが必要でした。そのためmacbookair2018,Paralells,Windows10proの環境でこれまで粘っていました。
移行前のストレージ状況はこんな感じです。
macbookair2018のssdが256GB、内Paralells用のWindows10proで100GB程度、macアプリ19GB、システム11GB、その他86GB(内Google driveで35GB程度)
本当はGoogle driveだけで41GBくらいあるんですが、容量不足に何度も陥ったため、ミラーリングから対象を絞ったストリーミングに途中で変更していました。

# 最初にやったこと
色々調べて、Paralells上のWindows環境、及びParalellsのライセンス自体は、移行すれば使えるらしいと結論づけて、やってみました。

移行ツールは使わずに、Googleドライブは新マシン(macbookair(M1))で、新たに同期、Paralellsは旧マシン(macbookair2018)でライセンスのログアウト後、新マシンでログインして移行、問題となる100GB程度のWindows10仮想化ファイルは、用意したthunderbolt4ケーブルで、共有をかけ、直接コピーしました。最初コピー完了まで64日とか出て、焦りましたが、すぐに表示が短くなって数時間になったので、残り40分くらいでしたが、一晩放置。おそらく全部で3～4時間でコピーできた感じです。
# 衝撃
ここまで準備ができたので、後は新マシンのParalellsでWindows10仮想化ファイルを起動するだけと思っていましたが、何と、intelベースのWindows10は、arm環境では動かないとParalellsにいわれ、元のWindows10仮想化ファイルそのまま使う作戦は頓挫しました。**当たり前といえば当たり前ですが、intelベースで作られたwindows仮想化ファイルは、armベースであるm1 mac環境では動かすことはできないという結論です。**
100GBのファイルコピーはムダになりました。
# 次善策
しょうがないので、新マシン上でarmベースのwindows環境を作ることにしましたが、どうせクリーンインストールならばWindows11にすることにしました。

# Paralles上でのWindows11インストール
Parallesを立ち上げるとすぐにWindows11新規インストールを聞いてくるので、とりあえずすすめたところ、ものの10分程度でWindows11環境が構築できました。しかしライセンス認証でハマりました。
ライセンス認証で旧マシンのwindows10proのライセンスキーを入力しても不正なコードとされ、microsoft storeも立ち上がらないため、新規購入も簡単にはできず。
後で気づきましたが、簡単にインストールできたWindows11はhomeエディションだったので、proのライセンスキーだと通らなくても当然でした。
いくつか試しましたが、最終的にはParallesで、別の仮想環境を作成。そこでisoファイルから作成することにしたら、途中でwindows11proが選べたのでインストール完了。Windowsライセンスのアクティベーション画面でトラブルシューティング、ハードウェア環境を変更　を選んで、対象ＰＣが表示されるも旧マシンが表示されず。どうやら旧マシンのWindows10proを移行しようと思ってマイクロソフトアカウントでのログインに切替えたりしたつもりですが、デジタル認証に移行していなかったようです。
前の画面でライセンスキー入力を選び、旧マシンのライセンスキーを入力したら無事認証されました。
# ムダだったこと
Windws11proのisoファイルをマイクロソフトから直接ダウンロードして、そこからインストールしようとしましたが、こちらはintel版なのではじかれました。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353601/6e86fb86-df3f-65a3-7d82-e1a61137188c.png">

Parallelsインストールと同時にインストールされていると思われる新マシン上のwindows11 isoが選べることに、途中で気づきました。

# 追記
ノートン360も移行しようとしたら、my nortonサイトからダウンロードしたもののでのインストールは失敗する。ノートンサイト内で調べたら、どうやらarmベースOSへのインストールは、windows store経由でとのことでした。試しましたがwindows storeからのノートン360インストールはエラー(コード: 0x8A150006)となってうまくいきません。
# 追記2
異なるネットワーク上のネットワークプリンタへの印刷がうまくいきません。Bonjourでの印刷は、うまくいくのですが、最終的に別ネットワークから印刷したいのでipアドレス指定でプリンターをインストールし、緑の〇で待機中と表示、印刷をかけるとスプールのところで、プリンタが応答しないとなって先に進まない状態です。問題の切り分けに時間がかかりそうです。
指定ディレクトリにあるファイル名をリストで取得する

指定ディレクトリにあるExcelファイル名の一覧をリストで取得した。

## 指定ディレクトリにあるファイル名をリストで取得する
**必要なusing記述**
```c#
using System.IO;
```
String型の配列を作成し、そこにファイル名の一覧が入る。

```c#
string[] files = Directory.GetFiles(@"C:\Users", "*.xlsx", System.IO.SearchOption.TopDirectoryOnly);
```
第一引数：指定ディレクトリまでのパス
第二引数：取得したいファイルの種類
　　　　　Excelファイルを取得する場合　`".xlsx"`
　　　　　すべての種類のファイルを取得したい場合 `"*"`
　　　　　ファイル名の文字数を指定したい場合　`"?????.xlsx"`　
第三引数：指定ディレクトリにあるファイルのみを取得する　`SearchOption.TopDirectoryOnly`
　　　　　サブフォルダにあるファイルも取得する　`SearchOption.AllDirectories`
<br>
あとは配列の要素を取得するコードを書けばOK。
　　　　
## 応用編
<br>

[パス情報をApp.configで指定する](https://qiita.com/suzuki_q/items/f77fd68226595648ae11)
と組み合わせて使用した。

**App.config**でディレクトリまでを指定しておく。
```App.config
<appSettings>
<add key="FilePath" value="C:\Users" />  
</appSettings>
```
※パスの区切りのバックスラッシュ(\\)は、実際のApp.configの見た目では¥になっています。(おそらく日本語環境を使用しているとそうなる)

組み合わせたコード↓
```c#
string[] files = Directory.GetFiles(ConfigurationManager.AppSettings["FilePath"], "*.xlsx", System.IO.SearchOption.TopDirectoryOnly);
```

<br>

参考：
[C#でフォルダ内のファイル名一覧を取得する](https://araramistudio.jimdo.com/2019/02/07/c-%E3%81%A7%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E5%86%85%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E4%B8%80%E8%A6%A7%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B/#:~:text=C%23%E3%81%A7%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%EF%BC%88%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%EF%BC%89%E3%81%AB%E3%81%82%E3%82%8B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%20System.IO.Directory%20%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%20GetFiles%20%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89,%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%20%E3%81%93%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%A7%E3%81%AF%20%E3%83%AF%E3%82%A4%E3%83%AB%E3%83%89%E3%82%AB%E3%83%BC%E3%83%89%20%E3%82%92%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%A6%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E7%B5%9E%E3%82%8A%E8%BE%BC%E3%82%93%E3%81%A0%E3%82%8A%E3%80%81%20%E3%82%B5%E3%83%96%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%BE%E3%81%A7%E5%90%AB%E3%82%81%E3%81%A6%E6%A4%9C%E7%B4%A2%20%E3%81%99%E3%82%8B%E4%BA%8B%E3%82%82%E5%8F%AF%E8%83%BD%E3%81%A7%E3%81%99%E3%80%82)
Amplifyのカスタムヘッダー設定時に判明したこと

## はじめに
Amplifyのカスタムヘッダーを設定した際に判明したことについてまとめます。

## カスタムヘッダーの設定方法
まず、Amplifyのカスタムヘッダー設定には、下記の2つの方法があります。
* AWSマネジメントコンソールからの設定
* customHttp.ymlをプロジェクトのルートディレクトリに配置

今回は後者の「customHttp.ymlをプロジェクトのルートディレクトリに配置」で行うことにしました。

## 判明したこと
設定後に反映されているかを確認するために、AWSマネジメントコンソール上のAmplifyの設定を確認してみました。
しかし、下記のように画面上には何も表示されていませんでした。

![Amplify_customHttp_yml.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2825569/2e6b3515-8969-38e7-4800-77c5459660d8.png)

設定した内容がここに表示されるものだと思い込んでいたため、設定できていないのかと思いましたが
対象ページにてChromeのデベロッパーツールから確認してみると、設定したカスタムヘッダーの内容がちゃんと適用されていました。

## サポートに確認したところ（2022/12時点）
この状況をAWSのサポートに確認したところ、設定自体は問題ないそうなのですが
ルートディレクトリの customHttp.yml の内容は、AWSマネジメントコンソール上のカスタムヘッダー（上記画面）には反映されない
との回答がありました。
なので設定できているかを確認したい方は、デベロッパーツールにて設定したカスタムヘッダーの内容が適用されていることを確認してみてください。
もし、同じように疑問を持った方のお役立てれば幸いです。

## 参考リンク
[カスタムヘッダー](https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/custom-headers.html)
SpringBootの@Transactionalでannotationがみつからない

# はじめに

SpringBootでトランザクションのアノテーションをしたところ、ライブラリが見つからない問題があったので簡単にまとめます

# 問題

```kotlin:BookService.kt
import org.springframework.transaction.annotation.Transactional
```

ここで`transaction`がないというエラーがでてしまった

# 解決方法

以下を依存関係に追加したところエラーが消えた

```kotlin:build.gradle.kt
	implementation("org.springframework:spring-tx")
```

# おわりに

以前同じようにAPIを作っていたときには問題なくアノテーションが使えていたので謎でしたが、エラーが消えてよかったです

# 参考

https://stackoverflow.com/questions/73603737/transactional-annotation-not-found-in-the-classpath
リモートワーク向かない人へのアプローチ方法

リモートワークを始めて5年ほどになり、働き方、周りとの関わり方が変わりました。
日々プログラムを書き、打ち合わせや後輩の教育などやっていますが、「リモートワーク向かないなぁ」と思う瞬間が何度かあり、その時にどのように解決していったのかを書こうと思います。

# なぜリモートワークを始めた？
本格的にリモートワークを始めたのは新型コロナウィルス蔓延によるところが大きいです。
大半の人がこれが理由でリモートワークをやることになったのではないでしょうか。

コロナ禍以前も本職とは別に個人的に受けている仕事もありリモートで仕事をすることがあったので、リモートワークをすることに対して抵抗はほとんどなかった。

逆に、通勤時間がなくなり、朝ゆっくりできるし、飯や飲み物代など無駄金を使わずに済んでいる。
（昼飯つくるの面倒で出前してしまうこともあるけど、、、）


# リモートワークって生産性が下がるんじゃないの？
リモートワークの話をすると、こんな問いを聞かれます。
リモートワークをすることで自分の時間ができたり、仕事しやすい環境で仕事ができ、プライベートも充実すると思います。
いい環境で仕事ができれば生産性は上がるはずだと思います。
じゃぁなぜリモートワークには生産性が下がるイメージがあるんでしょうか？

## リモートワークのメリット/デメリット
### メリット
* 通期時間にかけていた時間を別のことに使える
* 好きな環境で仕事ができる
* いつでもどこでも仕事ができる
* 宅配便など再配達がなくなる

### デメリット
* 誘惑がたくさんある
* リモート環境を作るために費用がかかる
* 仕事とプライベートのメリハリがなくなる
* チーム、現場での情報共有がしづらい

# リモートワーク向かない人へのアプローチ
生産性が下がる要因がデメリットにはいっぱいあります。
このデメリットに打ち勝てる人がリモートワークに向いている人で、デメリットに負けてしまう人が向いてない人となります。

リモートワークに向いてない人はなぜうまくいかないのか思い悩んで悶々とする日々を過ごすことでしょう。
まず、そんな人を見捨てずチームの課題として取り組むのが大事です。
日々自分自身だったり、後輩しているアプローチを紹介しようと思います。

## アプローチ方法
### 1日1つチームに貢献することを意識する。させる。
チームに貢献するという目標を持つことで環境の誘惑から目線を外されると共に、チームに貢献している成功体験を持つことによって生産性を上げていく。

小さいことでもいいので貢献することが大事。
積み重なれば技術も業務知識もいずれついてきてやれることも増えてくるはずです。

* プルリクエストのレビュー＆マージ
* 新しい技術、業務知識をチームへ共有 など...

### 1日1プルリクエスト作るためのタスクを作る
「1日1つチームに貢献することを意識する。させる。」にもつながり、明確にその日何をやるかが明確になります。
例えば、「◯○APIを実装するためのコントローラー層の実装」など、1日で実装が出来そうな分量をタスク化します。

### すぐ質問できる環境を作る
出勤して仕事をしている時は、話したい人の席まで行って話ができました。
リモートワークだとそういうわけにはいきません。
そこで、zoomやmeetなどでオンライン会議を設定し、仕事中はチームメンバーがそのオンライン会議に繋いでおくことで、聞きたい人にすぐ聞ける環境を作ります。
そうすることで、情報共有の漏れや質問しづらいということがなくなります。
ただ、各家庭、作業環境もあるので、下記のことは配慮してあげたほうがいいと思います。
* カメラオン、マイクオンの強制はしないこと。
* 質問や雑談したい時にマイクオンするような環境。


### 1日1回チームメンバーと話す
出勤していた時はチームメンバー間で仕事やプライベートの話をしたと思いますが、リモートワークではそういうわけにはいきません。
リモートワークをして、そういったメンバー間での会話で関係性ができて、仕事がやりやすくなっていたし、モチベーションも保たれていたんだなぁと実感しました。


# まとめ
自分がリモートワークをしている中で意識してやっていること書きました。
チームに貢献するとみんなから感謝されるし、自分の嬉しいのでその成功体験を増やしていくことで生産性を上げてより快適な環境で仕事ができるといいと思います。
「俺向いてないなぁ」って人はチームに貢献できることを考えてみてもいいですし、「向いてない後輩がいるんだよぉ」って先輩エンジニアは後輩くんと一緒に考えてみてはいかがでしょうか。
単語埋め込み系論文


## counter-fitting word vector
Counter-fitting Word Vectors to Linguistic Constraints
https://arxiv.org/abs/1603.00892

Gloveなどの単語埋め込みを得る手法には、意味的に似た単語が埋め込み空間上で近くに来やすいという性質がある。
その一方で、文脈から単語を学習するという仕組み上、対義語などの似た文脈に出るものも近くに来やすくなってしまう問題がある。
そこで、提案法は**辞書情報をもとに**単語埋め込みの再学習を行い、**類語語は近づけ対義語は離す**ように学習した。

結果として、このように類義語だけを近づけることができた。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/6cd124d4-b89b-1047-7758-4daabe2da433.png width=500>
vcpkg 依存ライブラリがダウンロードできなかった場合の対処方法

# vcpkg で install に失敗する原因
色々あると思うが今回遭遇したのは次の通り
* 依存ライブラリの消失
    ⇒ サポート終了のためか存在しない
* ターミナルを cmd でなく PowerShellで実行
    ⇒ エスケープ文字が異なるため異常終了する

今回は前者に対しての備忘録です

# MSYS系の場合
* vcpkg_acquire_msys.cmake を修正
`<インストールフォルダ>/scripts/cmake` 下にある `vcpkg_acquire_msys.cmake` を修正する

    ```cmake
    # To add new entries, use https://packages.msys2.org/package/$PACKAGE?repo=msys
    ```

    上記のコメントに従い `$PACKAGE` を任意のものに変更して ブラウザで表示すると 最新のものが表示されるので対象のライブラリを置き換える

    * libtool の場合
    ```cmake:変更前
    z_vcpkg_acquire_msys_declare_package(
        URL "https://repo.msys2.org/msys/x86_64/libtool-2.4.6-9-x86_64.pkg.tar.xz"
        SHA512 b309799e5a9d248ef66eaf11a0bd21bf4e8b9bd5c677c627ec83fa760ce9f0b54ddf1b62cbb436e641fbbde71e3b61cb71ff541d866f8ca7717a3a0dbeb00ebf
        DEPS grep sed coreutils file findutils
    )

    ```
    ```cmake:変更後
    z_vcpkg_acquire_msys_declare_package(
        URL "https://repo.msys2.org/msys/x86_64/libtool-2.4.7-3-x86_64.pkg.tar.zst"
		SHA512 a202ddaefa93d8a4b15431dc514e3a6200c47275c5a0027c09cc32b28bc079b1b9a93d5ef65adafdc9aba5f76a42f3303b1492106ddf72e67f1801ebfe6d02cc
        DEPS grep sed coreutils file findutils
    )
    ```
    ## Windowsでハッシュ値の求め方
    ターミナルで次のコマンドを実行
    ```cmd
    certut -hashfile <対象ファイル> SHA512
    ```
    |名前|内容|
    |-|-|
    |対象ファイル|ハッシュ値を算出する対象ファイル|

# MSYS系でない場合
`<インストールフォルダ>/ports/<パッケージ名>/portfile.cmake` の `vcpkg_download_distfile` を修正

# 参考

[vcpkgのissue に登録したら案内されたissue](https://github.com/microsoft/vcpkg/issues/28896)
【自分用】Domain Name System について

# ～ はじめに ～
DNSについて調べたが、どうせ時間が経つと忘れてしまうので、
ここに参考になったリンクや考え方を書き記しておきたいと思う。

**-- この時は、下記の疑問を調べた --**

- DNSってドメインってなんだっけ？
- ゾーンファイル、リソースレコードってなに？
- ゾーンファイルにでてくる＠ってなに？
- FQDNってどういう考えだっけ？
- ゾーンファイルに出てくるラベルってなに？

# ～ メモ ～
【[TCP/IP - DNS](https://www.infraexpert.com/study/tcpip15.html)】
- DNSとは何かドメインとは何かを分かりやすく説明されている。
- DNS名前解決のフロー図もあり、ためになる。
- [FQDN(ホスト名+ドメイン名)](https://www.kagoya.jp/howto/it-glossary/domain/fqdn/)のホスト名がなぜ「www」となるのかが意味が分からなかったが、この記事曰く「一般的にWEBサーバーの場合、ホスト名を「www」とする」らしい。

:::note info
www(ホスト名) + exsample.com(ドメイン名)とする。

$ORIGIN exsample.com.　　　-- ドメイン名
www IN A 172.16.0.10 　　 　-- Aレコード（WebサーバーのIPアドレスとする）
つまり www.exsample.com
:::


【[TCP/IP - DNS 2](https://www.infraexpert.com/study/tcpip23.html)】
- ゾーンファイルやリソースレコードがどういったものかが分かりやすく書かれている。
- ゾーンファイルにでてくる「＠」が何を意味していたのかが分かる。
- リソースレコードの省略方法のが分かりやすく書かれている。
- 基本的なレコード種類の記載あり。


【[ゾーンファイルの書き方について教えてください](https://atmarkit.itmedia.co.jp/fnetwork/dnstips/031.html)】
- ゾーンファイルでの「.」の書き間違いパターンの説明がある。
:::note info
ドメイン名の最後に「.」をつけるとFQDNと解釈する。
「.」をつけないとORIGINの内容が末尾に付加される。
:::


【[Origin (オリジン)](https://developer.mozilla.org/ja/docs/Glossary/Origin)】
- ORIGINがどういったものかが分かる。
:::note info
ORIGIN ＝ スキーム(プロトコル) ＋ ホスト(ドメイン) ＋ ポート番号
例. http://example.com:8080
:::


【[オリジンサーバーとはなんですか？](https://support.cdnext.stream.co.jp/hc/ja/articles/360001787832-%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8%E3%81%AF%E3%81%AA%E3%82%93%E3%81%A7%E3%81%99%E3%81%8B-)】
- コンテンツを提供する元のサーバーのことっぽい。
:::note
ユーザー　-->　[CDN](https://wa3.i-3-i.info/word16730.html)　-->　Webサーバー（オリジンサーバー）
:::
【BLOCS】select2で動的メニューを作る

# はじめに
BLOCSはLaravelで使えるテンプレートエンジンです。[こちら](https://qiita.com/hyada/items/11597f88102ed1c45407)で、BLOCSを使って簡単な本管理アプリを作ってみました。本の新規登録、編集、一覧表示はできましたが、それぞれの本にタグをつけたいので、今回はselect2を使っていい感じのプルダウンを作ります。

select2はプルダウンをちょっと便利にするJavaScriptのライブラリです。select2を使えば、プルダウンの項目を検索や複数選択することができます。また、オプションを指定することで、自由入力で項目を追加することもできます。select2を使って、本管理アプリに以下の2つの機能を追加します。

1. 過去に入力したタグを検索、複数選択する
1. 自由入力で新しいタグを追加する

https://select2.org/

開発は以下の3ステップですすめます。では、作っていきましょう。開発したLaravelアプリのソースは[GitHub](https://github.com/blocs/example_books)で公開していますので、全体のソースは[こちら](https://github.com/blocs/example_books)をご参照ください。

1. 新規登録画面、編集画面にselect2を導入
1. 過去に登録したタグを取得
1. プルダウン項目を追加

https://github.com/blocs/example_books

# select2を導入する

（管理画面では不要）composerでautoincludeをインストールします。BLOCSも一緒にインストールされます。

:::note info
composer require blocs/autoinclude
:::

タグのフォーム項目に`class="select2"`を付与してください。これだけで、検索と複数選択、自由入力で項目追加ができるプルダウンが作れます。今回は複数選択したいので、`multiple`を付与しました。複数選択で複数のvalueが入るので、`name`を`tags[]`とします。これで、select2の導入は完了です。

```html:create.blocs.html
<div class="col-4">タグ</div>
<div class="col-8">
    <select class="ai-select2" name="tags[]" multiple="multiple" style="width:100%"></select>
</div>
```

（管理画面では不要）BLOCSは`class`を参照して、select2の実行に必要なJavaScriptを自動で読み込みます。JavaScriptを差し込む場所は`data-include`で指定します。

```html:create.blocs.html
<!-- data-include="auto" -->
```

# 過去に登録したタグを取得する

次に、過去に登録されたタグを取得するメソッドを作りました。BLOCSでは、`\Blocs\Option::add`でプルダウンに項目を追加できます。Eloquentで`$book_tags`に過去に登録されたタグを取得して、`$book_tag->name`をプルダウンに追加しています。

```php:app\Http\Controllers\BookController.php
    private static function option_tags($option_name)
    {
        $book_tags = BookTag::select('name')->distinct()->orderBy('name')->get();
        foreach ($book_tags as $book_tag) {
            \Blocs\Option::add($option_name, $book_tag->name);
        }
    }
```

:::note info
`\Blocs\Option::add`でプルダウン項目を動的に追加できる
:::

# プルダウン項目を追加する

最後に、新規登録画面でフォームの項目名`tags`を指定して、プルダウン項目を追加しました。同様に編集画面にも追加します。これでいい感じのプルダウンが完成しました。

```php:app\Http\Controllers\BookController.php
    public function create()
    {
        $book = new Book();
        self::option_tags('tags');

        return view('books.create', compact('book'));
    }
```

編集画面では、登録されたタグを選択した状態で表示します。選択されたvalueを`tags`に配列で入れておけば、BLOCSがプルダウンを選択状態にします。以下の例では、`tagLabels`が選択されたvalueを配列で返します。

```php:app\Http\Controllers\BookController.php
    public function edit(int $id)
    {
        $book = Book::findOrFail($id);
        $val = compact('book');

        if (empty(old())) {
            $val = array_merge($val, $book->toArray());
            $val['tags'] = $book->tagLabels();
        }

        self::option_tags('tags');
        return view('books.edit', $val);
    }
```

![スクリーンショット 2023-01-09 22.34.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962814/9b7d5529-7763-1b51-258c-01f3f49daad7.png)

# おわりに
今回は、BLOCSとselect2でいい感じのプルダウンを作りました。JavaScriptのライブラリを活用することで、ユーザビリティーはすごく良くなりますね。BLOCSのデータ属性の詳しい説明は[こちら](https://blocs.jp/reference)で。最後まで読んでいただき、ありがとうございました！

# 関連サイト
1. [サービスサイト](https://blocs.jp)
2. [GitHub](https://github.com/blocs/blocs)
3. [Packagist](https://packagist.org/packages/blocs/blocs)
【Laravel】pluckメソッドを使ってみる

## pluckメソッドを使ってみる
開発をしていて、idがキーで特定のカラムをバリューとする配列を作りたくなることがある。
そんなときに使ってあげるのが`pluck()`メソッド。

#### pluck()
![スクリーンショット 2023-01-12 21.49.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589286/3661fa9d-6573-6bb7-6456-f8b3e54a0590.png)


### 実際の使い方(Laravel)

tinkerで見てみると下記のようにidがキーでpartカラムをバリューとした配列を作ることができています。
```TrRecordController.
>>> TrPart::pluck('part_name', 'id');
=> Illuminate\Support\Collection {#4549
     all: [
       1 => "胸",
       2 => "脚",
       3 => "肩",
       4 => "背中",
       5 => "二頭",
       6 => "三頭",
       7 => "腹",
     ],
   }

```
引数はpluck('バリュー', 'キー')という順番で記載する必要があるので注意。

またこのような形でViewにわたすことができます。
```create.blade.php
<div class="col-sm-10">
    <select class="form-control" id="menu_id" name="menu">
        <option value="" style="display: none;">選択してください</option>
        @foreach ($trMenus as $index => $name)
            <option value="{{ $index }}" {{ old('menu') === "$index" ? 'selected' : '' }} >{{ $name }}</option>
        @endforeach
    </select>
</div>
```

Collectionとか難しいですね。もっと勉強します(-_-)
paiza.ioでelixir その166

# 概要
paiza.ioでelixirやってみた。
application使ってみた。

# サンプルコード

```
defmodule Counter.Server do
	use GenServer
	def start_link(current_number) do
		GenServer.start_link(__MODULE__, current_number, name: __MODULE__)
	end
	def count_up do
		GenServer.call __MODULE__, :up
	end
	def count_down do
		GenServer.cast __MODULE__, :down
	end
	def current_number do
		GenServer.call __MODULE__, :current
	end
	def handle_call(:up, _from, current_number) do
		{:reply, current_number + 1, current_number + 1}
	end
	def handle_call(:current, _from, current_number) do
		{:reply, current_number, current_number}
	end
	def handle_cast(:down, current_number) do
		{:noreply, current_number - 1}
	end
	def kill do
		pid = Process.whereis(__MODULE__)
		Process.exit(pid, :kill)
	end
end

defmodule Counter do
	use Application
	def start(_type, _args) do
		import Supervisor.Spec, warn: false
		children = [{Counter.Server, 0}]
		opts = [strategy: :one_for_one, name: Counter]
		Supervisor.start_link(children, opts)
	end
end

Counter.start(nil, nil)
|> IO.inspect

Counter.Server.current_number
|> IO.inspect

Counter.Server.count_up
|> IO.inspect

Counter.Server.count_up
|> IO.inspect

Counter.Server.kill
|> IO.inspect

:timer.sleep(100)

Counter.Server.current_number
|> IO.inspect

Counter.Server.count_up
|> IO.inspect




```

# 実行結果

```
{:ok, #PID<0.99.0>}
0
1
2
true
0
1
```

# 成果物

https://paiza.io/projects/gSzO10I455Tt6P_riqxGEA?language=elixir


以上。
paiza.ioでelixir その165

# 概要
paiza.ioでelixirやってみた。
死活監視やってみた。

# サンプルコード

```

defmodule Counter.Server do
	use GenServer
	def start_link(current_number) do
		GenServer.start_link(__MODULE__, current_number, name: __MODULE__)
	end
	def count_up do
		GenServer.call __MODULE__, :up
	end
	def count_down do
		GenServer.cast __MODULE__, :down
	end
	def current_number do
		GenServer.call __MODULE__, :current
	end
	def handle_call(:up, _from, current_number) do
		{:reply, current_number + 1, current_number + 1}
	end
	def handle_call(:current, _from, current_number) do
		{:reply, current_number, current_number}
	end
	def handle_cast(:down, current_number) do
		{:noreply, current_number - 1}
	end
	def kill do
		pid = Process.whereis(__MODULE__)
		Process.exit(pid, :kill)
	end

end


#Counter.Server.start_link 0
#|> IO.inspect

#Counter.Server.count_up
#|> IO.inspect

#Counter.Server.count_up
#|> IO.inspect

#Counter.Server.count_up
#|> IO.inspect

#Counter.Server.count_down
#|> IO.inspect

#Counter.Server.current_number
#|> IO.inspect

defmodule Counter.Supervisor do
	use Supervisor
	def start_link(arg) do
		Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
	end
	@impl true
	def init(_arg) do
		children = [{Counter.Server, 0}]
		Supervisor.init(children, strategy: :one_for_one)
	end
end

Counter.Supervisor.start_link([])
|> IO.inspect

Counter.Server.current_number
|> IO.inspect

Counter.Server.count_up
|> IO.inspect

Counter.Server.count_up
|> IO.inspect

Counter.Server.kill
|> IO.inspect

:timer.sleep(100)

Counter.Server.current_number
|> IO.inspect

Counter.Server.count_up
|> IO.inspect



```

# 実行結果

```
{:ok, #PID<0.99.0>}
0
1
2
true
0
1
```

# 成果物

https://paiza.io/projects/_SleDMLn6Ev27wxMDv7iGw?language=elixir


以上。
Googleプロジェクト管理：ローンチとランディング

# はじめに

わたしが [Google プロジェクト管理:プロフェッショナル認定証で得られた素晴らしい体験][google]を、要点をまとめ小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ ***"Google プロジェクト管理:プロフェッショナル認定証"*** を受講してみてください。

[google]: https://qiita.com/mapami/items/317ae776a2268fd54c8f

https://jp.coursera.org/professional-certificates/google-project-management

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/a1cc3407-8d1d-b37c-1d3a-50bf9ea5159f.png" width="800">

# ローンチ

***<font color="MediumVioletRed">『プロジェクトの最終成果をクライアントやユーザーに提供することを、プロジェクトローンチ（またはローンチ）と呼びます。』</font>***

プロジェクトの構築や作成が終わり、タスクが完了し、成果物が完成した状態です。あなたは目標を達成したのです。

プロジェクトは成功し、その意味では完了したと見なされますが、それはうまく機能しているでしょうか？　望んでいた結果を得ることができたのか？

# ランディング

***<font color="MediumVioletRed">『ランディングとは、プロジェクト開始時に設定した成功基準を用いて、実際にプロジェクトの成功したときです。』</font>***

これは、開始の段階で見落とされがちな目標設定の重要な部分である。たとえば、飛行機で旅行することを考えてみてください。パイロットは飛行機を離陸させることができるだけでは十分ではありません。目的地に安全に到着するためには、着陸の仕方を知っていなければならないのです。

成功は、最終的なプロジェクトを納品した時点から続くものでなければなりません。プロジェクトが実行に移された後、意図したとおりに機能しているかどうかを測定できる必要があるのです。

# ローンチ vs ランディング

| | 内容 |
| :--- | :--- |
| ローンチ | プロジェクトを納品する |
| ランディング | 結果が期待通りかどうかを確認する | 


ほとんどのプロジェクトでは、立ち上げそのものは成功の尺度として意味を持ちません。本当に重要なのは、立ち上げの後なのです。***<font color="MediumBlue">ローンチはあくまで手段</font>*** であり、ローンチの先を見ることは、ローンチが全体的な目標を達成するために重要なことなのです。

打ち上げの先にある着地点を見据えることから始めると、目指す場所にたどり着ける可能性が高くなります。ランディングは概念であり、明確な定義があるわけではないので、特定のプロジェクトで成功するランディングとはどのようなものかを定義することが重要なのです。

幸いなことに、私たちはプロジェクトの成功を確実にするための測定方法を用意しています。それは ***<font color="MediumBlue">成功基準</font>*** と呼ばれるもので、プロジェクトのライフサイクルを通じてこの基準に沿って管理できれば、最終的にスムーズな着陸を実現することができるのです。

成功基準には、目標や成果物の具体的な内容がすべて含まれており、自分がやろうとしたことを達成できたかどうかを知るための指針になるのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/cbdb33e2-d304-4917-7cdc-2753dd792a95.png" width="600">


:::note info
企業が新しい製品やサービス、取り組みを開始したことを祝う言葉をよく耳にしますが、プロジェクトが世に出たとしても、仕事が完了したわけではないことを覚えておくことが大切です。プロジェクトに取り組む際のゴールは、単に立ち上げることではなく、「着地」させることなのです。着地とは、プロジェクトが一定の成功を収めたときに起こるものです。プロジェクトマネージャーにとって、着地は努力の結晶であり、喜びの結晶でもあります。私たちの努力に対する最高のご褒美なのです。

プロジェクトの着地は、ハードルを高くするものでないことも注意しなければなりません。正しく実行されれば、最終的な成果に対するチーム内の整合性が高まり、チーム全員が成功への道筋をよりよく理解できるようになります。
:::
[datetime] タイムゾーンを意識しよう

## この記事の目的
- datetimeにタイムゾーン情報を付与して出力する方法を知る

## awareとnaive
datetime 型にはタイムゾーンの情報を持たない naive と、タイムゾーンの情報を持つ aware な datetime 型がある

## なぜタイムゾーンが必要？
タイムゾーン情報を設定していない場合、ローカルマシン側ではJST（日本標準時）で、サーバ側ではUTC（協定世界時）となる可能性がある

## 実装例（３種類）
```datetime.py
from datetime import datetime, timedelta, timezone
from dateutil import tz
from zoneinfo import ZoneInfo

now = datetime.now(ZoneInfo("Asia/Tokyo"))
print(now)
# 2022-10-27 13:51:55.293383+09:00

JST = tz.gettz("Asia/Tokyo")
dt = datetime.now(JST)
print(dt)
# 2022-10-27 13:51:55.293613+09:00

JST = timezone(timedelta(hours=+9), "JST")
time = datetime.now(JST)
print(time)
# 2022-10-27 13:51:55.293648+09:00
```

システムにあう方法で出力しよう!!

## 参考
[[Python] datetime とタイムゾーンについてのメモ
](https://kuttsun.blogspot.com/2021/09/python-datetime.html)
主キーの無いSynapse Analytics 専用SQLプールでデータの重複を防ぐ方法

Azure Syanaps Analytics 専用SQLプールでは、以下の記事の通り主キーや一意キーが機能しません。

[注意が必要な一意キー、主キーの利用（Azure Synapse Analytics SQLプール）](https://qiita.com/masahiro-yamaguchi/items/c26858a1570b7319ba77)

一方で行の重複を防ぐ必要がある場面は多々発生します。
行の重複を防ぐためにいつも行っている方法を記載します。

# 値が存在しないことを確認することで行の重複を防ぐ
一般的にDWHシステムでは、テーブルから別のテーブルへデータの移動を行うことが多いと思います。

例えば、以下のような2つのテーブルがあるとします。
> stg_table(id,desc_col)
prd_table(id,desc_col)

データが`prd_table`にまだ存在しない行のみ、`stg_table`から`prd_table`にデータ移動を行いたいと思います。
これはよくあるシナリオだと思いますが、ここでよく利用するのは`NOT EXIST`を利用することです。

```SQL
insert into prd_table
select
    s.id,s.desc_col
from
    stg_table s
where not exists(
    select 1
    from prd_table p
    where p.id = s.id
);
```
また、`id`と`desc_col`を合わせて一意にしたい場合にはWHERE句を少し拡張します。
```SQL
insert into prd_table
select
    s.id,s.desc_col
from
    stg_table s
where not exists(
    select 1
    from prd_table p
    where
            p.id = s.id
        and p.desc_col = s.desc_col
);
```

クラスター化列ストアインデックスで細かくデータをインサートする場合は断片化などでパーフォーマンスが低下する可能性があるので、`CTAS`を使って再作成したり、クラスター化列ストアインデックスの代わりにHEAPテーブルを使うなどの注意が必要な場合があります。

[Synapse SQLプールのクラスター化列ストアインデックス](https://qiita.com/masahiro-yamaguchi/items/f2b3abb1f0d65e3fbf6c)
【AWS】IAMパスワードポリシーの変更方法

# はじめに
所属する組織によって、パスワードのルールは異なってくるかと思います。
私が所属する組織では、パスワード長が16桁に設定されております・・・。
IAMでもパスワードのルールを設定することができるようです。
今回は、そのやり方を書きたいと思います。
​
# IAMパスワードポリシーの設定
1. IAMコンソールの画面左側にある「アクセス管理」->「アカウント設定」をクリックし、
パスワードポリシーの「編集」をクリックする。
​
![](https://storage.googleapis.com/zenn-user-upload/032a51aa2deb-20230106.png)
​
2. パスワードポリシーの設定画面に遷移したら「カスタム」を選択し、ルールを決めていく。
今回は試しに、下記の設定を追加してみる。設定が完了したら「変更を保存」をクリックする。
- 「パスワードの有効期限を31日」
 - 「同じパスワード再利用制限を12回」
​
![](https://storage.googleapis.com/zenn-user-upload/321713b9d73e-20230106.png)
​
3. このルールは、新規ユーザーと既存ユーザーのパスワードの設定/変更時に促される。
​
![](https://storage.googleapis.com/zenn-user-upload/3e2efc98cce3-20230106.png)
​
4. 新たに追加されたルールが適用されていることが確認できる。
​
![](https://storage.googleapis.com/zenn-user-upload/be82cb861d21-20230106.png)
​
# その他
- [IAM ユーザーが自分のパスワードを変更する方法](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_passwords_user-change-own.html)
- [困ったときのIAMユーザーパスワードリセット方法](https://dev.classmethod.jp/articles/iam-user-password-reset/)
Thread class

start methodでthread start
run methodが処理。
いつ動くかはjvmに任せられている。

```java
class SampleThread extends Thread {
    int i;
    SampleThread(int i) {
        this.i = i;
    }
    @Override
    public void run() {
        super.run(); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody
        System.out.println("run:" + this.i);
    }

    @Override
    public synchronized void start() {
        super.start(); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody
        System.out.println("start:" + this.i);
    }
}
public class Outer {
    public static void main(String[] args) {
        for (int i=0 ;i<9 ;i++) {
            Thread t = new SampleThread(i);
            t.start();
           // t.run();
        }
    }
}
```
```
start:0
run:0
run:1
start:1
start:2
start:3
start:4
start:5
run:2
start:6
run:6
run:5
run:3
start:7
run:4
run:7
start:8
run:8
```
【AWS】IAMユーザーから請求情報にアクセスする方法

# はじめに
基本的にAWS請求情報にアクセスできる権限を持つユーザーは、「ルートユーザー」のみである。
デフォルトでは、IAMユーザーからAWS請求情報にアクセスできない。
これを回避するには、IAMユーザーにAWS請求情報にアクセスできる権限(ポリシー)の割り当てとアカウント画面から「IAMアクセスのアクティブ化」をしなければならない。
今回は、そのやり方を書きたいと思う。
​
# IAMユーザーに請求情報へのアクセス付与する方法
IAMユーザーは、デフォルトでAWS請求コンソールにアクセスできません。
そのための[対応方法](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/control-access-billing.html#grantaccess)を記述する。

​<font color="Red">※「AdministratorAccess」でアクセスできるのは、
　 この権限はAWS請求コンソールにアクセスできる権限を持っているため。</font>
  
1. AWSコンソール一番右上の自身のユーザー名をクリックし、アカウントを選択する。
遷移したページ内に「IAM ユーザー/ロールによる請求情報へのアクセス」の項目があるので、
そこの「修正」をクリックし「IAMアクセスのアクティブ化」にチェックを入れ更新する。
<img width="200" src="https://storage.googleapis.com/zenn-user-upload/84a0b634d397-20230105.png" >

![](https://storage.googleapis.com/zenn-user-upload/8fc01cad6779-20230105.png)
![](https://storage.googleapis.com/zenn-user-upload/17396404bf85-20230105.png)
​
2. 対象のIAMユーザーに請求情報にアクセスできる権限を割り振る。
　今回は試しに、請求情報にアクセスできないIAMユーザー(test_user)に権限を割り振る。
 
 **～請求情報にアクセスする権限を付与する前～**
 権限が無いため、エラーメッセージが出力される。
![](https://storage.googleapis.com/zenn-user-upload/1db9aaad0f7c-20230105.png)
![](https://storage.googleapis.com/zenn-user-upload/7cdbcde0df5f-20230105.png)
　
**～請求情報にアクセスする権限を付与する～**
赤枠で囲まれている「アクセス権限の追加」をクリック
​<font color="Red">※ IAMユーザーを修正可能なユーザーで実施すること。</font>
![](https://storage.googleapis.com/zenn-user-upload/0c610446e1e8-20230105.png)
​
「既存のポリシーを直接アタッチ」をクリックし、
検索欄で「Billing」と検索し「AWSBillingReadOnlyAccess」の権限にチェックを入れる。
「[AWSBillingReadOnlyAccess](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-permissions-ref.html)」の権限は、
「Billing and Cost Management コンソール」のページを表示する権限である。
​
権限の割り当てが完了したら、「次のステップ：確認」をクリックする。
![](https://storage.googleapis.com/zenn-user-upload/9fdf5e2630a7-20230105.png)
​
対象IAMユーザー(test_user)に、
「AWSBillingReadOnlyAccess」の権限が割り振られているのを確認する。
問題がなければ、「次のステップ：アクセス権限の追加」をクリックする。
![](https://storage.googleapis.com/zenn-user-upload/601b74c4b5f8-20230105.png)
​
するとIAMコンソール画面から、対象IAMユーザー(test_user)に
「AWSBillingReadOnlyAccess」の権限が付与されていることが確認できる。
![](https://storage.googleapis.com/zenn-user-upload/fd8100ab86e4-20230105.png)
​
AWS請求コンソールに対象IAMユーザー(test_user)でアクセスしてみると、
ちゃんとアクセスすることができる。
![](https://storage.googleapis.com/zenn-user-upload/1b6e39f72086-20230105.png)
​
～備考～
項番1の「IAM ユーザー/ロールによる請求情報へのアクセス」を無効化した場合、
IAMユーザーに請求情報にアクセスする権限が割り振られていてもアクセスはできない。
下記にAWSが用意したハンズオンがあるので、これを試してみるのもありです。
[IAM チュートリアル: 課金コンソールへのアクセスを委任する](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_billing.html?icmpid=docs_iam_console#tutorial-billing-step2)
[FastAPI] ライブラリを使用したCSRFトークンの実装

## この記事を読んでできること
CSRFトークンの実装ができる

## やりたいこと
ログイン認証機能がないパブリックサイトでクライアントへのCSRFトークンの付与と認証を[starlette-csrf](https://github.com/frankie567/starlette-csrf)というライブラリで実装する

## 記述しないこと
- FastAPIの実装について
- Cookieについて

## 使用技術
### バックエンド

- Python 3.10.4
- Fast API 0.78.0
- starlette-csrf 1.4.4

※ トークンを発行して認証するシステムは完全に[starlette-csrf](https://github.com/frankie567/starlette-csrf)というライブラリに任せます

## 発行と認証の流れ（フロントとの疎通）
1. GETメソッドでトークンを発行するAPIをフロントエンドに叩いてもらう
1. クライアントのCookieファイルに`csrftoken`というkeyでランダム文字列のトークンが格納される
1. リクエスト毎にクライアントから`x-csrftoken`というkeyでヘッダーを送ってもらう
1. ライブラリで最初に発行したものと一致するか確認し、問題がなければリクエストを通す


## 実装例
```main.py
import os

from fastapi import FastAPI
from starlette_csrf import CSRFMiddleware
# 環境変数を含めたクラス
from config import settings

from routers import router


app = FastAPI()

# CSRFミドルウェアの設定を格納する辞書を定義します
cookie_attribute = {
    "secret": settings.SECRET_KEY,
    "cookie_samesite": None,
    "cookie_secure": True,
}

# デバッグモードではない場合、クッキーのドメインを設定します
# クッキードメインを設定します。これにより、特定のドメインにクッキーが適用されます
if not settings.DEBUG_FLAG:
    cookie_attribute["cookie_domain"] = settings.COOKIE_DOMAIN

# CSRFミドルウェアを追加し、cookie_attribute辞書を引数として渡します
app.add_middleware(CSRFMiddleware, **cookie_attribute)
app.include_router(router.router)
```
```routers/router.py
@router.get("/api/get_csrf_token", tags=["token"])
def get_csrf_token():
    return "トークンを発行しました。"
```

## starlette-csrfについての詳細
### starlette-csrfの仕様
- 安全なHTTPメソッド（GET、HEAD、OPTIONS、TRACE）でリクエストされた場合、set-cookie ヘッダーを使用してクライアントのクッキーに csrftoken というキーでトークンを格納する
- クライアントがPOSTリクエストを送信する際、x-csrftoken というキーでトークンを含むヘッダーを送信することが期待される
- サーバー側で、クッキーに保存されたトークンとヘッダーに含まれたトークンの値を比較し、検証する
- トークンが一致する場合、リクエストは正常に処理される
- トークンが一致しない場合は、403 Forbiddenエラーが返される

## Cookie属性
READMEに詳細記載あり
- cookieの名前
- パス
- Secure属性
- Samesite属性等を変更することができる

## 処理の検証結果

- 現状、単純なapi/get_csrf_tokenというエンドポイントを作成し、tokenをセットする
- POSTMANで
  - ヘッダにx-csrftokenを用意しない場合は、403エラー
  - ヘッダにx-csrftokenを用意したが、valueが一致しない場合も403エラー
  - ヘッダにx-csrftokenを用意し、valueが一致した場合、リクエストを処理する

## 参考
- [starlette-csrf](https://github.com/frankie567/starlette-csrf)
- [HTTP Cookieの使用](https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies)
- [SameSite cookies](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie/SameSite)
ARCHS[@]: unbound variable Command PhaseScriptExecution failed with a nonzero exit code の対処

Xcode13.4.1で開発中シミュレータでは実行できたものの、archiveしようとしたときにビルドエラーが発生。
ライブラリはRealmをCocoaPodsで入れているだけ。
解決方法がいくつか載っていて、色々試したのに治らず。。
# 試した方法
- architectureからarm64を除外する
https://cpoint-lab.co.jp/article/202203/22239/
ただしこれはシミュレータで動かないときの解決法っぽい

- VALID_ARCHSを$(ARCHS_STANDARD)に変更
これはXcode12以下の場合の解決方法で、13以降はデフォルトでこの設定になっているため、関係がない
https://qiita.com/sekitaka_1214/items/ff4b99b2d9523425cf29

- キーチェーンのリフレッシュ
https://ios-docs.dev/command-phasescriptexecution/
macやxcodeのバージョン変更などはしていないため、これが原因である可能性は低そう

# 解決した方法
- Build Active Architecture OnlyのReleaseをNoにする。
- Base SDKをiOSにする
![スクリーンショット 2023-01-13 17.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726764/3a36d746-2b88-ef81-5022-d5996f45005b.png)

ビルド対象のアーキテクチャがアーカイブに必要なものより不足していたことが原因なのもしれないが、詳細は不明である。
SQLite3のデータをコマンドラインから操作してみる

# はじめに
以前は.NET Core 3.0を使ってSQLiteのデータをコマンドラインから操作してみましたが、今回はSQLite3の機能で操作してみます。
https://qiita.com/namikitakeo/items/5605ef2eb56cc34f352d

# 参考サイト
以下の記事を参考にしました。
https://qiita.com/kanegoon/items/fc1e4bfea0984dbe4b90

</pre>

以下のような使い方を想定しています。

<pre>
$ sqlite3 test.db 
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .mode csv
sqlite> .once test.txt
sqlite> select * from test;
sqlite> .shell cat test.txt
1,hoge0,0
2,hoge1,1
3,hoge2,2
4,hoge3,3
5,hoge4,4
6,hoge5,5
7,hoge6,6
8,hoge7,7
9,hoge8,8
10,hoge9,9

sqlite> delete from test;
sqlite> select * from test;

sqlite> .import test.txt test
sqlite> select * from test;
2,hoge1,1
3,hoge2,2
4,hoge3,3
5,hoge4,4
6,hoge5,5
7,hoge6,6
8,hoge7,7
9,hoge8,8
10,hoge9,9
</pre>
AWS CDKとAWS SDKの両方にprofileを設定する

[cdklink]:https://docs.aws.amazon.com/cdk/api/v2/
[rdslink]:https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_rds.DatabaseClusterFromSnapshot.html
[sdklink]:https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html

# やりたいこと

[AWS SDK][sdklink] と [AWS CDK][cdklink]で `profile` を指定して実行したい。

# 結論

`cdk`コマンドの前に、`AWS_PROFILE`で`profile`名を指定すれば、[AWS SDK][sdklink] と [AWS CDK][cdklink]に、同様の`profile`が入りました。

```sh
AWS_PROFILE=hogefuga cdk subcommand
```

# cdkコマンドで`profile`指定できるけど・・・sdkには渡らない

```sh
cdk subcommand --profile hoge
```

`cdk`コマンドのオプションで、`--profile`指定できますが、
上記コマンドでは、`cdk`に`profile`が渡り、`sdk`には`profile`が渡っておらず、`sdk`では`default`の`profile`が使われることになります。
`cdk`のコード内で指定したはずの`profile`を取得できる術が今の所なさそうです。

# 環境

```
typescript: 4.9.4
aws-cdk: 2.56.0
aws-cdk-lib: 2.56.0
```

# 参考

- コード： https://github.com/aws/aws-cdk/blob/dce662cae6eb493770d3c6f700c92a0b6c235195/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts#L33

# ちなみに

cdk内でsdkを実行するときには自分は下記のように、即時関数でラップしました。


```typescript:bin/cdk.ts
#!/usr/bin/env node
import { App } from 'aws-cdk-lib';
import 'source-map-support/register';
import { SdkStack } from '../lib/sdk-stack';
import { getSnapshot } from '../sdk/get-snapshot';

const account = process.env.CDK_DEFAULT_ACCOUNT ?? '';
const region = process.env.CDK_DEFAULT_REGION ?? '';

const app = new App();

// cdk 実行前に、ｓｄｋ で取得した値を
(async () => {

  const { snapshotId } = await getSnapshot(); // sdkで実装した関数

  app.node.setContext('snapshotId', snapshotId); // contextに渡すと、stack内で app.node.tryGetContext("snapshotId") で取得可能になる(このままだと型anyだけど)

  new SdkStack(app, "SdkStack", {
    env: { account, region },
  });

})();

```
【AWS】IAM作業ユーザー登録

# はじめに
今回は、IAMユーザー登録のハンズオンを行ってみたいと思います。
私自身が初心者ですので、間違っていたらご指摘お願いします。
​
# IAM（Identity and Access Manegement）について
・AWSリソースへのアクセスを管理するサービス
・主な機能は、(ユーザー)認証と(機能/サービスへの)アクセス許可の機能
・ルートユーザーはフル権限なので、IAMユーザーで作業することを推奨
・IAMユーザーをグループ単位で管理することも可能
・ユーザー認証に、MFA(多要素認証)を利用することを推奨
​
**～備考～**
[IAMセキュリティのベストプラクティスについて](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html)
[ルートユーザーのみでしかできないタスク](https://docs.aws.amazon.com/ja_jp/accounts/latest/reference/root-user-tasks.html)
​
# IAMユーザーの作成方法
1. IAMコンソールより、左の項目より「ユーザー」を選択する。
ユーザー画面に遷移したら「ユーザーを追加」をクリックする。
​
![](https://storage.googleapis.com/zenn-user-upload/e7656b33be30-20230105.png)
![](https://storage.googleapis.com/zenn-user-upload/5dcd0bae8116-20230105.png)
​
2. 遷移した画面で必要な項目を埋めていく。


【ユーザー名】
  　 お好きなユーザー名を入力
  　 「別のユーザーの追加」で複数のIAMユーザーを追加できる模様
   
【AWS 認証情報タイプを選択】
 　　AWSを操作する方法を選択（CLIまたはGUIのどちらか、もしくは両方）
   
【コンソールのパスワード】
  　 AWSコンソールにログインする際のパスワードを入力するか、自動生成するかを選択
   
【パスワードのリセットが必要】
  　 IAMユーザーでログインした後に、強制的にパスワードリセットをさせたい場合に選択
​
項目を埋め終わったら、「次のステップ：アクセス権限」をクリックする。
   　
![](https://storage.googleapis.com/zenn-user-upload/7cbc981048dd-20230105.png)
​
3. 遷移した画面でIAMユーザーに権限(ポリシー)を割り当てる。
　ここでいう権限は、IAMユーザーがAWSでできることの指す。
　基本的に必要最低限の権限を割り当てることが望ましい。
​
【ユーザーをグループに追加】
  　 グループ単位でIAMユーザーを管理することができる。
  　 グループに対して権限を割り振る。
     
【アクセス権限を既存のユーザーからコピー】
  　 権限を既存の(IAM)ユーザーからコピーすることができる。
    
【既存のポリシーを直接アタッチ】
  　 AWS側であらかじめ用意されている権限を割り振ることができる。
 
今回は「既存のポリシーを直接アタッチ」で「AdministratorAccess」の権限をIAMユーザーに割り当てる。「AdministratorAccess」は、ほとんどのサービスが利用できる権限である。
​
権限の割り当てが完了したら、「次のステップ：タグ」をクリックする。
​
～備考～
[アクセス権限の境界の設定](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html?icmpid=docs_iam_console)は、IAMユーザーが利用できる権限をより細かく制御するものである。
IAMユーザーのポリシーとアクセス許可の境界の両方で許可されている権限(アクション)のみが実行できる。
​
![](https://storage.googleapis.com/zenn-user-upload/19608c8a6341-20230105.png)
​
4. 遷移した画面でタグをIAMユーザーに付ける。
　「[タグ](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_tagging.html)」は、あくまで管理をしやすくするためのモノである。
　なので絶対に付けないといけないわけではないが、付けることが推奨されている。
​
タグ付けが完了したら、「次のステップ：確認」をクリックする。
![](https://storage.googleapis.com/zenn-user-upload/c47b5552aaed-20230105.png)
​
5. 最終確認を行う。
　設定が想定通りか確認し、問題なければ「次のステップ：ユーザーの作成」をクリックする。
![](https://storage.googleapis.com/zenn-user-upload/0cbf0c7f3c94-20230105.png)
​
6. IAMユーザー作成完了
　CLIでAWSを操作する(項番1:AWS認証情報タイプを選択)場合は、
　「アクセスキーID」と「シークレットアクセスキー」が発行され、これを使ってCLIで
　アクセスすることになる。なので忘れないように保管しておく必要がある。
　もちろん第三者への連携はNGです。
　また赤枠で囲われているURLからログインすることになるので、こちらも忘れずに。
　このリンクから行かない場合は、
　ログイン時にIAMユーザーのアカウント ID (12 桁) を入力する必要がある。
   
![](https://storage.googleapis.com/zenn-user-upload/0ca2c8b2db47-20230105.png)
![](https://storage.googleapis.com/zenn-user-upload/8a788813a912-20230105.png)
​
​
# その他
- [【AWS IAMとは？】初心者にもわかりやすく解説](https://www.wafcharm.com/jp/blog/aws-iam-for-beginners/)
- [IAM Permissions boundary（アクセス権限の境界）で明示的に許可していないアクションでも条件次第で実行できるということを評価論理の流れを眺めて再認識してみた](https://dev.classmethod.jp/articles/iam-policies-evaluation-logic-rikai/)
- [IAM ロールの PassRole と AssumeRole をもう二度と忘れないために絵を描いてみた](https://dev.classmethod.jp/articles/iam-role-passrole-assumerole/)
- [やってみようシリーズ：IAMアカウントを作ってみよう-IAMポリシー解説編-](https://www.idaten.ne.jp/portal/page/out/secolumn/multicloud/column005.html)
​
負荷分散装置(ロードバランサー）とは

# 負荷分散とは？
* p106 単一のサーバー機器で様々なリクエストを受けてもいいが、複雑な処理やアクセス数が多くなるとサーバーの負担が大きくなるので各層ごとに```サーバーを機器を分ける```こと。

* p174 サーバーを複数に並列に配置し、```リクエストを振り分けて並行実行```させることで```各サーバーの負担を軽減```する方法のこと。　サービスを継続できる冗長化の効果もある。(可用性)
### 出典
https://www.sbcr.jp/product/4797388817/

# 負荷分散装置/ロードバランサーとは？
p170 Webサーバーを冗長化させる際、システムに届くリクエスをどのWebサーバーに渡すかということを考える必要が出てくる。
その振り分け作業を行うための機器が```ロードバランサー```です。
ロードバランサーはWebサーバーインターネットよりに配置し、配下となるWebサーバーを認識させます。

### 出典
https://www.sbcr.jp/product/4797388817/

# ロードバランサーの実行手法
p174
### ラウンドロビン方式
各サーバーに```順番にリクエストを割り振る```方式。
```各リクエストの処理の複雑さが同程度```で、かつ```各サーバーの処理能力が同じ```である場合に、有効。
ただしリクエストの処理の複雑さにばらつきがある場合は、サーバー負荷の偏りが大きくなる。

### 動的分散方式
```サーバーの負荷を監視し、負荷の少ないサーバーに優先してリクエストを振り分ける```方式。
サーバーの負荷としてはCPUの使用率、メモリの使用量、ディスク負荷、コネクション数などが用いられる。

### パーシステンス
負荷分散を行うと同じクライアントからのアクセスでも振り分けられるサーバーが異なるため、ログインして利用するようなサイトでは、セッション情報を管理することが難しくなる。
そこで、```同一クライアントからのアクセスを判別し、常に同じサーバーへ転送する機能```が開発されました。
これを```パーシステンス```と呼ぶ。

# 出典
https://www.sbcr.jp/product/4797388817/

# HTTPヘッダ
p125 クライアントやサーバはヘッダを見てメッセージに対する挙動を決定します。
p337 Cookieの情報を見てセッションIDを確認してできる。

### 出典
https://gihyo.jp/book/2010/978-4-7741-4204-3
リアルタイムでログを出す　tail -f ファイル名

:::note 
こんな人におすすめ

・サーバー上でlogファイルがどの操作によって発生したのか切り分けをしたい人

:::

# tail -f ファイル名

打つコマンドは、「tail -f 追跡したいファイル名」です。
例えば、ログディレクトリに、log01というものがあって、このログファイルを追跡したい場合
「tail -f log.01」と打ちます。
```
[root@ip-〇〇] tail -f log.01
[2023/01/13 09:00:00]ログ内容       //tail -f log.01を打った時のファイル内容
[2023/01/13 09:00:01]ログ内容       //tail -f log.01を打った時のファイル内容
[2023/01/13 09:00:02]ログ内容       //tail -f log.01を打った時のファイル内容
```
　　　　　　　　　　　　　　　　　　　　　　　　　
この後に何かログに吐かれるような動作（操作A）を画面で行うと下記のように操作とファイル内容を切り出しすることが可能です。
tail -fコマンドを使用した後は、Enterを3回ほど押して、操作とログを離しておくとより見やすいかと思います。
そうすると下記のようになります。
```
[root@ip-〇〇] tail -f log.01
[2023/01/13 09:00:00]ログ内容       //tail -f log.01を打った時のファイル内容
[2023/01/13 09:00:01]ログ内容       //tail -f log.01を打った時のファイル内容
[2023/01/13 09:00:02]ログ内容       //tail -f log.01を打った時のファイル内容



[2023/01/13 09:00:02]ログ内容       //操作Aによって吐き出された内容
```

この追跡モードを終了したい場合は、Windowsの方は「Ctrl + C」、Macの方は「command + C」で終了することができます。

## 感想
サーバー上でエラーを見ている時に、どの操作によってどのログが吐かれているのか切り分けたいということは多々あるかと思うので、そういう場合はこのコマンド使用すると便利だなと思いました。
GitHubによる個人開発入門

# GitHubの概要
GitHubは、ソフトウェア開発のためのバージョン管理システムとして有名です。また、チーム開発のためにも使用されています。
# GitHubの使い方
以下は、GitHubの使い方の一般的な手順です:

1.GitHubアカウントを作成します。
URL：[GitHub](https://github.com/)
2.リモートリポジトリを作成します。
画像の黄色い枠で囲まれたところから作成できます。
![スクリーンショット 2023-01-16 090826.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991881/60396ef1-7359-d9b0-0441-8b7405e1b34d.png)
以下3~6はコマンドプロンプト上で行います。

3.リモートリポジトリをクローンして、ローカルリポジトリを作成します。
```
git clone 'リモートリポジトリのURL'
```
4.ファイルやフォルダを追加、編集、削除します。
```
# 自分のパソコンからファイルをコピー（""じゃないと日本語のファイル名を読み込んでくれないので注意）
copy "ファイルへのパス" 保存先のパス
# ファイルをブランチに追加
git add 'ファイルのパス'
```
5.変更をコミットします。
```
git commit -m '変更点に関するメッセージ'
```
6.リモートリポジトリにプッシュします。
```
git push origin [branch名]
```
以上でリモートリポジトリにデータが保存されました。必ず保存できたかをGitHub上で確認してください。

## その他の操作
* リモートリポジトリからローカルリポジトリへのデータの更新
```
git pull
```
* ブランチの切り替え
```
git checkout 切り替え先のブランチ
```


# まとめ
いかがだったでしょうか。

GitHubは、他のチームメンバーとのコラボレーションを簡単にするためにも使用されます。 
例えば、リモートリポジトリにプッシュした変更を他のチームメンバーが確認したり、他のチームメンバーがプッシュした変更を取り込むことができます。

また、GitHubには、コードのレビュー、バグのトラッキング、課題の追跡などの機能も提供されています。

つまりGitHubは、バージョン管理、チーム開発、共同作業のために非常に便利なツールです。

しかし、まずは個人で開発環境を整えることで、チームでの開発もスムーズにいくでしょう。
【AWS】１年無料期間がいつ終わるか確認する方法

# はじめに　
ご存知の通りAWSでは、新規ユーザーの場合１年間無料で利用できる制度がある。

:::note warn
利用できるリソース量には、制限があることを忘れずに・・・。
:::

 → [AWS 無料利用枠（AWS のプラットフォーム、製品、サービスを無料で実際に体験できます）](https://aws.amazon.com/jp/free/?gclid=Cj0KCQiA14WdBhD8ARIsANao07grSdH8hJu3tUkC_4J_b_iy_synhLyT94i2A16u_bZg-HV9HO2O2_UaArm0EALw_wcB&all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=tier%2312monthsfree&awsf.Free%20Tier%20Categories=*all&trk=ec4d2622-9132-4d67-996b-e37dbc3a40d7&sc_channel=ps&s_kwcid=AL!4422!3!591672863003!p!!g!!aws%20%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC&ef_id=Cj0KCQiA14WdBhD8ARIsANao07grSdH8hJu3tUkC_4J_b_iy_synhLyT94i2A16u_bZg-HV9HO2O2_UaArm0EALw_wcB:G:s&s_kwcid=AL!4422!3!591672863003!p!!g!!aws%20%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC)
 
私も現在利用してますが、
ある時「いつまで利用できるんだっけ？」と思ったので確認方法を調べることにした。
# IAMから確認する方法
IAMコンソール画面の左側項目「認証情報レポート」を押すと、下記の画面に遷移する。
![](https://storage.googleapis.com/zenn-user-upload/6e78b53be7c7-20221221.png)
そこから「認証情報レポートをダウンロード」実施し、認証情報レポートを取得する。
 → CSVファイルが取得できます。
 
項目「user_creation_time」がアカウントが作成された日時になるので、そこから１２カ月を引けば残りの日数となるわけですね。
 ![](https://storage.googleapis.com/zenn-user-upload/0c20af86cc15-20221221.png)
 # その他
 無料で利用できるリソース上限が迫っているものを確認するには、
 Billingコンソール画面の左項目「Free tier」から確認できる。
 
 ![](https://storage.googleapis.com/zenn-user-upload/00391434ac9f-20221221.png)
 
 # 備考
無料枠について知りたい場合は、下記をどうぞ。
[改めてAWSの「無料利用枠」を知ろう](https://dev.classmethod.jp/articles/overall-summary-about-aws-free-tier/)
gem 'capistrano-sidekiq' を使って デプロイ中にcommand not found(コマンドが見つかりません)エラー

バージョンが古いためか結構詰まってしまったので書いておきます。
gemをinstallしてCapfileに`require 'capistrano/sidekiq'`と書いただけのシンプルな設定です。

## 公式
capistrano: https://github.com/capistrano/capistrano
sidekiq: https://github.com/mperham/sidekiq/wiki/Deployment
capistrano-sidekiq: https://github.com/seuros/capistrano-sidekiq


## 解決方法
- capistranoのバージョンが3.4.0だったため、3.9.0にアップデート(※2023年/1月現在の最新は3.17です)
- deploy.rbに`set :rbenv_map_bins, %w(rake gem bundle ruby rails sidekiq sidekiqctl)`のように、sidekiqとsidekiqctlを追記

## どんなエラーだったか
`cap staging deploy`をしたところ、途中で以下のようなエラーが発生

```bash
$ cap staging deploy
略
00:00 sidekiq:stop
      01 bundle exec sidekiqctl stop /var/www/****/shared/tmp/pids/sidekiq-0.pid 10
      01 bash: bundle: コマンドが見つかりません
(Backtrace restricted to imported tasks)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as /****/@/****/: sidekiqctl exit status: 127
sidekiqctl stdout: Nothing written
sidekiqctl stderr: bash: bundle: コマンドが見つかりません


Caused by:
SSHKit::Command::Failed: sidekiqctl exit status: 127
sidekiqctl stdout: Nothing written
sidekiqctl stderr: bash: bundle: コマンドが見つかりません

Tasks: TOP => sidekiq:stop
(See full trace by running task with --trace)
```

## もう少し詳しく

deploy.rbに`set :rbenv_map_bins, %w(rake gem bundle ruby rails sidekiq sidekiqctl)`のように、sidekiqとsidekiqctlを追記すると、以下のように通りました

```bash
$ cap staging deploy
略
00:33 sidekiq:stop
      01 RBENV_ROOT=/usr/local/rbenv RBENV_VERSION=2.3.1 /usr/local/rbenv/bin/rbenv exec bundle exec sidekiqctl stop /var/www/****/shared/tmp/pids/sidekiq-0.pid 10
      01 Sidekiq shut down gracefully.
    ✔ 01 ****@**** 1.566s
00:34 deploy:symlink:release
      01 ln -s /var/www/****/releases/20230113053903 /var/www/****/releases/current
    ✔ 01 ****@**** 0.077s
      02 mv /var/www/****/releases/current /var/www/****
    ✔ 02 ****@52.198.51.57 0.083s
00:35 sidekiq:start
      01 RBENV_ROOT=/usr/local/rbenv RBENV_VERSION=2.3.1 /usr/local/rbenv/bin/rbenv exec bundle exec sidekiq --index 0 --pidfile /var/www/****/shared/tmp/pids/sidekiq-0.pid --environment staging --…
    ✔ 01 ****@**** 0.736s
略
```

`set :rbenv_map_bins, %w(rake gem bundle ruby rails sidekiq sidekiqctl)`
ここに追記すると、`rbenv exec ~` として実行されるようになります。

そのため、未記入の方のログでは実行コマンドが以下のようになっていますが、
```
略 bundle exec sidekiqctl stop 略
```

追記した場合のログでは実行コマンドが以下のように変わっています。
```
略 /usr/local/rbenv/bin/rbenv exec bundle exec sidekiqctl stop 略
```
Docker Imageの作成（Windows）

# Docker Imageの作成（Windows）

## Docker Hubを使用しない方法（ローカルPCで作成方法）

* `docker commit`コマンドを使用します。
  
* Pythonでnumpyモジュールを使用したく環境を構築する例で説明します。
  

### Python＆numpyモジュールDockerのImageを構築する

1. PythonをDockerにインストールします。
   1. [Python Office Image](https://hub.docker.com/_/python/tags)でインストールしたいバージョンのPythonを検索してコマンドをコピーします。
    
   2. コマンドプロンプトにて実行させます。下記のようなログが出ましたら完了とします。
    
      ```
        >docker pull python:3.11.1
        3.11.1: Pulling from library/python
        bbeef03cda1f: Pull complete
        f049f75f014e: Pull complete
        56261d0e6b05: Pull complete
        9bd150679dbd: Pull complete
        5b282ee9da04: Pull complete
        03f027d5e312: Pull complete
        741e8aa30cc2: Pull complete
        5ceb79cda400: Pull complete
        f2c00c886d59: Pull complete
        Digest: sha256:5f004bbd8b9b6ae1478fee7d4dfbf38305af7188946aa79925667fa658458ba9
        Status: Downloaded newer image for python:3.11.1
        docker.io/library/python:3.11.1
      ```
    
2. pipを使用してnumpyをインストールします。
  
   1. まずpythonのコンテナを立ち上げます。
    
      `docker run -i -t python:3.11.1 /bin/bash`
    
   2. numpyをインストールします。
    
      * pip listでnumpyが入っていないことを確認します。
      
      * numpyをインストールします。
      
        ```
          root@bf3ae658fb55:/# pip install numpy
          Collecting numpy
           Downloading numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.3 MB)
           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 MB 5.6 MB/s eta 0:00:00
          Installing collected packages: numpy
          Successfully installed numpy-1.24.1
        ```
      
      * pip listでnumpyが入っていることを確認できます。
      
   3. 一旦終了します。
    
      * `root@bf3ae658fb55:/# exit`
3. Docker Imageを作成します。
  
    1. Dockerコンテナを確認します。
    
        ```
        >docker ps -a
        CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
        bf3ae658fb55 python:3.11.1 "/bin/bash" 5 minutes ago Exited (0) 2 minutes ago jolly_ramanujan
        ```
    
    2. コンテナの`NAMES`と`docker commit`を利用してDocker Imageを作成します。
        
        ```
        docker commit jolly_ramanujan numpy_image_test
        sha256:c6ab95539a0e5daa10650e59dcd8a5f129820a7ab93a41d495433cb47d566ae3
        ```
    

これでDocker Imageの作成ができましたので、確認しましょう。

### 作成した`numpy_image_test`の確認

1. `docker images`を使って`numpy_image_test`があることを確認します。
  
      ```
      REPOSITORY         TAG       IMAGE ID       CREATED          SIZE
      numpy_image_test   latest    c6ab95539a0e   4 minutes ago    1.03GB
      ```
  
2. numpy_image_testのコンテナを一つ作ります。
  
      ```
      docker run -i -t numpy_image_test /bin/bash
      ```
  
3. numpyがあるかどうかを確認します。
      
      ```
      root@467e7e642188:/# pip list
      Package    Version
      ---------- -------
      numpy      1.24.1
      pip        22.3.1
      setuptools 65.5.1
      wheel      0.38.4
      ```
  
numpyが入っているので、Docker Imageの作成が成功ですね！！！