OmniAICreator/Qiita-1.07M huggingface dataset:
技育祭2022春に参加したよ

株式会社サポーターズさんが2022年3/17~19まで開催していた[技育祭](https://talent.supporterz.jp/geeksai/2022spring/)に参加したので、その感想を記憶がフレッシュなうちに備忘録的な感じで書こうと思います。
特に自分の印象に残っているものがメインになりますが、ご了承ください。

# 全体的な話
技育祭とは、「技」術者を「育」てることを目的とした学生向けのイベント(お祭り)です。そのため、会社の雰囲気紹介や就職に向けての戦略などをお話ししてくださる企業さんも一定数いました。もちろん、それに限らずGeek祭の名に恥じないようなギークっぷりを発揮し、最近の技術のこととかをお話ししてくださる方もいました。

3日間参加する中で、もう聞き飽きたよってくらい、耳にたこができたくらい言われていたことが
<strong>「目に見える形でアウトプット」</strong>でした。
「なにゆえ目に見える形なのか？」と「アウトプットの重要性」については以下で詳しく書いています。

また最近、機械学習が面白そうと思うようになった自分からしてみると、初日の東大教授である松尾先生のお話はとても身に沁みました。それも最後に書いておきます。

# 目に見える形である必然性

見える形でというのは、記事だったりGithubだったりなんでも良いのですが、つまりは第三者が確認できる形で何かを残すことだと思います。これがなぜ必要かについては、3日目のちょまどさんやchokudaiさんのトークセッションで、議論されていました。

結論としては、ポテンシャルを感じることができるからというものでした。ポテンシャルというのは、「その人が会社に入った後でも成長する可能性」のことですね。

新卒採用であれ、中途採用であれ、採用された人間に会社の将来を担ってもらうことになります。そういった人がこれから先、価値あるものを生み出す人材になりうるかという指標を見出すためのプロセスとして、面接だったりが行われるわけです。

目に見える形でアウトプットした痕跡を残すことは、その人が勉強したり努力したりすることが出来る人だという証拠になります。この証拠は、就職におけるアドバンテージになることは間違いないのです。

その点、競技プログラミングのレートなどは客観的な指標として扱いやすいものだったりもします(急に競プロの宣伝をしてしまいました)。とにかく、モノを作ってみてGithubのレポジトリを充実させたり、学んだことを記事にしたりするのが大事だということを忘れないようにしましょう。


# アウトプットの重要性
このトピックについては既に周知の事実ではあると思いますが、改めて書かせて頂きます。

現状として、実際に何か物を作ったことがある学生は10%程度だというようなことが、とあるスライドに載っていました。これを見て、「あれ、結構少ないな」と思いました。

既に社会人で企業に勤めている方にとっては、エンジニアである以上コードを書かないといけないのが当たり前で、いわばアウトプットを強制させられていると言っても過言ではないかと思いますが、学生にとってそのような環境はあまりありません。

ひろゆきさんは、「漫画家になりたいなら漫画を書け」という比喩を用いていましたし、落合陽一さんは、「とにかく何か作れば」とおっしゃっていました。エンジニアというものを作り出すことを基本とする職に就きたいなら、まずは「ものを作ることから始めろ」というのは至極真っ当な指摘だなあと感じました。

また具体的に作りたいものがあまりない、といった悩みを抱えている学生も多かったイメージです。個人的に、この原因として思い当たるものが幾つかあります。
1. 何が作れるのか思い描けない
1. プログラミングそのものを学ぼうとしている
1. 能動的に動くための意思力が不足している

1,3に関しては、今回のような技育祭などを通じて掴んでいったりすることも多く、またモチベーションを上げるきっかけになるので、そこは大丈夫な気がしています。しかし、原因が2の場合は、なんか間違えてしまっている可能性があるかもしれません。プログラミングをしようと思い至ったその根本の熱意や動機を改めて見直すのも良いことだと思います。

アウトプットをすると、定着率がよくなるだとかのメリットなどには触れませんが、この作業を学生のうちから積み重ねることで「つよつよ」になれるかもしれませんね！

# 松尾先生のAIの話
以下は完全に個人的な話ですが、東大のAI研究やそのスタートアップで有名な松尾豊先生のお話が、やはり一番記憶に残っています。

現在、画像分類などのさまざまな分野でAIが人間の性能を超え始めていることは、研究で示されてきました。GPT-3に代表される自然言語処理における進歩により、人間が書いた文章なのかAIが書いた文章なのかを見分けることすら難しいような、そういった時代になりつつあります。そして、AIがこれからどのように進展して行くのかと考えるとワクワクするばかりです。

とはいえ、ここまで性能を出せるようになったということは、理論がかなり進んでいることもまた確かな事実ではあります。そんな中、時代の最先端まで追いつこうとするのは一見大変そうですが、松尾先生はこんなエールを送ってくださいました。

<strong>「AIを学ぶのはまだ遅くない。むしろ早い。」</strong>

我々は上手くいっている部分に対して目を向けがちですが、AIにも不得意な部分がまだまだ大量に存在します。それらの分野を開拓していくのは、私たちの世代なのかもしれません。

また、大学の教授とは思えないようなこんなことも言っていました笑

<strong>「理論はどうでもいいから、とりあえず触れ」</strong>

難しそうな理論を勉強したくない、という理由で敬遠するのはとても勿体ないことだということを伝えたかったんだと思います。「とにかくアウトプットをしろ」ということと何か通じるものがあるような...

# 終わりに
以上、技育祭の備忘録でした。
皆さんも何か頑張ろうと思えたら嬉しいです。

# おまけ
せきぐちあいみさんのライブパフォーマンスめちゃくちゃ凄かったですねえ〜
VRでアートを創り出すという発想といい、その手捌きといい、そこに使われている技術といい、見どころ満載で自分の知らない世界を垣間見ることができた感じがして、とても楽しかったです。
VS Code ＋ Anacondaのデバッグ環境 Windows10（2022年3月版）

# はじめに
VS Code+Anacondaでデバッグを行う記事が既にありますが、2022年3月現在では設定も非常に簡単になっていますので、ミニマムの手順を書いてみました。

# 1. 環境
`
Windows: Windows 10 Pro バージョン21H2 ビルド19044.1586
Anaconda: 2021.11 (Navigator 2.1.1)
Visual Studio Code: 1.65.2
PowerShellでcondaコマンドが実行できるようにPATHが設定されています。
`

# 2. [Anaconda](https://www.anaconda.com/products/individual#Downloads)のインストール
Anacondaのインストールは多数の解説がある為省略します。
上のAnacondaをクリックするとダウンロードリンクに飛びます

# 3. Python Extensionのインストール
左側にあるアクティビティーバーにある拡張機能のアイコンをクリック、または\[Ctrl\]+\[Shift\]+\[X\]でサイドバーが現れます。サイドバーからPythonをインストールします。
![ExtFunc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601615/44c17ebd-f903-9c1b-4b04-43d5ae4a1ccb.png)

# 4. Python サンプルプログラムの作成
以下のようなPythonプログラムを作成してVS Codeで開きます。
```python:hello.py
print("Hello Python from Visual Studio Code")
```

# 5. Python インタープリターの設定
下のステータスバーに言語モード「Python」と表示されている左側の部分「3.9.7 64bit」[^1]をクリックして、上部に表示されるプルダウンでインタープリターを選択します。
![Anaconda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601615/7f55f1f1-1a62-d52e-fad1-2386e9475566.png)

# 6. Python の実行
左上の右三角の右横をクリックして「Debug Python File」[^2]を選択します。実行結果は下のターミナルに表示されます。ブレークポイントを設定してデバッグが可能です。</br>
![RunAnaconda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601615/c7ecf4ab-f866-07d5-97fe-8f355463e2e9.png)
[^1]:Pythonのプログラムを始めて開いたときにPythonインタープリターのフォルダーが自動的に検索されます。検索には数分かかります。
[^2]:「Run Python File」で実行するとターミナルで結果が見れないようです。
日の入りで指定のコマンドを実行するPythonスクリプト

日の入りのタイミングで夕焼け小焼けを再生したかったが、
動的に `crontab` を書き換えるのも気持ち悪く、`at` コマンドも使えなかったので、
かわりにPythonで実装した記録。

# やりたいこと
`runat.py sunset play -q yuyakekoyake.mp3`
とすると、日の入りのタイミングで `play -q yuyakekoyake.mp3` を実行する。
あとは、このコマンドを`crontab`に正午くらいにでも放り込んでおけばよい。

# つまずき・実装のポイント
## argparse でコマンドを受け取る
引数解析はもちろん `argparse` にやらせるが、前述の例だと `-q` もオプション引数と認識されてしまい、`unrecognized arguments` エラーが出る。
これを回避するには、コマンドを受け取る `add_argument` メソッドに `nargs = argparse.REMAINDER` を指定する。
cf. https://docs.python.org/ja/3.7/library/argparse.html#argparse-remainder

## 日の出の時刻の計算
`ephem` モジュールにお任せしました。
https://pypi.org/project/ephem/

## 外部コマンドの実行
Pythonに渡された時点でダブルクォート等の空白処理はなされているので、
絶対に `os.system(' '.join(args.command))` なんてことはしないこと！
`subprocess.run` 関数にリストを渡せるので、これを使いましょう。

# 以下、作ったスクリプト
~~~ python: runat.py
#!/usr/bin/env python
#encoding : utf-8

import sys
import argparse
import logging
import datetime
import time
import subprocess

try:
    import ephem
except ModuleNotFoundError:
    sys.exit (1)

class choice:
    def __init__ (self, star = None, attr = None):
        self.star = star
        self.attr = attr

CHOICES = {
        'sunrise' : choice (star = ephem.Sun,  attr = 'next_rising' ),
        'sunset'  : choice (star = ephem.Sun,  attr = 'next_setting'),
        'moonrise': choice (star = ephem.Moon, attr = 'next_rising' ),
        'moonset' : choice (star = ephem.Moon, attr = 'next_setting'),
        }

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument ('--city', default = 'Tokyo')
    parser.add_argument ('--longitude')
    parser.add_argument ('--latitude')
    parser.add_argument ('--elevation', type = int)
    parser.add_argument ('at', choices = CHOICES.keys() )
    parser.add_argument ('command', nargs = argparse.REMAINDER)
    args = parser.parse_args()
    logging.debug ('args = %s' % args)

    place = ephem.city (args.city)
    if args.latitude is not None:
        place.lat = args.latitude
    if args.longitude is not None:
        place.lon = args.longitude
    if args.elevation is not None:
        place.elevation = args.elevation

    logging.debug ('place = %s' % place)

    star = CHOICES[args.at].star()
    timeat = getattr(place, CHOICES[args.at].attr) (star)
    delta = timeat.datetime() - datetime.datetime.utcnow()

    logging.debug ('going at %s' % ephem.localtime(timeat))

    try:
        time.sleep (delta.seconds)
        subprocess.run (args.command)
    except KeyboardInterrupt:
        sys.exit(1)

if __name__ == '__main__':
    main()
~~~

https://github.com/Yasuwoh/dotfiles/blob/cfca70fdb6707874e5f4f55d9291a7b372313d91/bin/runat.py
Nablarch開発におけるH2 Databaseの利用方法

# はじめに
こんばんわ、きりです。
本記事は[Nablarchを使ってみよう](https://qiita.com/kirin1218/items/242ee0f174f1cb12ef17)のサブ記事として作成しております。

Nablarchのブランクプロジェクトでは初期の設定で「H2 Database」が設定されている。
pom.xmlを確認すると、nablarch.db.jdbcDriverやnablarch.db.urlがｈ２になっていることが確認できる。
「H2 Database」を使おうとするたびに使い方を忘れてしまうので、備忘録として記事を投稿します。

# H2 Databaseとは
Javaプラットフォーム上で動く、データベース。
OracleデーターベースやMySQLなどの重厚なデータベースではないが、JDBCにも対応しており、開発中に利用するデータベースとして利用できる。

# 目標
* ブラウザからアクセスし、テーブル作成、レコード追加を実行する

# 作業の流れ
1. H2 Databaseのコンソールサーバーを起動する
2. ブラウザでログイン
3. テーブルの追加
4. レコードの挿入
5. レコードの参照
6. ログアウト

# 前提
Nablarchのウェブアプリケーションのブランクプロジェクトがローカルに作成されていること

# H2 Databaseのコンソールサーバーを起動する
ブランクプロジェクトを作成すると、プロジェクトルート/h2/bin フォルダ に
* h2.bat
* h2.sh
* h2w.bat

が用意されているので、自身の環境に合わせ、シェルスクリプト(またはバッチファイル）を実行する

# ブラウザでログイン
ブラウザで
http://localhost:8082
にアクセスするとログイン画面が表示される
日本語表示も可能なようで、謎のこだわりを感じる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/29dd2fd1-733a-aa14-c93c-190f94924327.png)


初期設定ではログイン情報は以下、

|名前|値|
|---|---|
|JDBC URL|jdbc:h2:h2/db/SAMPLE|
|ユーザー名|SAMPLE|
|パスワード|SAMPLE|

※JDBC URLはブランクプロジェクトをそのまま使う場合は、上記の通りのパスとなる
※ログインすると、プロジェクトルート/h2/dbにSAMPLE.h2.dbとSAMPLE.h2.lock.dbが作成されていることがわかる。SAMPLE.h2.dbがデータベースの実体なので、このファイルをバックアップしたり、削除したりすることで、復元やクリアが可能。クリアしても再接続時に再作成されるが、当然、ユーザー側で追加したテーブルは削除されている。

ログインが成功すると、以下のようなコンソール画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/4b92d532-dea0-f8bc-ba5a-b600582898fb.png)

テキストエリアにSQL文を入力し、「実行」ボタンをタップすると、処理が行えるようだ。
試しに、テーブルの一覧を表示してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/2f6d7bd9-6a4b-527b-281e-69a31b23ff99.png)

おぉ！！
なんか、やってやった感がある。。自分は何もやってないけど。

※「CODE_NAME」「CODE_PATTERN」「USER_SESSION」はデフォルトでINSERTされているテーブルです。

# テーブルの追加
今回は安易ながらも、Webアプリケーションのトップページへのアクセスログを管理するテーブルを作成します。
項目はシンプルに以下、
* ID
* いつ(ACCESS_TIME)
* 誰が(USER_ID)
* どこに(REQUEST_ID)

[リファレンス](http://www.h2database.com/html/commands.html#create_table)とテンプレートに既に用意されているcreate.sql(db/ddl/h2/create.sql)を参考にコマンドを作成。

```
CREATE TABLE PUBLIC.ACCESS_LOG (
  ID CHAR(8) PRIMARY KEY,
  ACCESS_TIME TIMESTAMP(23, 10) NOT NULL,
  USER_ID CHAR(8) NOT NULL,
　　　　REQUEST_ID CHAR(8)
);
```
# レコードの挿入
テーブル作成時と同様にコンソールからレコードを挿入してみる。
構文は一般的なinsert文を利用
```
INSERT INTO ACCESS_LOG (
　ID,
　ACCESS_TIME,
　USER_ID
) VALUES (
　'33333',
　'2019-05-02 12:48:35',
　'moge'
);
```

# レコードの参照
念のため、INSERTしたレコードが追加されているかを確認

```
SELECT * FROM ACCESS_LOG;
```

# ログアウト
終了時は、「切断」ボタンをタップ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/37aca0a3-bcdd-4c2f-0d31-a96443390475.png)

# 最後に
最初は、DBといえば「Oracle」や「MySQL」とかだろー！と思ってましたが、開発時に簡単に利用できるH2はホント便利だなと感じました。

# 参考URL
[H2 Database](http://www.h2database.com/html/main.html)
[コマンドリファレンス](http://www.h2database.com/html/commands.html)
dockerイメージ作成

#Dockerイメージファイルからコンテナ起動

dockerフォルダに`index.html`,`Dockrefire`ファイルを作成する

```:dockerフォルダ
FROM httpd
COPY index.html /usr/local/apache2/htdocs/
```

`Dockerfile`でbuildする

```
$ docker build -t myimage:1.0 .

$ docker build -t [イメージ名]:[タグ(省略可)] [dockerディレクトリ]
```


作成したイメージで、コンテナ起動

```
$ docker run -dit --name web -p 8080:80 myimage:1.0
```

docker実行フォルダの`index.html`表示
[http://localhost:8080/](http://localhost:8080/)



#Dockerイメージファイルからlaravelのコンテナ起動

```
$ git clone https://github.com/ucan-lab/docker-laravel.git
$ cd docker-laravel
$ make create-project
```
[http://localhost](http://localhost)
[GORM]複合主キーによるDeleteのSQL文

[GORM](https://gorm.io/ja_JP/)の[Delete()](https://gorm.io/ja_JP/docs/delete.html)のSQL文が、複合主キーの場合に、少しイレギュラーであったため、書き留めました。

+ 環境
```
go 1.17
mysql 5.7

gorm.io/gorm v1.22.0 （ GORM自体のv2に当たる。v1は、jinzhu/gormの方 ）
gorm.io/driver/mysql v1.1.2
```


以下のような複合主キーのテーブルの場合に、
```golang
type Item struct {
	Pk1  string `gorm:"primaryKey;autoIncrement:false;"`
	Pk2  string `gorm:"primaryKey;autoIncrement:false;"`
	Name string
}
```

GORMの[Delete()](https://gorm.io/ja_JP/docs/delete.html)を使うと、
```golang
item := Item{
		Pk1:  "test1",
		Pk2:  "test2",
		Name: "name",
}
db.Delete(&item)
```

IN句を使ったSQL文になります。

```sql
DELETE FROM `item` WHERE (`item`.`pk1`,`item`.`pk2`) IN (('test1','test2'));
```

この場合、pk1,pk2のインデックスが効かなくなることがあるので注意が必要です。
圧縮系コマンド備忘録

# 概要
ファイルの圧縮/解凍コマンドを使う時にオプションを忘れて調べちゃうことが多いので自分用の備忘録的にまとめになります。

# gzipコマンド
gzip（ジー・ジップ）は、データ圧縮プログラムのひとつ、およびその圧縮データのフォーマットである。「GNU zip」の略であり、GNUプロジェクトによって開発・メンテナンスされている。現在、多くのUNIXに標準搭載される。(参考:wikipedia)

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  -d  |  圧縮ファイルを展開する  |
|  -c  |  標準出力へ出力する  |
|  -r  |  ディレクトリ内のファイルをすべて圧縮する  |

# bzip2コマンド
bzip2（ビージップツー）は、データ圧縮プログラムのひとつ、およびその圧縮データのフォーマットである。ジュリアン・スーアード（英語版） により開発され、その実装（プログラム）のライセンスは BSD-style である。bzip2圧縮プログラムを用いて処理されたファイルには、拡張子として標準的には「.bz2」が付けられる。アーカイブ機能はない。(参考:wikipedia)

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  -d  |  圧縮ファイルを展開する  |
|  -c  |  圧縮ファイルを標準出力へ出力する  |

# XZコマンド
xz は、データ圧縮プログラムのひとつ、およびその圧縮データのフォーマットである。LZMA/LZMA2圧縮アルゴリズムを利用している。xzの登場以前より使われていたgzip、bzip2と比較すると、圧縮時にはより多くの時間とメモリを消費するが、圧縮率では概ね優位で、また伸張速度もgzipより多少遅いがbzip2よりは速い傾向にある。このことから、特にアーカイブ配布用途として、tarとgzipを組み合わせて作成する場合やtarとbzip2を組み合わせる場合と並んで採用され、bzip2を置き換えるケースも増えている。xz自身にアーカイブ機能はないのでアーカイブする場合はtarと組み合わせて使用するのが一般的である。(参考:wikipedia)

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  -d  |  圧縮ファイルを展開する  |
|  -k  |  圧縮・解凍後に元ファイルを削除しない  |
|  -l  |  圧縮ファイル内のファイルを一覧表示する  |

# 圧縮ファイルの閲覧
|  コマンド  |  説明  |
| ---- | ---- |
|  zcat  |  gzipコマンドで圧縮されたファイルの内容を出力する  |
|  bcat  |  bzip2コマンドで圧縮されたファイルの内容を出力する  |
|  xcat  |  xzコマンドで圧縮されたファイルの内容を出力する  |

# tarコマンド
tarはファイルのアーカイブに用いられ、多数のファイルを一つのファイルにまとめることができる。ファイルのユーザ情報とグループ情報、パーミッション、最終更新日時、ディレクトリ構造などを同時にアーカイブすることができる。元来tarはアーカイブ、すなわち複数のファイルをまとめることのみで圧縮の機能はない。(参考:wikipedia)

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  -c  |  アーカイブを作成する  |
|  -x  |  アーカイブからファイルを取り出す  |
|  -t  |  アーカイブの内容を確認する  |
|  -f ファイル名  |  アーカイブファイル名を指定する  |
|  -z  |  gzipによる圧縮/展開を行う  |
|  -j  |  bzip2による圧縮/展開を行う  |
|  -J  |  xzによる圧縮/展開を行う  |
|  -v  |  詳細な情報を表示する  |
|  -u  |  アーカイブ内にある同名のファイルより新しいものだけを追加する  |
|  -r  |  アーカイブにファイルを追加する  |
|  -N  |  指定した日付けより新しいデータのみを対象とする  |
|  -M  |  複数デバイスへの分割を行う  |
|  --delete  |  アーカイブからファイルを削除する  |

# cpioコマンド
cpioは、ファイルアーカイバ・ユーティリティ並びにそのアーカイバで使われるファイルフォーマットである。主にUnix系オペレーティングシステムにインストールされることが多い(参考:wikipedia)

## フラグ一覧
|  フラグ  |  説明  |
| ---- | ---- |
|  -i オプション パターン  |  アーカイブからファイルを抽出する  |
|  -o オプション  |  アーカイブを作成する  |
|  -p オプション ディレクトリ  |  ファイルを別ディレクトリにコピーする  |

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  -A  |  既存のアーカイブにファイルを追加する  |
|  -d  |  必要なディレクトリを作成する  |
|  -r  |  ファイル名を対話的に変更する  |
|  -t  |  コピーはせず、入力された内容を一覧表示する  |
|  -v  |  ファイル名の一覧を表示する  |

# ddコマンド
ddの主な機能は指定されたバイト数もしくはブロック数のデータのコピーであり、この機能は、ハードディスク（全体もしくはパーティション単位、またはブートセクター等）のバックアップや、/dev/zeroや/dev/randomを用いて指定された領域を完全消去するために利用される。同様にディスクの（可能な限り）全状態をそのままクローンしたい、コンピュータ・フォレンジックスなどの場合にも使われる。(参考:wikipedia)

## オプション一覧
|  オプション  |  説明  |
| ---- | ---- |
|  if=入力ファイル  |  入力側ファイルを指定する（デフォルトは標準入力）  |
|  of=出力ファイル  |  出力側ファイルを指定する（デフォルトは標準出力）   |
|  bs=バイト数  |  入出力のブロックサイズを指定する  |
|  count=回数  |  回数分の入力ブロックをコピーする  |
Javaでスタックトレースを出力する方法

# 記事の目的
Javaの開発をしていて、デバッグするまでもないが、コールスタックを知りたかったので、調べた結果を備忘録として投稿

# やったこと
スタックトレースを表示したい、箇所で以下のコードを追加
```
Exception e = new Exception();
e.printStackTrace();
```

# 参考URL
[Java - Stack trace出力する方法 (Throwable、Exception)](https://codechacha.com/ja/java-print-stack-trace/)
Next.js実装をGithubActionsでS3に自動デプロイして静的ウェブサイトホスティングやる雑メモ

>https://dev.classmethod.jp/articles/github-actions-oidc-configure-aws-credentials/#toc-1
>AWS IAMのIDプロバイダーを利用することで、GitHub ActionsにAWSユーザーアクセスキーなど永続的なクレデンシャルを渡すことなく、IAMロールをベースとした権限管理によってAWSリソースの操作ができるようになる

## 1.`IAM > アクセス管理 > IDプロバイダ`から`OpenID Connect`でGithubの登録

>プロバイダのタイプ: OpenIDConnect
>プロバイダのURL: https://token.actions.githubusercontent.com
>対象者: sts.amazonaws.com

## 2.IAMロール作成

```json
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::721814306249:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:ta9to/.com:*"
                }
            }
        }
    ]
}
```

## 3.Github Actionsで実行するNext.jsアプリのビルドジョブ設定

![スクリーンショット 2022-03-19 18.51.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192321/22028c96-5325-5673-aef0-157a235d98e9.png)

```.github/workflows/deploy.yml
name: Deploy to S3
on:
  push:
    branches: [main]
env:
  AWS_ROLE_ARN: arn:aws:iam::721814306249:role/ta9to.com-GithubActions-DeployToS3
  AWS_REGION : ap-northeast-1
  BUCKET_NAME : ta9to.com
permissions:
  id-token: write
  contents: read
jobs:
  deploy-to-s3:
    runs-on: ubuntu-latest
    steps:
      - name: Git clone the repository
        uses: actions/checkout@v2
      - name: Setup Node
        uses: actions/setup-node@v1
        with:
          node-version: 16.x
      - run: npm install
      - run: npm run export
      - name: configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ env.AWS_ROLE_ARN }}
          role-session-name: github-oidc-role-session
          aws-region: ${{ env.AWS_REGION }}
      - run: aws s3 sync ./out s3://${{ env.BUCKET_NAME }}/
```

## 4.S3の静的サイトホスティング設定

## 5.CloudFront,証明書,Route53設定

## 6.完成

https://ta9to.com

### ハマりどこメモ

- CloudFrontの`代替ドメイン名 (CNAME)`設定するの忘れてハマった
    - ここが設定できてないとRoute53で登録してるドメインにAレコードをエイリアスで登録する時にCloudFrontのディストリビューションがサジェストされないのでサジェストない時は↑これ
swiftの画面遷移でつまづいた話

# はじめに
swiftでのアプリ開発をしていたのですが，新しく画面遷移を作ろうと思ったら，うまくいかずつまづいたので，自分への備忘録的な感じで書いときます．

# エラー文
`has no segue with identifier 'toPersonalPage'`

# 結論から言うと
Storyboard SegueのIdentifierを設定していなかった．

![スクリーンショット 2022-03-19 20.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600580/7089e72c-dedd-49f6-512e-06d8b7f5a265.png)

# 画面遷移のやり方
```swift:ボタンタップの関数
@IBAction func tapEnterButton(_ sender: Any) {
    performSegue(withIdentifier: "toPersonalPage", sender: (memArray,　tappedBtnTag))
}
```

上記のようにエンターボタンがタップされた時の関数を作る．
この時にコントロールキーを押しながら，stroryboardに設置されたボタンをViewControllerの関数を置きたい部分に部分に持ってくると対応づけられて，行番号のところに二重丸が表示される．

storyboardの方で同様にコントロールキーを押しながら遷移前の画面のviewcontrollerを選んで次の画面に引っ張ってくるとsegueのマークが表示される．

で，segueのマークを選んで，上の画像のようにidentifierを設定する．
シェルスクリプトで配列を使ってみる


:::note info
Alfredのワークフローなどで、スクリプトにzshをはじめました。初心者用にメモを残します
:::

# シェルスクリプトで配列を使ってみる

シェルスクリプトでは1次元配列のみサポートしていて、添字はブラケットで囲みます
``` 変数名[添字]```
<font color=red>※zshは添字は1から始まります</font>

 
### 配列に値をセットする

添字をひとつずつ指定してセットできるのは当たり前ですね
```zsh
array[1]=One; array[2]=Two; array[3]=Three
```
　

区切り文字（空白）を利用して一括でセットすることもできます
```zsh
array=(One Two Three)
```
　
　
セットした値をエコーしてみましょう
``` zsh
array=(One Two Three); for x in {1..3}; do echo 'array['$x']='$array[x]; done
 #=> array[1]=One
 #=> array[2]=Two
 #=> array[3]=Three
```
たしかにセットできていますね
　
　
上の例では、括弧の中に実際の文字列を指定していますが、変数で指定することもできます
下記のようにechoを利用している部分が味噌です
```zsh
 # 変数をechoして配列にセット
str='One Two Three'; array=(`echo $str`);for x in {1..3}; do echo 'array['$x']='$array[x]; done
 #=> array[1]=One
 #=> array[2]=Two
 #=> array[3]=Three
```
　

ファイルを1行ごとに配列へ格納することもできます

```zsh
 # ファイルをcatして配列にセット（下のサンプルはtemp.txtを出力して開きます）
echo -e 'One\nTwo\nThree' > temp.txt;array=(`cat temp.txt`);for x in {1..3}; do echo 'array['$x']='$array[$x]; done; open temp.txt
 #=> array[1]=One 
 #=> array[2]=Two 
 #=> array[3]=Three

 # 空白がある場合は、区切り文字(IFS)を改行('\n')にすればOKです（下のサンプルはtemp2.txtを出力して開きます）
echo -e 'One 1\nTwo 2\nThree 3' > temp2.txt;OLD=$IFS;IFS=$'\n';array=(`cat temp2.txt`);IFS=$OLD;for x in {1..3}; do echo 'array['$x']='$array[$x]; done; open temp2.txt
array[1]=One 1
array[2]=Two 2
array[3]=Three 3

 # ちなみにIFSの中身を確認するには下記です。あ、複数設定できるのですね
echo -n $IFS | od -ac
 #=> 0000000   sp  ht  nl nul                                                
 #=>               \t  \n  \0                                                
 #=> 0000004
 # SPace（空白）、Horizontal Tab（タブ）、New Line（改行）、Null（ヌル）
```


### 配列へのアクセス（なかば実験室です）

個々の要素を参照するには添字に数字を指定します
1個目が1、2個目が2、3個目が3・・・・
マイナスも指定することができ、その場合配列の最後からの順番となります
-1は最後の項目、-2は最後から2番目、-3は最後から3番目・・・・

```zsh
 # 2番目をエコー
array=(One Two Three Four Five);echo $array[2]
 #=> Tow

 # 後ろから2番目をエコー
array=(One Two Three Four Five);echo $array[-2]
 #=> Four
```
　
　
配列全体は添字なし、添字＊、添字＠のどれでもいけますね
全体をエコーすると空白で区切られて出力されます
```zsh
 # 配列全体のアクセス　添字なし、添字＊、添字＠のどれでもOK
array=(One Two Three); echo $array; echo $array[*]; echo $array[@]
 #=>  One Two Three
 #=>  One Two Three
 #=>  One Two Three
```
　

配列を部分的に参照する場合、連続した要素の取り出しが可能で
数字を2つ使って初めと終わりを指定ます
もちマイナスも可能

```zsh
 # 2番目から末尾2番目までをエコー
array=(One Two Three Four Five);echo $array[2,-2]
 #=> Two Three Four

 # 逆順は不可ですね
array=(One Two Three Four Five);echo $arrayE[2,1]

 # 実質1項目の指定も可能。2番目から2番目まで
array=(One Two Three Four Five);echo $array[2,2]
 #=> Two

 # 実質1項目の指定も可能。3番目から末尾3番目まで
array=(One Two Three Four Five);echo $array[3,-3]
 #=> Three
```
　

配列の要素の個数は、中括弧と#（ナンバー記号）で記述します
```zsh
 #　配列の要素数
array=(One Two Three); echo ${#array},${#array[*]},${#array[@]}
 #=>  3,3,3
```
　

### 雑談（変数と配列）　
中括弧と言えば、変数の一部を切り取るパラメータ展開で利用しましたね
[【じぶんメモ】シェルスクリプトで文字の一部を取り出す](https://qiita.com/kitanotamotsu/items/8f02391f3a3b3a347424)

そこで配列と一般変数の中括弧を比較してみました
似ているような、似ていないような。。。

```zsh
 # 変数の部分参照と配列の要素範囲の指定は似ている?
var=ABCDE; echo ${var:1:3}
 #=>  BCD
 #=>  変数の一部切り取り

array=(A B C D E); echo ${array[2,4]}
 #=>  B C D
 #=>  配列なので空白で区切られています


# ナンバー記号（#）は変数だと文字列長、配列だと要素数
var=ABCDE; echo ${#var} 
 #=>  5
 #=>  5文字という意味

array=(A B C D E); echo ${#array}
 #=>  5  
 #=>  5個という意味
```
Ruby と Python で解く TOTO くじ 削減

# はじめに
高橋君は、少ないお小遣いで`TOTOくじ`を楽しもうと思っています。
高橋君が楽しいとは、１等もしくは２等が当たることです。
高橋君が楽しむために最適な戦略を取った場合、合計金額の最小値を求めなさい。
# TOTOくじ
https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%E6%8C%AF%E8%88%88%E3%81%8F%E3%81%98

ここでは、組合せの少ない`totoGoal3`で計算を進めます。

https://www.toto-dream.com/toto/about/index.html
# 例１
一番シンプルな例は、３ダブルです。

http://www.01senmonten.com/com/home/toto5.html

２の３乗なので本来８通り（800円）必要ですが、２通りで楽しめます。

```rb:ruby
def check(i)
  f = false
  ['000'.to_i(2), '111'.to_i(2)].each do |x|
    f ||= true if (i ^ x).to_s(2).count('1') <= 1
  end
  ct = i.to_s(2).rjust(3, '0')
  puts f ? "#{ct} OK" : "#{ct} NG"
end

(2**3).times do |i|
  check(i)
end
```
```py:python
def check(i):
    ct = format(i, 'b').rjust(3, '0')
    for x in ['000', '111']:
        f = False
        c = 0
        for i in range(len(x)):
            if ct[i] == x[i]:
                c += 1
        if c >= 2:
            f = True
            break
    if f:
        print(ct, 'OK')
    else:
        print(ct, 'NG')

for i in range(2**3):
    check(i)

# output
000 OK
001 OK
010 OK
011 OK
100 OK
101 OK
110 OK
111 OK
```
ここでは`000`と`111`の２通りで、２等以上（はずれが１つ以下）を確認しています。
一つの買い目で全的中とはずれ１つの４通りに対応可能ですので、８÷４＝２通りでいいわけです。
`Ruby`の方は、`xor`を使用していますが、トリプル対応などを考えますと、よろしくないかもしれないです。
# 応用
応用は、４ダブルです。
３ダブルはシンプルですので、簡単に求めることができましたが、４ダブルの組合せはどのように求めればいいでしょうか。

一つの買い目で５通りに対応可能ですので、（２の４乗）÷５＝３．２となり４通り以上が必要と推定されます。

しかし、ここは`atcoder`のコンテスト中ではないので、`TLE`を気にせず全検索することにします。

```rb:ruby
def check(cs)
  a = (0...2**N).to_a
  cmb = []

  a.combination(cs) do |xs|
    return cmb.size if xs.include?(0).! || cmb.empty?.!
    h = Hash.new(0)
    a.each do |i|
      f = false
      xs.each do |x|
        if (i ^ x).to_s(2).count('1') <= 1
          f = true
          h[i] += 1
          break
        end
      end
      break if f.!
    end
    if h.size == 2**N
      pt = xs.map{ _1.to_s(2).rjust(N, '0') }
      puts pt.join(', ')
      cmb << pt
    end
  end
end

N = gets.to_i
(2**N / N.next.to_f).ceil.upto(2**N) do |zz|
  break if check(zz) > 0
end
```
```rb:ruby
# input
3
# output
000, 111
# input
4
# output
0000, 0001, 1110, 1111
# input
5
# output
00000, 00001, 00010, 01111, 10111, 11011, 11100
```
５ダブルまでは、実用的な時間で答えが返ってきます。
# 補足
TOTOくじは2000年初頭より発売されており、削減の考え方にはそれなりの歴史があります。
例えば、６ダブルの最小値は`12`であることが知られており、予め計算結果をテーブルに保存しておくことにより、計算時間を縮小する手法がとられることもあります。
# まとめ
+ TOTOくじに詳しくなった
【テンプレート】問題があったときの報告と相談するときのテンプレート

自分のためのメモです。

何かの問題の報告・相談するときに自分がいつも使うためのテンプレートです。

## テンプレート
- まず、含めるもの
    - 連絡か相談か、相手に何をしてほしいのか。相手に何をしてほしいかがわかるようにすると読む側はわかりやすい。
        - 例：「1点相談です。○○の対応方法について下記確認いただき、OKかNGかご連絡いただけますと幸いです」「連絡です。△△の作業を行いました。ご認識だけいただけますと幸いです」
    - いつまでに返信がほしいか。これが書いてあると読む側は返す期限がわかるので進めやすい。できたら根拠をつけると良いが、何の根拠もなくても「明日までにください」などの期限をつけると良い。その期限が相手にとって無理だったら無理だと連絡がくるはずなので。逆に期限をつけないと「いつまでに返信が必要ですか？」と質問されてしまって二度手間になる。
        - 例：「プロジェクトのスケジュールから鑑みて、できたら月曜、遅くとも水曜までにお返事いただけると幸いです」「急で申し訳ありませんが明日までに確認、返信をいただけますと幸いです」
- 背景
    - 報告先の人が背景に詳しい人だったらいらないので省いてしまってよい
    - いきなり「○○の問題があったので△△の対策しました！」みたいに話を始めてしまうと、背景をしらない人だと何の話かわからないしビックリするので
    - なぜ問題が発生したのかの歴史的な背景や事前知識を説明しておくと、後の問題と解決案への接続がスムーズになる
- 問題
    - どんな問題があるのか簡単に説明する。例：「バックエンドで使用されているサードパーティーライブラリーの○○に□□の脆弱性があることが発見され、不正アクセスされるリスクがある」
- 範囲と影響
    - 具体的な問題の範囲と影響を説明する。範囲はどの機能に影響があるのか、1つの機能なのか複数の機能なのか、システム全体なのかなど。影響は完全停止なのか部分停止なのか、ずっと停止なのかそれともときどきだけ停止になるのかなど。
    - ここに書かれた情報で問題の優先順位を決められるため重要
- 解決案
    - 解決案をいくつかだす。個人的に、3つだとなんとなく良いので3つ出すようにしている
    - 解決案が1つしかないということはない。まず、複数考えて、後述の評価でどれが良いかを決める。そうじゃないと後で「なぜそれにしたの？もっといい案なかったの？こっちの解決案の方が良さそうだけど、こっちに変えてもよいの？こっちの観点は考えた？」という質問に答えられなくて困ることになる
- 評価（観点 x 評価）
    - 観点を出して、各観点に対する評価を出す。例えば、拡張性、保守性、コスト、スケジュールなどの観点を出して、各観点で評価する（○×△や1〜3などを使う）。
- 結論
    - どの解決案を採用するのかを総合的に判断する
    - 採用した理由も書く。例えば、「初期コスト、拡張性は案1、2が良いが、機能追加も少なく、今後の保守性を考えると保守性が楽な案3を採用することとする」とすると、なぜ1つの観点しか勝っていない解決案を採用するのかがわかる。
    - また、理由を書いておくことで後で別の解決案が思い浮かんだときに、新しい方を採用するべきかの判断がしやすい
【個人開発】ランダムでカラオケで歌う曲を決めてくれるサービス「PICKUP TRACK」をリリースしました！

# はじめに
皆さんはカラオケに行った時、歌う曲に困った経験はありませんか？

最近はこのご時世なのでなかなかカラオケにも行きづらい状況ですが、私自身そういったことがよくありました。
また、私は一緒に行った友人の歌を聴くのも好きなので少しでも歌う曲に悩む時間を減らしたいとも思っていました。

そんな経験から自分と同じような悩みを持つ人に、よりカラオケを楽しんでもらいたいと思い、「PICKUP TRACK」を作成いたしました。

URL: https://pickup-track.com
GitHub: https://github.com/junjunpei/pickup_track
[![Pickup (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2564332/0ae464a7-32bf-17ac-96b4-b91ca10b5835.png)](https://pickup-track.com)

# サービス概要
※パソコン、スマホどちらからでも使用できますが、カラオケで使っていただくことを想定しているため、説明にはスマホ画面の画像を使用します。

**1. ホーム画面**

黒を基調としたデザインで統一しました。
<img src="https://i.gyazo.com/a324ea97511e1f2506c966ad50d3e1f8.gif" width="250">

**2. 会員登録、ログイン**

恐れ入りますが、会員登録とログインをお願いします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2564332/a791aa8b-b022-8fc0-4933-52d6deaabff9.jpeg" width="250">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2564332/42e862f4-e8bf-a57b-6f8c-e10fcf80c850.jpeg" width="250">

**3. 楽曲検索画面からマイライブラリに追加**

自分の好きな曲を曲名やアーティスト名で検索して、プラスボタンをワンタッチでマイライブラリに追加することができます。同じようにゴミ箱ボタンを押せばマイライブラリから削除することもできます。
<img src="https://i.gyazo.com/4ceba295340b2e518dfa73086f4af027.gif" width="250">

**4. マイライブラリに追加された曲からおすすめ曲を表示** 

曲を検索して追加するという手間を少しでも省くため、また、あまり曲を知らずもっと他の曲を知りたい方に向けてのレコメンド機能として、マイライブラリに追加されている曲から「おすすめ曲」を表示していて、そこから追加も削除も出来るようになっています。
<img src="https://i.gyazo.com/60f5bfc6d0b12d7e8c8cc0117b9647d0.gif" width="250">

**5. マイライブラリからランダムで1曲ピックアップ**

「ピックアップ」ボタンを押すとマイライブラリの中からランダムで1曲選んでくれます。「もう一度！」を押せば何度でもピックアップでき、「この曲を歌う！」で決定できます。また、下にスクロールすると右下にボタンが表示され、それを押してもピックアップができます。
<img src="https://i.gyazo.com/a11ff390bac4ee33290cb7b749822f8e.gif" width="250">
<img src="https://i.gyazo.com/a7501570a3b9bd84ec123098347a9774.gif" width="250">

**6. ユーザー情報画面に歌った曲の履歴を表示**

ユーザー情報画面には歌った履歴が「新着順」と「回数が多い順」で表示されます。「新着順」では履歴の削除ができ、「回数が多い順」では歌った回数が表示されます。どの曲をよく歌っているかが分かるので「あれ、いつも何歌ってたっけ？」となるのを防ぐことができます。
<img src="https://i.gyazo.com/1281db24b783190cf741347cae15a75a.gif" width="250">

# 使用技術
- **Ruby 2.7.2**
- **Rails 6.0.3**
- **Vue.js 2.6.14**

**主要Gem**
- sorcery
- jwt
- rubocop
- meta-tags
- dotenv-rails
- byebug
- capybara

**主要JavaScriptパッケージ**
- vuetify
- vue-router
- vuex
- axios
- vee-validate

**テスト**
- Rspec

**インフラ**
- Heroku
- MySQL

**API**
- Spotify API

# リリース後に導入した機能
- おすすめ曲機能

# 今後導入したい機能
- プレイリスト機能
- マイライブラリに曲を追加する手間をより省けるような機能
- SNSログイン

# 終わりに
最後まで見ていただき、ありがとうございました！
まだまだ自分に足りない部分だらけで開発も苦労しましたが、だからこそ完成した達成感は大きく、愛着のあるものになりました。
見ていただいた皆さんもよければ使ってみていただけると嬉しいです。
改めましてありがとうございました。
Vue3 で Vue Router4 を使う方法

## 背景
Vue3にVue Router4を導入した時の方法の備忘録です。

## 内容

### ページ作成
src フォルダ直下に「pages」というフォルダを作成し、その中に「IndexPage.vue」と「DetailPage.vue」というファイルを作成します。
※h1 タグの内容はそれぞれ「IndexPageです。」と「DetailPageです。」に変更します。
```
template>
  <div>
    <h1>IndexPageです。</h1>
  </div>
</template>
 
<script>
export default {
}
</script>
```
### Vue Router4 の設定
「main.js」ファイルに必要なコードを書きます。

```
import { createApp } from 'vue';
import App from './App.vue';
import router from "./router";
 
const app = createApp(App);
app.use(router);
app.mount('#app');
```

「main.js」と同じ階層に、「router.js」ファイルを作成し、以下のようにコードを書きます。

```
import {createRouter,createWebHashHistory} from 'vue-router';
import Index from "./pages/IndexPage";
import Detail from "./pages/DetailPage";
 
const routes = [
  { path: '/', component: Index },
  { path: '/Detail', component: Detail },
]
 
const router = createRouter({
  history: createWebHashHistory(),
  routes,
})
 
export default router;
```

「App.vue」を以下のようにコード書きます。
```
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```
IndexPage
![IndexPage](https://gyazo.com/0d60a05283ca82b1951b1a04b2da3f8e.png)
DetailPage
![DetailPage](https://gyazo.com/c13fa94d23bc7e85cda9a8581e874128.png)
それぞれ、表示することができました。
IBM Cloudの新認定試験IBM Cloud Professional SRE v2を受けてみた

# IBM Cloud Professional SRE v2とは

IBM Cloudの認定技術者の1つで、1～3年程度の実務経験を積んだ中級レベルの試験です。

IBM Cloud Professional SRE v2に合格すると、IBM Certified Professional SRE- Cloud v2の認定資格を得ることができます。もちろんOpen Badgeももらえます。

<img width="160" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/48ae7e3a-d50b-cc17-6c17-d6c16d2bf826.png">


認定資格および試験の概要はこちら。

> https://www.ibm.com/training/certification/C0007801

# 学習方法

難易度はIBM Cloudの経験者であればさほど難しくはありませんでした。下記サイトでラーニングパスが公開されています。

> https://www.ibm.com/training/path/ibmcloudprofessionalsitereliabilityengineer(sre)v2

もしIBM Cloudの経験があり、すでにProfessional DeveloperやProfessional Architectの資格を持っている方だったら、コース内のFlash Cardだけ勉強しておけば何とかなるかもしれません。

<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/8bd60457-8de7-d747-01e9-e42896f581af.png">

# 受験方法

PearsonVUE社のサイトで予約して受験してください。

https://www.pearsonvue.co.jp/Clients/IBM.aspx

以前は最寄りのテストセンターでしか受験できなかったのですが、最近はカメラ付きPCがあれば自宅でも受験可能になりました。こういうご時世ですので、可能であれば自宅での受験をお勧めします。ただし部屋の片づけはきちんとしておいてください。

# 合格点

61問中40問以上の正解で合格です。正答率は65%です。IBMの認定試験では甘い方だと思います。

# 出題内容

試験規約により具体的な問題文は書けませんので、雰囲気になりますが、先述のFlash Cardはかなり参考になりました。ずばりそのまま出たものも数問あった印象です。

IBM Cloudを普段使っていて、Professional ArchitectやDeveloperに受かるレベルの人であれば、Flash CardでSRE固有の部分をさくっと勉強すれば合格できると思います。

# 感想

v1は既に持っていたのですがv2は未受験だったので、挑戦してみました。勉強時間は試験直前にFlash Cardを一通り確認しただけの30分ほどでしたが、合格できました。最近受けたIBM Cloudの認定試験としては簡単な方だったと思います。それがいいかは別として、SREとしての実務経験がなくても合格できると思います。
【メモ】JupyterLabでbalck, isortを使用する方法

- 製造業出身のデータサイエンティストがお送りする記事
- 今回は、JupyterLabでbalck, isortを使用する方法をメモとして残しておきます。

## JupyterLabでbalck, isortを使えるようにする方法

### ライブラリーのインストール
```php
pip install black isort
pip install jupyterlab_code_formatter
```

[Jupyterlab Code Formatter](https://github.com/ryantam626/jupyterlab_code_formatter)をインストールする必要がございます。

### JupyterLabの設定方法

1. Settings/Advanced Seetings Editor をクリックします。

![スクリーンショット 2022-03-19 19.41.31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/d297e3bc-fa82-bf68-f369-5e6de7b2cd66.jpeg)

2. Jupyterlab Code Formatterで各種設定します。

![スクリーンショット 2022-03-19 19.43.22.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/6f715e2c-afd0-ed32-1770-5d55c52c8998.jpeg)

![スクリーンショット 2022-03-19 19.43.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/d2bacb0b-007f-0d98-c507-e7cb29483b78.jpeg)

上記設定を行う事で、JupyterLabでbalck, isortを使用できます。
【Kotlin】アルゴ式 標準入力 1-5（日が変わるまであと何時間）

アルゴ式「[標準入力 1-5](https://algo-method.com/tasks/23)」を `kotlin.time` を使って解く。

```Kotlin:Kotlin1.5
import kotlin.time.*

@OptIn(ExperimentalTime::class)
fun main() {
    readLine()
        .let { checkNotNull(it) }
        .toInt()
        .toDuration(DurationUnit.HOURS)
        .let { 1.days - it }
        .inWholeHours
        .also { println(it) }
}
```

0時から現在までの経過時間（入力値）を、丸一日から引いている。

アルゴ式ではまだ使えないが、Kotlin 1.6 を使うとこうなる。

```Kotlin:Kotlin1.6
import kotlin.time.Duration.Companion.days
import kotlin.time.DurationUnit
import kotlin.time.toDuration

fun main() {
    readLine()
        .let { checkNotNull(it) }
        .toInt()
        .toDuration(DurationUnit.HOURS)
        .let { 1.days - it }
        .inWholeHours
        .also { println(it) }
}
```

／以上
Python seleniumでAWSコンソールのログインを自動化する（PythonでWeb画面のスクレイピングする）

タイトルの通りですが、Pythonでseleniumを使ってAWSコンソールのログイン処理を自動化したので投稿します。
最近、AWSアカウントを複数利用する（個人用／会社用／顧客用などなど）ケースが増えてきており、さらにパスワードポリシーが様々で大混乱中のため自動化しました(^^;)
いわゆるPythonにseleniumをインストールしてWebスクレイピングする編です。

## 想定読者

* AWSコンソールのログインが面倒に感じている人
* Pythonが気になっている人
* Webの自動化に取り組みたい人

## 作業時間

約15分

## 参考ページ

https://www.studycloudtech.com/python/start-selenium-with-python/

こちらのページのseleniumの基本操作で実現出来ました(^^)

## 作業手順

1. ブラウザのドライバダウンロード
1. Pythonにseleniumをインストール
1. 実装

それでは1つ１つ手順を説明します。

### 1.ブラウザのドライバダウンロード

seleniumはブラウザのドライバを使ってWebサイトの操作を自動化します。
ということで事前にドライバをダウンロードします。
今回はChromeのドライバを用意することにします。
Chromeは以下のURLからダウンロードできます。

https://sites.google.com/chromium.org/driver/

stableバージョンの最新ドライバをダウンロードしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/63d0246b-bf05-9c65-c876-c7932a080b4c.png)

自身の環境に合ったものをクリックします。（私はWindowsユーザなので。。。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/4492fc57-6390-8583-1f95-132763508d22.png)

ダウンロードしたzipファイルを解凍して「**chromedriver.exe**」を任意のフォルダにコピーします。
以上です。この手順は終了です。

### 2.Pythonにseleniumをインストール

これはpipを使えばすぐですね。以下を実行してください。

```python
pip install selenium
```

### 3.実装

いよいよ実装です。
と、言ってもこちらも一瞬です。
以下のソースコードをコピーして

* CHROME_DRIVER
* AWS_ACCOUNT_ID
* AWS_IAM_ID
* AWS_IAM_PASSS

の４か所を自身の**Chromeドライバを格納したフォルダ**、**AWSアカウント**／**IAM ID**／**パスワード**に変えましょう。

```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

CHROME_DRIVER = "C:\\Python\\drive\\chromedriver"

OPEN_AWS_URL = "https://console.aws.amazon.com"
AWS_ACCOUNT_ID = "111111111111"
AWS_IAM_ID = "XXXXXX"
AWS_IAM_PASSS = "xxxxxxxx"

driver = webdriver.Chrome(CHROME_DRIVER,options=Options())

print("OPNE:" + OPEN_AWS_URL)
driver.get(OPEN_AWS_URL)
driver.find_element_by_id("iam_user_radio_button").click()

print("ACCOUT ID 入力")
driver.find_element_by_id("resolving_input").send_keys(AWS_ACCOUNT_ID)
driver.find_element_by_id("next_button").click()

print("USER NAME 入力")
driver.find_element_by_id("username").send_keys(AWS_IAM_ID)
print("PASSWORD 入力")
driver.find_element_by_id("password").send_keys(AWS_IAM_PASSS)
driver.find_element_by_id("signin_button").click()
```

では、実行。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/94e97832-7cb5-a54a-88f8-271c93bf7c67.png)

お、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/dae8512c-eae4-8068-ddbc-97604b4df13a.png)

おお、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/b2025aaa-5a6f-8936-6de8-0c2530427b12.png)

成功です！なんだか画面が勝手に動いているのを見ているとワクワクします(^^)
お疲れ様でした！！

### 補足

IAMユーザがMFA認証の場合（ほとんどの方がセキュリティ的にこっちだと思いますが）、最後が以下の画面表示になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/2894f35d-b92c-fd45-4638-51a5d9ff71d2.png)

MFAはパスワードが毎回変わるので、ここでMFAのパスワードを手動入力してログインします。（私はこっちで運用してます）
これでもAWSコンソールのAWSアカウント、IAM ID、パスワード入力が自動的にされるのでだいぶ楽になりました(^^)

## まとめ

今回は、Python seleniumを使ってAWSコンソールのログイン処理を自動化しました。
実は、seleniumを使うのが初めてで何か楽したいな思ってAWSコンソール自動化にチャレンジしました。
AWSコンソールのログインに煩わしさを感じている方はぜひ試してみてください。以上です。

ここまで読んで頂き、ありがとうございました！
p49 Fence Repair(C#)

#### 自分（正解）

```c#

using System;

public class Program
{
    public static void Main()
    {
        int N = 3;
        int[] L = { 8, 5, 8 };
        int first_back;
        int second_back;
        int answer = 0;
        List<int> L_list = new List<int>(L);

        while (L_list.Count > 1)
        {
            L_list.Sort();
            L_list.Reverse();

            first_back = L_list[L_list.Count - 1];
            second_back = L_list[L_list.Count - 2];

            answer += first_back + second_back;

            L_list.RemoveAt(L_list.Count - 1);
            L_list.RemoveAt(L_list.Count - 1);
            L_list.Add(answer);
        }
        Console.WriteLine("答え：{0}", answer);
    }
}

```


#### 解答

今回は合っていたが、貪欲法を考えるときにいかに早くルールに気付けるかが鍵になってきそう。
今回のを例でいうと、「一番短い板の節点とその次に短い板の節点は兄弟といてよい」にあたる。
変数の命名法

# 概要
リーダブルコードの変数の命名法について書かれている部分を読んだ覚書です。
特に、**「カラフル」な単語を使用する**の章に関しては、よく用いられる単語の代わりとなるより**具体的な情報を含む単語**をまとめているので参考になればと思います。

# 良い変数の名前とは
変数の**命名法として重要**なのが、

- その変数の情報、役割を含む
- 誤解されない名前を使用する

以上二つあり、それを**達成するために気をつけること**として、

- 「カラフル」な単語を使用する
- 汎用的な名前を避ける
- 名前に情報を追加する

これらを達成する名前を使用することで、
**名前に情報を詰め込まれ、変数が短いコメントとしての役割をもつ**ようになります。
以上の項目について以下で簡単に解説していきます。

# 「カラフル」な単語を使用する
広い意味を持つ単語ではなく、**明確かつ正確な意味を持つ単語を選ぶ**ことで変数の役割を明示する

| 単語 | 代替案 |
| --- | --- |
| send | deliver, dispatch, announce, distribute, route |
| find | search, extract, locate, open |
| start | launch, create, begin, open |
| make | create, set up, build, generate, compose, add, new |
| stop | kill, pause |
| get | fetch, download |

[本サイト](https://www.notion.so/ac028a9a361a4cc5a84d857abf78fd50)の方が詳細で参考になります!!

# 汎用的な名前を避ける
tmp, retval, fooやi, j, kのような名前は汎用的であるが、**その名前からは目的や値を判断することができない**。ただし明確な理由がある場合は例外。

- tmpではなくtmp_fileとすることで何を一時的に保管したいのかを明確にする
- retvalではなくその戻り値がどのような値を持つのかが明確な名前を使用する
- インデックスやイテレータに単にi, j, kを使用するのではなく、club_i, menbers_i, users_iまたはci, mi, uiなどの情報を加えることでインデックスに説明を付与する。

# 名前に情報を追加する
以下のような**情報を加えて名前を具体的にする**ことで、関数のメソッドや、変数がとりうる値を明確にする。

- 値の単位を追加する
size, limitではなくsize,_mb, max_kbps
- 値の属性を追加する
comment, passwordではなくunescaped_comment, plaintext_password

# その他気をつけたほうがいいこと
- 頭文字などを用いた**独自の省略を避ける**
    - BEManagerではなくBackEndManager
    - eval, doc, strなど汎用的な省略は例外
- 不要な単語は投げ捨てる
    - ConvertToString()はToString()としても必要な情報は損なわれない
    - DoServerLoop()をServerLoop()にするのも同様
- **CamelCase**(キャメルケース)や**lower_separated**(小文字をアンダースコアで区切ったもの)を言語やプロジェクトのフォーマット規約に従って有効に使用する。
    - HTMLにおける有力な規則の例
        
        ```html
        <!-- idの区切り文字にはアンダースコア、classの区切り文字にはハイフンを使用する -->
        <div id="middle_column"  class="main-content">
        	...
        </div>
        ```
        
    - JavaScriptにおける有力な規則の例
React フラグメント <>

Reactのライブラリで
<>
<Something>...
</>
という記法がありフラグメントという機能周りのことであることは知っていたがどんなものかはわかっていなかったので調べた。

結論
Reactでコンポーネントを作成するときには１つの要素しか返せない。
だが複数の要素を返したいというときがある。そういうときに使う。(<li>を返したりするとき)
FragmentにはlistなどのようにKeyを渡せる。
[Kotlin]JetpackComposeの画面パーツを別のComposableから制御するサンプルコード

# 概要
JetpackComposeの画面パーツを別のComposableから制御するサンプルコードを２種類掲載します。
何かの参考になれば幸いです:star2:

動作は両方とも、ボタンを押すとテキストの表示非表示が切り替わるだけです。

![スクリーンショット 2022-03-19 18.29.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/d21d8b1b-6ede-0f1e-11c9-4da990ff268d.png)


# 前置き
JetpackComposeとはなんぞや？という方は、とりあえず新規ファイルを作る時「Empty Compose Activity」を選んでおいてください。
![スクリーンショット 2022-03-19 17.46.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/d70389b2-2599-f129-273a-7872ade3e27f.png)


# サンプルコード１
MutableStateを画面同士で共有しています

```kotlin

class MainActivity : ComponentActivity() {
    val isDisplay: MutableState<Boolean> = mutableStateOf(true)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Greeting(isDisplay)
                GreetingController(isDisplay)
            }
        }
    }
}

@Composable
fun Greeting(isDisplay: MutableState<Boolean>) {
    if (isDisplay.value) {
        Text(text = "Hello!")
    } else {
        Text(text = "")
    }
}

@Composable
fun GreetingController(isDisplay: MutableState<Boolean>) {
    GreetingButton(isDisplay = isDisplay)
}

@Composable
fun GreetingButton(isDisplay: MutableState<Boolean>) {
    Button(
        onClick = { isDisplay.value = !isDisplay.value }
    ) {
        Text(text = "change")
    }
}
```


# サンプルコード2
MutableStateを含んでいるViewModelを画面同士で共有しています

```kotlin

class MainActivity : ComponentActivity() {
    private val viewModel: SharedViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Greeting(viewModel)
                GreetingController(viewModel)
            }
        }
    }
}

@Composable
fun Greeting(viewModel: SharedViewModel) {
    if (viewModel.isDisplay.value) {
        Text(text = "Hello!")
    } else {
        Text(text = "")
    }
}

@Composable
fun GreetingController(viewModel: SharedViewModel) {
    GreetingButton(viewModel = viewModel)
}

@Composable
fun GreetingButton(viewModel: SharedViewModel) {
    Button(
        onClick = { viewModel.isDisplay.value = !viewModel.isDisplay.value }
    ) {
        Text(text = "change")
    }
}

class SharedViewModel : ViewModel() {
    val isDisplay: MutableState<Boolean> = mutableStateOf(true)
}
```

# 解説
ボタンが押されて変数が切り替えられると、そのタイミングでテキストの表示も切り替わるのが確認できると思います。
postgres x dotnet(npgslq) でnullをセットしてnullで場分け

こんな感じ

fsharp side 

```fsharp
if Option.isNone opPaymentMethod
then command.Parameters.AddWithValue("paymentmethod", DBNull.Value |> box ) |> ignore
else command.Parameters.AddWithValue("paymentmethod", opPaymentMethod |> Option.get ) |> ignore
```

sql side

```sql
  -- ポイント（一旦 cast）
  and
  case
    when @paymentmethod::text[] is null
    then true
    else t.foo = any (@paymentmethod)
  end
```

現場からは以上です
OneNoteで貼り付けた画像を一括で操作したい

件名の通りなのですが
Excelだったら【検索と選択】＞【オブジェクトの選択】＞Ctrl+A
で全て選択した後＞サイズとプロパティ
で全てのサイズ変更は出来ます……
OneNoteのメモの画像もそのように対象したいのですが
どのようにやるのでしょうか？

と分かったらメモするため表記失礼します。
cythonでerror: could not create ~~や~~:not such file or directory が出るときの解決策

# 方法
setup.pyのsetup()にpackage_dirを追加する

hoge/
　├__init__.py
　├ setup.py
　├ core.pyx
　└ core.c

```setup.py
setup(
    name='name',
    package_dir={'hoge':''},
    ext_modules=cythonize("core.pyx"),
    include_dirs=[numpy.get_include()]
)

```
# 参考元
https://stackoverflow.com/questions/31776076/cython-no-such-file-or-directory-pyd-error-on-windows
CloudFormationのテンプレートをYAMLで書く場合、JSONのポリシーをYAMLに変換する

## はじめに

CloudFormationのテンプレートをYAMLで書いていて、テンプレートにIAMポリシーを書く場合のお話です。

## IAMポリシーはJSONで書かれているので、テンプレートをYAMLで書いているならIAMポリシーをYAMLに変換したい

公式ドキュメントはもちろんのこと、リソースとして作成されたIAMポリシーはJSONで書かれています。

よって、テンプレートをYAMLで書いているなら、IAMポリシーもYAMLで書きたいところです。それで、JSONで書かれたIAMポリシーがあり、それをYAMLのテンプレートに書く場合には、JSONをYAMLに変換するツールを利用すると良いです。

また、先にAWS管理コンソールでIAMポリシーを作り、そのJSONを元にYAMLに変換するのも良いと思います。IAMポリシーを作るのに、AWS管理コンソールは便利です。既存のAWS管理ポリシーを取り込みながら新たなポリシーを作ることが出来ますし、一からポリシーを組み立てる場合でも「サービスを選択→アクションを選択→リソースを指定」といったことをGUIで出来ます。こういった用途だったら、AWS管理コンソールを使った方が楽だと思います（最初からコードとして書いたほうが早いというケースもあると思いますから、その辺は状況に応じて）。

そして、実際に作ったJSONのIAMポリシーをYAMLに変換して、テンプレートに書こうということです。

## JSONをYAMLに変換する方法と注意点

JSONをYAMLに変換する方法はいくつかあります。ここでは以下の方法について取り上げてみます。

* ネット上のサービスを利用する
* json2yamlパッケージを利用する（Python）
* yqパッケージを利用する（Python）
    * jqコマンドのラッパーなので、jqコマンドのインストールが必要


このうち、ネット上のサービスは手軽なのは良いのですが、ポリシー内にAWSアカウントIDやS3バケット名など、自分達の環境固有の値やリソース名などが記述されている場合は利用を控えたほうが無難だと考えています。AWS外のサイトにそのような情報を送信すること自体が危うい行為になりかねないということです。

「いくつかあるネット上のサービスのうち、どれが危険でどれが危険ではないか」という話ではなく、「環境固有の値やリソース名などが載っているIAMポリシーを『AWS外』のサービス上に送信する」という行為自体を控えることが望ましい、という意味です。

なお、公式ドキュメントや信頼できるメディアなどで公開されているIAMポリシーを変換するような用途であれば、ネット上のサービスを利用しても良いと思います。

## 使用するサンプル

簡単な見本として、以下のJSONを使います。

### sample.json

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "*"
        }
    ]
}
```

## json2yamlパッケージを利用する

Pythonを使える環境でしたら、json2yamlを使う方法があります。

https://pypi.org/project/json2yaml/

### インストール方法

`$ pip install json2yaml`

### 使用方法

#### JSONをYAMLに変換

量が少なければ標準出力にそのまま表示させ、それをコピーすれば良いと思います。

```bash
$ json2yaml sample.json
Version: '2012-10-17'
Statement:
- Effect: Allow
  Action:
  - s3:Get*
  - s3:List*
  Resource: '*'
```

YAMLに変換したファイルを作成したい場合は、以下のとおりです。

```bash
$ json2yaml sample.json sample.yaml
```

#### YAMLをJSONに変換

json2yamlのパッケージをインストールすると、YAMLをJSONに変換するyaml2jsonもインストールされます。

```bash
$ yaml2json sample.yaml
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "*"
        }
    ]
}
```

JSONに変換したファイルを作成したい場合は、以下のとおりです。

```bash
$ yaml2json sample.yaml sample.json
```

## yqパッケージを利用する

JSONを扱うjqのラッパーとして、yqというラッパーがあります。

もしjqがインストールされていなかったら、先にjqをインストールします。


### jqのインストール

#### Ubuntu(20.04.4 LTSで確認)

```bash
$ sudo apt update
$ sudo apt install jq
```

#### CentOS Stream

```bash
# dnf install jq
```

### yqのインストール

```
$ pip install yq
```

### 使用方法

#### JSONをYAMLに変換

```bash
$ yq -y '.' sample.json
Version: '2012-10-17'
Statement:
  - Effect: Allow
    Action:
      - s3:Get*
      - s3:List*
    Resource: '*'
```
envoyをGraceful shutdownする

## 概要
KubernetesにデプロイしたenvoyのPodが停止する際、処理時間の長いリクエストを受けていてもクライアントにエラーが返らないようにしたい

## 調査
こちらのPRを見ていると、envoy自体にGraceful shutdownは実装されてなさそう？

https://github.com/envoyproxy/envoy/issues/7841

PRのコメントにはメトリクスを見てねとあります

> Scripting around /healthcheck/fail and sleeping is also what we do for draining. After failing the healthcheck we watch the listeners' downstream_rq_active metric to drop to an acceptable range before terminating.

Kubernetesの`PreStop`を使って、コンテナの終了前にメトリクスを見て判定をしようと思います

https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/

## 実装
```yaml
spec:
  template:
    spec:
      containers:
        - name: envoy
          image: envoyproxy/envoy:latest
          ...
          lifecycle:
            preStop:
              exec:
                command: 
                  - /bin/sh
                  - -c
                  - |
                    curl -X POST --unix /tmp/envoy.admin http://localhost/healthcheck/fail
                    for i in `seq 60`
                    do
                      cx=$(curl localhost:9000/stats?filter=http.ingress_http.downstream_cx_active -s | cut -d ' ' -f 2)
                      if [ $cx = 0 ]; then
                        break
                      fi
                      sleep 1
                    done
```
やってること
* コンテナが終了する前に`/healthcheck/fail`を叩いてヘルスチェックが失敗するようにする（Readiness Probedeで`/ready`を見ておけば新規のリクエストが来なくなる）
* メトリクスを見てアクティブなコネクションが無くなるまで最大60秒程待つ

## 参考
https://www.envoyproxy.io/docs/envoy/latest/operations/admin

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/stats
Laravel HomesteadにphpMyAdminをインストールする

## この記事に書いてあること
Laravel Homesteadで構築した環境にphpMyAdminをインストールする方法

## 前提条件
環境構築時にyamlファイルでmysqlを設定

```yaml:Homestead.yaml

features:
    - mysql: true
    - mariadb: false
    - postgresql: false
    - ohmyzsh: false
    - webdriver: false

```

## データベースの確認について
Laravel Homesteadで環境構築した場合、データベースの確認する方法はいくつかあります。
`mysql`を使ってCLIで確認したりもできるし、[Sequel Proなどで接続する方法](https://qiita.com/namizatork/items/7776a33383186cc57307)もあるようですので、好みに応じてググってください。

ぼくはphpMyAdminが好きなので、今回紹介する方法をお勧めしてます。

## phpMyAdminをローカル環境に設置する
[phpMyAdmin](https://www.phpmyadmin.net/downloads/)の公式サイトから、ファイル一式をダウンロードします。

**ダウンロードファイル**
PHP7.1以上
phpMyAdmin-5.1.0-all-languages.zip

PHP5.5以上PHP7.1未満
phpMyAdmin-4.9.7-all-languages.zip

解凍したフォルダは、yamlファイルのfoldersで設定したフォルダ内に設置します。
名前は適当に変更します。

```yaml:Homestead.yaml

folders:
    - map: ~/Documents/LaravelStudy
      to: /home/vagrant/code
```

##  yamlファイルを編集する
次にHomestead.yamlファイルにデータベース情報を反映します。

`sites:` に PhpMyAdmin用の情報を追加します。

```yaml:Homestead.yaml

sites:
    - map: study-app.test
      to: /home/vagrant/code/study-app/public

    - map: phpmyadmin.test #追記
      to: /home/vagrant/code/phpmyadmin #追記
```

## 仮想環境上にphpMyAdminを反映
ローカル上のプロジェクトの場所（Homesteadディレクトリ）に移動してください。

そこで、vagrant upを行います。
yamlファイルの設定を変更したので`--provision`オプションをつけるのを忘れずに。

```
vagrant up --provision
```

## ブラウザ上で表示を確認
yamlファイルで設定したURLにアクセスします。

```
phpmyadmin.test
```

ユーザー名とパスワードはhomestead／secretです。

## 参考記事
- https://biz.addisteria.com/laravel_homestead_phpmyadmin/