OmniAICreator/Qiita-1.07M huggingface dataset:
MySQLの簡単なサンプルデータを作成する方法

# 概要
デモサイト構築やDBの正規化について学習する上で、作り込み過ぎない（第3正規形程度）、なるべく最小限の入力情報でデータ登録ができるようサンプルデータ環境を作成方法について考えてみました。

# バージョン
MySQL7.4

# テーブル一覧
* ordersテーブル（注文情報）


| colmun | type | option |
|:---|:---|:---|
| id | INT | PK / NN / AI |
| stationary_id | INT |  |
| factory_id | INT |  |
| description | VARCHAR|  |
| volume | INT |  |
| total_price | INT |  |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP |

* factoryテーブル（生産工場マスタ）

| colmun | type | option |
|:---|:---|:---|
| id | INT | PK / NN / AI |
| name | VARCHAR|  |
| price | INT |  |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP |


* stationaryテーブル（商品情報マスタ）

| colmun | type | option |
|:---|:---|:---|
| id | INT | PK / NN / AI |
| name | VARCHAR|  |
| price | INT |  |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP |



# テーブル作成・データ登録
```

-- 製品工場マスタテーブル作成、データ登録
CREATE TABLE factory (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(30),
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO factory(name) VALUES ('京都府');
INSERT INTO factory(name) VALUES ('大阪府');
INSERT INTO factory(name) VALUES ('兵庫県');
INSERT INTO factory(name) VALUES ('滋賀県');
INSERT INTO factory(name) VALUES ('奈良県');


-- 商品情報マスタテーブル作成、データ登録
CREATE TABLE stationary (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(30),
  price INT UNSIGNED,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO stationary(name) VALUES ('消しゴム');
INSERT INTO stationary(name) VALUES ('鉛筆');
INSERT INTO stationary(name) VALUES ('シャーペン');
INSERT INTO stationary(name) VALUES ('定規');
INSERT INTO stationary(name) VALUES ('修正テープ');
INSERT INTO stationary(name) VALUES ('クリップ');

-- 商品情報マスタ情報更新
UPDATE stationary SET
  price = CEIL(RAND() * 15) * 100 -- 単価
;

-- 注文情報テーブル作成、データ登録
CREATE TABLE orders (
  id INT PRIMARY KEY AUTO_INCREMENT,
  stationary_id INT,
  factory_id INT,
  description VARCHAR(30),
  volume INT,
  total_price INT UNSIGNED,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO items () VALUES (); -- 1件
INSERT INTO items (id) SELECT 0 FROM items; -- 2件
INSERT INTO items (id) SELECT 0 FROM items; -- 4件
INSERT INTO items (id) SELECT 0 FROM items; -- 8件
INSERT INTO items (id) SELECT 0 FROM items; -- 16件
INSERT INTO items (id) SELECT 0 FROM items; -- 32件登録

-- 注文情報更新１
-- FKとしてそれぞれのPKの最大値を上限としたランダムな値をセット
UPDATE orders SET
  stationary_id = CEIL(RAND() * (SELECT MAX(stationary.id) from stationary)),
  factory_id = CEIL(RAND() * (SELECT MAX(factory.id) from factory)),
  volume = CEIL(RAND() * 10)
;

-- 注文情報更新２
-- 商品説明、価格合計を生成してセット
UPDATE orders SET
  description = CONCAT(
    (SELECT name FROM factory WHERE factory.id = orders.factory_id),
    "の",
    (SELECT name FROM stationary WHERE stationary.id = orders.stationary_id)
  ),
  total_price = (
    (SELECT price FROM stationary WHERE stationary.id = orders.stationary_id)
    *
    volume
  )
;
```
Gitでコミットする前にRubocopを自動で実行する方法

# はじめに
RubocopのCIを導入しているRuby開発の現場ではRubocopの実行を忘れてpushし、
CIで弾かれてから「忘れてたぁぁ」と言うシーンをよく見ます。
はい、私もそんなことによく出くわしている一人です。
そこでcommitコマンドの実行と同時に毎回Rubocopを回してやろうと思い,
動くものができたので記事にしました。

**※環境**
OS => macOS Big Sur
シェル　=> zsh
# 結論、以下の手順で設定を行えばコミット時に毎回Rubocopが実行される!!
**１. 「git init」したディレクトリ内の「.git/hooks」に移動**
**２. pre-commitファイルを作成**
**３. 以下の内容をpre-commitファイルに記述する**
``` pre-commit
# 対象のファイル名を取得
function getfilenames() {
  git diff --cached --name-only --diff-filter=AM | grep '\.rb$'
}

# NGフラグ
ISNG=0
if getfilenames; then
  echo '---Rubocopの自動修正---'
  getfilenames | xargs bundle exec rubocop -a 
  # 変更があった場合はAddする
  git diff --name-only　--diff-filter=AM | grep '\.rb$' | xargs git add
  echo '---Rubocopで警告がないかチェック---'
  getfilenames | xargs bundle exec rubocop --fail-level C --display-only-fail-level-offenses
  # 警告が出たかどうかのチェック(直前の処理の実行結果がNGの場合は1が取得できる。この場合はrubocopのチェック機能の実行結果)
  if [ $? -gt 0 ]; then
    echo '---RubocopチェックNG---'
    ISNG=1
  fi
fi

# NGの場合はコミットをしない
if [ $ISNG = 1 ]; then
  echo '---Rubocop解析にNGがあったためコミットできませんでした---'
  exit 1
else
  echo '---Rubocop解析OK:コミットします---'
fi
```
**４. rubyファイルを修正してコミットしてみよう!!!(完)**
以上であなたの上記で実装したディレクトリではコミットする度にRubocopが実行されるようになりました。
ここまで読んで頂けただけで私は感激です。
これより以降はあまり重要でない個人の感想とか自分用のメモをつらつら書こうと思います。

# 解説
## pre-commitファイルって？
「commit」コマンドの前に実行されるファイルです。
お察しの通り、「push」コマンドの前に実行されるファイルはpre-pushファイルです。
詳しい説明は[こちら](https://qiita.com/noraworld/items/c562de68a627ae792c6c)を参照ください。
## pre-commitで何しているの?
以下の流れでRubocopを実行する処理を行なっています。
1. 対象のファイル名を取得(拡張子が「rb」のgit addされているファイル・修正・追加されたファイルのみで削除されたファイルは対象外です)
1. 対象のファイルが存在する場合にそれらのファイルに対してRubocopによる自動修正を行う
1. 自動修正されたファイルに対して「git add」を行う
1. Rubocopによるチェックを行う
1. チェックがOKであればそのままコミットを行い、チェックがNGであればコミットを中断する
## コードについてのメモ
### git diffコマンドのパラメータ
```
git diff --cached --name-only --diff-filter=AM
```
- --cached => git addしたファイルのみ取得する
- --diff-filter=AM => AがAddで追加されたもの、MがModifyで修正されたもののみを取得するためのフィルター
### rubocopコマンドのパラメータ
```
bundle exec rubocop --fail-level C --display-only-fail-level-offenses
```
「--fail-level C --display-only-fail-level-offenses」を記述することでレベルC以上の項目のみ表示されます。
レベルについては以下です。下に行くにつれてレベルが上がります。
[A] autocorrect
[I] info
[R] refactor
[C] convention
[W] warning
[E] error
[F] fatal
### xargsって?
```
getfilenames | xargs bundle exec rubocop -a
```
「getfilenames」で取得した情報を
「bundle exec rubocop -a」の引数にすることができます。
例えばgetfilenamesで「a.rb」と「b.rb」とファイル名が取得できた場合に
「bundle exec rubocop -a　a.rb b.rb」が実行されます。
### 「if [ $? -gt 0 ]; then」の「$?」には何が入る？
```
  getfilenames | xargs bundle exec rubocop --fail-level C --display-only-fail-level-offenses
  # 警告が出たかどうかのチェック(直前の処理の実行結果がNGの場合は1が取得できる。この場合はrubocopのチェック機能の実行結果)
  if [ $? -gt 0 ]; then
    echo '---RubocopチェックNG---'
    ISNG=1
  fi
```
「\$?」を使うことで直近のコマンド実行の結果を取得することができます。

ここでは「getfilenames | xargs bundle exec rubocop --fail-level C --display-only-fail-level-offenses」によるRubocopのチェック結果が「$?」に入り、
正常終了でない場合は0以外が設定されます。
### 「exit 1」を行うとどうなるの?
コミットされることを防ぐことができ、そのまま以降の処理を行わず処理を終了します。
# 最後に
日頃携わらないzshについて触れてみて慣れてない分、苦労しましたが、学びも多かったです。
シェルを学習し、自分の開発環境をよりよくするための一歩として踏み出せてよかったです。
この記事が誰かの役に立てば幸いです。
初めてのLINEBotとmakeを連携させてみた。

# はじめに

今回機会があり初めてLINEBotという存在を知ることになった。今までそんなものがある事を知らなかった自分にはかなり衝撃でした。
そこで今回はLINEBotとｍakeを利用して初心者の自分にも何かできないかとチャレンジしてみました。

# 郵便番号で住所を自動返信してくれるBotを作成

今回作成したLINEBotは郵便番号を入力すると住所を返信してくれるものを作成してみました。私は仕事上でお客様がネットで入力していただいた住所を確認することが度々ありますが春と秋に増えることがあります。引越しによってお客様情報の住所は変更しているのに郵便番号は変更していない。そしてお客様から問い合わせにより発覚するというパターンが多い。一見するだけでは郵便番号があっているかどうか分からないので覚えたてのLINEBotとmakeに郵便番号APIの組み合わせて調べられるようにしてみました。

### 完成したLINEBot
![unnamed.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613547/d972da23-5bcf-7edf-e98c-79a1c7972bdb.jpeg)

正しい郵便番号を入力すると対応した住所を返して、誤った郵便番号だと『郵便番号は存在しません』と返信してくれることに何とか成功しました。


# 手順

・LINE DevelopersにてLINEBotを作成
・連携させる為makeのアカウント登録
・郵便番号API情報のURL入手　　https://zipcloud.ibsnet.co.jp/api/search
・makeにてLINE、HTTP、JSON、Routerを連携

### make
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613547/1f383976-caee-2b01-3f4e-47f7e62a3403.png)

# 感想

今回作成してみたが返信が来るようになるまでなかなか大変でした。特にmakeの設定が１か所でも間違っているとエラーが出て、直しても違うところでエラーが出て修正の繰り返しでした。しかしいざ完成すると嬉しいの一言です。また色々APIを探してみましたが世の中にはたくさんある事を知り可能性を感じました。今の自分では単純なことしか出来ないですが今後学ぶべきことは多く色々チャレンジしていきたいと思います。
HerokuからGithubのOAuthトークンが流出した事件をわかりやすく解説


※今あらためて見ると色々間違ってそうなので話半分で見てください

OAuthとは？
-

> OAuthとは、異なるシステム間でデータや機能へのアクセス権限の許可を行う仕組みです。
https://medium-company.com/oauth/

例えばtwitterでツイートすると、自動でfacebookに投稿されるようにtwitterとfacebookを連携することができますが、そのときに使われている仕組みですね。

簡単にいうFacebookが発行した信用証明書(OAuthトークン)をTwitterにもたせることで上記のような機能が実現されます。

もちろんOAuthトークンは勝手に発行されるものではなく、ユーザーの認証などのプロセスを経て発行されるわけですが、その際の発行手順を標準化したものがOauthというプロトコルになります。

OAuthの詳細はこちらの記事がとても完結でわかりやすかったです↓

https://tech-lab.sios.jp/archives/8026


なにが起きた？
-

最近、GitHubが発行したOAuthトークンが流出し、npmなどのプライベートリポジトリのデータが不正ダウンロードされるという事件がありました。
調査の結果、HerokuやTravis-CIといったサードパーティ製のOAuthアプリケーションから盗まれたことがわかったそうです。

簡単にいうと、GithubがOAuthトークンを発行してHerokuに渡していたけど、Herokuに不正アクセスがありOAuthトークンが盗まれたよーという流れです。

先程、OAuthトークンをもっていると発行元のリソースにアクセスできると説明しました。
Githubは、Herokuにリポジトリへのアクセスを許すOAuthトークンを発行していたので、悪い人がそのOAuthトークンを使ってGithubから不正にダウンロードしたわけですね。

対策は？
-

以下の記事がよくまとまっていました。

https://zenn.dev/hiroga/articles/heroku-incident-2413-checklist
Docker で "device or resource busy" と言われ rm できなかったら

# やろうとしたことと生じた問題
php コンテナを立ちあげ，コンテナ内部をこねくりまわしている途中， node_modules(Javascript のモジュールが入っているディレクトリ) を消したくなった。
```bash
$ rm -rf node_modules
> rm: cannot remove ‘./node_modules’: Device or resource busy
```
[Device or resource busyが原因でrm削除できない！！解決法はmountやmvではなく、〇〇だ！！](https://japan-challenge.net/device-or-resource-busy%E3%81%8C%E5%8E%9F%E5%9B%A0%E3%81%A7rm%E5%89%8A%E9%99%A4%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%EF%BC%81%EF%BC%81%E8%A7%A3%E6%B1%BA%E6%B3%95%E3%81%AFmount%E3%82%84mv%E3%81%A7/)

この記事に基づき，以下を試してみた。
```bash
$ lsof

```

:::note info
lsof, fuser は，コンテナにインストールされていない場合 ```command not found``` となります。
Debian 系なら ```apt-get update && apt-get install lsof```
CentOS系なら ```yum install lsof```
でパッケージをインストールしてください。
:::

この php-fpm を kill すると，コンテナ自体が止まってしまいます。しかも，php-fpm が node_modules を使用しているわけではありません。

# 何が原因だったのか
**node_modules を volume mount** していたことが原因でした。
コンテナ内部に集中していたため，盲点でした。
```docker-compose.yml
workspace:
    image: php:7.4-fpm-buster
    ports:
      - 9000:9000
    volumes:
      - type: volume
        source: node_modules-store
        target: /var/www/html/node_modules
```

# どう解決するか
```rm -rf``` したいときだけ volume mount を外せば良いです。
```docker-compose.yml
workspace:
    image: php:7.4-fpm-buster
    ports:
      - 9000:9000
    volumes:
      #- type: volume
      #  source: node_modules-store
      #  target: /var/www/html/node_modules
```

```bash
$ docker compose down # コンテナを廃棄してマウントをリセットする
$ docker compose up php -d
```
Twitterクローンを作ります #25 画面の部品のコンポーネント化

# コンポーネント化

名前やら画像やら、クリックして遷移できるべきところは遷移できるようにしておきましょう。
下記のようにrouter-linkで囲んであげます。

```vue
    <div class="uk-margin-small-left uk-margin-small-bottom" v-if="isRetweet">
      <router-link
        :to="'/profile/' + post.posted_by.username"
        class="uk-link-text"
      >
        {{ post.posted_by.display_name }}がリツイート
      </router-link>
    </div>
```

HTMLが結構ごちゃごちゃしてきたので表示名等をコンポーネント化しておきましょう。

```vue:client/src/components/DisplayName.vue
<template>
  <div class="uk-text-bold">
    <router-link :to="'/profile/' + user.username" class="uk-link-text">
      {{ user.display_name }}
    </router-link>
  </div>
</template>

<script>
export default {
  props: {
    user: Object,
  },
};
</script>

```

```vue:client/src/components/UsernameLink.vue
<template>
  <span class="uk-text-muted uk-margin-small-right">
    <router-link :to="'/profile/' + user.username" class="uk-link-text">
      @{{ user.username }}
    </router-link>
  </span>
</template>

<script>
export default {
  props: {
    user: Object,
  },
};
</script>
```

```vue:client/src/components/AvatarPic.vue
<template>
  <router-link
    :to="'/profile/' + user.username"
    :class="{ 'large-link': size === 'large' }"
  >
    <img
      :src="url"
      class="uk-border-circle avatar"
      :class="{ large: size === 'large' }"
    />
  </router-link>
</template>

<script>
import { computed } from "vue";

export default {
  props: {
    user: Object,
    size: String,
  },
  setup(props) {
    const imageUrl = (user) => {
      if (!user || !user.display_name) {
        return "https://ui-avatars.com/api/?name=?";
      }

      if (!user.profile_pic) {
        return `https://ui-avatars.com/api/?name=${user.display_name}`;
      }
      return user.profile_pic;
    };
    const url = computed(() => imageUrl(props.user));
    return {
      url,
    };
  },
};
</script>

<style scoped>
.avatar {
  max-width: 50px;
  width: 50px;
  height: 50px;
}

.avatar.large {
  max-width: 132px;
  width: 132px;
  height: 132px;
  border: 4px solid #fff;
}

.large-link {
  z-index: 20000;
}
</style>
```

これで結構スッキリしましたね。

Atomic Design的なコンポーネントの分割ルールを採用したいところですが、Atomic Designだとちょっとやりすぎ感があるのでこのままにしておきます。部品 / 組み合わせたもの / ページ くらいの粒度で手軽なものがあるといいのですが...
whereやorderをモデルのscopeで書く方法

先日レビューで先輩エンジニアに教えてもらったことが勉強になったので備忘兼ねて投稿します。
whereやorderなどを使うときはモデルのscopeとして書くとスッキリするのと、使い回しもできて良いみたいです。

## controllerに書く方法

今回は商品（products）テーブルで開発日（development_date）降順で並べるとします。

```ruby:products_controller.rb
def index
  @products = Product.order(development_date: :desc)
end
```

## modelのスコープとして書く方法

まずモデルに以下のようにscopeを定義します。

```ruby:product.rb
scope: :development_order, -> { order(development_date: :desc) }
```

コントローラで呼び出します。

```ruby:products_controller.rb
def index
  @products = Product.development_order
end
```

このようにすることで、コントローラがスッキリし、複雑な条件の時にscope名からどんな処理をしているのかを推測しやすかったり、別の箇所で使うときに再利用できたりするメリットがあります。
macOS(M1, Monterey)でSSTP VPNを使いたい

macOSからもSSTPのVPNを使いたい（使わないといけない）場面に遭遇しますが、あまり情報がなかったためまとめ
作業環境はMacBook Air (2020,M1)でMonterey(12.2.1)、Homebrew導入済み、ネットワーク規制なし

# iSSTPをインストール
### ダウンロード
https://github.com/axot/isstp/releases/download/v1.4.1-rc1/iSstp.v1.4.1-rc1.zip
をダウンロードして展開してiSstp.appを/Applicationsに移動
バージョンが古いとM1に対応していないので接続できなくなります

### 以下のコマンドを実行する
iSSTPはバックグラウンドでsstp-clientを実行するので、検証用にHomebrewを使ってsstp-clientもインストールしておく
またpppdで接続を管理するので事前に空の設定ファイルを作る
iSSTPで利用するsstpcはアプリーケーションに内蔵されているが、Homebrewでインストールしたsstpc（`/opt/homebrew/Cellar/sstp-client`を探すとあるかも）を利用するように設定することも可

```
brew install sstp-client
sudo touch /etc/ppp/options
```

# iSSTPの設定
iSSTPのアプリケーションを起動して`New`で接続設定を作る
`Name`は適当な接続設定名で
`Server Address`にVPNサーバーのアドレスを入力
　これはホスト名もしくはIPアドレスを直打ちする、VPNGateはIPアドレス直打ちじゃないと繋がらないことが多々ある、SoftEtherのVPN Azure使う場合ならVPNサーバーの設定に表示されるvpnazure.netのホスト名を入力
`Username`と`Password`は設定したもしくは指定されたものを入力
そうしたら`Edit`で以下のオプションを入力して保存する
VPNサーバーの証明書が自己証明書であるため警告を無視するオプション、ホスト名で接続するためのTLS拡張を有効化するオプションなどを指定する必要があった

```shell:Advanced Options
--cert-warn --tls-ext noauth defaultroute usepeerdns
```
入力できたら`Save`をクリックする
そうしないと次回起動時に初期状態になってる

`Connect`を押すと接続されるが、１回目は失敗しやすいので２回目も試してみる、もしダメならVPNGateのIPアドレス・ユーザー名・パスワードの設定で作成して接続できるかを試す
またデバッグ用にsstp-clientを入れておいたため
```
sudo sstpc [接続するホスト名] --user "[ユーザー名]" --password "[パスワード]" --log-level 5 --log-stderr --cert-warn --tls-ext noauth usepeerdns defaultroute
```
でCUI上から接続できるかを試す、エラーが出てたらそれに基づいて対処する
【AWS】AmazonConnectインスタンスから携帯電話への発信ができるようにする（2022/4/20時点）

# 1.はじめに
どうも、ARIの名古屋支社に勤務している愛知県民です♪
(/・ω・)/

前回の記事ではAmazonConnectの電話番号を取得する方法について記事にしました。

https://qiita.com/Aichi_Lover/items/c15b0df871eca3a1108f

ドキュメントを見ると、**2021年8月以降に作成されたAmazonConnectインスタンスでは、
日本の携帯電話（070,080,090から始まる電話番号）への発信ができなくなっている**ようです。

そこで今回は**AmazonConnectインスタンスから携帯電話への発信ができるようにする方法**について記事にしたいと思います！
AmazonConnectについて勉強中の方の参考になれば幸いです♪
(*^^)v

参考URL：https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/country-code-allow-list.html

# 2.用語の説明
## 2.1.AmazonConnectとは
AmazonConnectとは、AWSが提供するサービスの一つで、
クラウドコンタクトセンタを作ることができます。

AmazonConnectからLambdaを呼び出し、
LambdaからDynamoDBやS3に接続する事で各種サービスと連携することができます。
（この辺りについても記事を書きたい・・・）

# 3.前提条件
以下に前提条件を示します。

* AmazonConnectインスタンスが作成済であること

# 4.概要
AWSのサポートから申請をすることで携帯電話への発信ができるようになります。

# 5.AWSのサポートから申請をする
AWSのサポートから携帯電話への発信を許可するための申請をします。
5.1.WebブラウザからAWSにログインします。
5.2.検索欄に「サポート」と入力し、「サポート」を選択します。

|![010_サポートを選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/d1f7c759-e4d9-b729-96f2-60e3a96f7fba.png)|
|:--|

5.3.画面中央の「ケースの作成」を選択します。

|![020_ケースの作成を選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/19a13385-8bea-2faf-8608-94c95f8d018d.png)|
|:--|

5.4.以下の表のとおりに入力し、「送信」を選択します。
※画面が縦に長かったため、キャプチャは2枚としました。

|項目|設定内容|
|---|---|
|サービス制限の緩和 | チェックあり |
|制限タイプ | AmazonConnect |
|コンタクトセンターのインスタンスARN | AmazonConnectインスタンスのARN |
|リージョン | アジアパシフィック（東京） |
|制限 | 発信通話のホワイトリスト国登録 |
|新しい制限値 | 許可したいプレフィックスの数<br>（例では3つのプレフィックスすべてを許可する申請をします。）|
|申請理由の説明 | 申請理由<br>（例では以下の文章としました。<br>「日本の携帯電話への架電を有効化したいため、<br>&emsp;以下の3種類のプレフィックスのホワイトリスト登録を申請いたします。<br>&emsp;ご確認をお願いいたします。<br>&emsp;①+8170<br>&emsp;②+8180<br>&emsp;③+8190」）|
|連絡時のご希望の言語 | 日本語 |
|Web | チェックあり |


|![120_申請画面_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/206230d0-d7b0-644b-35dd-4ca0aba3fd18.png)|
|:--|

|![130_申請画面_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372071/a60fc5b9-529f-c779-1570-e1022b288ae6.png)|
|:--|

5.5.AWSからの返信を待ちます。
※早くても2,3営業日ほどかかります。

5.6.AWSから、該当プレフィックスへ発信を許可した旨の返信が来ます。

以上でAmazonConnectインスタンスから携帯電話への発信ができるようになります。
お疲れ様でした。

# 6.おわりに
ここまで読んで下さり、ありがとうございます！！！
(^^)

以前はデフォルトで日本の携帯電話への発信ができましたが、
AWSにも色々事情があるようで、今はサポートからの申請が必要になっていました。
日々仕様が変わるのはクラウドならではなので、今後も気を付けていきたいと思います！

次回も何かしら試してみたことを記事にします♪
(:3_ヽ)_
【Route53】CloudFormationでシンプルルーティングから加重ルーティングに瞬断無しで変更する方法

状況としてはこんな感じです。
このようなシンプルルーティングを、
```
  Route53RecordSetApi:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneId: 'example.com.'
      Name: 'mysite.example.com.'
      Type: 'CNAME'
      TTL: '300'
      ResourceRecords: 
        - 'example-ec2.amazonaws.com'
```

こんな加重ルーティングにしたい。瞬断無しで。
```
  Route53RecordSetGroupApi:
    Type: 'AWS::Route53::RecordSetGroup'
    Properties:
      HostedZoneId: 'example.com.'
      RecordSets:
      - Name: 'mysite.example.com.'
        Type: 'CNAME'
        TTL: '300'
        SetIdentifier: 'Frontend One'
        Weight: 60
        ResourceRecords: 
          - 'example-ec2.amazonaws.com'
      - Name: mysite.example.com.
        Type: 'CNAME'
        TTL: '300'
        SetIdentifier: 'Frontend Two'
        Weight: 40
        ResourceRecords: 
          - 'example-ec2-larger.amazonaws.com'
```


### 結論、瞬断無しではできません
それは以下の2つの事実があるからです。

事実1：リソースタイプが違う
シンプルルーティングと加重ルーティングは異なるリソースタイプを用いています。
それぞれ `AWS::Route53::RecordSet` と `AWS::Route53::RecordSetGroup` です。

事実2：同じ名前とタイプを持つレコードを同時に登録できない
上の例だとシンプルと加重でレコード名とタイプが重複しています。
これらが同時に存在することはできないですよね。

そのため、
1. シンプルルーティングを削除する変更セットを作成 → 適用
2. 加重ルーティングを作成する変更セットを作成 → 適用

の順に作業しなければなりません。
1 と 2 の間でレコードが存在しない時間ができるため、一時的に名前解決ができなくなります。
(AWS サポートにも問い合わせてみましたが同じ回答でした)

### ちなみに
マネージドコンソールからであればシンプルルーティングから加重ルーティングへ、
既存レコードを削除することなく変更できました。

一旦 CloudFormation スタックからレコードを切り離して手動で変更し、
後からインポートすればいいのでは？と思いましたが、[こちら](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html)にあるように、
`AWS::Route53::RecordSetGroup` はインポート非対応でした。
ディスククォータ とは

## 勉強前イメージ

ディスクサイズ的ななにか？

## 調査

### ディスククォータ とは

複数の利用者が使用するコンピュータで、ユーザごとにディスクの容量制限をかける機能があります。
これをディスククォータと言います。

元々Linuxは複数ユーザで利用することを前提として設計されたOSで、
複数の人がいろんなデータを置くと悪意がなくてもデータ容量を圧迫させてしまう可能性があります。
これを解消するための機能になります。

### クォートの種類

クォートには2種類あります。
また、以下の種類をユーザごとなのかグループごとなのかでも設定を行うことができます。

- ソフトリミット

ディスク容量が指定の容量に達した際に `警告を行う`
警告が発されるだけで書き込みは可能。
しかし、猶予期間をすぎると書き込みができなくなる。

- ハードリミット

ディスク容量が指定の容量に達した際に `書き込みを制限する`
書き込みができなくなる。

## 勉強後イメージ

## 参考

- [ディスククォータ 【disk quota】 ストレージクォータ / storage quota](https://e-words.jp/w/%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%82%AF%E3%82%A9%E3%83%BC%E3%82%BF.html)
- [ディスククォータ（クォータ）](https://linuc.org/study/knowledge/403/)
- [Linux - disk quota](https://www.infraeye.com/study/linuxz25.html#:~:text=%E3%81%AA%E3%81%8A%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E4%BD%BF%E7%94%A8,%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7%E7%A2%BA%E8%AA%8D%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82&text=%E3%81%AB%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB,%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82&text=%2Fetc%2Ffstab%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E8%A8%AD%E5%AE%9A,%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)
EntityをDTOに変換する方法【Java】【Spring Boot】

実装メモです。参考になれば幸いです。
## EntityをDTOに変換
### DTOクラス
DTOクラス内にofメソッドを定義。
```java:DTO.java
public static DTO of(Entity entity) {
  DTO dto = new DTO();
  dto.setId(entity.getId());
  dto.setTitle(entity.getTitle());
  dto.setDescription(entity.getDescription());
  dto.setCreateTime(entity.getCreateTime());
  dto.setUpdateTime(entity.getUpdateTime());
  return dto;
}
```
### Serviceクラス
あとはofメソッドの引数にEntityをセットすれば、DTOに変換できます。
※私はServiceクラスでDTO変換の処理をしていますが、Controllerクラスで実装していただいても構いません。（どこで処理するかは設計思想によるってやつですね）
```java:aaaService.java
return DTO.of(aaaRepository.save(entity)); 
```
## List&lt;Entity&gt;をList&lt;DTO&gt;に変換
### Serviceクラス
List&lt;Entity&gt;をList&lt;DTO&gt;に変換するメソッドを定義（先程定義したDTOクラスのofメソッドを使い回します）
```java:aaaService.java
public List<DTO> entityToDto(List<Entity> entity) {
    List<DTO> dtoList =
        entity.stream().map(DTO::of).collect(Collectors.toList());
    return dtoList;
  }
```
あとはentityToDtoメソッドの引数にList&lt;Entity&gt;をセットすれば、List&lt;DTO&gt;に変換できます。
```java:aaaService.java
return entityToDto(aaaRepository.findAll());
```
OpenCVに加わった深層学習ベースの顔検出・顔照合のデモ用のサンプル

OpenCV (>= 4.5.4) で深層学習ベースの顔検出・顔照合ライブラリが含まれるようになった。
その利用の普及を応援するために、自作のサンプルプログラムを作ったので、それを紹介する。
既に作成されているサンプルスクリプトを参照して作りました。



## OpenCV自体の中のサンプルスクリプト
Github のOpenCV のなかにもオリジナルのサンプルコードがある。

https://github.com/opencv/opencv/blob/4.x/samples/dnn/face_detect.py


## Qiita, Gist でのサンプル（UnaNancyOwen　さんによる）
また、以下の場所にも顔検出から顔照合までのステップがわかるサンプルコードがある。
Qiita  https://qiita.com/UnaNancyOwen/items/8c65a976b0da2a558f06
Gist https://gist.github.com/UnaNancyOwen/49df508ad8b6d9520024354df0e3e740

- generate_aligned_faces.py :  画像から顔を検出して切り出し、顔画像として保存する
- generate_feature_dictionary.py : 顔画像から特徴を抽出、特徴辞書として保存する
- face_recognizer.py : 入力画像から顔を検出し特徴を抽出、特徴辞書と比較して顔認識する
このサンプルスクリプトは、それぞれの機能がどのように実装されているのかを理解するのに適している。

## 今回作ったサンプル
https://github.com/waragai-katsunori/cv_dnn_face#readme
### detector.py
- カメラ入力に対して顔検出を行い、結果を画面表示するスクリプト
### recognizer.py
- カメラ入力に対して顔検出・顔照合とを行い、結果を画面表示するスクリプト
カメラ入力で画面出力なので、どの程度顔検出・顔照合ができるのかを確認しやすいと期待する。

- 顔照合用の画像と特徴量の抽出は、以下のスクリプトを使用している。
- generate_aligned_faces.py　顔画像を正規化するとともに、特徴量をnpyファイルに変換するのを１つのスクリプトにまとめた。
- aligned_faces の下にbaiden.npy があれば、その特徴量の人物はbaiden とみなすようにしてある。
## 最後に
- 今回のサンプルの作成にあたっては、UnaNancyOwen　さんのサンプルを大いに参考にした。
- OpenCVの顔検出と言うとcv2.CascadeClassifierを使うものが有名だが、深層学習の時代においては、それを積極的に使うべき理由はない。
- また、[EigenFace](https://docs.opencv.org/4.5.5/da/d60/tutorial_face_main.html)を用いた顔照合よりも、深層学習ベースの顔照合の方が適用できる範囲が広いものになっている。
- 従来例：[cv2.CascadeClassifierを使うサンプル](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_objdetect/py_face_detection/py_face_detection.html)
iOS14.8から15.4になったらiOSビルドが通らなくなった時(code:806)

昨日までiPadでflutterからrunが通ってビルド出来てアプリが動いていました。
朝起きるとビルドが通らなくなっていました。
これから進捗会議なんですけど…。

## 環境
・iPad(iOS14.8だったのがiOS15.4になってた)
・XCode13.2.1
・flutter2.10.0
・Monterey 12.2.1
・M1 Macbook Air

## 症状
・『Failed to prepare device for development』
・XCodeでビルドは出来る
・エミュレータでアプリの起動まで行ける
・flutterで端末が対象外と言われる（806）
・XCodeのデバイス一覧でなんか警告出てる
・development teamがおかしいとかflutterに起こられる

## 結論
・XCode13.3.1に上げたら直った。（たどり着くまで一日かかった）

##他試したこと（≒ほぼ意味なかった事）
・flutter upgrade
・iOSダウングレード
・iPadとMAC何度も再起動（警告文にそう書いてあった）
・設定から対象iOSバージョン変えてみる→治ったと見せかけて直ってなかった
React.js 18 以降 React.FC で childrenが削除される対処法

型定義で`React.FC`に`children`の暗黙的型定義が含まれていたが、
React.js 18 以降 `children`の暗黙的型定義が外された。

では`children`の型はどのように指定するか？

`children: React.ReactNode` という感じで、 `React.ReactNode`と、型定義する。

```tsx
import React from 'react';

interface props {
  children: React.ReactNode;
}

const Text:React.FC<props> = ({ children }) => {
  return (
    <p>{ children }</p>
  )
}
```
Terraform - TerraformCloudをtfstate状態管理機能のみ利用


# 概要

* TerrafromCloudをtfstate置き場、状態管理として利用したい
* Terraformのデプロイはローカルから実行

# 前提

:::note
* ローカルはaws-vaultによる実行なのでセキュア
* AWS環境はマルチアカウントでスイッチロールする環境である
* aws-vaultでMFA認証及びスイッチロールできる状態
* 以下の記事の設定確認が既に済んでいること
:::

https://qiita.com/ezaqiita/items/4fd008bf3cbaf9a0a315

# 詳細

## TerraformCloud側WorkSpace作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/65317ace-3fb9-729b-cf8b-6bcfd4cf83a8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/4495bbf0-4e58-dbfc-0431-2f30e403638f.png)


* organization => Workspaces => dev-test => Settings => General
* Execution ModeをLocalにする
* Localに設定するとAWS操作は自端末から行い、tfstateのみTerraformCloud上で管理可能
* RemoteにするとTerraformCloudからAWS操作するため、credentials登録が必要になってしまう。
* 他のworkspaceと共有しないためひとまず”Share with all workspaces in this organization”を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/661cfc35-e158-ed8a-2e27-fb821542a375.png)


## ユーザトークンを発行

* 右上ユーザアイコンから”UserSettings”を選択
* 以下の画面の場所を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/29ec9741-5b7f-e7bd-a1e5-a97cce930af1.png)

* トークンのタイトルを決めて入力。CreateAPITokenをクリック
* 次画面で生成されたトークンをコピーして控える

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/fb330621-0a53-6ea5-454f-1878ad260b43.png)

## 設定ファイル作成

```
$ touch $HOME/.terraformrc
$ touch <terraform_dir>/remote-state.tf
```

```:$HOME/.terraformrc       
credentials "app.terraform.io" {
  token = "<user_token>" #発行したユーザトークン
}
```

```:remote-state.tf              
terraform {
  backend "remote" {
    organization = "hoge-corp" #TerraformCloudのorganization名を入力

    workspaces {
      name = "dev-test" #WorkSpace名を入力
    }
  }
}
```

```:main.tf
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "example" {
  ami           = "ami-0ce107ae7af2e92b5"
  instance_type = "t2.micro"
  subnet_id = "subnet-XXXXXXXXX"
  vpc_security_group_ids = [ "sg-XXXXXXXXX" ]
  tags = {
    Name = "test-terraform-ec2"
    Project = "test"
  }
}
```

# デプロイテスト

* MFA環境ではaws-valutを利用しプロファイル名を実行してデプロイ

```
$ aws-vault exec hogeuser-admin -- terraform init
$ aws-vault exec hogeuser-admin -- terraform plan
$ aws-vault exec hogeuser-admin -- terraform apply
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/648d07ca-b3d9-583d-dfc5-add53930af96.png)

* 確認したら削除

```
$ aws-vault exec hogeuser-admin -- terraform destroy
```

# 課題

* 実施環境はMFA認証によるマルチアカウント＆スイッチロールである
* TerraformCloudからのMFA認証のやり方がわかればTerraformCloudからの実行も検討
* TerraformはMFA認証のような対話型のUIは認めていないらしい
* OIDCによる認証が可能なのであればその手段も検討したい
テキストファイルに記述したpsqlメタコマンドを実行する

## 環境
Ubuntu 20.4
PostgreSQL 12.10

## やったこと
psqlメタコマンドを実行するには、PostgreSQLに接続してからコマンドを実行する手順となるが、毎回、PostgreSQLに接続に接続することなく、実行したいpsqlメタコマンドをバッチファイルに記述して、一発で実行する方法があります。

この方法を始めて知ったとき「それ、早く言ってよ～」と思ったので、記事にしました。

テーブルの一覧を表示させたいときは、次の１行を記述した、test.sqlファイルを作成します。
```test.sql
\d
```

次のコマンドを実行すると、test.sqlが実行されて、test.sqlに記述したコマンドの結果が出力されます。
```
$psql -f test.sql データベース名
```

テーブルの一覧を参照したい場合は、test.sqlをこのように記述します。そして、上記のコマンドを実行します。（SQL文の最後につける、;はあってもなくても動きます。つけておいた方が丁寧でしょう）
```test.sql
select * from テーブル order by id;
```

COPY文でCSVファイルを出力することもできます。test.sqlをこのように記述します。
```test.sql
COPY テーブル TO './テーブル.csv';
```

PostgreSQLのバージョンを知りたいときは、test.sqlをこのように記述します。
```test.sql
select version();
```
Firebase Authenticationで新規登録を禁止する

TL;DR : Google Identify Platformから切れる

Firebase authのバックエンドにはGoogle Identify Platformを使ってるらしく、こいつから切れる。  
プロジェクトもFirebaseのものを不可逆な形でGIPにマイグレーションしてくれる上、トークンやAPIしよライブラリなどもそのまま使えてできることが広くなる. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335219/42ce07d1-7ac5-abbf-43b4-7e7370e112a6.png)

最初Google Identify Platform自体知らなかったのでFirestoreのルールを組み合わせたり、登録時にEventが発火するのを使用してアカウントを操作したりなど、先人たちのいろいろな方法が出たけど、この方法なら不要なドキュメントを作ったりCLIからのユーザー作成とか気にしないで作れたので確実だし安全だし何より楽だった。  

スクショに書いてある通り、Firebase Admin SDKからの登録は通るので注意。
Atcoder初心者学習②　状態DP　【競プロ典型　008】

# 問題
https://atcoder.jp/contests/typical90/tasks/typical90_h

# 状態DP
本問題の場合、atcoderという文字列に一致する部分文字列の数を探すのだが、
全探索をすれば$O(n^7)$かかる。
ここで$N$は入力文字列、$n$はNの長さ、$S="atcoder"$である。

そこで次のように考える。

$N[i]$までの文字を使って$S[j]$までの文字列を作る通りの数は
① $N[i-1]$までの文字を使って$S[j]$までの文字列を作る通りの数 + $N[i-1]$までの文字を使って$S[j-1]$までの文字列を作る通りの数（N[i]=S[j]）
② $N[i-1]$までの文字を使って$S[j]$までの文字列を作る通りの数（N[i]!=s[j]）

例. N="attcoder", S="atcoder"とする

N[i=1]までの文字（a,t）を使ってS[j=0]までの文字列（a）を作る通りの数は1。これは
N[i=0]までの文字（a）を使ってS[j=0]までの文字（a）を作る通りの数1と等しい。
→②のパターン

N[i=1]までの文字（a,t）を使ってS[j=1]までの文字列（at）を作る通りの数は1。これは
N[i=0]までの文字（a）を使ってS[j=1]までの文字（at）を作る通りの数0とN[i=0]までの文字（a）を使ってS[j=0]までの文字（a）を作る通りの数1の和と等しい。
→①のパターン

N[i=2]までの文字（a,t,t）を使ってS[j=1]までの文字列（at）を作る通りの数は2。これは
N[i=1]までの文字（a,t）を使ってS[j=1]までの文字（at）を作る通りの数1とN[i=1]までの文字（a,t）を使ってS[j=0]までの文字（a）を作る通りの数1の和と等しい。
→①のパターン

ここで$DP[i][j]$を$N[i]$までの文字を使って$S[j]$までの文字列を作る通りの数とすれば

$DP[i][j]=\begin{cases}
DP[i-1][j-1] + DP[i-1][j] & s.t.N[i]=S[j] \\\\\\\\\\
DP[i-1][j]  & s.t.N[i]\neq S[j]
\end{cases}
$
といった漸化式に書き表せます。
つまり、$N[n]$までの文字を使って$S[7]$までの文字列（atcoder）を作る通りの数$DP[n][7]$
は$O(7\times n)$で求まります。（下の例では厳密には$O(8(n+1))$）

このようにある時点での状態が前の時点の状態によって決まるような構造に着目したアルゴリズムを状態DPと呼びます。


以下にN="attcoderer"としたときのDPの値の変化を載せます。
1. 初期設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/fee11a41-d166-b7ad-840c-3a7b40b05cc9.png)
2. i=1を埋める
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/e7f8442c-d081-143f-7d0c-c49533db3960.png)
3. i=3を埋める
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/d16dc9f9-4278-7ec9-496f-6b7239981bb9.png)

4. 最終的に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/2a513e5b-f9c2-e169-9895-f4dca6efa086.png)
pythonでの設定ファイルの作り方

私が最もシンプルで分かり易いと思っているやり方です．
調べるとよく出てくるJSONはコメントが書けないデメリットがありそれを補うメリットが見出せませんでした．（私はpythonしか普段触っていないからこの方法が最適なだけで他の言語の方だとYAMLなどが良い場合もありそうです．）
#### 設定ファイルとは
機械学習をやっていると，何かのパラメータを変更したローラー作戦をやりたくなることがあります．
そういったときに1つの変数の値だけを変更したメインのファイルを沢山つくるのは管理がとても大変です．
そのため，変更しそうなパラメータ類だけを抜き出したサブのファイルを作成して，そのファイルのみを複製して1つの実行ファイルでパラメタ読み込み→学習→別ファイルから別のパラメタ読み込み→学習...のループを回すやり方が一般的です．
このパラメータを抜き出したファイルのことを設定ファイル（あるいはconfigファイル）と呼びます．
#### 設定ファイルの書き方
まずconfig.pyというpyファイルを作ります．
そこにconfigクラスを作りパラメータを羅列します．
（パラメータが沢山ある場合はココでクラスを分けて可読性を高めるのもアリです．)

```python:config.py
class config: 
    def __init__(self):

        self.save_name = "work/rlt/rlt.npy"  
        self.a = 16 
        self.b = 4 
        self.save = True #保存するかどうか
```

#### 設定ファイルの使い方
実行ファイルで読み込んで使います．
```python:main.ipynb
from config import * #設定ファイルの名前
conf = config() #設定ファイルから読み込み

rlt = conf.a * conf.b
if conf.save:
    np.save(conf.save_name, rlt) 
```
こんな感じで使えます．
#### ローラーのやり方
最終的には実行ファイルを，config1.py, config2.py, config3.py ...と複製してローラー作戦時に使います．
その時はメインで実行したい部分を関数化してしまって，別でローラー用のコードを書く必要があります．

```python:mainv2.ipynb
def multi(conf): #さっきのmain.ipynbでやってたことを関数にした
    rlt = conf.a * conf.b
    if conf.save:
        np.save(conf.save_name, rlt) 

config_files =["config1","config2","config3"] #ローラーしたい設定ファイルたち
for i in config_files:
    config = import_module(i) 
    conf = config.load_config() #設定ファイルから読み込み
    multi(conf)

```
おわり．
Effective Java 第3版まとめ（項目6）

# 項目6.不必要なオブジェクトの生成を避ける

## 書かれている内容

* ```String s = new String("bikini");```ではなく、```String s = "bikini";```
* 同じ文字列リテラルは同一仮想マシン上で再利用することが保証されている
* コンストラクタではなくstaticファクトリメソッドを使うことで、その両方を提供している不変クラスに対しては不必要なオブジェクトの生成をたいていは避けられる
* ```new Boolean(String)```ではなく```Boolean.valueOf(String)```
* 生成が「高くつくオブジェクト」を繰り返し必要とするなら、再利用するためにキャッシュすることが勧められる
* ```String.matches```は簡単な方法だが、パフォーマンスが重要な状況で繰り返し使うことには適していない
* ```Pattern.compile```し、```Pattern.matcher.matches```することでパフォーマンスを改善できる
* 遅延初期化で不必要な初期化を取り除けるが、遅延初期化は勧められない
* 遅延初期化は計測できるほどのパフォーマンスの改善がなく、実装を複雑にする
* 意図しない自動ボクシングに注意すること
* コンストラクタでの明示的な処理がほとんどない小さなオブジェクトの生成と回収は、最近のJVM実装では安上がり
* 自分でオブジェクトプールを管理することはオブジェクトの生成が重たいものではない限り、悪い考え
* 必要な場所では、防御的コピーを行う
Unity Shader チートシート （Builtin Pipeline）(WIP)

※未検証な内容や書きかけの内容が含まれています。
# 座標変換
記事中での変数の表記を可読性の為に、以下で統一します。
Builtin(=Legacy)パイプラインに関する内容ですが、分かりやすいので変数名はURPのシェーダーの命名を踏襲しています。変数名の後に`〇S`(=○○ Spaceの意)が接尾語として付けることでその座標やベクトルがその空間での値かを表しています。

| 変数名 | 意味 |
|:-----------|------------|
| positionOS | オブジェクト空間（ローカル空間）での座標  |
| positionWS | ワールド空間での座標      | 
| positionVS | ビュー空間での座標        | 
| positionCS | クリップ空間での座標      | 

## Object to World (モデルtoワールド)
```
float4 positionOS = float4(x,y,z,1);
float3 positionWS = mul(unity_ObjectToWorld, positionOS);
```

## World to Object(ワールドtoモデル)
```
float4 positionWS = float4(x,y,z,1);
float3 positionOS = mul(unity_WorldToObject, positionWS);
```

## World to View（ワールドtoビュー）
```
float4 positionWS = float4(x,y,z,1);
float3 positionVS = mul(UNITY_MATRIX_V, positionWS);
```

## View to World（ビューtoワールド）
```
float4 positionVS = float4(x,y,z,1);
float3 positionWS = mul(UNITY_MATRIX_I_V, positionVS);
```

## View to Clip (ビューtoクリップ)
```
float4 positionVS = float4(x,y,z,1);
float3 positionCS = mul(UNITY_MATRIX_P, positionVS);
```

## Clip to View (クリップtoビュー)
```
float4 positionCS = float4(x,y,z,1);
float3 positionVS = mul(UNITY_MATRIX_I_P, positionCS);
```

## 参考
https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
https://gist.github.com/sugi-cho/60b676bf04c0f971c182
https://gist.github.com/sugi-cho/2094612a6ba566f09e9e

# 深度関係
## 非線形の深度取得
描画APIによって`[near, far] = [0, 1]`の場合と`[near, far] = [1, 0]`の場合があるのでキーワードを使って反転。

## 0~1の線形の深度取得
## ワールドスケールの線形深度取得
ワールド空間とビュー空間はスケールは同じなので、深度をビュー座標に作用させたい場合も同じです。

## Depth to World (深度 to ワールド)
```

```

https://github.com/FinGameWorks/DepthToWorldPos/blob/master/Assets/DepthToWorldPos.shader
ブランチから別のブランチへコミットをコピーしたいとき

今日使う機会があったのでメモしておきます。

## 基本のコマンド
```
git cherry-pick [コミットID]
```

## 使用例
branchAのコミットをbranchBにコピーしたい場合

```
# コピー元のブランチに移動
$ git checkout branchA

# コミットログを確認
$ git log --oneline
6c49ad2 Bootstrapをインストール  # ←このコミットをコピーしたい！
a8d8544 Laravel UIをインストール

# コピー先のブランチに移動
$ git checkout branchB

# コミットIDを指定して実行
$ git cherry-pick 6c49ad2
```
venv　環境での OpenCVのインストール上の注意点

## 要点
 venv 環境にopencv をソースからビルドしてインストールする際には、インストール先の変数をカスタマイズしてからビルドして、インストールするようにということ。

# やらかした失敗
venv 環境を使っているのにもかかわらず、CMAKE_INSTALL_PREFIXをデフォルトのままcmake、 make 、 sudo make install
してしまうと、 利用環境先の環境には、別の版のopencv のライブラリが残ってしまう。

## 手順
OpenCV のソースコードを入手する。
$ git clone https://github.com/opencv/opencv.git

$ mkdir build
$ cd build
$ cmake-gui .. &

ここで変数CMAKE_INSTALL_PREFIXの値をvenvでの利用環境に合わせる。/home/{your_name}/.venv
そうすると、その下にインストールされるようになる。

$ make -j4 ..
$ sudo make install

## 確認方法
```
import cv2
print(cv2.__file__)
print(cv2.__version__)
print(cv2.getBuildInformation())
``` 


## 補足
opencvを入れる前には, numpyが入っている必要がある。
また、環境によってはnumpyを入れる前にcython のインストールが必要になるかもしれない。
さらにはヘッダーファイルが必要になるかもしれない。

```
$ sudo apt-get install python3.6-dev
```
OpenShiftにInstana導入してみた

# 初めに
InstanaはIBMが提供するAPMソリューションです。エージェントを導入することで自動的に監視を開始し、ダッシュボードでメトリクスデータを確認できます。

 Instanaの特徴は主に以下の３つです。
 * 導入の容易さ
  エージェントを入れると自動的に稼働しているテクノロジーを検知して必要なセンサーをロードするのでエージェントの構成が不要

 * アプリからインフラまで１つのダッシュボードで監視
 別のツールを使わなくてもInstanaだけでさまざまな監視対象をカバー（Webサイト、アプリケーション、コンテナ、インフラ）

 * 問題の根本原因をAIが自動解析
 Instanaでは監視対象に問題が発生した際はそれをイベントとしてアラートをあげ、その根本原因も解析しダッシュボードに表示する

 このような機能が提供されており、特別なスキルがなくても簡単に操作できるのがInstanaのいいところです。

この記事ではInstanaをOpenshiftクラスターに導入する手順を解説します。

# 前提条件
今回の導入に必要なものは以下の通りです。
* Red Hat OpenShiftクラスター
* Instanaライセンス

導入のレベル感の参考として筆者のスペックはこんな感じです。
* プログラミング未経験、 ターミナルもほぼ触ったことない
* IT企業入社1年目

こんな超初心者でもできるくらい簡単です。

# InstanaのOpenshiftクラスターへのインストール手順
※Openshifの操作にはOpenShift CLIのインストールが必要です。インストール方法は[こちら](https://cloud.ibm.com/docs/openshift?topic=openshift-openshift-cli)

 1 .まずはターミナルで管理対象クラスタにログインします

```
oc login
```
2 .Instana-agentプロジェクトを作成します
```
oc new-project instana-agent
```
3 .Security Context Constraint （セキュリティ制約）の設定
instana-agentのサービスアカウントにpriviledged権限を与えます。
```
oc adm policy add-scc-to-user privileged -z instana-agent
```


4 .ここからはOpenshiftのwebコンソールを使って作業していきます。
管理対象クラスターのwebコンソールを開き、左のメニューからOperatorを選択しInstana Agent Operatorをインストールします。バージョンは一番新しいもの（今回は2.0.3）を選択します
![p9-1ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/cfb27403-7acb-4347-429f-5f6d6e780d8f.png)
![p9-2ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/3d750363-619c-4957-aa17-4a35eb28c068.png)
インストール時の設定はデフォルトのままで大丈夫です。
![p10 ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/3d432089-192b-dce4-9cf7-8ebc032f1dd7.png)
導入が完了するとインストールされたOperatorにInstana Agent Operatorが表示されます。![p10−2 ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/de28cd80-5127-2784-0a41-c3b5fac918cf.png)

5 .Operatorが準備できたらエージェントを導入していきます。
Operatorの詳細画面を開き、InstanaAgentの作成をクリックします。
![p11-1 ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/87148fe2-1e66-e35a-d867-16e887b3500f.png)

![p11-2 ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/3313d6fc-cc83-6f91-58a5-ea6bea257ed8.png)
YAMLビューを選択し、サービス・エンドポイント、サービス・ポート、アプリケーション・キーを入力します。zoneやclusterの名前も任意の名前に変更可能です。サービス・エンドポイントやアプリケーション・キーの情報はInstanaのダッシュボード上で確認できます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/b8317222-2773-a113-4464-9588998110e2.png "エージェント導入に必要なアプリケーションキーなどはこの画面から確認できます")



6 .必要な情報をYAMLビューで入力したら「作成」をクリックします。エージェントがデプロイされます。
正しく導入できたかを確認するにはPodの画面を確認します。ワーカーノードの数だけエージェントが表示されていれば大丈夫です。（画像は3ノードなので3つエージェントが入っています）
![PODの画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627874/d4340c7a-b429-f24a-4d03-dc7985c53ece.png)

これでエージェントの導入は完了です。

# 最後に

ほとんどGUIベースで導入できる上に必要な作業も少ないので簡単に導入できました！
Instanaを検討されている方や試しに導入してみたい方はこの記事を参考にぜひ試してみてください。
pythonのosモジュールを初めて調べた備忘録

# osモジュールの概要
OSに依存した機能を利用できる。
主にファイルやディレクトリ操作に用いられる。

使いそうなメソッドだけ備忘録にする。

# os.system()でunixコマンドを使う
わざわざ端末を使う必要がなくなる。
cdを使ったディレクトリ移動はできなかった。
```python
os.system("ls")
```
```bash:結果
folder1
a.txt
b.txt
.
.
.
```
os.get("pwd")とos.getcwd()の結果は同じだった。
なので、unixコマンドで賄える処理はわざわざメソッドを覚えなくてよさそう。

# os.path()でファイルの存在確認やパスの取得をする
パス名の取得や分割、結合などの操作ができる。

os.path.join()は引数に与えた2つ以上のパスを結合して返す。str型。

```python
path = os.getcwd()
print(path)

print(os.path.join(path, "abc.txt"))
```
```bash:結果
/home/user/デスクトップ
/home/user/デスクトップ/abc.txt
```

# その他
* os.mkdir()でパスを引数に与えてディレクトリの作成
* os.rename()でファイル名の変更
* os.remove()でファイル削除

# 参考サイト
https://www.sejuku.net/blog/63651
GraalVMを御紹介します。(関連記事へのリンクまとめ）

皆さま、

初めまして。
Oracle Javaには多彩な機能がございますが、当面は、次世代Java開発基盤のGraal VMについて、Qiitaさんのプラットフォームで、ご紹介をさせて頂こうと思います。
よろしくお願いします。

本日は、初めてなので、下記にて、全体資料／技術資料／Use Case／ハンドオンセミナーのご案内等のリンク情報を共有しますね。


＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
■　全体資料
・　https://www.oracle.com/jp/java/graalvm/ (日本語)
・　https://www.oracle.com/java/graalvm/　（英語）
・技術概要 : https://www.oracle.com/jp/a/ocom/docs/tools/graalvm-ee-data-sheet-jp.pdf
・Dummies eBook無料ダウンロード:https://www.oracle.com/jp/java/graalvm/graalvm-for-dummies-ebook/
 

■　Technical Info.
・　Full Doc : https://docs.oracle.com/en/graalvm/enterprise/22/docs/overview/　（英語）
・　PoC Doc(Simple) :
https://urldefense.com/v3/__https://medium.com/graalvm/graalvm-ten-things-12d9111f307d__;!!ACWV5N9M2RV99hQ!e3kNq_A7OMZc0rwP4bK8CiuMOzH6xkTq_6ya9CfeN2nE0A10PAEToRhoz0rti-rtcoTEkg$ 　（英語）
・　GraalVM Enterprise downloads page ：
https://www.oracle.com/jp/downloads/graalvm-downloads.html
・　GraalVM マニュアル（日本語） 
https://docs.oracle.com/cd/F44923_01/index.html

■ 価格情報（Java SE Subscription）
「Java SE Subscriptionにはどれくらいコストがかかりますか。」の項をご参照く
ださい。（上から２つ目です。）
https://www.oracle.com/jp/java/technologies/java-se-subscription-faq.html#:~:text=Java%20SE%20Subscription%E3

■ ユーザーケース
a)　Pearson様
Minutes to Seconds: Pearson VUE’s GraalVM Journey
https://www.oracle.com/nl/a/ocom/docs/customer-reference-pearson.pdf

b) Standard　Chartered　Bank様
Simplifying the cloud native journey with GraalVM and Helidon
https://blogs.oracle.com/java/post/simplifying-the-cloud-native-journey-with-graalvm-and-helidon

c）　Facebook様
GraalVM at Facebook
https://urldefense.com/v3/__https://medium.com/graalvm/graalvm-at-facebook-af09338ac519__;!!ACWV5N9M2RV99hQ!e3kNq_A7OMZc0rwP4bK8CiuMOzH6xkTq_6ya9CfeN2nE0A10PAEToRhoz0rti-qjtaC2Qw$

d）　Alibaba様、
https://urldefense.com/v3/__https://medium.com/graalvm/alibaba-becomes-a-member-of-graalvm-advisory-board-dd3e99d5c702__;!!ACWV5N9M2RV99hQ!e3kNq_A7OMZc0rwP4bK8CiuMOzH6xkTq_6ya9CfeN2nE0A10PAEToRhoz0rti-oshin2CA$

e） Others
https://urldefense.com/v3/__https://www.graalvm.org/use-cases/__;!!ACWV5N9M2RV99hQ!e3kNq_A7OMZc0rwP4bK8CiuMOzH6xkTq_6ya9CfeN2nE0A10PAEToRhoz0rti-ogrETotA$


＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
Neumorphismを自動生成するアプリをリリースした

# Neumorphismとは？
![スクリーンショット 2022-04-20 16.49.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/fefbab8f-925a-1523-2d95-594801140df8.png)
こんな感じのやつです

「Soft UI」とも呼ばれています

# Neumorphism for SwiftUI

![スクリーンショット 2022-04-20 17.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/ee20f780-d379-d061-d182-4c4a31da35fd.png)

- BaceColor (基準となる色)
- Intensity (影の強度)
- Distance (影のぼかし)
- Light (光の方向)
- Shape (Neumorphismの形)

上記の5項目を設定すればSwiftUIのNeumorphismコードを自動生成します。

↓ここからインストールできます↓

https://apps.apple.com/jp/app/neumorphism-for-swiftui/id1619280099?mt=12


# 使いこなせばすごいカッコ良くなる
![400e0acd9cacd671a584a49ee566ac4c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/207ced3c-1a74-5af2-4a54-d8e77b3cce1a.png)

https://dribbble.com/shots/7994421-Skeuomorph-Mobile-Banking

# おわり
以上！宣伝記事でした！
delikaを使って日本の名山情報を見てみた

## はじめに
何か面白そうだったので、記載練習がてらに触ってみました。

https://qiita.com/official-events/30be12dd14c0aad2c1c2

## データ取り出しまで
ほぼこの記事そのままです。

https://qiita.com/hanaseleb/items/33649108281bd6d00aa4

```python
# delikaのclientとPandas他、必要なパッケージ
!pip install --extra-index-url=https://docs.delika.io/python/ delika[DataFrame]

import delika

#JWTの取得
token = delika.new_token(host= "https://api.delika.io/v1", open_browser = "true")
token.save()
client = delika.load_client()

# データフレームで取得
import delika.pandas
df1 = delika.pandas.read_delika_data(account_name="bpk_t", dataset_name="mountain", data_name="日本100名山.csv", client= client)
df1.head()
```
普通のimport pandasではエラーになっていた(import delika.pandasが必要)。delika用のpandasモジュールと思えばいいのだろうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/933ad2fb-e4f5-169d-0712-4859c5630e80.png)

## データで何するか
難しいことはする気力がなかったので、単純に条件に当てはまる標高の山を探してみます。
日本100名山の中に、1000m以上1500m以下の山がどれだけあるのでしょうか？

```python
df1[(df1['altitude'] >= 1000) & (df1['altitude'] <= 1500)]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/14c042e5-3d07-62cb-8781-3e22e34c1171.png)
答えは3つでした。名山なだけあってもっと高い山が多いようです(ちなみに1000未満は2つでした)。


## まとめ
高度なことはしてないけど、ちゃんとデータをとりだして使ってみることはできたのでないでしょうか。自分のデータセットも登録できるので、機会があればやってみたいです。
iOS アプリで古い iOS バージョンをサポート終了するときのチェックリスト

# はじめに
業務で iOS12 のサポート終了対応を行った。
次回作業時ラクするために対応したことをチェックリストにしておく。

# チェックリスト

- [ ]  ユーザー数の調査
    - サポート終了する iOS バージョンのユーザーがどれくらいいるのか GA などのアナリティクスツールで調べる
    - DAU、MAU それぞれ全体の何パーセントか、ユーザー数の推移とか
- [ ]  責任者へ確認
    - サポート終了の決定権を持っている責任者へユーザー数の調査結果を確認してもらって判断してもらう
    - サポート終了したい理由があればそれも合わせて確認
    - NG の場合
        - どうすればサポート終了していいのか明確にしてもらう
        - 明確にするために追加で調査が必要なのであれば対応
        - 次回確認日を決める
    - OK の場合
        - サポート終了までのスケジュールを決めて関係各所へ共有する
        - ユーザーに周知することも考慮し余裕を持ったスケジュールにする
- [ ]  お知らせ掲載
    - ユーザーへサポート終了のお知らせを掲載する
    - 掲載文の例
        ```
        - タイトル
        【重要】iOS 13未満サポート終了のお知らせ

        - 本文
        いつも「○○○」をご愛用いただき、誠にありがとうございます。

        このたび、「○○○」では、安全な環境でご利用いただくため、XXXX年XX月XX日をもちまして、iOS 13未満のサポートを終了いたします。
        iOSバージョンをご確認いただき、iOS 13未満でご利用の場合は、お手数ですが最新のOSバージョンにアップデートをお願いいたします。

        サポート終了後は、最新版アプリへのアップデートができなくなります。すでにインストール済みのアプリはそのままご利用いただけますが、サポートの対象外とさせていただきます。

        ---------------------------------
        iOS バージョン確認方法

        1.ホーム画面上で、「設定」を選択する
        2.「設定」の画面で、「一般」を選択する
        3.「一般」の画面で、「情報」を選択する
        ---------------------------------

        ご利用のみなさまにはご迷惑をおかけいたしますが、ご理解のほどよろしくお願いいたします。
        ```
- [ ]  `iOS Deployment Target` を変更する（スクリーンショットの XCode は 13.2.1 のもの）
![スクリーンショット 2022-04-18 13.55.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/118f4290-eda9-fb93-b76b-2c1dddf14b18.png)
    - 今回の iOS アプリでは [XCodeGen](https://github.com/yonaskolb/XcodeGen) を導入していたので `project.yml` の `deploymentTarget` を変更した
    ![スクリーンショット 2022-04-18 14.08.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/0db5142e-c7a1-9fee-de60-c95a8f688134.png)
- [ ]  `Podfile` の `platform` を変更する
![スクリーンショット 2022-04-18 14.09.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/149d53c3-92c1-c222-6729-7b1988b54c10.png)
- [ ]  iOS バージョンの条件処理を削除する
    - 以下のような処理
    ```swift
    guard #available(iOS 13.0, *) else {
        return
    }
    ```
    ```swift
    @available(iOS 13.0, *)
    private func handleAppRefresh(task: BGAppRefreshTask) {
    ```
- [ ]  検証
    - サポート対象の iOS で検証する
- [ ]  申請
- [ ]  リリース
- [ ]  推奨環境の更新
    - サービス内に推奨環境など記載している場合はそちらも更新
    - ドキュメント等も更新

# サポート終了になった iOS バージョンはどうなるか

- 新しいバージョンのアプリをリリースしてもアップデートできなくなる
- アプリのインストールは可能
    - サポート終了する前のバージョンのものがインストールされる
서로다른코드입니까?

#코드비교
filter안에 화살표함수를 사용했는데 결과값이 다르다.
아래 두코드가 다른코드입니까?
```javascript:code1
   addItem(state, item) {
// 여기부터
      const cartItems = state.items.filter(
        (cartItem) => cartItem.id === item.id
      );
// 여기까지
      if (cartItems.length === 0) {
        state.items.push({
          ...item,
          qty: 1,
        });
      } else {
        cartItems[0].qty++;
      }
    },
```
```javascript:code2
    addItem(state, item) {
// 여기부터
      const resultItems = state.items.filter((cartItem) => {
        cartItem.id === item.id;
      });
// 여기까지
      if (resultItems.length === 0) {
        state.items.push({
          ...item,
          qty: 1,
        });
      } else {
        resultItems[0].qty++;
      }
    },
```
【初心者応援】デグレしないために気をつけること

# 初めに
今回は、デグレを起こさないために気をつけるべきことを紹介していきたいと思います。
デグレとは、不具合修正をした際に元々正常だった動作が不具合を起こすことを言います。

### 正常動作と異常動作の確認をする
正常時の動作はどういったものなのか、今回の不具合はどういった異常が起こってしまっているのかを把握することで、不具合の原因に見当をつける際にかなり絞ることができます。
そして、正常時との違いを把握することで他の部分に対して無駄な変更をしなくて済むので、間接的にデグレが起こることを未然に防ぐことができます。

### 修正は大雑把にしすぎない
通信部分や変数に修正を加える際に、大元を変えてしまったりすると意図しない変更が起こってしまい他の部分にも影響が出てしまいます。
そのためにも3段回に分けるといいかと思います。
　1.原因を発見
　2.それを修正するのに必要なことを見定める
　3.実装するのにはどうするのが適切なのかを考える
このように、修正に必要なものを見定めた後に適切な修正はどれかを考えることで、直線的な考えをしてデグレが起こってしまうということを防ぐことができます。

### 修正前に目印を立てる
対象に変数の値が更新される場所などにLog.dやBreakPointなどで目印を立てておくことで、自分の修正による予期せぬ値の更新を即座に気付くことができます。
これはコードだけでなくxmlファイルなどにも同じことが言えます。
color.xmlやdrawableファイルは共通して使用することが多いので目印を立てておくことで、確認漏れが減ることにつながります。

# 最後に
今回は初心者だけでなく誰しもが気づかずやってしまうデグレについて書いてみました。
初心者だけでなく誰でも可能性があることなので、ぜひ初心者以外の皆さんにもお役に立てれば嬉しいです。
【AWS】AmazonLinux2にmysql-community-clientをインストールする際のGPGキーのエラー対処

# はじめに
AWSの学習の一環でRDSに接続するためのMySQLクライアント(`mysql-community-client`)をAmazonLinux2にインストールを実施しました。
しかし、GPGキーのエラーが発生しインストールができなかったため、対処方法を記事にしたいと思います。

# 前提
- AmazonLinux2とMySQLクライアント(`mysql-community-client`)のバージョンは以下になります。

```bash:AmazonLinux2バージョン
[ec2-user@ip-192-168-1-105 ~]$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
[ec2-user@ip-192-168-1-105 ~]$
```

```bash:MySQLクライアントバージョン
[ec2-user@ip-192-168-1-105 ~]$ mysql --version
mysql  Ver 8.0.28 for Linux on x86_64 (MySQL Community Server - GPL)
[ec2-user@ip-192-168-1-105 ~]$
```

- 本記事ではエラー対処のみの解説とさせて頂きます。

MySQLクライアント(`mysql-community-client`)のインストール手順は以下の記事等を参照下さい。

https://qiita.com/tamorieeeen/items/d9b2af588f1dfd43120d

# 事象
以下のコマンドを用いてMySQLクライアントをインストールしようとするとGPGキーのエラーが表示され、インストールが途中で止まる。

```bash:実行コマンド
sudo yum install -y mysql-community-client
``` 

```bash:実行内容
[ec2-user@ip-192-168-1-105 ~]$ sudo yum install -y mysql-community-client
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd

mysql-connectors-community                               | 2.6 kB     00:00     

mysql-tools-community                                    | 2.6 kB     00:00     

mysql80-community                                        | 2.6 kB     00:00  
〜〜〜省略〜〜〜
mysql-community-client-8.0.28-1.el7.x86_64.rpm の公開鍵がインストールされていません

 Failing package is: mysql-community-client-8.0.28-1.el7.x86_64
 GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql 
```

# 対処方法
以下コマンドを用いて、GPGキーのインポートを実施する。

```bash:コマンド
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
```

GPGキーのインストール実施後に、再度以下のコマンドでMySQLクライアントのインストールを実施する。

```bash:実行コマンド
sudo yum install -y mysql-community-client
``` 

# 解説
以下のMySQL公式のドキュメントを確認すると、MySQL 8.0.28以降のバージョンをインストール(アップデート)する際はGPGキーのインポートが必要とのことです。

https://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/

# 参考記事
https://blog.katsubemakito.net/mysql/mysql-update-error-gpg