OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】 「CloudFront＋S3」構成で、「Uncaught SyntaxError: Unexpected token <」が出現した話

# はじめに

「CloudFront＋S3」構成で、「Uncaught SyntaxError: Unexpected token <」が出現したので、S3に配置している
VueかReactの内容を確認しても、問題なさそうだった。

ではなぜだろうというので調べ、

解決方法は、まあそうだよねって感じですが、無駄にソース追う時間を取られたので、自分用メモ。



# 解決

再度、VueかReactでbuildした内容をS3にアップロードして、
"何度か" CloudFrontのキャッシュ削除を「/*」で実行する。


いつもより削除するのに時間がかかり、待っていると問題なくキャッシュ削除完了。
再度アクセスすると問題なく、画面が表示された。


キャッシュ削除しても、何度か実行してみるといいと思います。


https://stackoverflow.com/questions/48612240/react-app-hosted-on-s3-unexpected-token


上記にもあるように、CloudFrontのキャッシュやブラウザキャッシュをつかむことがよくあるので、
それを粘り強く（キャッシュ削除しきる）やると、うまくできます。
【AWS】 「This XML file does not appear to have any style information associated with it. The document tree is shown below.」への対応を、CloudFront Behaviorパスパターンで解決

# はじめに

```
This XML file does not appear to have any style information associated with it. The document tree is shown below.
```

「ああ。このエラーな。どうせ、CloudFrontとかS3のデフォルトルートオブジェクトがずれているのだろう」
と思ってみてみても、ずれていない。

何でだってなっているときに、調べたときのメモ。


# 内容

## 構成

「CloudFront + S3 + (WAF + API Gateway + Lambda)」

## 原因

403エラーの時の、CloudFrontのBehaviorパスパターンをしっかり設定していなかった。


## 解決

403の時に、CloudFrontのBehaviorパスパターンを適切なファイルに流れるようにしたら解決した。

# 参考

https://blog.nijot.com/aws/maintenancewindow-with-cloudfront/
SPSS Modelerで複雑なストリームからノードを探したい

ストリームが複雑になってきた場合にノードを探したくなることがあります。
そんな時にはノードの検索機能が利用できます。

「現在のストリームのノードの検索」で検索画面が開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6f5a62b4-7a3f-c372-37ab-27fe8e52fd61.png)

検索方法はいくつも用意されています。いくつかピックアップして紹介します。

# 1 「ノードカテゴリ」で検索
まず「ノードカテゴリ」で「入力ノード」を選び、「検索」ボタンをクリックします。
するとこの例では2件の入力ノードが検索されています。
検索された行をクリックするとキャンパス上で、対象ノードが選択状態（黄色い影）になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/655d8756-dc11-f8ce-dd59-7a61bf695c99.png)

# 2「次の名前のフィールドを生成」で検索
「次の名前のフィールドを生成」に列名を入れてみます。この例では「大分類_アクセサリ_小計_Sum」です。
「大分類_アクセサリ_小計_Sum」の列がつくられた集計ノードを突き止めることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/d134704f-65ea-6336-0f1c-293c05a29606.png)

# 3「ノードラベルが次を含む」で検索
「ノードラベルが次を含む」で入力データを探してみます。この例では「sampletranDEPT4.csv」です。
sampletranDEPT4.csvを入力としているノードが見つかりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/82f94ece-e6d4-0079-0644-808667e68ebd.png)

# 4「キーワード」で検索
「キーワード」であらかじめ任意のキーワードを入れておいたノードを探してみます。この例では「本番モデル作成」をCHAIDのモデル作成ノードにあらかじめ設定しておきました。ちゃんと見つけることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6c89340c-7a03-5826-84ad-098ec4ed7aea.png)

* テスト環境
Modeler 18.3
Windows 10 64bit
AWS-CLIを使う準備

S3のバケット内にあるファイルを一括ダウンロードしたいと思ったところ、マネジメントコンソールではできませんでした。
しかし、AWS-CLIを使えば一括ダウンロードできるということだったので、その際に必要だった色々な準備をメモしておきます。

# AWS-CLIとは
コマンドライン上でAWSサービスに対して色々な操作ができるアプリケーションです。
Linuxなどでコマンドを扱うのに慣れている人にとっては便利なツールでしょう。

# 手順
1. AWS-CLIのダウンロードとインストール
1. AWS-CLI用のアカウントを作成する
1. AWS-CLIにアクセスキーIDとシークレットアクセスキーを設定する

# AWS-CLIのダウンロードとインストール
AWS-CLIはAWSのサイトからダウンロードできます。

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

英語ページですが、ページ中央付近にある以下の記述部分をクリックすればインストーラーをダウンロードできます。

![スクリーンショット 2022-06-02 14.46.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1926542/a3798c25-6007-17b3-0fc3-54942f928a30.png)


# AWS-CLI用のアカウントを作成する
自身のAWSにアクセスできるように設定するには、まずはIAMにてAWS-CLI用ユーザ（プログラムによるアクセスを許可したユーザ）を準備する必要があります。
私は以下のサイトを参考にしてユーザを作成しました。

https://blackbird-blog.com/setup-aws-cli


# AWS-CLIにアクセスキーIDとシークレットアクセスキーを設定する
Windowsならコマンドプロンプト、Macならターミナルを開いて、以下のコマンドを実行します。
```
$ aws configure
```
アクセスキーIDとシークレットアクセスキーの入力を促されるので、IAMでユーザを作成した際に表示されたコードをそれぞれ入力してください。
こちらも以下のサイトに詳細が載っています。

https://blackbird-blog.com/setup-aws-cli

以上でAWS-CLIが利用できるようになりました。
今後はAWS-CLIのコマンドも色々と覚えていかないと。
プロジェクト成功のポイントとは

# はじめに
以下のページを拝見しました。言っていること、とてもよくわかります。

https://blog.tinect.jp/?p=76707

このページをみて、私も昔、先輩から教えていただいた **「プロジェクト成功のポイント」** を思い出しました。
プロジェクト成功のポイントは、いろいろな視点があり、視点を変えばたくさんあると思いますので、ひとつではないとは思いますが。（小さいことの積み重ねだったりします）


# プロジェクト成功のポイント

### 「プロジェクトに関わるメンバーが、どれだけ主体性をもって、我が事として取り組むことができるか」である。

と教えていただきました。

#### プロジェクトに対する姿勢
**1. プロジェクトが皆さんのために何をしてくれるかを問わないこと。皆さんがプロジェクトのために何ができるかを問うこと。**（ジョン・F・ケネディ大統領「国があなたのために何をしてくれるのかを問うのではなく、あなたが国のために何を成すことができるのかを問うて欲しい。」より）
**2. システム(※1)を変えているのではなく、日常を変えている、という意識を持つこと。**
**3. すべての事柄について、Will(意志)を持って取り組むこと。**


プロジェクトのキックオフなどで、参加するメンバー全員にこのことを伝えられるとよいと、個人的には考えています。外部からの働きかけで、「主体性を持って」とか、「我が事として考えて」というのは、なかなか大変かもしれませんが、不可能ではないと思います。
**これが成功のポイントなのです！** と全員で共有することはとても大事なのではないでしょうか。


***
もう結論は終わりましたので、ここからは知識整理です。
PMP(Project Management Professinal)の試験を受けた際に、プロジェクト・プロジェクトマネジメントについてまとめたものを整理しておきたいと思います。鷹の目(※2)てきな大きな視点での整理です。

## プロジェクトとは何か

#### 有期性　
　⇒ 明確な始まりと終わりがある
#### 独自のプロダクト・サービス・所産　
　⇒全てのプロジェクトとは、独自のプロダクト・サービス・所産を創造する


## プロジェクト目標

プロジェクトの成功のためには、目標の設定が重要です。目標の設定は、SMARTに行いましょう。
> S: Specific　具体的に
> M: Measurable　測定可能に
> A: Agreed-upon　合意されている
> R: Realistic　現実的に
> T: Time-Limited　期限が明確

## プロジェクトの3大制約とは
プロジェクトの3大制約は、**スコープ・タイム（スケジュール）・コスト**です。
その制約の中で、どのように **品質(成果物・プロジェクト)** を保つかが大事になります。

![Screenshot_1 (カスタム).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/001e8730-75bc-b187-ab0b-45e6690288c0.png)



## プロジェクトの心得え

#### プロジェクトへの問い
> 1　なぜこのプロジェクトをやるのか
> 2　メリットはなにか？
> 3　変革しなければ、どうなるか？
> 4　やり方を変える必要があるのはどこか？

#### プロジェクトの成功基準
> 1　プロジェクトを期限内に完成する
> 2　プロジェクトを予算内で完成する
> 3　プロジェクトチームとステークホルダーが合意した品質目標を満足する



## プロジェクト・マネジメントとは
プロジェクトの要求事項を満足させるために行われるマネジメント活動である
> 1.　要求事項を特定する
> 2.　クライアントなどを含めた各種ステークホルダーのニーズ・関心事・期待に取り組む
> 3.　活発に、効果的に、協力的に、ステークホルダー間のコミュニケーションを確立し、継続し、実行する
> 4.　プロジェクトの要求の達成に向けて、ステークホルダーをマネジメントし、成果物を生成する
> 5.　品質・スコープ・タイム・コストなど競合する制約条件のバランスをとる

## プロジェクト・マネジャーとは
プロジェクトの目標を達成することに責任をもつチームをリードするために母体組織が任命する人物

特性：基本的に3つの特性が必要とされる
> 知識：　PMBOK等
> 執行能力：　パフォーマンス力
> 人間性：　コミュニケーション・リーダーシップ・組織への影響力・動機付け・交渉スキル



## プログラム / ポートフォリオマネジメント

#### プログラム
プロジェクトの集合体。各プロジェクトを個別に管理するより、集合体として、大きな効果を引き出すことを意図したもの

#### ポートフォリオ
プロジェクトやプログラムなどを、組織の戦略的目標達成のために大きくグルーピングしてマネジメントの対象とするもの

![Screenshot_2 (カスタム).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/6c449eb9-d1ce-ca75-a2b3-4b0276129a63.png)


## プロジェクトマネジメントオフィス(PMO)とは
複数のプロジェクト・プログラムをマネジメントを一元化し、調整する組織

> PMの役割：自分の担当するプロジェクトに対する利益確保
> PMOの役割：母体組織全体の利益を考慮する　⇒PMOの種類：支援型PMO・コントロール型PMO・指揮型PMO


## ステークホルダーとは
組織に価値をもたらす製品・サービスに何らかの影響を受け、定義される個人や組織のこと

> ステークホルダーを特定する作業は、継続的に行う必要がある。その理由は、外的要因・内的要因によって、プロジェクトに関わる人が変化する可能性があるため。ステークホルダー = お客様・ユーザではない。
>例えば、チームメンバーもステークホルダーとなる。（例：スポンサー・顧客・ユーザ・納入者・ビジネスパートナー（ベンダーなど）・機能部門マネージャー・チームメンバー）


***
## おまけ：PMBOK進化しています

プロジェクトマネージメントの知識を担当するPMBOKも進化してます。

https://speakerdeck.com/miz_kushida/jie-wei-kasawatukuhotochao-jin-hua-sitapmbokdi-7ban-nisi-tatihatouqu-rizu-muka


## 注釈

※1: システムとしているのは、業務に関わる新システム導入プロジェクトを想定しているからで、システムという文字は置き換え可能かと思います。

※2: 鷹の目
> 鷹の目：鷹のように、大空から眺めるように、物事を大局的にとらえる視点です。長期的な目標ともいえます。
> 蟻の目：蟻のように、事象をより身近に細かく見る視点です。短期的な目標でより現場的な視点といえます。
> 魚の目：魚のように激しい流れの中でも泳ぐための先を見通す視点です。未来的な目標といえます。

https://workaholicdiary.com/work-hacks/three-eyes
AngularCLI、nodejs、npmバージョン変更について

Ubuntu環境でangularの開発環境構築に手間取ったため、議事録としてのメモ

1.node.jsとnpmのバージョン変更

// 先にubuntuのアップデートを行う
$sudo apt update

// nodeとnpmのインストール（ただしこのコマンド実行時は古いバージョンでインストールされる）
$sudo apt install nodejs
$sudo apt install npm

// nodeとnpmのバージョン変更するためにnコマンドをインストールする。
$sudo npm install -g n


//　nコマンドを利用（先にnodeをインストールしないといけない）
// nodeとnpmのバージョン変更する。終わったら一度ubuntuを再起動する。
$sudo n バージョン番号

// nodeとnpmのバージョン確認
$node -v
$npm -v

nodeをインストール参考記事
https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-ja



2.angularCLIのバージョン変更

// angularCLIのアンインストール
$sudo npm uninstall -g @angular/cli

// バージョン指定のインストール
$sudo npm install -g @angular/cli@バージョン番号

// バージョン確認
$ng version
Cloud Formationで環境構築してStep FunctionsからAthenaを動かすときにはまった話

# はじめに
AWSで環境構築するときCloud Formationを使うことは多いかと思います。
今回AthenaをStep Functionsから動かそうとした際にはまった点があるため備忘録代わりに記事にしておきます。

# 構成
雑にですが以下のようなもの
* Step Function
  * Athena

# はまったポイント
Athenaを動かす際にWorkGroupが必要となります。
自前で用意しなければ初期状態で存在しているprimaryがあり使われるようになっているかと思います。
今回は自前で用意したWorkGroupを使おうとしたところ、取り込み自体は出来るがクエリ実行時にエラーになるという状況に陥りました。

# 何が悪かったか
以下は問題なかったところ
* WorkGroupの作成の記載は問題なさそう（公式のドキュメントを見ても問題なさそう）
* Step Functionsでのステートマシンには権限は問題なく付いていそう

問題のあったところ
* 実際の挙動を書いていたステート部分でクエリ実行を書いていたタスク内にWorkGroupを指定できていなかったためデフォルトのprimaryを使おうとしていた（primaryへは権限付与なし）
  * 今回はstartQueryExecution.syncのタスクに付与出来ていなかった

# 終わりに
ちゃんと関係する箇所の最初から最後まで公式のドキュメントと突き合わせて正しさの検証をする癖をつけたい。
そして、さっと書くために図も何もなしで記載しましたが気が向いたら後で更新したい。
（メモ）missing signature keyエラーでoc new-appが失敗してしまう

対策
- skopeo copy commandで--format v2s1を指定する
- podman build時に--format=docker オプションを使う

…で解決。

- 参考にした情報
  - https://learn.redhat.com/t5/Containers-DevOps-OpenShift/DO288-lab2-ch2s07/td-p/22088
> If anyone else facing this issue. Here is workaround and tracking for your information 
> 
> As a workaround kindly try the below suggestion.
> Add the `--format v2s1` flag to the skopeo copy command in the previous step to push the image to Quay with an OCP4.6 compatible manifest.
> 
> Refer to https://issues.redhat.com/browse/PROJQUAY-3285 to track the long term fix.
> 
> Alternatively, you can build the image by using the podman build --format=docker in step 3.3.
> 
> podman build --format=docker --layers=false -t do288-apache ./container-build
M5Paper で 文字を点滅

こちらのプログラムを改造して文字を点滅させてみました。
[M5Paper で Hello World](https://qiita.com/ekzemplaro/items/aa8ac0808e7b754aa314)

```text:hello_blink.ino
// ---------------------------------------------------------------
//	hello_blink.ino
//
//					Jun/02/2022
// ---------------------------------------------------------------
#include <M5EPD.h>

M5EPD_Canvas canvas(&M5.EPD);

  String ssx[] = {"Hello World","Good Morning","Good Afternoon",
    "Good Evening","Good Night"};

// ---------------------------------------------------------------
void setup(){
    M5.begin();
    M5.EPD.Clear(true);

    M5.RTC.begin();
    canvas.createCanvas(960, 540);
    canvas.setTextSize(5);
    int xx = 100;
    int yy_start = 30;

  for (int it=0; it< 5; it++)
  {
    int yy = yy_start + it * 80;
    canvas.drawString(ssx[it], xx, yy);
  }
 
    canvas.drawString("Jun/2/2022 PM 14:27", xx+100, yy_start+400);
    canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
}

// ---------------------------------------------------------------
void loop(){
    int xx = 100;
    int yy_start = 30;

  for (int it=0; it< 5; it++)
  {
    int yy = yy_start + it * 80;
    canvas.drawString("               ", xx, yy);
    canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
	delay (1000);
    canvas.drawString(ssx[it], xx, yy);
    canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
	delay (1000);
  }

}
// ---------------------------------------------------------------
```

Arduino IDE 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/1da3f714-3c81-a5ef-c5dd-d01d7aa4803a.png)
Baseline Environment on AWS(BLEA)ざっくり説明

# CDKざっくり説明
プログラム言語でAWSのリソースを定義出来ます。
JavaScript、TypeScript、Python、Java、C#、Go（開発者プレビュー）がサポートされています。
コードをデプロイするとCloudFormation(CFn)のスタックが作成されAWSリソースが作成されます。
CFnで書いくのと比べて可読性が高く、コード量を減らすことが出来ます。

# BLEAざっくり説明

https://aws.amazon.com/jp/blogs/news/announcing-baseline-environment-on-aws/

AWSのセキュリティのベストプラクティスを実装したテンプレートです。CDKで実装されています。
ガバナンスベース（共通設定）とゲストシステム（システム固有の設定）の2層になっています。
提供されているガバナンスベースのテンプレートをデプロイすると下記リソースが自動的に作成されます。また標準的なゲストシステムのサンプルも提供されています。
環境によるカスタマイズは必要ですが、標準的なセキュリティ設定適用の自動化が可能になります。

## ガバナンスベーステンプレートで設定される内容
* CloudTrail による API のロギング
* AWS Config による構成変更の記録
* GuardDuty による異常なふるまいの検知
* SecurityHub によるベストプラクティスからの逸脱検知 (AWS Foundational Security Best Practice, CIS benchmark)
* デフォルトセキュリティグループの閉塞 （逸脱した場合自動修復）
* AWS Health イベントの通知
* セキュリティに影響する変更操作の通知（一部）
* Slack によるセキュリティイベントの通知
# BLEAを試してみた理由
「BLEAはCDKの学習用途」もあるようです。（下記AWS BlogやAWSサミットのBLEA解説の動画より）
これからCDKを勉強するときに最初から書くのは大変だなと思っていましたが、提供されているサンプルがあったり、サンプルの中のコメントがしっかり書かれているため、CDK学習のハードルが少し下がりました。TypeScriptはしっかり勉強しようと思いました。。

# BLEAざっくり手順
デフォルトで提供されるガバナンスベースのテンプレートをデプロイしてみます。
下記のようにお試しであれば複雑な手順なく実行可能です。

* CDKの前提環境用意（Nodejs、VSCode、認証設定など）

https://qiita.com/Toru_Kubota/items/c0da04eaffdf23562dbb

* リポジトリの取得（git clone）とプロジェクト初期化

* AWS ChatBotの準備
BLEAでは通知にSlackを使いますのでSlack上にチャネルを作成してChatBotの初期設定をします。

* ガバナンスベースのデプロイ

詳細は下記公式のREADMEを参照下さい。

https://github.com/aws-samples/baseline-environment-on-aws/blob/main/README_ja.md


# 実行結果

* スタック作成
下記のようにCFnのテンプレートが作成後、AWSリソースが作成されます。
なお既にリソースがある場合（例.AWS Configが既に有効可されていたり）はスタックデプロイ時にエラーとなりますのでリソース削除後に再実行してみます。

![bl1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/1369ee0a-eec9-a6c7-4df1-08f7f0926e42.png)

* リソース作成
AWS Config、Cloud Trailの証跡設定など、各種設定が実施されていることが確認出来ます。
また、セキュリティアラートの通知が設定したSlackに通知されたことを確認出来ました。

![bl2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/970a9745-ae0b-20e0-e100-4a1fc6679539.png)
【AWS】「CloudFront+S3+API Gateway+Lambda」でBASIC認証を実現するために、AWS SAM(CloudFormation)利用してLambda@Edge作って、権限割り振っているのに「Lambda@Edge cannot retrieve the specified Lambda function. Update the IAM policy to add permission: lambda:GetFunction for resource」言われた

# はじめに

タイトル長々と書いたが、
AWS SAM(CloudFormation)で、「「CloudFront+S3+API Gateway+Lambda」でBASIC認証」を実現しようとしたたら、「Lambda@Edge cannot retrieve the specified Lambda function. Update the IAM policy to add permission: lambda:GetFunction for resource」

と怒られて、GetFunctionの権限ないよということだった。

ただ、権限は問題なく割り振っていた。なぜだと思い対応したときのメモです。

# 内容

## 構成

「WAF + Lambda@Edge + ACM※1」と「CloudFront + S3 + (WAF + API Gateway + Lambda)※2」
※1: us-east-1指定をして作成
※2: ap-northeast-1指定をして作成

みたいな構成で、インフラ構築するためのテンプレートファイルは、
「template_lambdaedge.yaml」と「template.yaml」のように分けて対応していた。

当時は、CloudFront FunctionsでBASIC認証できなかったので上記の構成にしていた。

## 原因

Lambda@Edgeのバージョン指定が異なっていたことが原因


## 解決
AWS SAM(CloudFormation)で、Lambda@Edgeのバージョンをパラメータ指定しており、
しかも、tomlファイルに内容を保存していたため、バージョン指定の見落としだった・・・

「template.yaml」（CloudFront + S3 + (WAF + API Gateway + Lambda)）を実行する際に、
Lambda@Edgeの名前と、”適切なバージョン指定”をして設定したところ
問題なく作成された。
よかったー

# 所感
CloudFront FunctionsでBASIC認証できるようになった現在は関係ないかもですが、
バージニアにLambda@Edge作って対応している人には役立つ内容かなと思いますー。
🔰【初学者用】RSpecでテストコードを書こう！②【簡単な実装例】

# はじめに
RSpecでテストコードを書こう！２記事目です！
①の投稿はこちら↓

https://qiita.com/hondano_gentuki/items/2003971a4f5a97481930

# テストコード書き方
Userモデルにはnameカラムとemailカラムがあるとします。
```rails:spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
   context '登録ができるとき' do
　　　it '全ての項目が正しく入力されている時' do
     　#その処理を記述
　　　end
　　end
   context '登録ができないとき' do
　　　it 'nameが空では登録できない' do
      # nameが空では登録できないテストコードを記述
    　end
    　it 'emailが空では登録できない' do
      # emailが空では登録できないテストコードを記述
    　end　
　　end
  end
end
```
この記述で初学者が？となる部分を1つづつ確認していきます。

## Rspecで最初に覚える基本的なメソッド等
### describe
describeとは、テストコードのグループ分けを行うメソッドです。
「どの機能に対してのテストを行うか」をdescribeでグループ分けし、その中に各テストコードを記述します。
上記の場合だと`ユーザー新規登録`の部分にあたります。
`describe`につづく`do~end`の間に、さらにdescribeメソッドを記述することで、`入れ子構造`をとることもできます。

### context
特定の条件を分けたい場合に用います。contextはどのような「状況」を確認したいのかを書きます。
上記の場合だと`登録ができるとき`と`登録ができないとき`の部分にあたります。
contextまでの記述でユーザー新規登録で登録できるときと登録できないときをテストすることが分かります。

### it
describeメソッド同様に、グループ分けを行うメソッドです。
itの場合はより詳細に、「describeメソッドに記述した機能において、どのような状況のテストを行うか」を明記します。
contextよりもさらに詳細なものを記述します。
上記の場合だと`全ての項目が正しく入力されている時`、`nameが空では登録できない`、`emailが空では登録できない`の部分にあたります。
これで何をテストしているか一目瞭然ですね！

### example
exampleとは、itで分けたグループのことを指します。

それでは実際にテストを実装してみましょう！

# テストコードの実装
```rails:spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
   before do
     @user=User.new(name:"honda-gentuki",email:"abc@abc")
   end

   context '登録ができるとき' do
     it '全ての項目が正しく入力されている時' do
       expect(@user).to be_valid
　　　    end
　　  end
   context '登録ができないとき' do
　　    it 'nameが空では登録できない' do
       @user.name=""
       @uer.valid?
       expect(@user.errors.full_messages).to include("名前を入力してください")
    　 end
    　it 'emailが空では登録できない' do
       @user.email=""
       @uer.valid?
       expect(@user.errors.full_messages).to include("メールアドレスを入力してください")
    　end　
  end
end
```
# 上記記述の確認すべき点
### before do~end
これはコントローラーでいうbefore_actionと同様です！
もっと簡単に記述できる方法もあるので、電材の記述の中身は流し読みで結構です！

### expect
検証で得られた挙動が想定通りなのかを確認する構文のことです。
`expect().to matcher()`という雛形をもとにに、テストの内容に応じて引数やmatcherを随時変えて記述します。includeやeqなどがこれにあたります。includeは後で説明します。
`matcher`は、「expectの引数」と「想定した挙動」が一致しているかどうかを判断します。

### be_valid
インスタンスが正しく保存されるかどうか判断します
以上を踏まえると、以下の一文は、@userがちゃんとDBに保存されたかどうかを確認します。
```
expect(@user).to be_valid
```

### valid?
valid?は、バリデーションを実行させて、エラーがあるかどうかを判断するメソッドです。
エラーがない場合はtrueを、ある場合はfalseを返します。
これを実施しないと、errorsが発生しないため、エラー文を引き出すことができません。

### errors
errorsは、インスタンスにエラーを示す情報がある場合、その内容を返すメソッドです。
`full_messages`を付け加えることでは、エラーの内容から、エラーメッセージを配列として取り出します。

### include
includeは、「expectの引数」に「includeの引数」が含まれていることを確認するマッチャです。
つまりexpectの()の中身=includeの（）の中身になるように記述します。

**現在エラー分は日本語で記述されていますが、binding.pryで止めて確認してみてください！**
binding.pryは上記の記述で言うと@user.valid?の下に記述します。
使うためには`gem 'pry-rails'`をGemfileに記述して`bundle install`してから！

# 終わりに
本日はここまで。
あしたはコントローラーのテストです！
続き↓

https://qiita.com/hondano_gentuki/items/7f5a36c08b9785022d33
SwiftUIでdeviceのorientationを取得する

SwiftUIでdeviceのorientationを取得する方法
```
.onReceive(NotificationCenter.default.publisher(for:UIDevice.orientationDidChangeNotification)) { _ in
         guard let scene = UIApplication.shared.windows.last?.windowScene else { return }
         self.orientation = scene.interfaceOrientation
   }
```

 UIDevice.current.orientationで取得する[UIDeviceOrientation](https://developer.apple.com/documentation/uikit/uideviceorientation)は[faceUp](https://developer.apple.com/documentation/uikit/uideviceorientation/faceup)
, [faceDown](https://developer.apple.com/documentation/uikit/uideviceorientation/facedown)のz軸含めた6方向で、今回は4方向の取得をしたかったので、[UIInterfaceOrientation](https://developer.apple.com/documentation/uikit/uiinterfaceorientation)を取得している。
Nuxt.jsでb-table-input内のPlaceholderにfontawesomeを使いたいができない場合はどうするのか？

そこそこ調べましたが、たぶんplaceholderにfontawesome5以降のunicodeはnuxt.jsなどのSSRでは無理っぽいので、
bootstrapVueの公式に書いてある書き方を少し変えて書いてみました。
すごい簡単です。

```
<b-input-group>
 <b-input-group-prepend is-text>
　 <em class="fas fa-search fa-lg search-icon-color"></em>&nbsp;&nbsp;
　　</b-input-group-prepend>
　　<b-form-input type="search" placeholder="検索条件を入力してください" v-model="kensaku"></b-form-input>
</b-input-group>
```

スペースを開けたり、検索条件のv-model名は適宜適当なものを入力してください。

### 参考URL
[Icons | BootstrapVue - input-groups](https://bootstrap-vue.org/docs/icons#input-groups "Icons | BootstrapVue")


### 画像










![bootstrapVue](https://qiita-img.s3.ap-northeast-1.amazonaws.com/search_new.png "bootstrapVue")
AzureVMのシリーズのサイズ変更方法


# AzureVMのシリーズのサイズ変更方法(一例)
1.Azure PortalでVM「tyoukan」を選択。(vMのサイズは「Standard E8s_v4」)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/e7616e3e-8af1-5752-355a-370df18e53e0.png)


 
2.VMが実行中である場合、VMのサイズを変更すると、再起動される。
パブリックIPアドレスの割り当て設定が「動的」の場合にはIP アドレスが更新されるので、必要に応じて「静的」に設定する。
 
VMの「ネットワーク」 を選択し、「NICパブリックIP」で青い文字のIPアドレスをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/8597c5bc-78b4-8629-ce7a-bee7b5c2e111.png)

 
パブリックIPアドレスの「構成」を選択し、画面にある「IPアドレスの割り当て」で設定が「動的」から「静的」へ設定。
その後、「保存」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/7c6dfec4-06b8-79cf-a75e-0de771071e3c.png)

 
3.IP構成の変更が正常に保存した後、VMの 「サイズ」 を選択。
一例として、利用可能なサイズの一覧から新しいサイズ「E8s_v5」を選択し、 「サイズ変更」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/14a2cc1c-3d83-fd7e-2141-692141c30367.png)

 
4.VMを確認し、VMのサイズは「Standard E8s v5」になる。
パブリックIPアドレスも変更されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/03f28c96-a5e0-fc5a-50b4-1100d323e947.png)


 
# 注意事項とご参考
# 1. 注意事項
VMのサイズを変更する際に、以下の点について注意する方が良い。
 
・VMサイズを変更する際に、VMをホストしている物理サーバーがリソースを改めて割り当てる。
従って、仮想マシンが現在実行されている場合、そのサイズを変更すると、再起動される。
パブリックIPアドレスの割り当て設定が「動的」の場合には IP アドレスが 更新されるので、必要に応じて「静的」に設定する。 

・一時ディスクは更新されるので、永続的なデータは保管しないよう注意。
 
# 2.ご参考
 
・地域によって、VMのサイズが制限される（サポートされません）場合がある。
ポータル以外、下記のコマンドは、該当地域でVMのサイズが制限されているかどうかを確認できる。

``` 
az vm list-skus --location japanwest --size Standard_E --all --output table
```

実行結果は以下の通りで、「Standard_E」サイズは地域「japanwest」で制限されていないので利用可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386944/70aabc5d-65cb-8177-c15e-da7f606f6500.png)


# 公式サイト 
VMのサイズを変更する方法に関し、詳細な情報は下記の公開サイト。
 ＜参考＞[仮想マシンのサイズの変更](https://docs.microsoft.com/ja-jp/azure/virtual-machines/resize-vm?tabs=portal)

# 以上
【docker-compose】よく検索するコマンド集

# はじめに
こちらは、個人的な覚書です。
Dockerの再起動やログ調査に使うコマンド集です。

#### 下記の環境を想定しています
```
- docker-compose 3
```

# もくじ
 - 状態確認
 - 停止
 - 開始
 - 再起動
 - 作成や変更点の反映
 - 滅びの呪文
 - ログ閲覧
 - マイグレート
 - コンテナ内参照


## 状態確認
```
docker-compose ps
```
## 停止
```
docker-compose ps
```
## 開始
```
docker-compose start
```
## 再起動
```
docker-compose restart
```
## 作成や変更点の反映
```
docker-compose up --build -d
```
## 滅びの呪文
```
docker-compose down --rmi all --volumes --remove-orphans
```
## ログ閲覧
```
docker-compose logs -f --tail=10 my_container_name
```
## マイグレート
```
docker-compose exec django python manage.py migrate
```
## コンテナ内参照
```
docker-compose exec my_container_name bash
```

# おわりに
何回も検索するなーと思ったら追記していきます。
GithubActionにcurlコマンドでdispatchを起動

slackや単にcurlコマンドをトリガーにGithubActionのdispatchを実行したい時のコマンドを覚えられないので備忘録メモ

```
curl \
   -X POST \
   -H 'Authorization: token xxxxxxxxxxxx' \
   -H "Accept: application/vnd.github.v3+json" \
   https://api.github.com/repos/[ユーザー名]/[リポジトリ名]/actions/workflows/hello.yml/dispatches \
   -d '{"ref":"main"}'
```
参照元
[公式ドキュメント](https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event)

アプリ開発だと
slack(ターゲットを指定)⇨ci(githubactionなど)⇨fastlane⇨slack結果出力（成功 or 失敗）
が定番になっていると思う
M5Paper で Hello World

こちらを参考にしました。
[Arduino IDE environment - M5Paper](https://docs.m5stack.com/en/quick_start/m5paper/arduino)

実行結果
![IMG_20220602_131655.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/78e5354b-827b-e3f3-2a08-c6af82ad3bb0.jpeg)

プログラム

```text:hello_world.ino
#include <M5EPD.h>

M5EPD_Canvas canvas(&M5.EPD);

void setup(){
    M5.begin();
    M5.EPD.Clear(true);

    M5.RTC.begin();
    canvas.createCanvas(960, 540);
    canvas.setTextSize(5);

    int ypos[]= {30,110,190,270,350,430};
    int xx = 100;
    
    canvas.drawString("Hello World", xx, ypos[0]);
    canvas.drawString("Good Morning", xx, ypos[1]); 
    canvas.drawString("Good Afternoon", xx, ypos[2]);
    canvas.drawString("Good Evening", xx, ypos[3]);
    canvas.drawString("Good Night", xx, ypos[4]);
    canvas.drawString("Jun/5/2022 PM 13:05", xx+100, ypos[5]);
    canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
}

void loop(){
}
```

Arduino IDE からプログラムをアップロードしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/e2ca1ca8-b78a-a93a-b8f2-c3d09a12f785.png)

## 設定の手順 ##

ボードマネージャーの URL を加える

```text
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json
```

![m5paper-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/e71a42e3-fad4-ffd2-ff52-abf1acafa4f8.png)

ボードマネージャーで M5Stack を加える

![m5paper-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/c5402155-01ac-bee8-9fd4-d65e5fb9aa30.png)

M5EPD.h をインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/e2f4e327-c47a-0a85-01ad-32d5d7a94968.png)
【CSS】position:sticky が効かない時に確認すること【備忘録】

2022年6月、ついにIEのサポートが終了しますね。よっしゃー！！！！！
それに伴い、気軽に使えるようになるCSSプロパティがたくさんあります。
今回の記事は、その中のひとつ position:stickey についての備忘録です。

position:stickey は、少ないCSSの記述でスクロールに応じてページ要素を固定表示できる素敵CSSプロパティですよね！
とっても便利なのでよく使用するのですが、その度に忘れっぽい性格の私は
「あれ？うまく動作しないやんけ」と数分悩んで、
「そうだ！この記述書くの忘れてたわ！」と思い出すことが多々あるので、ここに書き残しておきます。

# ①top:0 がない
position:sticky を使用する上で基本中の基本なのですが、top:0 が抜けているとうまく動作しません。
```
.hoge{
　position:sticky
　top: 0
}
```

のように、セットで書きましょう。

# ②先祖要素にoverflow:visible（初期値）以外が設定されている
意外と忘れがち、overflow 問題。
先祖要素にoverflow: hidden とか scroll とか設定してるとstickyはうまく動作しません。
これよく忘れて引っ掛かる率ナンバーワンじゃないでしょうか？私がそうです。

先祖要素には、overflow:visible（初期値）のみ設定するようにしましょう。


# まとめ
今回はposition:sticky が効かない・うまく動かない時に確認する事項をまとめました。
基本的なことなんですけど、忘れがちですよね。

何らかの参考になれば幸いです。
読んでくださった皆様のコーディングライフに幸あれ～！
EfficientNetB0 - Error - AttributeError

#### Using EfficientNetB0 - Error - AttributeError: module 'keras.utils' has no attribute 'get_file' が出た時

 ```
Name: keras
Version: 2.6.0

Name: tensorflow-gpu
Version: 2.6.0
 ```

原因はおそらくモジュールのバージョン

 ```
import efficientnet.tfkeras as efn
base_model = efn.EfficientNetB0(input_shape = (224, 224, 3), include_top = False)
 ```
【JavaScript】JavaScriptのクラスとコンストラクタ

```JavaScript
class Person {
  constructor(name) {
    this.name = name;
  }
  introduce(num) {
    console.log(`Hello, my name is ${this.name}`);
    console.log(num);
  }
}

const otto = new Person('Otto');
otto.introduce(123);
```

# 結果
```
Hello, my name is Otto
123
```
とりあえずLeetCodeに手を出したい

<h1>さっそくマークダウン記法でこころ折れかけています。</h1>

練習だと思ってとりあえず少しだけマークダウンしながら書き進めたいけど、多分**すぐにやめます**。
まずは何事も質より量から（？）、慣れたら後で質を上げます。
というか続くんだろうかこの習慣。自信のなさにしか自信がありません。

<h2>今回の経緯</h2>

学業の方で節目を迎え、いよいよ就活に目を向ける必要が出てきました。
やはり早く動けばそれだけメリットはでかいだろうと思いながらサマーインターンの〆切を次々と逃して。。。
ESかいたりそんなのはストレスなので、いい感じにやってる感出しつつ好きなことをしよう。
そうLeetCodeに辿り着きました。

<h2>さっそく</h2>

~~LeetCodeに登録してさあスタート!~~
まず何から始めればいいの。。。
大学のComputer Scienceの授業をとったのはだいぶ前だしあんまり定着してない。。。
Problems？
よし、
Study Plan?
よし、
うーん、とりあえず復習もかねてData Structureから手を出そう！
となったので始めます。

<h2>将来的には</h2>
前にTwitterでみかけた
これ！

https://1kohei1.com/

の、これ！

https://docs.google.com/spreadsheets/d/1Y98QKaYPazWImEt1nA_ocpGNJ-yQjH1FAsVQhUQ7OTw/edit#gid=0

を制覇したいです。

<h2>つまずきひとつめ</h2>

え、言語なにでやる？？
これまでcommunity collegeでやってきたのはC++。個人的にもかなり好きだ。（素人）
でも編入先で主に扱うのはPythonらしい？？？
なにーーーーーー
よし、Pythonはほぼわからないからとりあえず**Pythonかこう**！

ん？Python?Python3？なにがちがうの。。。
（調べた）
なるほど、Python3の方が新しいバージョンだけど互換性などの問題で両方存在しているらしい。
新しく学ぶならPython3とじっちゃんが言ってたのでPython3をとりあえず書いてみます。

<h2>つまずきふたつめ</h2>

文法から何から何もわからないが？？？てか忘れたが？？？
2年前に友達の課題を代わりにやったっきり。Pythonとはお友達ではありませんでした。
はぁ。。。心折れるが。

そんなわけで一から知識を吸収しようと思い、いろんなサイトを見ながら頑張ろうと思ったのであった。
そしてその経過を逐一メモに残すことでのちの自分に役立てよう計画が発足。（コレ）

（ちなみにどのサービスでメモを取るかを調べて、また時間を費やしたのはご愛嬌）

いままでメモもとったことないしコードもずぶずぶの素人だしなにもかも投げ出したくなるよなそんな今日ですが、まずはやりましょう。
1日３問は最低ときたいよね。よし元気よく、Let's La Go~~~！

（次へ）
GCP(Google Cloud Platform)のFunctionsにおけるOPENCVの使い方

# GCPのFunctionsで開発をする際に困ったOPENCVの使い方メモ
## 1.本記事について
:::note 
本記事は著者がGCPでOPENCVを利用して画像処理をしようとしたときにもがいた先にたどり着いた解決方法を記したものです。
なお、社会人になりたてで、開発経験がまだ薄いので、間違ったりしてるところがあればご教授お願い致します。
:::
## 2.本記事で使ったもの
<dl>
  <dt>Functions</dt>
  <dd>GCPの中にあるツールの一つでサーバレス開発で使用する。

https://cloud.google.com/functions?hl=ja
</dd>
　<dt>storage</dt>
  <dd>GCPの中にあるツールの一つでデータの保管、トリガーとして利用したりできる。

https://cloud.google.com/storage?hl=ja

</dd>
  <dt>OPENCV</dt>
  <dd>よく使われる画像処理関係のオープンソース 

https://opencv.org/</dd>

  <dt>GoogleVisionAPI </dt>
  <dd>Googleの画像関係のAIツールが簡単に安く利用できるAPIツール 

https://cloud.google.com/vision?hl=ja</dd>
</dl>

## 3.今回はGCP（Google Cloud Platform）の中にある画像データにVison AI と OPENCV を利用して処理を加えて。違う所に保存するプログラムを例に進める
### 1.画像をstorageからダウンロード
https://cloud.google.com/storage/docs/downloading-objects?hl=ja#storage-download-object-python

こちらのurlを開き少しスクロールするとバケットからオブジェクトをダウンロードするというのが書かれていて、そこに出てきたプログラミング言語の候補の中から自分の使っている言語を選択
そこに書かれているソースコードをコピーしfunctionsの中に関数として入れれば画像をstorageからローカル環境にダウンロードできる（今回はpythonを選択）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641616/cc42dd55-1c81-f1e8-2e55-bfbe2bac258d.png)
正直、クラウドの勉強を始めたのがついこの二三か月でFunctionsでダウンロードしたものがどこに入っているのか全く分からなかったです。
ログを見たところ
```
File "/workspace/main.py", line 162,
```
どうやらmain.pyはworkspaceというフォルダの中に格納されてるみたい。
つまりダウンロードした画像はmain.pyと同じフォルダに格納されていると考えてよさそう。

:::note warn
ログを出力させる際
まだGCPを使いこなせていないのですがログをCLIを使ってみる際に注意すべきことをここにメモ

#### 1.ログを見る時
##### 1.リージョンについて
デフォルトでfunctionをコマンド等から生成した時は自動でUSリージョンになってしまいます。もし近いリージョンを利用したい場合はリージョンの指定が必要です。
今いるリージョンのログを見たいときは
```
gcloud functions logs read --region=asia-northeast2
```
の様にリージョンを指定する必要があります。
もし指定しないと自動的にUSリージョンのログが表示されます。
##### 2.デメリット
1.今直したfunctionの内容が反映されてないと勘違いする危険性
2.何度もfunctionをデプロイして無駄なタイムロス

ログは各リージョンごとに管理されているようです。

#### 2.ログの見方
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641616/349e82b8-908c-7ddb-dc75-661cecd01ac7.png)
vs等とは違い、ログは上が最も新しく、下に行けば行くほど古いログになります。
一つの関数のみを実行している場合でしたら

```
gcloud functions logs read --limit 3
```
と制限をつければ間違えて何個も前のログを見なくても済みます。
:::
### 2.画像OPENCV(cv2.imread)を使って読み込み(cv2.imwrite)を利用して同じフォルダに保存
1の説明にあるように1でダウンロードした画像はworkspaceというフォルダにダウンロードされています。
読み込み方法としては普段同じフォルダに画像を保存した時と同じように

```
img = cv2.imread(file_name) #filenameには画像のファイル名を文字列で入力
```

これ以降は普段の様にOPENCVで処理すればいい

```
cv2.imwrite(file_name, image_data) #image_dataには最終的な処理したデータを代入
```

### 3.画像をstorageへアップロード
手順はダウンロード時とほぼ同じ

https://cloud.google.com/storage/docs/uploading-objects?hl=ja#storage-upload-object-python

## 4.最後に
クラウドでプログラムを構築してデプロイするのにまだまだ不慣れですがこれからより知識と技術を蓄えその都度記事ももっといい書き方があれば更新します。
save!とは？

# save!とは
・モデル保存させるもの
・既存のデータベースは更新される
# 特徴
## save!は常にバリデーションが走っている。
・常にバリデーションを走らせている。
・保存に失敗したら"ActiveRecord::REcordINvalid"が発生する。そしてレコードが保存されない。
### しかし例外も
・validate: falseを指定するとsave!のバリデーションをスキップすることが可能
## 現在時間も保存する
・デフォルトによると"save!"は現在時刻を"updated_at/updated_on"属性もを設定する。

### 例外も
・"touch: false"を指定すればこれらのタイムスタンプは更新されない。
### :touch
:touchオプションをtrueに設定すると、そのオブジェクトがsaveまたはdestroyされたときに、関連付けられたオブジェクトのupdated_atタイムスタンプやupdated_onタイムスタンプが常に現在の時刻に設定されます

出典 https://railsguides.jp/association_basics.html

# save!に関するコールバックの一連
### コールバック
コンピュータプログラム中で、ある関数などを呼び出す際に別の関数などを途中で実行するよう指定する手法のこと。

出典　https://ewords.jp/w/%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF.html

##### パーセントエンコーディング（書き方）
コールバックを書くと
%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%となるのかな？

もし"before_*"コールバックのいくつかが:abortを投げる(コールバックの停止)と
そのアクションはキャンセルされる。そしてsave!メソッドは例外"ActiveRecord::RecordNotSaved"を発生させる。

readonlyと印を付けられた属性は、もしレコードが更新される場合、静かに無視されます。

出典 見つけられなかった。
参考　deepL,Weblio

## :abortを投げるとは？　検索してみた。
めぼしいサイトでサイト内の文字検索をかけてみたらそれっぽい説明があった。

### 実行を停止させる
あなたがモデルの新しいコールバックを登録し始めるとして彼ら(コールバック)はキューに入れられます。
このキューは登録されたコールバックそして実行されるためのデータベース操作の全てを含みます。

#### キュー（queue)待ち行列
キューとは、最も基本的なデータ構造の一つで、要素を入ってきた順に一列に並べ、先に入れた要素から順に取り出すという規則で出し入れを行うもの。順番を待つ人の行列と同じ仕組みであるため「待ち行列」とも訳される。

出典　https://e-words.jp/w/%E3%82%AD%E3%83%A5%E3%83%BC.html#:~:text=%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%A8%E3%81%AF%E3%80%81%E6%9C%80%E3%82%82%E5%9F%BA%E6%9C%AC,%E8%A1%8C%E5%88%97%E3%80%8D%E3%81%A8%E3%82%82%E8%A8%B3%E3%81%95%E3%82%8C%E3%82%8B%E3%80%82

全体のコールバックチェーンは処理の中で包まれる。
もしいくつかのコールバックが例外が発生したら実行のチェーンが停止の状態になり、ロールバックが発行される。意図的にチェーンを停止させるには
throw :abortがある。
”ActiveRecord ;:Rollback"か"ActiveRecord::RecordInvalid"以外の例外は、Railsによってコールバックチェーンが停止された後、再び発生します。
#### 思ったこと
”ActiveRecord ;:Rollback"か"ActiveRecord::RecordInvalid"以外に不備があった場合かな？

"ActiveRecord::Rollback"か"ActiveRecord::RecordInvalid"以外の一つ例外が発生すると、saveとupdateのようなメソッド達（標準的にtrueかfalseを返そうとする）が例外が発生することを予期していないコードを破壊するかもしれない。

出典 https://guides.rubyonrails.org/active_record_callbacks.html
使用サイト deepL,weblio
#### 思ったこと
saveとupdateが予期しない例外が発生するとコードが破壊されることがあるのか。
なるほどそれでsave!やupdate！が存在するのか。

throw :abortは停止させるために使うのか。


# 思ったこと
和訳しながら理解することは大変だな。
少し理解できたからよかった。
【AWS】AWS ソリューションアーキテクトアソシエイト(SAA) 合格までの勉強方法と振り返り

# はじめに
AWSの資格である『AWSソリューションアーキテクトアソシエイト(AWS SAA)』試験に合格したため、勉強方法などを簡単に書きます。

# まずやるべきこと

勉強方法などを考える前にまずやるべきは、受験日を決めることです。
目標達成までの期限を決めることで、勉強の計画が立てやすくなります。
試験日は何回か変更することができるので、
まずは試験日を決めてそれからいつまでに何を勉強するかを決めると良いと思います。


# どんな教材で勉強したか？ (50～60時間くらい)
①[【2022年版】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座](https://www.udemy.com/course/aws-associate/)
　→85%くらいまで進めて、テスト用の勉強 (②以降) に切り替えました。

②[AWS認定ソリューションアーキテクト アソシエイト試験：短期突破講座（300問の演習問題）](https://www.udemy.com/course/aws-uoyc/)
　→本番レベルの模試1650問を分析し、必要最低限の内容をまとめた講座です。

③[AWS認定ソリューションアーキテクト アソシエイト試験：短期突破講座（300問の演習問題）](https://www.udemy.com/course/aws-knan/)
　→私は正答率80%～90%出せるレベルで合格出来ました。合格レベルの参考になればと思います。

④[ななななんと！AWS認定の模擬試験が無料になりました！！](https://dev.classmethod.jp/articles/new-aws-official-practice-questions/)
　→③完了後に公式模試(20問程度)を進めました。
上記サイトがAWS Skill Builderへのアカウント登録～模擬試験受検までの流れが紹介されていていい感じです。

⑤[AWS サービス別資料](https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)
　→PDFを閲覧して最終確認を進めました。

# 試験を受けた感想
本番では試験時間(130分)ギリギリまで見直しが必要だったため、試験と模試のギャップを感じました。
合格するには、「AWSのサービスをどれだけ暗記しているか？」よりも、
「問題文をよく読んで、複数AWSサービスを組み合わせた構成のイメージができる力」が必要だと思います。

もしAWSに興味があれば、是非SAAの資格を取得してみてください！

※現行試験の最終受験日は 2022 年 8 月 29 日のため、受験を考えている方はこの日までに受けたほうが教材なども充実していると思います。
詳しくは　https://aws.amazon.com/jp/certification/coming-soon/
OCI Windows VMでオーディオ・サービスを有効にする方法

このシリーズの他の記事は、[オラクル・クラウドの個人ブログ一覧 ](https://qiita.com/letian/items/10152a4fec813c1b7d98)からご覧いただけます。
# 初めに
OCI(Oracle Cloud Infrastructure)でWindowインスタンスを作成した後、タスクバーから分かるように、オーディオ・サービスはデフォルトで<font color=blue>無効</font>となっています。 音声を聞きたい場合、有効にする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/8b7f5698-ea5e-38df-52de-2e9afc65b8cb.png)

__検証環境__
OS: Windows Server 2019 Standard

__設定方法__
以下の２つ方法を紹介します。いずれも簡単です。

[1. オーディオ・サービスを手動で有効にする](#1-オーディオサービスを手動で有効にする)
[2. Cloud-init スクリプト](#2-cloud-init-スクリプト)

# 1. オーディオ・サービスを手動で有効にする
RDPでインスタンスにログインし、スピーカー・アイコンを右クリックして、「サウンド」を選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/f69b9c3f-b089-3e6d-58b8-f8234a24bd88.png", width="400">

「はい」を押してオーディオ・サービスを有効にします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/02c12584-bdc7-fb7a-34e0-b23f546a659a.png", width="400">

サウンド設定画面が表示されます。サウンドを選択し、テストを実施してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/84934328-1ff3-8c3f-05af-30028521ca35.png)

オーディオ・サービスを有効にすると、スピーカー・アイコンの「X」マークが消えます。通常どおり、スピーカー・アイコンを左クリックして音量を調整できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/c12163b8-4635-a77c-f93d-faf8c15ab63e.png", width="400">

# 2. Cloud-init スクリプト
PowerShellスクリプトを使用して、1行のコマンドだけでオーディオ・サービスを有効にできます。
`net start audiosrv`

Windowsインスタンスの作成時に、cloud-initスクリプトにこの行を追加すると、起動後にオーディオ・サービスが自動的に有効化されます。

__注意__
PowerShellの場合、Sysnativeパラメーターは必須であり、<font color=blue>最初の行</font>にある必要があります。
`#ps1_sysnative`

インスタンス作成時に「<font color=blue>詳細オプションを表示</font>」をクリックし、次のようにCloud-initスクリプトを入力します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/d12c5e41-96a6-e1b9-2ec9-b32abf9e2f75.png", width="600">

以上です。

----
__関連記事__
[OCI Cloud-initスクリプト](https://qiita.com/letian/items/10152a4fec813c1b7d98#11-cloud-init%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88)
pip install fasttext できない

fastText は単語埋め込みやテキスト分類のための定番NLPツールです。
しかし導入でハマるという声をよく聞きます。

`pip install fasttext` しようとすると`error: command 'gcc' failed with exit status 1` のようなエラーを吐いてインストールに失敗する場合があります。

リポジトリをクローンしてインストールしたり conda を使うといった方法でインストール自体は可能なのですが、 poetry や requirements.txt でシンプルに管理したかったり(Dockerを使う場合は) Dockerfile にごちゃごちゃ書きたくなかったりするので、pip 一発で入れられたほうが嬉しいシーンがあります。


## 原因
インストールに必要な GCC のバージョンが古い(or 入っていない)ことが原因です。fastText ではビルド時に C++14 の機能を使うため、GCC 6.1 以降が必要になります。
```
gcc --version
```
で6.1 未満の場合やそもそもコマンドが見つからない場合、アップデート/インストールしましょう。

centos7 には GCC 4.x が入っていたり, MacOS は初期状態で C(++)コンパイラが無効なのでこの現象に遭遇するようです。

### CentOS
centos の人は下記のコマンドでより新しい gcc が利用できます。
```
yum install centos-release-scl
yum install devtoolset-8
scl enable devtoolset-8 -- bash
```

### MacOS
MacOS Mojave以降で、Cコンパイラが未インストールの場合、`gcc --version ` すると
```
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```
のようなエラーが出るので、ターミナルで
```
xcode-select --install
```
をして開発者ツールをインストールし、 gcc, g++ のパスが通るようにしてください。



## 補足
- pip でのインストールではこのようなエラーが生じる場合があるので、リポジトリを clone してインストールする方法を推奨する記事をよく見ます。
- docker にインストールする場合にもコンパイラが必要になります。slim イメージだと gcc が入っていなかったりするので注意してください。
- 同じ現象でハマっている人をよく見るので公式ドキュメントのインストールガイドい書いておいてほしいですね......

## 参考
以前は そもそも pip でインストールすること自体に不具合があったようですが、こちらの方は fasttext v0.9 で修正されています。
[fastTextをpipインストールしてはいけない話（2019/4/11現在、pyenv環境)](https://qiita.com/YuukiMiyoshi/items/c862ab8b5796ee717a3d)

言及されている Issue
https://github.com/facebookresearch/fastText/issues/1052
rails でTypeError  can't convert ActiveSupport::TimeWithZone into an exact numberで途方に暮れたら

rails6.1に上げる設定をしていた時に出たエラーですが、appとかconfigの下のファイルがダンプに出て来ません。
てっきり6.1の
ActiveSupport.utc_to_local_returns_utc_offset_times
関係かと思いきや、同時に調整しようとしたcookieの設定で
Rails.application.config.session_store
（略）
expires: 20.years.from_now
とすべきところを
expire_after: 20.years.from_now
としていたのが原因でした。
この設定ファイルでエラー、とは出ないので、戻すまで気がつきませんでした。
こんなやらかしは多分自分だけとは思いますが、検索しても全然ヒントがなく、しばらく途方に暮れたので恥を晒しておきます。
PrometheusのConsoleでちょっとしたHTMLを配信する

# PrometheusのConsole機能とは

PrometheusにはConsoleという機能があり、テンプレートをもとに任意のHTMLを配信することができます。

https://prometheus.io/docs/visualization/consoles/


このConsolesではPrometheusで定義済みのグラフ描画のライブラリなどを利用することができ、よく見るメトリクスのグラフの画面を提供することができます。

通常このような用途ではGrafanaなどを用いる事が多いですが、簡易的なものとしては有用な場面もあるでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/6d6e036c-6130-e82d-b700-a30cf6d60a72.png)

まぁ本筋的な使い方は上記のドキュメントを見てください。

今回は、この機能をちょっと違う使い道で活用する方法を紹介します。

# 開発ツールのリンク集を配信してみる

任意のHTMLが配信できるということで、グラフではなく、開発ツールのリンク集のようなものもここで配信できるなと思い、試してみました。

## index.htmlがあるとnavarにリンクが表示される

Console機能を有効にするにはPrometheusの起動時の引数に `--web.console.template=<テンプレートのあるディレクトリ>`を指定する必要があります。

このディレクトリの中に`index.html`というファイルが存在すると、PrometuesのWeb UIの上部に「Consoles」というリンクが出現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/d741d44f-a852-be56-8dc1-ae084c3d1ca4.png)

## Prometeusのライブラリを一部使いつつリンク集を作ってみる

ヘッダのデザインなどはPrometheusのライブラリを使いたいので、うまいことこれを流用してリンク集を作ってみます。

```ｈｔｍｌ
<html>
<head>
{{ template "prom_console_head" }}
</head>
<body>

{{ template "navbar" . }}
<div class="prom_console_content">
  <div class="container-fluid">

<h1>運用ツールリンク集</h1>

<li>Alertmanager</li>
<ul>
  <li>
    <a href="あどれす">あどれす</a>
  </li>
</ul>
<li>Grafana</li>
<ul>
  <li>
    <a href="あどれす">あどれす</a>
  </li>

</ul>

</div>
</div>
</body>
</html>
```

こんなファイルを用意します。

Console機能用のライブラリはPrometheusのコマンドライン引数`--web.console.libraries`でパスを指定する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/a129906f-77c4-1db9-ceee-8eda6b9d9f4a.png)

それっぽいものができました。

# まとめ

PrometheusのConsole機能は、簡易的なグラフ表示を提供するのに便利です。
また、任意のHTMLを配信できるので、運用に必要なリンク集や、JavaScriptを使ったWebアプリケーションのようなものを配信する事もできそうです。

あくまで簡易機能なので、本格的に使う際はGrafanaや、ちゃんとしたWebサーバを利用することを検討するのが良いと思います。
Transformersから始めるAI(2022.6.2)

# 前置き
G検定をまとめるための記事の一つです。私のまとめ方の癖で「気になる物をいくつか上げて、流れを作りながら細かく見ていく」という事をしています。とりあえず、少しは参考になるくらいの粒度で記事を上げてはいるつもりです。随時、更新する予定ですので多めに見て頂ければ幸いです。
# 概要：近年(2022)はAttention機構が良く使われていますね
先日、「[きゅうりの仕分けから始めるAI](https://qiita.com/items/55d245768be875e316b2)」という記事を書かせて頂きました。ここで紹介したきゅうり農家では物体検出を使っていました。ディープラーニングの構造も様々ですが、大きく分けてCNN, RNN, Attentionに分けられると考えています。今回はいろんな場面で使われているTransformerについて見ていきたいと思います。
# Transformerの構造
全体の構造は以下の様になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/f50bf407-0621-9ecb-fef1-41fda23fc262.png)
ここで、更にEncoderとDecoderを定めておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/ff133d71-1d05-a93d-3cf5-97563609275d.png)
Encoderの構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/8b0ada22-78a8-7031-d7cd-2ca1854edb9f.png)
Decoderの構造
(参考：[Ashishら(2017),"Attention Is All You Need",arXiv](https://arxiv.org/pdf/1706.03762.pdf))

# データの流れ
流れとしては、3つに分けました
1. Encoderの流れ
Input=>Input Embedding => Positional Encoding => Encoder => Decoder
1. Decoderの流れ
Outputs => Output Embedding => Decoder
1. EncoderとDecoderが合流してからの流れ
Decoder => Linear => Softmax => Output Probabilities

# Transformersで使用される要素技術
Attension, Dot-Product Attention, Multiplicative Attention, Source-Target-Attention, Self-Attention, Scaled Dot-Product Attention, Multi-Head Attention, Position-wise Feed-Forward Network, Positional Encoding

# 参考

https://youtu.be/50XvMaWhiTY

https://youtu.be/g5DSLeJozdw

https://deeplearning.hatenablog.com/entry/transformer

https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part3.html

[Ashishら(2017),"Attention Is All You Need", arXiv](https://arxiv.org/pdf/1706.03762.pdf)
selenium から Twitter にログインして画像投稿

TwitterにPythonからログインして画像を伴って投稿する方法のメモ。
AlmaLinux, Chrom, Mac で確認。

Python 3.6.8
Google Chrome 98.0.4758.102, 96.0.4664.110, 102.0.5005.61
selenium 3.141.0


[selenium から Twitter にログインして投稿](https://qiita.com/katafuchix/items/8d4c2bed73d79ba072d9) の続編

## 投稿

「input type=file」　要素に投稿したい画像を指定

```python
def send_tweet(text):
    # テキスト入力
    element_text = driver.find_element_by_class_name("notranslate")
    element_text.click()
    element_text.send_keys(text)

    # 画像選択 & アップロード
    image_file_path = "画像ファイルをフルパスで"
    image = glob.glob(image_file_path)
    driver.find_element_by_xpath('//input[@type="file"]').send_keys(image)

    # ツイートボタン
    tweet_button = driver.find_element_by_xpath('//*[@data-testid="tweetButtonInline"]')
    driver.execute_script("arguments[0].click();", tweet_button)
```

複数の画像を一度に投稿したい場合はsend_keysを複数回実行する
AWS Cloud9でPython環境構築　※編集中

本記事はAWS Cloud9の学習を始めた筆者が、備忘録として残したい内容を記述します。

■AWSアカウント作成
リンクよりAWSアカウント作成を行う。
https://aws.amazon.com/jp/register-flow/

■Cloud9環境作成
AWSマネジメントコンソールにサインインし、画面上部より「cloud9」を検索する。


「Create environment」をクリック


設定を確認し「Create environment」をクリック


■Pythonをアップデート
既定のバージョンが古いのでアップデートを実施。
既定のバージョン：Python 3.7.10

アップデートは以下の記事を参考にした。
(https://ponsuke-tarou.hatenablog.com/entry/2021/02/22/174431)

(Pythonのバージョンを3.10.4にアップデートは調査中)

■Python実行
・コマンドラインから実行
　1.コマンドラインに「python」を打ち込みEnter
　2.「>>>」が表示されたらOK
　3.試しに「print('Hello, World!')」と入力し実行
　4.終了時は、ctrl+d

・ファイルから実行
　1.Cloud9の作業フォルダに「ファイル名.py」を作成。
　2.ファイルを開き、「print('Hello, World!')」と入力し保存。
　3.コマンドラインに「python ファイル名.py」を打ち込みEnter
Spring Securityでconfigure(auth: AuthenticationManagerBuilder)メソッドをアップデートする

## この記事を書いたきっかけ
先日(2022年5月26日)、Spring Securityに脆弱性が発見されました（[ソースはこちら](https://jvn.jp/vu/JVNVU96405576/)）。
幸いにも、脆弱性が見つかった"RegexRequestMatcher"を使用してはいませんでしたが、せっかくの機会なのでSpring Securityをアップデートしようと決意しました。
しかし！！今まで継承していた"WebSecurityConfigurerAdapter"がdeprecatedになってしまいました。
[偉大なるQiita先輩](https://qiita.com/suke_masa/items/908805dd45df08ba28d8)や[本家のブログ](https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter)を参考に移行を試みましたが、新しい書き方がどうしてもわからない部分があり、数時間悪戦苦闘した結果、ようやく書き方がわかったのでまとめます。

## ハマりポイント
問題となったのは以下の部分。
認証時のユーザー名・パスワード・ロールをDBに収納するような設計にしており、そのためconfigure(auth: AuthenticationManagerBuilder)のauth.jdbcAuthentication()を呼び出していまいました。これをどう移行すればいいのかわからなかった。
```kotlin:SecurityConfig.kt

class SecurityConfig： WebSecurityConfigurerAdapter {

　　　　　　　　@Bean
    fun passwordEncoder(): PasswordEncoder? {
        return BCryptPasswordEncoder()
    }

    @Autowired
    lateinit var dataSource: DataSource

    companion object {
        // ユーザーIDとパスワードを取得するSQL文
        private const val USER_SQL = ("SELECT user_name, password, true FROM login_spring WHERE user_name = ?")

        // ユーザーのロールを取得するSQL文
        private const val ROLE_SQL = ("SELECT user_name, role FROM login_spring WHERE user_name = ?")
    }

    //--省略--
　　　　　　　//↓ハマりポイント

    override fun configure(auth: AuthenticationManagerBuilder) {
        //ログイン処理時のユーザー情報をDBから取得する
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(Companion.USER_SQL)
                .authoritiesByUsernameQuery(Companion.ROLE_SQL)
                .passwordEncoder(passwordEncoder())
    }
}
```

## どう直したか
下のように直したら動きました。


```kotlin:SecurityConfig.kt

class SecurityConfig {

　　　　　　　　@Bean
    fun passwordEncoder(): PasswordEncoder? {
        return BCryptPasswordEncoder()
    }

    @Autowired
    lateinit var dataSource: DataSource

    companion object {
        // ユーザーIDとパスワードを取得するSQL文
        private const val USER_SQL = ("SELECT user_name, password, true FROM login_spring WHERE user_name = ?")

        // ユーザーのロールを取得するSQL文
        private const val ROLE_SQL = ("SELECT user_name, role FROM login_spring WHERE user_name = ?")
    }

    //--省略--

    @Bean
    fun users(): UserDetailsManager? {
        val users = JdbcUserDetailsManager(dataSource)
        users.setUsersByUsernameQuery(Companion.USER_SQL)
        users.setAuthoritiesByUsernameQuery(Companion.ROLE_SQL)
        return users
    }
}
```

公式ブログを見る限り、JdbcUserDetailsManagerクラスをインスタンス化して、それにユーザーを加えて返却すればよいみたいです。
ちなみに、setUsersByUsernameQueryとsetAuthoritiesByUsernameQueryはJdbcDaoImplというクラスから継承したメソッドということらしいです（[Springドキュメントより](https://spring.pleiades.io/spring-security/site/docs/current/api/org/springframework/security/provisioning/JdbcUserDetailsManager.html)）

ここ違うよ〜、などありましたら、コメントください。
Githubの自分のリポジトリ一覧をターミナルに表示する

# はじめに

Githubにいろいろリポジトリを登録していくと、次第に自分がどんな名前のリポジトリを作ったか忘れてしまうことがある。

## gh コマンドを使う

https://github.com/cli/cli

```
gh repo list
```

ただし、APIの制限でデフォルトでは30個までしかとってきてくれないので、`-L` もしくは `--limit` を自分のリポジトリの数とだいたい同じ数だけ指定しておいたほうが便利だ。
あとは grep するなり、bat に流し込むなりすればよい。

```
gh repo list --limit 200 | grep hoge
gh repo list --limit 200 | bat -
```

プライベートリポジトリだけ表示したい場合は、`--visibility` を設定する。

```
gh repo list --visibility private
```

そのほか便利なオプションが揃っている。

```
      --archived            Show only archived repositories
      --fork                Show only forks
  -q, --jq expression       Filter JSON output using a jq expression
      --json fields         Output JSON with the specified fields
  -l, --language string     Filter by primary coding language
  -L, --limit int           Maximum number of repositories to list (default 30)
      --no-archived         Omit archived repositories
      --source              Show only non-forks
  -t, --template string     Format JSON output using a Go template
      --topic string        Filter by topic
      --visibility string   Filter by repository visibility: {public|private|internal}
```

ちなみに、自分以外の人のリポジトリでも表示できる。（Publicリポジトリのみ）

```
gh repo list torvalds
```

この記事は以上です。
Grafanaが乱立して一見どれかわからない問題に対応する

# Grafanaが乱立するとは？

[Grafana](https://grafana.com/)はPrometheusなどと組み合わせてメトリクスを可視化することができる便利なツールで、デファクトスタンダードと言っても良いものです。

本番環境のメトリクスの可視化はもちろん、ステージング、開発環境にも存在するのはふつうの事です。

さて、これらのGrafana, Web UIを見てもどれも似通っていて、上記に書いたように複数のGrafanaが存在する環境において、どれを見ているのかわからなくなることがあります。

# ホームダッシュボードの名前をアドホックに変更する

解決策が無数にありますが、なるべく簡単なもの・・ということで・・

`/usr/share/grafana/public/dashboards/home.json` にデフォルトのホームダッシュボードがあるので、これの名前をサクッと変えてみます

```bash
cat /usr/share/grafana/public/dashboards/home.json|sed -e 's/"title": "Home"/"title": "inajob"/'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/f5f0b41b-c6dd-0fcb-fbe8-7ca47981ba05.png)

できました！

もっとちゃんとやりたい場合は下記を参考にホームダッシュボード自体を新しく作って、読み込ませるのが良いと思います。

https://grafana.com/docs/grafana/latest/administration/preferences/change-home-dashboard/
WSL上のKali Linuxでsudo apt-get updateができない ※

### 環境
- powershellで下記コマンドを実行してインストールしたもの
  `wsl --install --distribution kali-linux`
- Kali Linuxのターミナルで確認(`cat /etc/os-release`)した内容は下記の通り
```
PRETTY_NAME="Kali GNU/Linux Rolling"
NAME="Kali GNU/Linux"
ID=kali
VERSION="2019.2"
VERSION_ID="2019.2"
ID_LIKE=debian
ANSI_COLOR="1;31"
HOME_URL="https://www.kali.org/"
SUPPORT_URL="https://forums.kali.org/"
BUG_REPORT_URL="https://bugs.kali.org/"
```

### 事象
題名の通り、WSL上のKali Linuxで`sudo apt-get update`が失敗する。
コマンドを実行すると、以下のような内容が出力された。

```
Get:1 http://linux3.yz.yamagata-u.ac.jp/pub/linux/kali kali-rolling InRelease [30.6 kB]
Err:1 http://linux3.yz.yamagata-u.ac.jp/pub/linux/kali kali-rolling InRelease
  The following signatures were invalid: EXPKEYSIG ED444FF07D8D0BF6 Kali Linux Repository <devel@kali.org>
Fetched 30.6 kB in 1s (48.0 kB/s)
Reading package lists... Done
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://linux3.yz.yamagata-u.ac.jp/pub/linux/kali kali-rolling InRelease: The following signatures were invalid: EXPKEYSIG ED444FF07D8D0BF6 Kali Linux Repository <devel@kali.org>
W: Failed to fetch http://http.kali.org/kali/dists/kali-rolling/InRelease  The following signatures were invalid: EXPKEYSIG ED444FF07D8D0BF6 Kali Linux Repository <devel@kali.org>
W: Some index files failed to download. They have been ignored, or old ones used instead.
```

### 原因
```
W: Failed to fetch http://http.kali.org/kali/dists/kali-rolling/InRelease  The following signatures were invalid: EXPKEYSIG ED444FF07D8D0BF6 Kali Linux Repository
```
で検索をかけたところ、[このサイト](https://superuser.com/questions/1644520/apt-get-update-issue-in-kali)を発見。<br>

そのサイトでは、以下のような説明がされていた。
```
The Kali archive keys appear to be missing and cannot be installed using apt-add key
since it relies on GnuPG, which cannot be installed using apt, since the signatures cannot be verified.
```
アーカイブキーなるものがないので、apt キーを使ってインストールできないみたい？<br>
GnuPGに依存しているため....？よくわからない....　★要調査★

### 解決策
上記のサイトを参考に
```
wget http://http.kali.org/kali/pool/main/k/kali-archive-keyring/kali-archive-keyring_2022.1_all.deb

sudo dpkg -i kali-archive-keyring_2022.1_all.deb
```
を実行することで`sudo apt-get update`が成功するようになった。<br>
※kali-archive-keyring_2022.1_all.debのバージョンは変更されている可能性が高いので注意したい。