OmniAICreator/Qiita-1.07M huggingface dataset:
Jenkinsで削除したアカウントを再作成し、権限を付与する方法

##背景
Jenkinsでアカウントを管理する方法は多く溢れているが、一度削除したアカウントを再作成するとなると、ちょっと様子が異なったので、備忘録として記す。
尚、Jenkinsの権限はManage and Assign Rolesで管理されているものとする。

##生じた問題
削除したアカウントを再作成し、Assign Rolesにて権限を付与したところ弾かれてしまった。(権限が付与されない！)
この問題に対処していく。

##手順
###①アカウントを作成する
アカウント作成については以下資料に詳細が記載されていたので、そちらを参考にする
[Jenkinsのユーザー作成と権限管理](https://qiita.com/unsoluble_sugar/items/55508a6319463acc863d)

###②Jenkinsサーバを再起動する
サーバにログインし、再起動を実行
※今回はLinuxにJenkinsサーバが存在していた為、以下コマンドにて再起動を行う

```
# systemctl restart jenkins
```

###③Jenkinsの状態が起動していることを確認する
statusがactiveになっていればOK

```
# systemctl status jenkins
```

###④アカウントの権限の付与
[Jenkinsの管理]-[Manage and Assign Roles]-[Assign Roles]を選択。
付与したい権限にチェックを入れ、[Save]を選択。

###感想
困ったら再起動

##参考資料
[When I assign users to roles, changes are not applied until Jenkins restart](https://issues.jenkins.io/browse/JENKINS-61470)
【AWS認定試験】SCS-C01取得しました

# はじめに
先日、SCS-C01に合格しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/3d0fa8f3-37e8-cbf5-92c7-b6a1aac20555.png)


合格するまでやったことを記載します。

## これまでのAWS認定受験歴
|年月|試験|点数(合格点)|合否|
|---|---|---|---|
|2020/08|[AWS認定クラウドプラクティショナー(CLF)][link-2]|809/1000(700)|〇|
|2020/11|[AWS認定ソリューションアーキテクトアソシエイト(SAA)][link-3]|753/1000(720)|〇|
|2021/01|[AWS認定デベロッパーアソシエイト(DVA)][link-4]|862/1000(720)|〇|
|2021/02|[AWS認定SysOpsアドミニストレータアソシエイト(SOA)(C01)][link-5]|731/1000(720)|〇|
|2021/04|[AWS認定ソリューションアーキテクトプロフェッショナル(SAP)][link-6]|698/1000(750)|×|
|2021/06|[AWS認定ソリューションアーキテクトプロフェッショナル(SAP)][link-6]|832/1000(750)|〇|
|2021/06|[AWS認定DevOpsエンジニアプロフェッショナル(DOP)][link-7]|821/1000(750)|〇|

## 試験対策
### 学習時間
約1週間(約15~20H)

### やったこと
以下のUdemyの問題集をメインでやりました。
といいますか、ほぼこちらの問題集のみで乗り切りました。

https://www.udemy.com/course/aws-certified-security-specialty-scs-c01-practice-tests/

問題文はすべて英語でしたが、Google翻訳で十分日本語の意味が分かるくらいになりました。本番も似たような翻訳精度なのでその練習にもなるのかな？と思ったり。。。

Udemyは仕様上、すべての問題を解き終わるまで答えが見られません。
正直、それでは効率が悪いので、ブラウザのウィンドウを隣り合わせで開き、片方で問題を進めながら、もう片方で答えを表示していました。自力一問一答です。
こちらの問題集は演習テスト1,5,6のみ解説がついていたので、1,5,6それぞれを90%以上取れるまで周回し、試験に臨みました。

結果、本番の問題の方が難しいと感じましたが、なんとか合格することができました。

### 重点的に確認したサービス
問題集を解いていて、このサービスは深く知るべきだと思ったのが以下のサービスです。

- [AWS Key Management Service (KMS)][link-8]
    - 特にキーローテーション時の制約や使う時のアクセス権限(ポリシー)は確認しました。
- [AWS Certificate Manager][link-9]
    - 証明書のインポートや使いどころなど。
- [AWS WAF][link-10]
    - 利用できるサービス、対象の攻撃など。
- [Amazon Inspector][link-11]
    - できること、使い方など。
- [AWS Shield][link-12]
    - 対象の攻撃、WAFとの使い分けなど。
- [AWS Trusted Advisor][link-13]
    - サービス概要、推奨内容など。
- [Amazon Macie][link-14]
    - サービス概要など。
- [Amazon GuardDuty][link-15]
    - サービス概要など。

ほかにもCloudTrail,Config,CloudWatchといった基本的なサービスは当然のように出るので抑えておくのはマストです。

# 感想
AWSのセキュリティ関連知識を包括的に問われる試験だと思いました。アカウントやサービスのセキュリティを見直すきっかけにもなりそうで、ためになりました。


<!-- link -->

[link-1]:https://qiita.com/t_tsuchida/items/3b3e4393c31c97fd4423
[link-2]:https://aws.amazon.com/jp/certification/certified-cloud-practitioner/
[link-3]:https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/
[link-4]:https://aws.amazon.com/jp/certification/certified-developer-associate/
[link-5]:https://aws.amazon.com/jp/certification/certified-sysops-admin-associate/
[link-6]:https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/
[link-8]:https://aws.amazon.com/jp/kms/
[link-7]:https://aws.amazon.com/jp/certification/certified-devops-engineer-professional/
[link-9]:https://aws.amazon.com/jp/certificate-manager/
[link-10]:https://aws.amazon.com/jp/waf/
[link-11]:https://aws.amazon.com/jp/inspector/
[link-12]:https://aws.amazon.com/jp/shield/
[link-13]:https://aws.amazon.com/jp/premiumsupport/technology/trusted-advisor/
[link-14]:https://aws.amazon.com/jp/macie/
[link-15]:https://aws.amazon.com/jp/guardduty/
暗号スイートとTLS拡張の関係を再整理

#1. はじめに

TLS1.3では暗号スイートの表記が大幅に簡素化され、共通鍵暗号のアルゴリズムと鍵導出のためのハッシュアルゴリズムだけを指定するようになりました。指定が簡素化されたのは良いのですが、関連するTLS拡張との関係が少しわかりにくくなっているかもしれません。この記事では、TLS1.2以前と1.3の暗号スイート、それと関連するTLS拡張について再整理してみます。

|バージョン|暗号スイートの構成|
|---|---|
|TLS1.2|鍵合意＋署名＋共通鍵＋ハッシュ<br>例：TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384|
|TLS1.3|共通鍵＋ハッシュ<br>例:TLS_AES_128_GCM_SHA256|

　　　　表1 TLSの暗号スイート

#2. TLS1.3の整理項目

まずはTLS1.3で見直されたポイントについて復習です。

１）鍵合意アルゴリズムとしては静的RSAを廃止し、一時鍵ECDH、DHのみとなりました。<br>
２）静的RSAが廃止されたため、証明書はピア認証のみに使用することになりました。これによって、鍵合意と認証は完全に分離、独立した扱いが可能となりました。<br>
3）危殆化した共通鍵暗号アルゴリズムが大幅に整理されました。また、認証付き暗号(AEAD: Authenticated Encryption with Associated Data)アルゴリズムのみに整理されました。これに伴い、MACによる真正性検証もなくなりました。<br>

# 3. 暗号スイートとTLS拡張の関係

これらの変更、整理の結果、TLS1.2の暗号スイートの4つのフィールドがTLS1.3でどのように整理されたのか、表にまとめてみます。

|スイート<br>項目|TLS1.2|TLS1.3|関連するTLS拡張、補足|
|---|---|---|---|
|鍵合意|RSA<br>(EC)DH(E)|なし|- SupportedGroups拡張<br>(TLS1.2ではElliptic_curves):<br>　　ECDHで使用できる楕円曲線一覧<br>　　DHの鍵長一覧<br>- Key_Share拡張：<br>　　上位２候補までのDHパラメータ|
|署名|RSA<br>DSA<br>ECDSA|なし|署名アルゴリズム拡張：<br>　　ECDSAの楕円曲線とハッシュ一覧<br>　　RSA鍵長、パディング、ハッシュ一覧<br>DSAの廃止|
|共通鍵|多数|AES-GCM<br>AES-CCM(_8)<br>CHACHA20_POLY1305|危殆化アルゴリズムを廃止<br>AEADのみに|
|ハッシュ|多数|SHA256, SHA384|MACの廃止<br>鍵導出のハッシュのみ指定|

　　　　　　　　　　　　表２ TLS1.2/1.3の暗号スイートフィールドと対応するTLS拡張

鍵合意の(EC)DH系の情報は、SupportedGroups拡張にECDHに使用できる楕円曲線種別の一覧、DHの場合のサポートする鍵長の一覧を格納します。また、Key_Share拡張にサポートする(EC)DHのうち上位２候補までの楕円曲線種別または鍵長と対応するDHパラメータを格納します。サーバ側でこれにマッチしない場合は１度だけHelloRetryRequestで次の候補を要求することができます。表3にSupportedGroups拡張の例を示します。ECDHの場合は楕円曲線の種類、DHの場合は鍵長がIDによって定義されます。

|アルゴリズム|表記|ID|
|---|---|---|
|ECDH|secp224r1|0x0015|
|DH|ffdhe2048|0x0100|

表3 SupportedGroups拡張の例

署名アルゴリズムについては、署名アルゴリズム拡張にECDSAの楕円曲線とハッシュの組合わせ一覧、RSAの鍵長、パディング、ハッシュの一覧を格納します。DSAは廃止されました。表4に署名アルゴリズム拡張の例を示します。RSAの場合はパディングスキームとハッシュ、ECDSAの場合は楕円曲線の種類とハッシュがID値によって定義されます。

|アルゴリズム|表記|ID|
|---|---|---|
|RSA|rsa_pss_pss_sha256<br>rsa_pkcs1_sha512|0x0809<br>0x0601|
|ECDSA|ecdsa_secp256r1_sha256|0x0403|

表4 署名アルゴリズム拡張の例


ハッシュアルゴリズムは、TLS1.2では鍵導出におけるハッシュアルゴリズムとMACにおけるハッシュアルゴリズムを兼用して指定していました。TLS1.3でMACが廃止されたのに伴い、暗号スイート上のハッシュ表記はHKDF鍵導出のためのハッシュアルゴリズムのみを指定するものとなりました。

# 4. まとめ

このようにTLS1.3では不要なものを削除するとともに本来独立、直交する項目については暗号スイートではなくTLS拡張で定義できるようなりました。そのようにすることで、TLS1.2では4項目の組み合わせであるために非常に多種のスイートができてしまったのに対して、TLS1.3では暗号スイートでは２項目の組み合わせを定義するのみとなりスイートの種類を大幅に絞り込むことに成功しています。現在、TLS1.3として定義されているスイートは以下の５種類です。


|暗号スイートの表記|ID|
|:---:|:---:|
|TLS_AES_128_GCM_SHA256|0x1301|
|TLS_AES_256_GCM_SHA384|0x1302|
|TLS_CHACHA20_POLY1305_SHA256|0x1303|
|TLS_AES_128_CCM_SHA256|0x1304|
|TLS_AES_128_CCM_8_SHA256|0x1305|

　　　　　　表3 TLS1.3の暗号スイート

この記事の内容を含めてTLプログラミングについて解説をまとめる機会をいただきました。興味のあるかたはご覧ください。[徹底解剖 TLS 1.3](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E8%A7%A3%E5%89%96-TLS-1-3-%E5%8F%A4%E5%9F%8E-%E9%9A%86/dp/4798171417/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1WX07IBUINBBR&keywords=%E7%BF%94%E6%B3%B3%E7%A4%BE+TLS&qid=1643343354&sprefix=%E7%BF%94%E6%B3%B3%E7%A4%BE+tls%2Caps%2C177&sr=8-1) (翔泳社から 3/7刊行)。
PINTOさんのTFliteをRPiで動かす2021年10月版

#１．はじめに
AIってなにかしら憧れますよね。私もそろそろAIの勉強でも始めようかと思っています。
しかしAIを勉強する方法にもいろいろあって、よく使われる学習環境の筆頭といえばGoogle Colaboratoryです。ウェブブラウザさえあれば、重要な計算はクラウドで実行してくれるし、面倒な開発環境構築も不要とあって、もっともすぐれた学習環境だと思います。
しかし、今回はあえてRPiでやってみます。
というのも、最終的に目指すのがコンパクトなedge AI端末の制御だからです。
将来、5Gやそれ以上の高速なネットワーク環境が広く普及すれば、多くのAIはクラウド上で動作し端末がその結果を享受する、という使われ方が増えると思いますが、それまでの過渡期では端末側で推論を行うニーズも発生すると思われます。
それに、チープな計算能力しか持たないエッヂ環境で自律動作するロボットって格好いいとおもいませんか？

参考にさせていただくのは次の2つのサイトです。


https://github.com/PINTO0309/TensorflowLite-bin

PINTO様のgitではtensorflowliteのをRPi版にビルドしてくださっています。まさに神。

https://qiita.com/karaage0703/items/38f314d01a67ded949c2

karaage様は本やblogで私の様なサルにもわかるようにAI実施事例を紹介していくださっています。まさに神。

神様が二人もいるのでサルも人に進化できそうなものですが、私はあまりもにサル過ぎて何もないたいらな平野でさえ躓きいてしまうよぼよぼじいさんなので、躓いた内容含めて覚書き。これを機にAIという輝かしいフロンティアへ歩き出せるといいな。



#２．早速やってく

OSは公式イメージャで焼いたRaspbianです。バージョンは次の通り。

```sh
$ uname -a
Linux raspberrypi 5.10.60-v7l+ #1449 SMP Wed Aug 25 15:00:44 BST 2021 armv7l GNU/Linux
```

まずは、パッケージの更新と作業用フォルダ作成です。Workspaceフォルダ配下で作業を進めます。venvとか使った方が良いかもだけど、raspiならmicrosdごと使い分けた方が楽かな。

```sh
$ sudo apt update
$ sudo apt upgrade
$ mkdir Workspacce
$ cd Workspace
```

次に画像処理のためのOpen CV(python版)をインストールします。
モジュールのほか、必要なライブラリファイルも併せてインストールしています。


```sh
$ sudo pip3 install opencv-python
$ sudo apt install libatlas-base-dev libjasper-dev libqt4-test
```

次に、ビルド済みのTFliteをダウンロードし、必要なモジュール類と合わせてインストールします。

```sh
$ sudo apt install swig libjpeg-dev zlib1g-dev python3-dev \
                   unzip wget python3-pip curl git cmake make
$ sudo pip3 install numpy==1.20.3
$ wget "https://raw.githubusercontent.com/PINTO0309/TensorflowLite-bin/main/2.5.0/download_tflite_runtime-2.5.0-cp37-none-linux_armv7l.whl.sh"
$ chmod 755 download_tflite_runtime-2.5.0-cp37-none-linux_armv7l.whl.sh
$ ./download_tflite_runtime-2.5.0-cp37-none-linux_armv7l.whl.sh
$ sudo pip3 install --upgrade tflite_runtime-2.5.0-cp37-none-linux_armv7l.whl
```
最後に、PINTO様のリポジトリをクローンしてデモを実行してみます。

```sh
$ git clone https://github.com/PINTO0309/TensorflowLite-bin
$ cd TensorflowLite-bin
$ python3 mobilenetv2ssd.py
```

うまく動くと/TensorflowLite-binの中にresult.jpgが作成されています。

ちなみに、次のエラーがが出ることがありますがnumpyのバージョンが合っていないためです。

```sh
RuntimeError: module compiled against API version 0xe but this version of numpy is 0xd
Traceback (most recent call last):
  File "mobilenetv2ssd.py", line 4, in <module>
    import cv2
  File "/usr/local/lib/python3.7/dist-packages/cv2/__init__.py", line 5, in <module>
    from .cv2 import *
ImportError: numpy.core.multiarray failed to import
```
2021/9/29時点でopencv-pythonのバージョンは4.5.3.56です。このバージョンをインストールするとnumpyの1.19がセットで入りますが、TFliteはnumpyのバージョン1.20.3を要求しています。
次のコマンドでnumpyを入れなおしてください。

```sh
$ sudo pip3 install numpy==1.20.3
```

#３．最後に
今回は神様お二人の言う通り実行しただけでした。
しかし、実行環境も関連するモジュールのバージョンアップなどでどんどん風化していくので、エラーを読んで解決するなかでいろいろ学ぶことが多くあります。
次はデモを動かすだけでなく、他のモデルをTFLiteに変換したり、自分でモデルを作成したりしてさらに理解を深めたいと思います。

※追記　なんとなんとkaraage神にこのエントリーを発見されてPINTO神の名前を間違えていたことを指摘されるという。。。神よ鎮まりたまへ  orz
validatorのエラーフィールド名に構造体のフィールド名ではなくjsonタグ名をセットしたい

## この投稿で使用している言語、ライブラリのバージョン

* Go v1.17.1
* [github.com/go-playground/validator](https://github.com/go-playground/validator) v10.9.0

## やりたいこと

[github.com/go-playground/validator](https://github.com/go-playground/validator)で構造体をバリデーションした場合、
エラーの中には以下のように構造体のフィールド名が埋め込まれています。

```go:main.go
package main

import (
	"fmt"
	"strings"

	"github.com/go-playground/validator/v10"
)

type Person struct {
	Name  string `json:"name" validate:"required,max=100"`
	Email string `json:"email" validate:"required,email"`
}

func main() {
	p := Person{
		Name:  strings.Repeat("x", 101),
		Email: "aa.bb",
	}

	validate := validator.New()
	if err := validate.Struct(p); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("Field=%s, Tag=%s\n", errrs.Field(), errrs.Tag())
		}
	}
}

```

```
$ go run main.go
Field=Name, Tag=max
Field=Email, Tag=email
```

バリデーションエラーの結果をAPIのレスポンスとして返す場合に、構造体のフィールド名ではなく、jsonタグの名前で返したかったので方法を調べました。


## 解決策

ドキュメントにそのものズバリ書いてありました。

[func (*Validate) RegisterTagNameFunc](https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.RegisterTagNameFunc)

RegisterTagNameFuncを使うことで、エラーフィールドを取得する際にjsonタグ名を取得することができます。

```go:main.go
package main

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-playground/validator/v10"
)

type Person struct {
	Name  string `json:"name" validate:"required,max=100"`
	Email string `json:"email" validate:"required,email"`
}

func main() {
	p := Person{
		Name:  strings.Repeat("x", 101),
		Email: "aa.bb",
	}

	validate := validator.New()
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] // jsonタグ名を取得する
		if name == "-" {
			return ""
		}
		return name
	})
	if err := validate.Struct(p); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("Field=%s, Tag=%s\n", errrs.Field(), errrs.Tag())
		}
	}
}
```


```
$ go run main.go
Field=name, Tag=max
Field=email, Tag=email
```

## 参考

https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.RegisterTagNameFunc
WordpressプラグインAll-in-One WP Migrationエラーの対処

#動作環境
`CentOS-7.9.2009`
`Apache-2.4.6`
`php-8.0.10`
`MariaDB-10.6.4`
`WordPress-5.8.1`

#WordPressダッシュボードエラー内容

`All-in-One Migration は /var/www/html/nakatou.jp/keep/wp-content/ai1wm-backups/.htaccess ファイルを作成できません。親フォルダーのパーミッションを変更するか、support@servmask.com までメールでお問い合わせください。`

`All-in-One Migration は /var/www/html/nakatou.jp/keep/wp-content/ai1wm-backups/web.config ファイルを作成できません。親フォルダーのパーミッションを変更するか、support@servmask.com までメールでお問い合わせください。`

`All-in-One Migration は /var/www/html/nakatou.jp/keep/wp-content/ai1wm-backups/index.php ファイルを作成できません。親フォルダーのパーミッションを変更するか、support@servmask.com までメールでお問い合わせください。`

`All-in-One Migration は /var/www/html/nakatou.jp/keep/wp-content/ai1wm-backups/index.html ファイルを作成できません。親フォルダーのパーミッションを変更するか、support@servmask.com までメールでお問い合わせください。`

#原因
PHPがディレクトリ権限を持っていない

変更すべき箇所：
`wp-content/plugins/all-in-one-wp-migration/storage`
`wp-content/ai1wm-backups`

#ApacheのPHP実行ユーザーを確認

```:#&nbsp;cat&nbsp;/etc/httpd/conf/httpd.conf
User apache
Group apache
```

#ディレクトリ権限の確認

```
# ls -l /var/www/html/example.com/wp-content/
# ls -l /var/www/html/example.com/wp-content/plugins/all-in-one-wp-migration/
```

#ディレクトリ権限の変更

```
# chown -R apache:apache /var/www/html/example.com/wp-content/ai1wm-backups

# ls -l /var/www/html/example.com/wp-content/
```

```
# chown -R apache:apache /var/www/html/example.com/wp-content/plugins/all-in-one-wp-migration/storage

# ls -l /var/www/html/example.com/wp-content/plugins/all-in-one-wp-migration/
```

#変更の確認

```
# ls -l /var/www/html/example.com/wp-content/
# ls -l /var/www/html/example.com/wp-content/plugins/all-in-one-wp-migration/
```

#WordPressダッシュボードでエラーが消えているかを確認

#参考記事
`https://lunalunadesign.net/2019/09/71/`
NVIDIA-Device-PluginがPC再起動で動かなくなった場合(nvidia-container-cli: initialization error: nvml error: driver not loaded))


# reboot後「 nvidia-device-plugin-daemonset」で以下が発生

```bash
Error: failed to start container "nvidia-device-plugin-ctr": 
Error response from daemon: OCI runtime create failed: container_linux.go:349:
starting container process caused "process_linux.go:449: 
container init caused \"process_linux.go:432: 
running prestart hook 0 caused \\\"error running hook:
 exit status 1, stdout: , stderr: 
nvidia-container-cli: initialization error: nvml error: driver not loaded\\\\n\\\"\"": unknown
```

# ndivia-smiも効かない
```bash
# nvidia-smi
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
```

# Driverを再インストール
```bash
# bash NVIDIA-Linux-x86_64-470.57.02.run
Verifying archive integrity... OK
Uncompressing NVIDIA Accelerated Graphics Driver for Linux-x86_64 470.57.02
```

# nvidia-smi再チェック→OK

```bash
# nvidia-smi
Wed Sep 29 01:08:37 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.57.02    Driver Version: 470.57.02    CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  Off  | 00000000:01:00.0 Off |                  N/A |
| 35%   32C    P8    N/A /  75W |      0MiB /  4040MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

```

# Device-Plugin再Deploy

```bash
# kubectl apply -f nvidia-device-plugin.yml
daemonset.apps/nvidia-device-plugin-daemonset unchanged

# kubectl get pods --all-namespaces
NAMESPACE       NAME                                        READY   STATUS        RESTARTS   AGE
kube-system     nvidia-device-plugin-daemonset-tmn88        1/1     Running       10         32m
```
【Laravel】 Selectフォームでdisableを使用するとバリデーションに引っ掛かる


###Selectフォームでdisableを使用するとバリデーションに引っ掛かる


####問題となったコード
edit状態の際にdisableが有効になると思ってほしい

```PHP.○○Blade.php
{{Form::select('fruits', ['apple', 'banana', 'kiuwi']),
  [$is_edit ? 'disable' : '',
]}}
```
Requestで必須としてバリデーションしている

```PHP.○○Request.php
'fruits' => [
     'required',
 ],
```
####具体的な問題点
disableするとPOSTされないので必須のバリデーションに引っ掛かる

参考記事
https://lightgauge.net/language/html/2525/


####解決策 
インプットタグにtype=hiddenとvalueを指定して記述する

```PHP.○○Blade.php
{{Form::select('fruits', ['apple', 'banana', 'kiuwi']),
  [$is_edit ? 'disable' : '',
]}}
@if ($is_edit)
  <input type="hidden" name="fruits" value="{{$fruits}}">
@endif
```


####終わりに
一時間ぬまりました。
LaravelのAjax通信エラー 500 (Internal Server Error)

# 500 (Internal Server Error)

Ajax通信での500番エラー
Xdebug等で、コントローラには行っていることは確認できたが、console画面がエラーになってしまう。

![スクリーンショット 2021-09-29 9.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/63d19320-2a1f-ecdd-93b5-15fbb07a47a0.png)

##結論

おそらく、コントローラにエラーがある。
useの宣言を忘れているなどの凡ミスだと思われる。
どうしても見つからなければ、一度同期通信で行えば、エラーの場所が分かるはず。

##なぜ厄介か

同期通信の場合は、laravelのエラー画面が表示される➡どこが間違えているか分かる。
Ajax通信の場合は、Ajax通信の.failの処理を通るだけで、エラー画面が表示されない。➡コントローラの記述を疑わない。
Cloudflare WorkersでRustを使う

## 概要

Cloudflare WorkersにおいてRustがサポートされたので検証してみます

https://blog.cloudflare.com/workers-rust-sdk/

cratesはこちらです

https://crates.io/crates/worker

## ブラウザからCloudflare Workersの初期設定を行う

### アカウントを作成する

Cloudflareのアカウントを作成してログインします
https://dash.cloudflare.com/

今回は「Workers」を使っていきます
![Screen Shot 2021-09-29 at 8.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/6e30cd45-a7ba-7ddf-b586-a07cba52b481.png)


### Workersの初期設定を行う

`*.workers.dev` というサブドメインを設定します

![Screen Shot 2021-09-29 at 7.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/d24a713b-0f2b-8620-0a90-2a71e6f57df0.png)

「CLIクイックスタート」と「APIトークン」のリンクがあります

## Cloudflare Workersの編集権限を持つAPIトークンを作成する

「トークンを作成する」からトークンを作成していきます
![Screen Shot 2021-09-29 at 7.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/33906936-f70a-3d01-e515-4a7b35549d54.png)

「Cloudflare Workersを編集する」のテンプレートを利用します
![Screen Shot 2021-09-29 at 7.26.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/854f4dc1-8ec7-1364-3e86-fb07109f6ed5.png)


![Screen Shot 2021-09-29 at 8.59.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/f912545a-6635-62a8-b62a-006d94144859.png)


APIトークンを作成したら、CLIからAPIトークンが有効かどうか確認できます

```
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
     -H "Authorization: Bearer ${API_TOKEN}" \
     -H "Content-Type:application/json"
{"result":{"id":"ef760f6d7d396a80fe1f42eb9d649861","status":"active","not_before":"2021-09-28T00:00:00Z","expires_on":"2021-10-03T23:59:59Z"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}
```

## CLIツールの設定を行う

### CLIツールをインストールする

`npm i @cloudflare/wrangler -g`

https://developers.cloudflare.com/workers/cli-wrangler/install-update

```
wrangler -V
wrangler 1.19.3
```

### Cloudflareのアカウントを認証する

`wrangler login`

ブラウザからCLIからのアクセス許可を行います
![Screen Shot 2021-09-29 at 7.32.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/45741ef1-5587-c25e-658e-ecc516cb4c94.png)

`~/.wrangler/config/default.toml` にトークンが保存されています

```
cat ~/.wrangler/config/default.toml 
oauth_token = "xxxxxxxxxxxxxxxxxxxxxxxx"
refresh_token = "xxxxxxxxxxxxxxxxxxxxxxxx"
expiration_time = "2021-09-29T01:12:49.834253+00:00"
```

### プロジェクトを作成する

rustのテンプレートを使います

```
wrangler generate cw-rust https://github.com/cloudflare/rustwasm-worker-template
```

buildしてdevサーバーを立ち上げる
`wrangler dev`

`build` ディレクトリへ WebAssemblyが生成されます

```
ls build/worker/
export_wasm.mjs index_bg.mjs    index_bg.wasm   shim.mjs
```

以下のようにローカルでAPIの動作確認を行うことができます

```
curl -X POST 'http://127.0.0.1:8787/form/test' -d 'test=test data'
{"test":"test data"}
```

### デプロイする

`wrangler publish`

作成したプロジェクト名をサブドメインとしたエンドポイントが作成されてアクセスできます

`https://cw-rust.xxxxxxx.workers.dev/`


## 参考資料

- https://developers.cloudflare.com/workers/get-started/quickstarts
- https://blog.cloudflare.com/workers-rust-sdk/
- https://crates.io/crates/worker
AWS Transcribeでリージョン違いでエラー

#AWS Transcribe使おうとしたらエラー出た…

表題の通りの出オチなんですが、
https://dotnet-developer-dojo.workshop.aws/lab7-ai-ml/transcribe.html

上記のURLを参考にしながら、
音声ファイルをS3にアップして、アップしたファイルをTranscribeでテキスト化するというのをやってたんですが
実行すると以下のエラーが出て困っておりました。

####エラー内容

> 要求した名前は有効ですが、要求された種類のデータは見つかりませんでした。

このエラーだけ見るとなんかファイルの形式が違うとか、アクセス権が無いとかと思ってしまい
その点で色々調べていたんですが解決せず:sweat:

```transcribe.cs
using (var transcribeClient = new AmazonTranscribeServiceClient(
    "IDだよ",
    "アクセスキーだよ",
    Amazon.RegionEndpoint.APNortheast3))
{
    var media = new Media()
    {
        MediaFileUri = bucketUri
    };

    var transcriptionJobRequest = new StartTranscriptionJobRequest()
    {
        LanguageCode = "ja-JP",
        Media = media,
        MediaFormat = MediaFormat.Wav,
        TranscriptionJobName = "transcribe-job",
    };

    // ★ここでエラーが出たよ★
    var transcriptionJobResponse = await transcribeClient.StartTranscriptionJobAsync(transcriptionJobRequest);

    if (transcriptionJobResponse.HttpStatusCode != HttpStatusCode.OK)
    {
        Console.WriteLine("成功したよ");
    }
}

```

##原因わかりました

S3のバケットを
**アジアパシフィック (大阪) ap-northeast-3**
にしてたんですが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149339/11a2397b-8b94-add1-6d7d-4dc30526cfb7.png)
**Transcribeに大阪無いじゃん！！**


というわけで、S3のバケットを東京で作りなおして、ソースを修正したら無事動きました。

```transcribe.cs
using (var transcribeClient = new AmazonTranscribeServiceClient(
    "IDだよ",
    "アクセスキーだよ",
    Amazon.RegionEndpoint.APNortheast1))  // ←ここ直す
```

わかってみればその通りのうっかりでしたが、エラー内容がわかりにくい気が…:joy:

以上です。
「The server quit without updating PID file (xxx.pid)」となるmysql.serverを起動する方法

mysqlがクラッシュ中に`brew upgrade`してはいけない
クラッシュ中のupgradeはサポート対象外で、mysqlが起動できなくなる。

# 事象

```sh
mysql.server start
Starting MySQL
.. ERROR! The server quit without updating PID file (/usr/local/var/mysql/xxxx.local.pid).
```

`xxxx` は `whoami`で出てくるユーザー名

# pidファイルを手作り(失敗)
手作りして権限与えても解決しなかった

```sh
touch /usr/local/var/mysql/xxxx.local.pid
chown xxxx:xxxx /usr/local/var/mysql/xxxx.local.pid
```
pidファイルはプロセスIDが書いてあるだけのファイルで、起動するとプロセスIDが書き込まれ、終了すると削除される
`mysql.server start` すると手作りpidファイルも削除されたので、pidファイルが原因ではなさそう

# 再インストール(失敗)
失敗したらやり直せばいいのさ

`brew uninstal && brew install mysql`　してみる

```sh
brew install mysql
Warning: The post-install step did not complete successfully
You can try again using:
  brew postinstall mysql
```

post-installが失敗してるっぽい
もう一度やれって言われたので `brew postinstall mysql` してみたが、やはり失敗する

# Macの再インストール(失敗)
状況変わらず
時間を無駄にして焦り始める


# 関連ファイル全消し、足りない設定追加、再インストール(成功)

```sh
brew uninstall mysql

# 関連ファイルも消す
sudo rm -rf \
  /usr/local/mysql \
  /Library/StartupItems/MYSQL \
  /Library/PreferencePanes/MySQL.prefPane \
  /Library/Receipts/mysql-.pkg \
  /usr/local/Cellar/mysql* \
  /usr/local/bin/mysql* \
  /usr/local/var/mysql* \
  /usr/local/share/mysql* \ 
  /usr/local/opt/mysql* \

# 設定ファイルも消す(my.cnf)
sudo rm -rf /etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf 

brew install mysql

# 足りない設定追加
echo "explicit_defaults_for_timestamp = 1" >> /usr/local/etc/my.cnf
brew postinstall mysql

mysql.server start
Starting MySQL
 SUCCESS!
```
PySide2とPyCharmでGUIツールを作ってみる

# ■ はじめに

Youtube で Cygames さんが期間限定で公開していた Python の動画を見てちょっとやってみたくなって触ってみました。
ひとまずは触りだけ。

# ■ 開発環境

- PyCharm Professional 2021.2.2
- PySide2 5.15.2
- Python 3.7

# ■ PySide2 をインストール

- 1. PyCharm 上で Python3 に対応したプロジェクトを作ります。(ここでは **PySide2Proj** で作ったものとする)
- 2. 「メニューバー」>「ファイル(F)」> 「設定(T) Ctrl+Alt+S」> 「プロジェクト: PySide2Proj」>「Python インタープリター」>「+マーク」を選択。
- 3. `PySide2` と入力しパッケージをインストール。

# ■ 外部ツール設定

PySide2 を使いやすいように外部ツール設定をしておきます。

「メニューバー」>「ファイル(F)」> 「設定(T) Ctrl+Alt+S」> 「ツール」>「外部ツール」>「+マーク」を選択。

## QTdesigner：Qt Designer を開く

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/44e0deb5-baac-eef2-98fb-6eb362a5ea35.png)

- プログラム：`[PySide2Projのフルパス]\venv\Scripts\pyside2-designer.exe`
- 引数：空欄でOK（`$FileDir$\$FileName$` のように入れておくとuiファイルを直接開くことが出来ます。）
- 引数：`$ProjectFileDir$`

## PyUIC：uiファイルをpyファイルへ変換する

![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/e919f004-87d7-66c7-6baf-3670931f096b.png)

- プログラム：`[PySide2Projのフルパス]\venv\Scripts\pyside2-uic.exe`
- 引数：`-o $FileDir$/$FileNameWithoutExtension$.py $FilePath$`
- 引数：`$ProjectFileDir$`

# ■ Qt Designer でベースウィンドウを作成

- 1. 「メニューバー」>「ツール(T)」> 「External tools」> 「QTdesigner」を選択で Qt Designer が開きます。

![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/d8032bd6-fb21-e8d3-3a27-7c52b191b661.png)

- 2. 「Main Window」を選択し「作成(R)」を選択。
- 3. 「オブジェクトインスペクタ」>「MainWindowオブジェクト」を選択状態にしておく。
- 4. 「プロパティエディタ」>「QWidget」>「geometry」を「[(0, 0), 800 x 600]」にし、ウィンドウサイズを 800x600 に設定。
- 5. 「ファイル(F)」>「保存(S) Ctrl+S」、ファイル名を「MainWindow.ui」にし、「保存(S)」。
- 6. Qt Designer を閉じておきます。（PyCharm の停止ボタンで閉じると正常終了扱いにならないので注意）

# ■ ui ファイルを py ファイルへ変換する

- 1. PyCharm 上の「プロジェクト」>「PySide2Proj」>「MainWindow.ui」を右クリック。
- 2. 「External tools」>「PyUIC」を選択。
- 3. `MainWindow.ui` と同一階層に `MainWindow.py` が出来ていれば成功です。

# ■ Pythonスクリプトからウィンドウを実行する

main.py に下記のように記載します。

``` main.py
import sys
from PySide2.QtWidgets import QApplication, QMainWindow
from MainWindow import Ui_MainWindow


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = QMainWindow()
    ui_window = Ui_MainWindow()
    ui_window.setupUi(main_window)
    main_window.show()
    sys.exit(app.exec_())
```

「実行'main'(U) Shift+F10」をして下記ウィンドウが出れば成功です。

![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/d21d6d3a-9791-4c09-204e-7de238dc943e.png)

# まとめ

UI画面を作っていく環境が整いました。
今回は以上になります。

気が向けば作っているGUIツールの情報も公開していこうと思います。

# ■ 参考資料

- [Python による大規模ゲーム開発環境 ～Cyllista Game Engine 開発事例～ - CEDiL](https://cedil.cesa.or.jp/cedil_sessions/view/2278)
    - 今回 PySide2 を触るきっかけとなった情報になります。ここまで作れるようになりたい。

- [LEARN PYTHON PYQT - pythonpyqt.com](https://pythonpyqt.com/how-to-install-pyqt5-in-pycharm/)
    - こちらの記事は PyQt5 ですが、ほぼこちらの記事の流用になります。
Access to XMLHttpRequest_at ○○ from Origin ‘○○’ has been blocked by CORS policy ..メッセージが出た

## 状況
APIを叩いて外部のアプリケーションリソースにアクセスしようとしたら以下のようなエラーが出た。

```
Access to XMLHttpRequest_at ○ from Origin ‘’ has been blocked by CORS policy …
```
## 環境
環境: Laravel 6.x
ブラウザ: chrome

## 解決方法
Corsヘッダーを設定する。
（Laravel7.0よりこのパッケージは初期テンプレートにバンドルされ、初期状態で利用可能となった。）

## 手順

[1.パッケージのインストール](#1-パッケージのインストール)
[2.Middlewareを追加する](#2-Middlewareを追加する)
[3.設定ファイルをpublishする](#3-設定ファイルをpublishする)
[4.項目を設定する](#4-項目を設定する)


## 1. パッケージのインストール
```
　　composer require fruitcake/laravel-cors
```
　　上記コマンドを実行し、composer　でパッケージの追加。

## 2. Middlewareを追加する
```PHP:App/Http/Karnel.php

protected $middleware = [
　　　　　　　　// ...
    \Fruitcake\Cors\HandleCors::class,
    // ...
];
```

## 3. 設定ファイルをpublishする
```
　　php artisan vendor:publish --tag="cors"
```
## 4. 項目を設定する

pathsはfruitcake/laravel-cors 固有の設定、allowed_originsはワイルドカードが利用できるようになっているので
あらゆるoriginを許可することでアクセスできるようにした。

```php5:config/cors.php
return [
 
    /*
     * CORSヘッダーを出力するパスのパターン、任意でワイルドカード(*)が利用できる。
     * 空だと一切のルートで機能しない。
     * Example: ['api/*']
     *   全てのルートを対象にする場合: ['*']
     *   APIと特定の画像を対象にする例: ['api/*', 'resources/example.png']
     */
    'paths' => [],
 
    /*
    * マッチするHTTPメソッド。 `[*]` だと全てのリクエストにマッチする。
    * GETとPOSTだけを許可する場合: ['GET', 'POST']
    */
    'allowed_methods' => ['*'],
 
    /*
     * マッチするOrigin。`*`かオリジンに完全一致、またはワイルドカードが利用可。
     * '*', allowed_origins(完全一致), allowed_origins_patterns, allowed_origins(ワイルドカード)の順に評価されることになる。
     *  `[*]`にすると全てのオリジンで許可。
     * example.comとそのサブドメインを許可: ['https://example.com', 'https://*.example.com']
     */
    'allowed_origins' => ['*'],
 
　　　　　　　　・・・
];
```
## 最後に

 以上の設定をすることでcorsの許可ができ、メッセージも消えた。

参照
 - https://github.com/fruitcake/laravel-cors#installation
 - https://larapet.hinaloe.net/2020/03/05/laravel-cors/
javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify


Selenideでブラウザ操作中に発生

```:エラー内容
Wed Sep 29 00:28:34 UTC 2021 WARN: Caught while disconnecting...

    EXCEPTION STACK TRACE:



    ** BEGIN NESTED EXCEPTION ** 

    javax.net.ssl.SSLException
    MESSAGE: closing inbound before receiving peer's close_notify

    STACKTRACE:

    javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify
    	at sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.java:735)
    	at sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.java:714)
    	at com.mysql.cj.protocol.a.NativeProtocol.quit(NativeProtocol.java:1312)
    	at com.mysql.cj.NativeSession.quit(NativeSession.java:182)
    	at com.mysql.cj.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:1750)
    	at com.mysql.cj.jdbc.ConnectionImpl.close(ConnectionImpl.java:720)
    	at com.zaxxer.hikari.pool.PoolBase.quietlyCloseConnection(PoolBase.java:135)
    	at com.zaxxer.hikari.pool.HikariPool.lambda$closeConnection$1(HikariPool.java:441)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    	at java.lang.Thread.run(Thread.java:748)


    ** END NESTED EXCEPTION **


    Wed Sep 29 00:28:34 UTC 2021 WARN: Caught while disconnecting...

    EXCEPTION STACK TRACE:
```

はじめはSSLの設定かと思ったが全く別にある。
SSLとは全く関係ないバグ（メモリが足りないとか）でプロセスが中断されるとSSLExceptionが発生する。


```
ドメイン駆動設計入門で学んだこと #5

# はじめに

本記事は以下の書籍を読んで学んだことをまとめることを目的としています。
[前回](https://qiita.com/minoura_a/items/6a054cfa10ac1bfa23e2)の続きです。
[ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 | 成瀬 允宣 |本 | 通販 | Amazon](https://www.amazon.co.jp/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80-%E3%83%9C%E3%83%88%E3%83%A0%E3%82%A2%E3%83%83%E3%83%97%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8B-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E3%81%AE%E5%9F%BA%E6%9C%AC-%E6%88%90%E7%80%AC-%E5%85%81%E5%AE%A3/dp/479815072X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=325IZJW8OL7R9&dchild=1&keywords=%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88&qid=1593219430&sprefix=%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3,aps,244&sr=8-1)

# 集約

オフジェクトの不変条件を維持する単位のことです。例えば、Userの集約にはUserIdとUserNameといったオブジェクトが含まれ、集約の外部からはUserを経由しないとUserIdとUserNameを操作することができないようにします。
このとき、Userは集約のルートと呼ばれ、UserによってUserIdやUserNameといった集約内部の不変条件を保つことができます。
Userからしかオブジェクトを操作できないようにすることで、不正なデータを防いだり、条件であったり、ルールを集約内に持たせることができます。外部にルールが点在し、変更が大量に発生することを防ぎます。

重要なのは、外部からUserが持っているUserIdやUserNameを操作するのではなく、UserがChangeNameのようなメソッドを用意し、外部から内部のオブジェクトを触れないようにしていることです。オブジェクト指向では外部から内部のオブジェクトに直接操作するのではなく、それを保持するオブジェクトに依頼することによって、直感的な実装ができ、また、不変条件を維持することにつながります。これはデメテルの法則といいます。

## デメテルの法則

オブジェクト同士のメソッド呼び出しのガイドラインです。法則によるとメソッドを呼び出すオブジェクトは以下の4つに限定されるそうです。

- オブジェクト自身
- 引数として渡されたオブジェクト
- インスタンス変数
- 直接インスタンス化したオブジェクト

フィールドに対する操作はそれを保持するオブジェクトに対して命令を行い、フィールドは保持しているオブジェクト自身が管理するべきということです。

# 仕様

複雑な評価処理を行うオブジェクトです。単純な判定処理はメソッドとしてエンティティ・値オブジェクトに持たせればいいですが、複雑な判定処理や大量の判定処理メソッドがあると、ドメインオブジェクトの意図が見えづらくなってしまいます。
また、ドメインオブジェクトに評価メソッドが増えてしまうということは、それをほかの色々なオブジェクトから使うわけですから、オブジェクトに対する依存が増えてしまう可能性が大きくなります。
上記2点の問題点解決するために、判定処理を仕様オブジェクトに切り出すことを一度考慮してみることが重要だと思います。

## 仕様とリポジトリの組み合わせ

リポジトリには検索を行う様々なメソッドが定義されますが、それはドメインにとって重要なルールかもしれません。ドメインの知識がリポジトリに漏れ出すことを防ぐために仕様が使われることがあります。

ただし、仕様で検索を行うには、リポジトリからすべてのデータを取得してきて、オブジェクトを生成し、仕様オブジェクトに渡すことが必要になるので、何万件というデータに対して検索をかける可能性があるのだとすると、パフォーマンスのことも考慮に入れておく必要があります。

# さいごに

ここまでお読みいただき、ありがとうございました。
今回をもって、ドメイン駆動設計入門で学んだことの記事は終了です。
irbを終了させるには？

**結論**
-

```
irb(main):001:0>exit
```

もしくは、

```
irb(main):001:0>quit
```

をコマンドライン上で入力して、Enterキーを押すことで、終了させることができます。

**そもそもirbとは？**
-

> irb は Interactive Ruby の略です。 irb を使うと、Ruby の式を標準入力から簡単に入力・実行することができます。

Ruby 3.0.0 リファレンスマニュアルにはこう書いてありました。
数行のコードを実行するときは、わざわざファイルを作成して、ターミナルで実行しなくて済むので便利です。

ちなみに、irbは人と人とが会話をしている様子に似ていることから、対話型と呼ばれているそうです。


**最後に**
-

MacBookを使用しているので、Windowsでは操作が異なるかもしれません。
ご覧くださり、ありがとうございます。
Raspberry Pi で Grove の LCD モジュールを使う (背景色)

こちらのプログラムを改造して、バックライトの色を変えるプログラムを書きました。
[Raspberry Pi で Grove の LCD モジュールを使う](https://qiita.com/ekzemplaro/items/38257ac6a55951b0d99d)

```py:backlight.py
#! /usr/bin/python3
#
#	backlight.py
#
#						Sep/29/2021
# ------------------------------------------------------------------
import	sys
import	time
import	backlight_lib
# ------------------------------------------------------------------
sys.stderr.write("*** start ***\n")
while True:
	backlight_lib.setRGB(0xff,0,0)
	time.sleep(2)
	backlight_lib.setRGB(0,0xff,0)
	time.sleep(2)
	backlight_lib.setRGB(0,0,0xff)
	time.sleep(2)
	backlight_lib.setRGB(0,0,0)
	time.sleep(2)
#
sys.stderr.write("*** end ***\n")
# ------------------------------------------------------------------
```

```py:backlight_lib.py
#
#	backlight_lib.py
#
# ------------------------------------------------------------------
import	smbus

DISPLAY_RGB_ADDR = 0x62
DISPLAY_TEXT_ADDR = 0x3e

bus = smbus.SMBus(1)
# ------------------------------------------------------------------
def setRGB(r,g,b):
	bus.write_byte_data(DISPLAY_RGB_ADDR,0,0)
	bus.write_byte_data(DISPLAY_RGB_ADDR,1,0)
	bus.write_byte_data(DISPLAY_RGB_ADDR,0x08,0xaa)
	bus.write_byte_data(DISPLAY_RGB_ADDR,4,r)
	bus.write_byte_data(DISPLAY_RGB_ADDR,3,g)
	bus.write_byte_data(DISPLAY_RGB_ADDR,2,b)
# ------------------------------------------------------------------
```

次のバージョンで確認しました。

```text
$ python3 --version
Python 3.7.3
```
【Ruby on Rails】whereメソッドを使って投稿内容の絞り込み表示をしよう

今回は投稿内容を絞り込みで表示してみましょう

##目次
**1.前提**
**2.whereメソッドについて**
**3.コントローラー記述**
**4.ビュー記述**
**5.ルート記述**

###1.前提
今回は既に投稿と一覧ができる状態であることとします。
例としては下記のような状態であるとします。

```ruby:burgers_controller.rb
class BurgersController < ApplicationController

    def index
        @burgers = Burger.all
    end

    def new
        @burger = Burger.new
    end

    def create
        burger = Burger.new(burger_params)
        
        if burger.save
            redirect_to :action => "index"
        else
            redirect_to :action => "new"
        end
    end

    private
  def burger_params
    params.require(:burger).permit(:burger_name, :shop_name, :price, :adress)
  end
end
```

```ruby:burgers/index.html.erb
<h3>Burger一覧</h3>
<div class="burgers-container">
  <% @burgers.each do |t| %>
    <div class="burger">
      <%= t.burger_name %>
      <%= t.shop_name %>
      <%= t.price %>
      <%= t.adress %>
    </div>
  <% end %>
</div>
```

```ruby:burgers/new.html.erb
<h3>新規burger</h3>
<%= form_for @burger do |f| %>
  <div class="field">
    <%= f.label :burger_name %>
    <%= f.text_field :burger_name, :size => 30 %>
  </div>

  <div class="field">
    <%= f.label :shop_name %>
    <%= f.select :shop_name, 
    [["マク○ナルド", "マク○ナルド"], 
    ["モ○バーガー", "モ◯バーガー"], 
    ["バーガー○ング", "バーガー○ング"]], include_blank: "選択して下さい" %>
  </div>

  <div class="field">
    <%= f.label :price %>
    <%= f.number_field :price, :size => 10 %>
  </div>

  <div class="field">
    <%= f.label :adress %>
    <%= f.text_area :adress, :size => "30x2" %>
  </div>
  <%= f.submit "Burgerを投稿する" %>
<% end %>

<%= link_to "Burger一覧に戻る", burgers_path %>
```

```ruby:routes.rb
Rails.application.routes.draw do
  root 'burgers#index'
  resources :burgers  
end
```

今回は　shop_nameというカラムを元に、お店ごとの絞り込みをできるようにしていきます。

###2.whereメソッドについて
今回はwhereメソッドというものを使って絞り込みを実装します。

**whereメソッドとは？:与えられた条件にマッチするレコードを全てしてくれる役割**

これだけだと「？？」ってなると思うので例をあげます。
テーブル内に下記の表のようなデータが入っているとします。

|id|shop_name|adress|price|
|:--:|:---:|:---:|:--:|
|1|マク○ナルド|東京|600|
|2|モ○バーガー|神奈川|700|
|3|バーガー○ング|埼玉|800|
|4|モ○バーガー|福岡|600|
|5|マク○ナルド|長崎|800|
|6|バーガー○ング|福岡|700|

shop_nameが「マク○ナルド」のものを絞り込んだら1と5
priceが「600」のものを絞り込んだら1と4といった感じになります。
このように条件にあったレコードを返してくれるのがwhereメソッドです。
それではこれを用いて実際に絞り込みのコードを書いていきます。

###3.コントローラー記述

まずは1.前提にあったburgersコントローラーにいくつか追記していきます。
今回はshop_nameが「マク○ナルド」のものを絞り込む場合のコードを書いていきます。

```ruby:burgers_controller.rb
#省略

    def mac
        @burgers = Burger.all
        @mac = Burger.where(shop_name:"マク○ナルド")
    end

#省略
```
where(カラム名:"絞り込む名前")
という形で書いています。

###4.ビュー記述

次にビューを書いていきます。
今回は新しくmac.html.erbを作成した場合で書いていきます。

```ruby:burgers/index.html/erb
<%= link_to "マク○ナルドへ", burgers_mac_path %>
```
まずはindexにmac.html.erbに遷移するためのコードを書いてあげました。

```ruby:mac.html.erb
<div class="burgers-container">
<h2>マク○ナルド</h2>
  <% @mac.each do |m| %>
    <div class="burger">
      <%= m.burger_name %>
      <%= m.shop_name %>
      <%= m.price %>
      <%= m.adress %>
    </div>
  <% end %>
</div>
```

###5.ルート記述

```ruby:routes.rb
Rails.application.routes.draw do
  root 'burgers#index'
#追記
  get 'burgers/mac' => 'burgers#mac'
#ここまで
  resources :burgers  
end
```
###終わり
以上です！
[Dart] Enum文字列化、自分なりの最適解

こんにちは。Dart赤ん坊です。

Dartでよく言われる、Enum使いにくい問題。文字列化できないので、使い勝手が悪いんですよね。そこでextensionで使いやすくしてみました。staticも使えますし、もちろんパッケージのEnumも拡張できます。

以下のコードです。

```dart
/// サンプルEnum
enum Number { One, Two, Three }

/// サンプルEnumを拡張
extension NumberExtension on Number {
  /// Enum内個別に文字列を取得
  get name => this.toString().split(".").last;

  /// Enum全体（NumberExtension）から全てのEnum内文字列を取得
  static get names => Number.values.map((value) => value.name).toList();
}

/// 実行
main() {
  print(Number.One.name);
  // ↑結果：One
  print(NumberExtension.names);
  // ↑結果：[One, Two, Three]

  // print(Number.names);
  // これは出来ない
}
```

要点を解説すると、

```dart
extension NumberExtension on Number {
  get name => this.toString().split(".").last;
  static get names => Number.values.map((value) => value.name).toList();
}
```

extensionで、enumを拡張しています。一つ目はenumのメンバー？をtoString()した代物に"."でスプリットして、良い感じの文字列をとっています。二つ目では一つ目で作成したnameを利用して、staticでnamesを定義しています。

staticで設定したものはNumber.namesとして使用できそうなものですが、なぜかできないので、仕方なくNumberExtension.namesとして利用しています。それほど大きな面倒ではありませんので、十分利用価値はあるかと思います。

以上です。それでは。
【JavaScript】クロージャを理解する

# はじめに
JavaScriptのクロージャの学習メモです。
誤りご指摘等あれば、気軽にコメントいただけると嬉しいです。

# クロージャとは？
自分の言葉で簡単に表現してみると
「定義した関数の外側のスコープにある変数や関数を参照できる仕組み（または関数）」のこと
だと理解しました。

公式だとこのように書かれてました。
[クロージャ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures)
>クロージャは、組み合わされた（囲まれた）関数と、その周囲の状態（レキシカル環境）への参照の組み合わせです。言い換えれば、クロージャは内側の関数から外側の関数スコープへのアクセスを提供します。JavaScript では、関数が作成されるたびにクロージャが作成されます。

# クロージャのメリット
関数内などの変数や関数などを他のプログラムから簡単に変更されないように制御できること。

# クロージャの実行サンプル
初期値の数値を引数で渡して、それをクロージャ関数（内部に定義した関数）から計算して、計算結果をコンソールに出力するサンプル。

※サンプルコードは``TypeScript``で記述してます。が気にせず。

```ts
// ４つのクロージャ関数を生成して返す関数
function calcFactory(def: number) {
  // ローカル変数result： calcFactory関数のスコープ内でしか参照できない
  let result: number = def;

  // この４つの関数たちがクロージャ
  const plus = (num: number) => {
    console.log("計算前", result);
    result = result + num;
    console.log("計算後", result);
  };
  const minus = (num: number) => {
    console.log("計算前", result);
    result = result - num;
    console.log("計算後", result);
  };
  const multiply = (num: number) => {
    console.log("計算前", result);
    result = result * num;
    console.log("計算後", result);
  };
  const divide = (num: number) => {
    console.log("計算前", result);
    result = result / num;
    console.log("計算後", result);
  };

  // クロージャ関数を返す
  return { plus, minus, multiply, divide };
}

// このタイミングでクロージャが生成される 
const calc = calcFactory(10);
calc.plus(3);
calc.minus(5);
calc.multiply(8);
calc.divide(4);
```
**コンソール出力結果**
![スクリーンショット 2021-09-29 8.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621162/e5cb31d5-48ca-d9f6-13b5-03ee71142fd6.png)



このとき``calcFactory関数``の中でしか参照できない``変数result``に計算結果を保ちながら、処理が繰り返される。
``変数result``にはクロージャ関数``plus`` ``minus`` ``multiply`` ``divide``からしか参照できない。

```ts
const calc = calcFactory(10);
calc.plus(3);
calc.minus(5);
calc.multiply(8);
calc.divide(4);
// クロージャを経由せずにresultを参照することはできない
calc.result; // エラー
```

### 関数が作成されるたびにクロージャが作成される
公式にもこのような記述がありますが、
>JavaScript では、関数が作成されるたびにクロージャが作成されます。

どういうことかコードで確認してみる。

```ts
// このタイミングでdefに10をもつクロージャが生成される
const calc = calcFactory(10);
calc.plus(3);
calc.minus(5);
calc.multiply(8);
calc.divide(4);

console.log("--------------------------------------");

// このタイミングでdefに20をもつcalcとは異なるクロージャが生成される
const calc2 = calcFactory(20);
calc2.plus(3);
calc2.minus(5);
calc2.multiply(8);
calc2.divide(4);
```

``calcFactory関数``を実行するたびに異なる(今回の場合は``引数def``が違う数値を渡すことにより``変数result``が異なる）クロージャが生成される。

**コンソール出力結果**
![スクリーンショット 2021-09-29 8.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621162/f5267c25-6158-2d89-d6d3-89b93d5eb735.png)



# 最後に
大変有益でわかりやすい記事ばかりで助かりました！ありがとうございました！

- https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures
- https://www.udemy.com/course/javascript-essence/
- https://qiita.com/takeharu/items/4975031faf6f7baf077a
- https://qiita.com/righteous/items/494340cf16c7a35f742e
- https://www.sejuku.net/blog/25026
Amazon Linux2におけるsystemdのバージョンは古め

Amazon Linux2がサポートしているsystemdのバージョンはかなり古いよという話。

## Amazon Linux2におけるsystemdバージョン
Azmazon Linux2 の systemd で `RuntimeMaxSec` オプションを利用しようとしたら
サポートされていないよとエラーになったことで気付いた。

[Amazon Linux2のリリースノート](https://aws.amazon.com/jp/amazon-linux-2/release-notes/)を確認したところ
Amazon Linux 2.0.20210617.0 更新のバージョンで systemd-219だった。
これは[systemdのChangeLogs](https://github.com/systemd/systemd/blob/main/NEWS)を見る限りでは 2015-02-16 リリースのバージョンなのでかなり古い。

```
$ rpm -q systmed
systemd-219-78.amzn2.0.14.x86_64
```

## その他のOSにおけるsystemdバージョン

### RHEL 8.4
同じRHEL系列の最新バージョンである RHEL8.4 では [Red Hat パッケージ検索](https://access.redhat.com/downloads/content/systemd/239-45.el8_4.3/x86_64/fd431d51/package) によると systemd-239 が採用さている。
これは 2018-06-22 リリースなので、RHEL8.0のリリースが2019-05だったことを考えてもちょっと古め。

### RHEL 7.9
Amazon Linux2がベースとしているRHEL7系最新の 7.9 では [Red Hat パッケージ検索](https://access.redhat.com/downloads/content/systemd/219-78.el7/x86_64/fd431d51/package) によると systemd-219を採用している。
これはAmazon Linux2のバージョンと同じ。

### Ubuntu 21.04
Ubuntu系最新の21.04 は [Ubuntu packages](https://packages.ubuntu.com/hirsute/systemd)によると 247.3-3ubuntu3.4
このsystemdは2020-11-26リリースのバージョン。

### Ubuntu 20.04
Ubuntu系最新のLTSである 20.04 では [Ubuntu packages](https://packages.ubuntu.com/focal/systemd) によると systemd-245が採用されている。
これは 2020-03-06 リリースのバージョン。

```
$ dpkg -l systemd
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version           Architecture Description
+++-==============-=================-============-=================================
ii  systemd        245.4-4ubuntu3.11 amd64        system and service manager
```

### Debian 11 bullseye
Debian bullseyeは [Debian packages](https://packages.debian.org/bullseye/systemd)によると 247.3-6 がサポートされている。
このsystemdはUbuntu21.04と同一バージョンなので 2020-11-26リリース。


## まとめ
Amazon Linux2も初リリースが[2017-12](https://aws.amazon.com/jp/about-aws/whats-new/2017/12/introducing-amazon-linux-2/)だったのですでにいろいろなパッケージバージョンが古くなっている。
Amazon Linux3の登場が待ち遠しいが、リリースはいつだろう？
Raspberry Pi で Grove の LCD モジュールを使う

次のページを参考にしました。
[Grove - LCD RGB Backlight](https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/#play-with-raspberry-pi)

ベースシールドは次のものを使いました。
[Stackable Shield for Raspberry Pi 2.0](https://www.elecrow.com/wiki/index.php?title=Crowtail-_Stackable_Shield_for_Raspberry_Pi_2.0)

実行時の様子
![IMG_20210929_080733.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/bf72166e-feb2-624c-a4ad-87e9e2cff37a.jpeg)


プログラム

```py:display_lcd.py
#! /usr/bin/python3
#
#	display_lcd.py
#
# ------------------------------------------------------------------
import	sys
import	time
import	lcd_lib

# ------------------------------------------------------------------
sys.stderr.write("*** start ***\n")
count = 0
while True:
	text = 'count = ' + str(count)
	lcd_lib.setText_norefresh(text)
	time.sleep(1)
	count += 1
#
sys.stderr.write("*** end ***\n")
# ------------------------------------------------------------------
```

```py:lcd_lib.py
#
#	lcd_lib.py
#
# ------------------------------------------------------------------
import	time
import	smbus

DISPLAY_RGB_ADDR = 0x62
DISPLAY_TEXT_ADDR = 0x3e

bus = smbus.SMBus(1)
# ------------------------------------------------------------------
def textCommand(cmd):
    bus.write_byte_data(DISPLAY_TEXT_ADDR,0x80,cmd)
# ------------------------------------------------------------------
def setText_norefresh(text):
    textCommand(0x02) # return home
    time.sleep(.05)
    textCommand(0x08 | 0x04) # display on, no cursor
    textCommand(0x28) # 2 lines
    time.sleep(.05)
    count = 0
    row = 0
    while len(text) < 32: #clears the rest of the screen
        text += ' '
    for c in text:
        if c == '\n' or count == 16:
            count = 0
            row += 1
            if row == 2:
                break
            textCommand(0xc0)
            if c == '\n':
                continue
        count += 1
        bus.write_byte_data(DISPLAY_TEXT_ADDR,0x40,ord(c))
#
# ------------------------------------------------------------------
```

次のバージョンで確認しました。

```text
$ python3 --version
Python 3.7.3
```
【Java】カプセル化の理解ついての復習をしていく


#目的

* カプセル化に関しての復習と定着 

#実際の手順と実例
###1.カプセル化とは

* カプセル化とはオブジェクトの情報をカプセルのようにまとめ、中身を隠蔽したままオブジェクトを利用すること
* カプセル化のイメージは
    * 外から防御されている
    * カプセルに包まれている
* 「オブジェクト内のデータ」を包み、「オブジェクト外からの不正アクセス」を防ぐ

これらのイメージを持って問題を例にして考えていきます。


###2.例題

####問題

「Practice.java」を実行した結果が同じになるように、「NoCapsule.java」を「Capsule.java」に変更して、カプセル化したプログラムに変更してください。

**実行結果**

`````java
好きな食べ物はラーメンです。
週に１回食べています。
最近は週に2回食べるようになりました。。。
`````

`````NoCapsule.java
package practice;

public class NoCapsule {
    public String food;
    public int count;

    public NoCapsule(String food, int count) {
        this.food = food;
        this.count = count;
    }
}
`````

````Practice.java
package practice;

public class Practice {
    public static void main(String[] args) {
        NoCapsule eat = new NoCapsule("ラーメン", 1);
        System.out.println("好きな食べ物は" + eat.food +  "です。");
        System.out.println("週に" + eat.count + "回食べています。");
        eat.count = 2;
        System.out.println("最近は週に" + eat.count + "回食べるようになりました。。。");
    }
}
`````



####回答

まず、問題通り、「NoCapsule.java」を「Capsule.java」に変更します。

このままでも実行は可能ですが、誤って外部のプログラムが変更禁止のフィールドを変更してしまうことを防止するため、メソッドやフィールドにアクセス修飾子を設定してアクセスを制限します。

````Capsule.java
package practice;
//「NoCapsule.java」を「Capsule.java」に変更
public class Capsule {
//	アクセス修飾子をpublicからprivavteに変更
	private String food;
	private int count;

	public Capsule(String food, int count) {
		this.food = food;
		this.count = count;
	}
//	実行ファイルで使用できるようにpublicで定義
	public String getFood() {
		return food;
	}
//	getterはフィールドの値を取得できるようにするメソッド
	public int getCount() {
		return count;
	}
//	setterはメソッドや値を変更するメソッド
	public void setCount(int count) {
		this.count = count;
	}
}

````

````Practice.java
package practice;

public class Practice {
	public static void main(String[] args) {
//		「NoCapsule.java」を「Capsule.java」に変更
		Capsule eat = new Capsule("ラーメン", 1);
//		getterで定義した変数を使用する
		System.out.println("好きな食べ物は" + eat.getFood() + "です。");
		System.out.println("週に" + eat.getCount() + "回食べています。");
//		setterで値を変更
//		引数に変更する値を代入
		eat.setCount(2);
		System.out.println("最近は週に" + eat.getCount() + "回食べるようになりました。。。");
	}
}
`````


実行結果も全く同じになりました。

````java
好きな食べ物はラーメンです。
週に1回食べています。
最近は週に2回食べるようになりました。。。
````



また、Eclipseでは、下記の箇所からカンタンに自動でカプセル化も可能です！
![スクリーンショット 2021-09-29 8.01.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681213/4d9c30ad-5094-ffd0-2f73-a2d6138bb748.png)



#参考にさせて頂いた記事

* [カプセル化とはなにか？超わかりやすく解説します！](https://webpia.jp/encapsulation/)