OmniAICreator/Qiita-1.07M huggingface dataset:
Python/FastAPIからのElasticsearch利用方法メモ

* ローカル環境で起動中のElasticsearchにPythonで接続・操作する方法についてメモする。

## 事前準備

### ライブラリインストール

```shell
pip install 'elasticsearch<7.14.0'
```

※バージョン指定しないと`raise UnsupportedProductError(
elasticsearch.UnsupportedProductError: The client noticed that the server is not Elasticsearch and we do not support this unknown product`なるエラーが出力された。

### Elasticsearch準備

* **[こちら](https://qiita.com/KWS_0901/items/c300b5ee010cb48dbaa3)**の手順でElasticsearchコンテナを起動しておく。

## サンプルAPIコード

* `app.py`

```python
from fastapi import FastAPI
from elasticsearch import Elasticsearch

app = FastAPI()

@app.get("/indices")
def indices():
    # Connect to Local Elasticsearch
    es = Elasticsearch(
        "http://localhost:9200",
        # Your Credentials
        http_auth=("elastic", "P@ssw0rd")
    )
    
    # Getting Indices
    indices = es.cat.indices(index='*', h='index').splitlines()
    
    # Showing Indices
    for index in indices:
        print(index)
    
    # Close Connection
    es.close()
    return {"indices": indices}
```



## 動作確認

* サンプルAPI起動

  ```shell
  uvicorn app:app --reload
  INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
  INFO:     Started reloader process [29459] using statreload
  INFO:     Started server process [29464]
  INFO:     Waiting for application startup.
  INFO:     Application startup complete.
  ```

* リクエスト

  ```http
  GET /indices HTTP/1.1
  Host: 127.0.0.1:8000
  ```

  

* レスポンス

  ```json
  {
      "indices": [
          ".monitoring-kibana-7-2022.02.19",
          ".security-7",
          "test-index",
          ".apm-custom-link",
          ".kibana_task_manager_1",
          ".kibana-event-log-7.11.1-000001",
          ".apm-agent-configuration",
          ".monitoring-es-7-2022.02.19",
          ".kibana_1"
      ]
  }
  ```

  ※インデックス一覧が取得される



## 参考情報

* [Python Elasticsearch 基本的な使い方まとめ](https://qiita.com/satto_sann/items/8a63761bbfd6542bb9a2)
iOS / Android のロケールID一覧

端末の地域と言語の設定は、アプリでは Locale として観測できますが、Locale ID を網羅した最新のリストが見当たらなかったので CSV ファイルを作りました。数年前のデータは Google 検索すると見付かるのですが、広東語とかが入ってないんですよね。

# CSV ファイル

- iOS版 [ioslocaleidentifiers.csv](https://gist.github.com/okaxaki/e355b3784983edc8b357f48e92b0e69c)
- Android版 [androidlocaleidentifiers.csv](https://gist.github.com/okaxaki/fc4fa7c96812de6444cffdbeaa9d647f)

# 製法
iOS は NSLocale の availableLocaleIdentifiers と localizedStringForLocaleIdentifier を使って、次のコードをビルドし、iOS 15.1 端末実機で動かして取得しました。OSバージョンが違うと結果は変わります。

```objc
NSArray *locales = [NSLocale availableLocaleIdentifiers];
for(NSString *locale in locales) {
  NSLog(@"%@:%@", locale, [[NSLocale currentLocale] localizedStringForLocaleIdentifier:locale]);
}
```

Android は Locale の getAvailableLocales を使って、次のコードを Android 12 エミュレータ (API 31) で実行して取得しました。APIレベルが違うと結果は変わります。

```kotlin
for (locale in Locale.getAvailableLocales()) {
  Log.d("LOCALE", locale.toLanguageTag() + "\t" + locale.displayName);
}
```
タブオーダーでエンジニアのレベルを測る

ということを十数年前はやっていました。
今はデフォルトでいい感じなので、あまり意識されません。
# Tabキーによるフォーカスの移動
webアプリでもネイティブアプリでも、TabまたはShift+Tabによりフォーカスを移動する事ができます。

Qiitaのトップでやるとこんな感じでした。
![qiitaanimation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/73ed7575-8729-3b25-6557-acb18113854f.gif)
この、フォーカスが移動する順番を**tab order**といいます。

# tab order
tab orderは別名**tab index**とも呼ばれます。
言語やフレームワークによって呼び方が違うのかと思いましたが、あまり調べていません。
知っている方はコメントください。
このtab orderがユーザーの直観にマッチしているか否かで、操作が気持ちい物になるか、気持ち悪い物になるかの分かれ目となります。(主観)

# ネイティブアプリ
MFCやWPF等ではtab orderは**いい感じ**にはならず、デフォルトではコントロールの追加順に割り振られます。
MFCでは手動でtab orderを調整します。
WPFではxamlの記述順で調整できます。

よって、如何に見た目を整えようとそこに育ちの悪さが出ます。
以下は見た目も悪いですが
![mainwindow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/34454613-12e1-33cb-aa9b-cf0164fffc61.gif)
フォーカス移動が気持ち悪いですね 
今どきのアプリはちゃんとしてるので、いい悪い例を探すのは難しいです。
# まとめ
フロントエンド開発ではあまり意識する必要はないでしょう。
古来の日本人よろしく、右上から左下にかけてフォーカス移動したいぜって方は、技術上可能だという事を覚えておいてください。
ランダムに割り振るのも面白い？

古いアプリと出会ったら、タブ移動で遊んでみてください。

## ところで
Qiitaのトップページ狭めて検索フォームちっちゃくすると、タブで移動できなかったのはそんなもんですかね。
API Gateway + Lambda(Python) の REST API でステータスコード管理をする

# 背景
API Gateway + Lambda(Python) の REST API があったのですが、えいやで作ったのでエラーハンドリングを全然していませんでした。
全てステータスコード200で返してパラメータでエラーかどうかを設定する方法のが簡単そうでしたが、やっぱり個人的に気持ち悪さを感じるのできっちりステータスコードを使い分けようと思いました。
AWS初心者の私には結構複雑だったのでメモっておきます。
自分的ベストプラクティスのつもりですが、一般的なベストプラクティスがあればぜひコメントください。

# 結論
先にざっくりと結論から。

### API Gateway の設定
- [メソッドレスポンスにステータスコードを追加する](#メソッドレスポンスにステータスコードを追加する)
- [総合レスポンスにステータスコードに対応するマッピングを追加する](#総合レスポンスにステータスコードに対応するマッピングを追加する)

### Lambda でやること
- [マッピングに該当する"errorMessage"を返却する](#マッピングに該当するerrormessageを返却する)

模索している時は大変だったけど結論にするとなんと簡単そうなことか・・・

# API Gateway の設定
### メソッドレスポンスにステータスコードを追加する
1. メソッドを選んでメソッドレスポンスを選択
1. [レスポンスの追加]から追加したいステータスコードを入力して追加

![スクリーンショット 2022-02-19 14.14.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231600/bc2831d6-0def-7096-ff0b-7b276944f717.png)

これだけです。簡単です。
今回は400を追加しています。（200はデフォルト）

### 総合レスポンスにステータスコードに対応するマッピングを追加する
1. メソッドを選んで総合スポンスを選択
1. [統合レスポンスの追加]からステータスコードに対応するマッピングを設定する

|項目|値|
|-|-|
|Lambda エラーの正規表現|^\\\[400\\\].*|
|マッピングテンプレート<br>Content-Type|application/json|
|マッピングテンプレート<br>JSON内容|{<br>"errorMessage": "\$input.path('$.errorMessage')"<br>}|

![スクリーンショット 2022-02-19 14.19.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231600/e089eba4-14d9-f306-0bd9-05546d28e180.png)
一度保存するとマッチングテンプレートが設定できる。
![スクリーンショット 2022-02-19 14.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231600/e374a2e4-faac-62e9-b404-4756e67857c7.png)


正規表現は"[400]"で始まるerrorMessageにマッチします。
マッチングテンプレートはレスポンスに"errorMessage"だけ設定されるようにしています。
そのままだとスタックトレースとかも出てしまうので。
この辺はお好みで設定してください。

このように設定を入れると

```json
{
    "errorMessage": "[400] バリデーションエラー",
    "errorType": "Exception",
    "requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "stackTrace":[
        "hogehoge"
    ]
}
```

というLambdaのレスポンスを検知するとステータスコードが400になり、

```json
{
    "errorMessage": "[400] バリデーションエラー"
}
```

に変換して返却してくれます。

設定を入れたらAPIのデプロイをして反映させます。

# Lambda でやること
### マッピングに該当する"errorMessage"を返却する

```python
raise Exception('[400] バリデーションエラー')
```

このように例外を発生させてあげるだけで必要としている以下のようなレスポンスが生成されます。（上で書いた奴と同じレスポンス）

```json
{
    "errorMessage": "[400] バリデーションエラー",
    "errorType": "Exception",
    "requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "stackTrace":[
        "hogehoge"
    ]
}
```

### 結果
APIのリクエスト結果が下のようになりました。
![スクリーンショット 2022-02-19 14.34.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231600/8774cfbd-122f-c6bb-a4d7-8ab0a0990f5d.png)

これが私のやりたかった形でした。
あとはLambda側で独自の例外を作ったりをすればいい感じになるかなと思います。
Elasticsearch + Kibana ローカル環境構築方法メモ

## Elasticsearch

* Elastic社により開発されたJSONベースの検索/分析エンジン

## Kibana

* Elastic社により開発されたデータ可視化ツール
* Elasticsearchと連携してグラフ描画などが可能

## 構築手順

* `docker-compose.yml`用意

  ```yaml
  version: "3.3"
  
  services:
    elasticsearch:
      image: docker.elastic.co/elasticsearch/elasticsearch:7.11.1
      container_name: elasticsearch
      environment:
        - discovery.type=single-node
        - cluster.name=docker-cluster
        - bootstrap.memory_lock=true
        - xpack.security.enabled=true
        - xpack.monitoring.collection.enabled=true
        - ELASTIC_PASSWORD=P@ssw0rd
        - "ES_JAVA_OPTS=-Xms512M -Xmx512M"
      ulimits:
        memlock:
          soft: -1
          hard: -1
      ports:
        - 9200:9200
      volumes:
        - elasticsearch-data:/usr/share/elasticsearch/data
      restart: always
    kibana:
      image: docker.elastic.co/kibana/kibana:7.11.1
      container_name: kibana
      ports:
        - 5601:5601
      environment:
        - ELASTICSEARCH_URL=http://elasticsearch:9200
        - ELASTICSEARCH_USERNAME=elastic
        - ELASTICSEARCH_PASSWORD=P@ssw0rd
      depends_on:
        - elasticsearch
      restart: always
  
  volumes:
    elasticsearch-data:
      driver: local
  ```

* 起動

  ```shell
  docker-compose up -d
  ```
  * <http://localhost:9200>でElasticsearchが、<http://localhost:5601>でKibanaが起動する。


## 動作確認

* <http://localhost:5601>にアクセス(ログイン画面が表示される)

* `docker-compose.yml`に記載の認証情報でログイン(次の画面が表示される)
![kibana.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/4daa41fd-5901-98ea-8154-1d6f90e24c89.png)


* [`Dev tools`](http://localhost:5601/app/dev_tools#/console)にアクセス

  ![kibana_devtool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/1f807344-440f-f9c1-af86-44dc97eb9586.png)


* コンソールに次のコマンドを張り付け、実行

  ```
  GET /_cat/nodes?v
  ```

  ```
  ip         heap.percent ram.percent cpu load_1m load_5m load_15m node.role  master name
  172.28.0.2           30          74   4    0.14    0.35     1.25 cdhilmrstw *      bd2adf4adca9
  ```

  ※nameにElasticsearchのコンテナIDが表示される。

## 参考情報

* [docker image を使って Elasticsearch & Kibana を実行してみるまで](https://qiita.com/blueskyarea/items/ebf219c413d0329ceb4f)
運用管理ソフトウェア「Hinemos」を使ってみる！！part1 ～はじめに～

# 1.はじめに
基盤系のエンジニアしています。
最近、運用管理ソフトウェアである「Hinemos」を利用する機会があったので、備忘がてらまとめていきます。あとは、少しでも誰かのお役に立てれば。。

Qiitaに投稿するの初めてなので、読みにくかったらすいません。m(__)m

# 2.Hinemosとは

Hinemos（ヒネモス）は、複数のコンピュータを単一のコンピュータのイメージで運用管理することを実現するオープンソースソフトウェア。運用目的ごとにコンピュータをグループ登録し、グループに対して状態監視、ジョブ管理、性能管理、環境構築、収集蓄積を行う機能を備えている。
(出典: フリー百科事典『ウィキペディア（Wikipedia）』[リンク](https://ja.wikipedia.org/wiki/Hinemos))

というわけで、「ジョブ管理」とか「サーバ監視」をしてくれる。
巷では、富士通"SystemWalker"や日立"JP1"やIBM"Tivoli"とかあるけど、HinemosはOSSであることが最大の魅力かな。デメリットにもなるけど。。。

# 3.導入環境
貧弱なノートパソコン上に仮想環境用意して、マネージャとエージェントの2台のサーバを構築します。
（商用時はちゃんとサイジングしましょう。）

[Hinemosマネージャ]
Hinemos：manager-6.2.2
OS：Centos7.9-2009
CPU：4コア
メモリ：1000MB
ディスク：50GB
IPアドレス：192.168.1.1

[Hinemosエージェント]
Hinemos：agent-6.2.2
OS：Centos7.9-2009
CPU：4コア
メモリ：512MB
ディスク：50GB
IPアドレス：192.168.1.150

# 4.今後の展望
下記をこれから記載していく予定です。
（自分にプレッシャーをかけるスタイル）
◆Hinemosマネージャインストール
 ・[運用管理ソフトウェア「Hinemos」を使ってみる！！part2 ～マネージャインストール①～](https://qiita.com/takuyasuzuki9/items/c00079a3bf0096e59920)
 ・[運用管理ソフトウェア「Hinemos」を使ってみる！！part3 ～マネージャインストール②～](https://qiita.com/takuyasuzuki9/items/14b7754ac37f92c6d18a)
◆hinemosエージェントインストール
・[運用管理ソフトウェア「Hinemos」を使ってみる！！part4 ～エージェントインストール～](https://qiita.com/takuyasuzuki9/items/b31f52f049737905dd5b)
◆エージェント登録
・[運用管理ソフトウェア「Hinemos」を使ってみる！！part5 ～エージェント登録～](https://qiita.com/takuyasuzuki9/items/7df23705bcfba25dd8b3)
◆監視機能
・[運用管理ソフトウェア「Hinemos」を使ってみる！！part6 ～監視機能～](https://qiita.com/takuyasuzuki9/items/997f32dbd9dd4e288e39)
◆ジョブ機能
・[運用管理ソフトウェア「Hinemos」を使ってみる！！part7 ～ジョブ機能～](https://qiita.com/takuyasuzuki9/items/edff69e9fa3b8112d248)
複数画像アップロード/アップロード先の指定（PHP）

# はじめに
複数画像を指定のディレクトリにアップロードしたいシーンがあったので、忘れないようにここにまとめます。

# 実装

```html:index.html
<form action="upload.php" method="post" enctype="multipart/form-data">
	<input type="file" name="files[]" multiple>
	<input type="submit" value="アップロード">
</form>
```

```php:upload.php
foreach ($_FILES["files"]["error"] as $key => $error) {
    if ($error == UPLOAD_ERR_OK) {
        $tmp_name = $_FILES["files"]["tmp_name"][$key];
        $name = basename($_FILES["files"]["name"][$key]);
        $upload_path = "./img/".$name; //upload先のパス
        move_uploaded_file($tmp_name, $upload_path);
    }
}
```

# 複数画像アップロード
## enctype="multipart/form-data"
画像をアップロードするためにはフォームで`enctype="multipart/form-data"`を指定する必要があります。

> enctype属性は、フォームの送信データのMIMEタイプを設定するための属性です。
属性値にMIMEタイプを示す文字列を指定することで、フォームのデータが送信される際に用いられるMIMEタイプを設定することができます。
type属性の値に「file」が設定されたinput要素をフォームに用いる際は、enctype属性の値に「multipart/form-data」を指定する必要があります。
引用元：[enctype属性 | 用語集 | ミツエーリンクス](https://www.mitsue.co.jp/glossary/html4_xhtml1/attribute/enctype.html#:~:text=enctype%E5%B1%9E%E6%80%A7%E3%81%AF%E3%80%81%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82)


## multiple
multiple属性を設定することで、フォームコントロールが1つ以上の値を受け入れられるようになります。また、name部分で`files[]`のように指定することで、同じnameで配列として取得することができます。

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/multiple

https://www.php.net/manual/ja/features.file-upload.multiple.php

# アップロードファイルの移動
## POSTされたデータについて
`$_FILES`にPOSTされたデータが格納されています。以下に、$_FILESの詳細について記載します（※userfileはinputのnameを指しています）。

 - ***$_FILES['userfile']['name']***
クライアントマシンの元のファイル名。

 - ***$_FILES['userfile']['type']***
ファイルの MIME 型。ただし、ブラウザがこの情報を提供する場合。 例えば、"image/gif" のようになります。 この MIME 型は PHP 側ではチェックされません。そのため、 この値は信用できません。

 - ***$_FILES['userfile']['size']***
アップロードされたファイルのバイト単位のサイズ。

 - ***$_FILES['userfile']['tmp_name']***
アップロードされたファイルがサーバー上で保存されているテンポラ リファイルの名前。

 - ***$_FILES['userfile']['error']***
このファイルアップロードに関する エラーコード

 - ***$_FILES['userfile']['full_path']***
ブラウザからアップロードされたファイルのフルパス。 この値は実際のディレクトリ構造を反映しているとは必ずしも言えないため、 信用できません。 PHP 8.1.0 以降で利用可能です。

https://www.php.net/manual/ja/features.file-upload.post-method.php

今回は、`name`、`tmp_name`、`error`を使います。

`UPLOAD_ERR_OK`はエラーがなく、ファイルのアップロードに成功した場合のことです（値:0）。
そのほかにもエラーによって値が決まっているため、詳細は公式ドキュメントを。

https://www.php.net/manual/ja/features.file-upload.errors.php


## ファイルの移動
ファイルアップロードに成功したら、一時ファイルの名前（tmp_name）とファイルの名前（tmp_name）を取得し、`move_uploaded_file()`で指定の場所に移動させています。

https://www.php.net/manual/ja/function.move-uploaded-file.php

# まとめ
今回は、PHPで複数画像のアップロードとアップロード先の指定方法についてまとめました。

以上。
[Oracle Cloud] Identity Domainsを使ってみる③ 管理者ロールを使ってドメイン内のユーザ管理権限を委任する

# はじめに

Identity Domainsが使えるアカウントを触る機会があったので、いろいろと試しています。
今回は、管理者ロールを試します。

[管理者ロールのマニュアル](https://docs.oracle.com/ja-jp/iaas/Content/Identity/roles/understand-administrator-roles.htm)

管理者ロールは、IDCS側にもともと存在していました。ただし、従来はOCI IAM側の権限も必要で、設定が面倒だったと思います。
Identity Domainsになって、OCI IAMと統合されたことにより、OCI IAM側の権限設定が不要になり設定が簡素化されたと思います。

ここでは、「ユーザー管理者」ロールを使って、ドメイン内のユーザ管理権限を別ユーザに委任してみます。

# さわってみる
## ユーザ管理を委任するユーザの作成

ドメイン管理者でログイン後、ドメインの設定画面に遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/5fd1afbe-84f5-7268-40c2-513a312924bb.png)


「ユーザー」リンクを押下して、「ユーザーの作成」ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/70c1ec93-67f3-2450-129b-e685f46cf998.png)

ユーザ管理を委任するユーザを作成します。所属グループは指定せずに作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/75b65592-735f-9ddb-1e3f-238826abc988.png)


## ロールの割り当て

ドメインの設定画面から、「セキュリティ」リンクを選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/d76c7b2c-5cc3-ca8c-0b34-2773e66651a6.png)


「管理者」のリンクを選択し、「ユーザー管理者」を選択⇒「ユーザーの追加」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/270e40ff-da9f-8728-316d-4f7dfac32255.png)

先ほど作成したユーザを選択して、「ユーザーの追加」ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/18e4b4ab-e391-c671-7d14-6ba5f5948c64.png)

## ユーザ・グループが作成できることを確認

ユーザ作成時に指定したメールアドレスにアクティベート用のメールが送信されます。初期パスワードを設定し、OCIにログインします。

ドメインの設定画面に遷移します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/6c54b05f-6e84-3916-64b2-050ed4d36b8b.png)

グループが作成できることを試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/098c6311-5a62-2cca-87aa-4f9ef889ff7c.png)

作れました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/78344dc3-908c-325d-76b7-3acfba73fb47.png)

続いて、ユーザを作成できることを試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/c8b08966-9992-1fef-621f-26f8cd901c09.png)

こちらも作成できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1674918/61a95d3c-de15-0c1a-30d8-f9e7dafbdb74.png)


ということで、ユーザ管理専用のユーザを簡単に作成することができました。

# 補足

管理者ロールを使わない場合は、従来どおりに、以下のようにポリシーを使って、ドメイン内のグループに権限を付与することでもユーザ/グループの作成権限を付与することもできました。でも、管理者ロールを使った方が設定が簡単・シンプルになる気がします。

```
allow group ドメイン名/グループ名 to manage users in tenancy
allow group ドメイン名/グループ名 to manage groups in tenancy
```
Ruby3.1.1のインストール(忘備録)

エラー内容を載せてなくてすみません。とりあえずの忘備録。

macOS Monterey(12.2.1)
CPUはIntel

```
$ rbenv install -v 3.1.1
```

がこける

以下やったこと


これをみると`binutils`が新しいといいらしい
https://github.com/rbenv/ruby-build/issues/1723

自分は入ってなかったので

```
$ brew install binutils
```

とした上で(binutils 2.37が入りました)pathを通す

.zshrcに

```
export PATH="/usr/local/opt/binutils/bin:$PATH"
```

を書く


まだダメだった(opensslのビルドでだめ)のでopensslをHomebrewで入れてある`openssl@1.1`の方を使う
参考: https://qiita.com/mikan3rd/items/d1dfd7cb62cc23393dd9

```
$ export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1) --with-readline-dir=$(brew --prefix readline) --with-libyaml-dir=$(brew --prefix libyaml) --with-zlib-dir=$(brew --prefix zlib)"
```

まだエラーが出るのでさっきのissueを参考にRUBY_CONFIGURE_OPTSに`rb_cv_symbol_prefix=_`を足してみる
https://github.com/rbenv/ruby-build/issues/1723

```
$ export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1) --with-readline-dir=$(brew --prefix readline) --with-libyaml-dir=$(brew --prefix libyaml) --with-zlib-dir=$(brew --prefix zlib) rb_cv_symbol_prefix=_"
```

これでも`llvm-ar`が見つからないというエラーが出るのでこうしてみる

```
$ export AR=/usr/bin/ar 
```

これで入った。

追記：

上記で入れたrubyでgrpc gem(1.43.1)が入らない
Node.js: Cognito から Access Token を取得

AWS の Cognito から JWT Access Token を取得する方法です。

ライブラリーのインストール

```bash
sudo npm install amazon-cognito-identity-js
```

```js:get_token.js
// ---------------------------------------------------------------
//
//	get_token.js
//
//						Feb/19/2022
// ---------------------------------------------------------------
'use strict'

console.error("*** start ***")

var cognito = require('amazon-cognito-identity-js')

const dotenv = require('dotenv')

dotenv.config()
const user_pool_id = `${process.env.USER_POOL_ID}`
const user_pool_client_id = `${process.env.USER_POOL_CLIENT_ID}`
const usr = `${process.env.USR}`
const password = `${process.env.PASSWORD}`

console.error(usr)
console.error(password)


var poolData = {
	UserPoolId : user_pool_id,
	ClientId : user_pool_client_id
}

var userPool = new cognito.CognitoUserPool(poolData)

var authenticationData = {
	Username : usr,
	Password : password
}

var authenticationDetails = new cognito.AuthenticationDetails(authenticationData)
var userData = {
	Username : usr,
	Pool : userPool
}

var cognitoUser = new cognito.CognitoUser(userData)
cognitoUser.authenticateUser(authenticationDetails, {
	onSuccess: function (result) {
		console.log('access token')
		console.log(result.getAccessToken().getJwtToken())
	},

	onFailure: function(err) {
		console.error("*** error ***")
		console.error('error ' + err)
	},
})

console.error("*** end ***")
```

```text:.env
USER_POOL_ID="ap-northeast-1_510w*****"
USER_POOL_CLIENT_ID="818aso07e5pd8dj*******"
USR="aaa@example.com"
PASSWORD="secret123"
```

実行スクリプト

```bash
export NODE_PATH=/usr/local/lib/node_modules
node get_token.js
```

次の環境で確認しました。

```text
$ uname -a
Linux iwata 5.13.0-27-generic #29-Ubuntu SMP Wed Jan 12 17:36:47 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

$ node --version
v17.5.0

$ npm --version
8.5.1
```
Qt+OpenGLでゲーム制作 ～OpenGLを使う その2

#Qt+OpenGLでゲーム制作
######OpenGLの便利なラッパークラスを使いたい

Qtを使うメリットの一つだと思っていますが、Qtで用意されている便利なOpenGLのラッパークラスを色々使いたい。QOpenGLFunctionsクラスで色々定義されていて、なんだか見覚えのある関数が。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/a8ddb376-2a11-c1ea-4081-e564566a34ab.png)

このあたり、私が書くより公式のサンプル見た方が分かりやすい気がしてきたぞ！！　公式の「Hello GL2 Example」とか見ると初期化とかウィンドウ生成とか頂点バッファとかシンプルなソースコードでまとまっているのでそっち見た方が早いと思います。（丸投げですが）

https://doc.qt.io/qt-5/qtopengl-hellogl2-example.html

ゲーム制作をそもそもやったことないので、どちらかと言うとソースコード云々より今まで全くゲーム制作経験ない人間が、どう言う過程で色々作っていくのかを書いた方が良いですよね。

とりあえず真っ先に必要なのは文字描画とか思っています。OpenGLは文字描画機能が標準で無いですし。まずはゲーム向けの文字描画からですね。

+  テクスチャに事前に書いた文字を貼り付け　(英字はこれでOK)
+  ある程度リアルタイムにオフスクリーンサーフェス生成してUV指定して描画(日本語向け)
+  特殊な表現向けにポリゴンで描画

の3種類くらい用意すれば当面大丈夫そうな気がするのでこの辺から。
VS Code エディターとターミナルのフォーカスを切り替える

VS Codeでターミナルを利用するとき、フォーカスするのにマウスクリックが面倒。

## フォーカス切り替えのショートカットを登録する

[コマンドパレット(`Ctrl+Shift+P`)]→[`Preferences: Open Keyboard Shortcuts (JSON)`]を開き、以下の設定を追加する

```json
[
  {
      "key": "ctrl+:",
      "command": "workbench.action.focusActiveEditorGroup",
      "when": "terminalFocus"
  },
  {
      "key": "ctrl+:",
      "command": "workbench.action.terminal.focus",
      "when": "editorFocus"
  }
]
```

## その他ターミナル関連ショートカット

- `ctrl+@`：ターミナルを表示/非表示する
- `ctrl+PageUp`,`ctrl+PageDown`：前/後のターミナルに移動する
Rails 'error Command "webpack" not found.'について

#内容
ターミナルにて

```
$ rails s
```

をした際、

```
Webpacker::Manifest::MissingEntryError
Webpacker can't find application in /public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
}
):
     6:     <%= csp_meta_tag %>
     7:
     8:     <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
     9:     <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    10:   </head>
    11:
    12:   <body>

app/views/layouts/application.html.erb:9
```
とでてしまう。

webpackerをinstallし、下記のコマンドを打っても

```
$ rails webpacker:compile
Compiling...
Compilation failed:
yarn run v1.22.10
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.


error Command "webpack" not found.
```

と出てしまった。

#解決策

1,gemファイル内のwebpackerを最新のものにする。 

```rails:Gemfile
gem 'webpacker',    '~> 5.0'
```

2,その後に、bundleを行う。

```
bundle
```

3,webpackerのinstallを再度行う。その際に、conflictを起こして何か聞かれてもYで押し切る。

```
bundle exec rails webpacker:install
```

4,その後、webpackerをcompileする。

```
bundle exec rails webpacker:compile
```

再度rails sをするとerrorが直っている。
以上。

#参考
(https://techblg.app/articles/handle-webpacker-manifest-missing-entry-error/)
Chrome拡張開発 Getting Started（React×Webpackのボイラープレートを利用した場合）

# はじめに
公式ドキュメント読みながらちょっと触ってみるだけの記事

https://developer.chrome.com/docs/extensions/mv3/getstarted/

## 前提

- 環境構築は別記事にしてるので割愛。（ボイラープレートを用いてます）

https://qiita.com/nh321/items/cf7282cc3874220ad399

# Getting Started

https://developer.chrome.com/docs/extensions/mv3/getstarted/

## Create the manifest
> Load an unpacked extension

終わってまーす

## Add functionality

背景色を修正するのを試すらしい。やってみよう。

> Register the background script in the manifest

```json:公式
  "background": {
    "service_worker": "background.js"
  }
```

```json:今回
  "background": {
    "service_worker": "background.bundle.js"
  },
```

公式は `background.js` だけど、 `background.budle.js` が環境構築時に既に設定されてるっぽいな。

> Create the background script

ボイラープレート側で既に作られているのかと思いきや、見当たらない。。。
ボイラープレート側の説明によると、機能は`src`フォルダに記載すべきということなので、そこら辺を調べてみる。

```javascript:src/pages/Background/index.js
console.log('This is the background page.');
console.log('Put the background scripts here.');

```
これが該当するっぽい。これが自動生成されて`background.bundle.js`になるんじゃなかろうか（推測）

```javascript:src/pages/Background/index.js
let color = '#3aa757';

chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ color });
  console.log('Default background color set to %cgreen', `color: ${color}`);
});
```
公式の言う通りに書き換えてみる。

> Add the storage permission

ストレージへのアクセス権をマニフェストに追加しろとのこと。
ボイラープレート側には記載されてないので、追加する。

```json:manifest.json
  "permissions": [
    "storage"
  ],
```
"background"と"action"の間くらいに追加

> Inspect the background script

1. chrome://extensions/
1. 今回の拡張の再読み込みボタンを押下
1. 青いリンクの「Service Worker」をクリック！
1. 開いたウィンドウのconsoleタブに「Default background color set to green」が表示される

:relaxed:

## Introduce a user interface
何やら「ポップアップ画面のUIを表示してみよう」と言うことらしい。
ただ、ボイラープレート側で既に用意してくれてるので、確認したいだけなら右上の拡張からページを表示できることを確認できる。
が、一応Reactに当てはめたら・・・ってのでやってみよう。

マニフェストは一旦無視して良さそうなので、無視。
公式ではpopup.htmlだが、ボイラープレートはreactにしてるので、そこは違う。
ボイラープレートには`src/pages/Popup/`あたりにソースがある。

`popup.html`＞`head`＞`css`:直接`index.html`に記載してもいいけど、`Popup.jsx`でインポートする感じのがreactっぽいので、そうする。
`popup.html`＞`body`＞`button`：直接`index.html`に記載してもいいけど、`Popup.jsx`に記載する感じのがreactっぽいので、そうする。
`button.css`：index.cssに記載してもいいけど、reactっぽくないので、単独ファイル化する。
（reactぽい/ぽくないは、雰囲気でやってます）

```css:src/pages/Popup/button.css
button {
  height: 30px;
  width: 30px;
  outline: none;
  margin: 10px;
  border: none;
  border-radius: 2px;
}

button.current {
  box-shadow: 0 0 0 2px white,
              0 0 0 4px black;
}
```

```jsx:src/pages/Popup/Popup.jsx
import React from 'react';
import './Popup.css';
import './button.css';

const Popup = () => {
  return (
    <button id="changeColor"></button>
  );
};

export default Popup;
```
jsxはボイラープレートよりシンプルになったな。

この状態で、右上のアイコンをクリックすると、こんな感じで表示される！やったー！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214587/a60691df-b223-59a7-49c3-697e1e2a1e54.png)

この先にあった、読み込み時にボタンを緑に変えるやつは、できなかった・・・
（html/javascriptで実装されているものを、react/typescriptに変換するスキルがなかった）

また勉強して戻ってこよう。

## Layer logic
jsだー
今は諦め。

## Give users options
う〜ん、ここもJS前提。
諦め。

## Take the next step
次に進む前に、React/Typescriptに変換する力を身につけるかな。
とはいえ、ポップアップでUI表示ができる仕組みを今回理解できたので、ひとまずオッケー。

以上。
AWS Certified Developer - Associate(DVA) 合格しました

DVAに合格したので、取得を目指されている方の参考になればと投稿させていただきます。

DVA試験自体はこちらを参照ください。
https://aws.amazon.com/jp/certification/certified-developer-associate/

## 準備したこと

* [トレノケート社のDVA研修受講](https://www.trainocate.co.jp/reference/course_details.aspx?code=AWC0004V) ← 9カ月ぐらい前・・
* [ポケットスタディ AWS認定 デベロッパーアソシエイト (アソシエイト試験ポケットスタディ)](https://amzn.to/3Mt78By)
* [AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)の90日間ベーシックを購入（4,480円 税抜き）　←結局、こればかりやっていた・・

## AWS経験

以前から個人で検証やお遊びで使用していますが、仕事でAWSだけを扱うわけではないので経験は少ないほうだと思います。
ただ、試験で問われるサービスは多くないため、問題集で分からないサービスがあったら実機操作で学習する程度で十分でした。

## 試験の得点

1,000点中801点でした。720点が合格ラインなので、ボチボチの点数でした。
各セクション（展開、セキュリティ、AWSサービスを使用した開発、リファクタリング、モニタリングとトラブルシュート）スコアパフォーマンスも一通り満たさせているとのことでした。

## 勉強内容

DVA研修受講やポケットスタディを購入して学習していたのですが、最終的に[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)でDVA問題を4周（1パートごとに7問。パート48まであるので336問）ほど回しました。
回答率の推移はこんな感じです。
1周目：50%
2周目：80%
3周目：85%
4週目：91%

4周目になると、問題の傾向やDVA試験で問いたい範囲を理解したこともあり、ほぼ正解となりました。

## 学習時間・期間

[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)を毎朝30～1時間つかって5～7パート消化しました。3周目ぐらいになるとスピードも上がってきて、30時間ぐらい勉強したと思います。期間は、1週間で1周していたので、1カ月ぐらいになります。

## 試験環境

自宅からのオンライン試験で実施しました。カメラ付ノートPCを使い、試験中は常時カメラONの状態でした。
RedHat認定試験は専用OSの起動や外部カメラ使用など面倒な制約が多かったですが、AWS試験はWindowsOS上で受験できる環境であり、準備も試験も非常にスムーズでした。

部屋は、カンニングと思われないようにカレンダーや絵などを除いて壁に貼っているモノを全て取り除いておきました。

## 感想

まず、学習で使用した[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)は、本当によく出来た問題集だと思いました。300問以上の問題と考えると気が遠くなりそうですが、それを7問ごとにパートを分けることで、モチベーションを保つことができました。

試験問題は[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)と似たような問題もありましたが、全体的にサービスの内容やDVA試験の傾向が理解できていれば合格できる内容でした。

次は[AWS Certified SysOps Administrator - Associate](https://aws.amazon.com/jp/certification/certified-sysops-admin-associate/?ch=sec&sec=rmg&d=1)を取得し、アソシエイト三冠を取ります。
会社ではAzure系が押せ押せなので、その後はAzure系がんばります。
link_toにclassを付けるのにハマった話とその対処法

## やりたかったこと
・aタグにclassを設けて、flexboxを使う。
## 前提
・Ruby 3.0.2
・rails 6.1.4.4
・Bootstrap、slim導入済み
※htmlはslimで記述しています。erbの方は、適宜erbに読み替えてください。
今回、controllerとactionを指定して、リンク先を設定してます。
## 先に結論
以下のように記述することで解決できました！

```slim:
= link_to({ controller: 'messages', action: 'roomshow', to_user_id: message_user_id }, class: "d-flex flex-row") do
```
## 失敗したパターン
######１. classを普通に追記する

```slim:
= link_to controller: 'messages', action: 'roomshow', to_user_id: message_user_id, class: "d-flex flex-row" do
```

```html:生成されるHTML
<a href="/users/1/messages/room/2?class=d-flex+flex-row"></a>
```

この場合、設定したclassがURLに含まれてしまい、classが設定できていません。
※なぜかリンク先には正しく遷移します。。。

######2. controllerとaction部をハッシュ（`{}`）で囲う
link_toについて調査したところ、リンク先のルーティングについてコントローラーとアクションを指定している場合、ハッシュを使っているパターンを発見したので、それを試してみることに。

```slim:
= link_to({ controller: 'messages', action: 'roomshow' }, to_user_id: message_user_id, class: "d-flex flex-row" ) do
```

このパターンは、ActionController::UrlGenerationErrorが発生します。

######3. class部もハッシュ（`{}`）で囲う

```slim:
= link_to({ controller: 'messages', action: 'roomshow' }, to_user_id: message_user_id, { class: "d-flex flex-row" } ) do
```

このパターンは、ActionView::SyntaxErrorInTemplateが発生します。

## 成功したパターン

```slim:
= link_to({ controller: 'messages', action: 'roomshow', to_user_id: message_user_id }, class: "d-flex flex-row") do
```
成功したパターンは、上記の結論の繰り返しになりますが、この書き方です。
URLに関係する箇所すべてをハッシュで囲み、URL部とそれ以外を分ける必要があるようです。
パターン2,3では、`to_user_id`を囲み忘れていたことが原因でした。

以上、参考になれば幸いです！

##参考
[https://teratail.com/questions/64203](https://teratail.com/questions/64203)
【Rust】Releaseビルドでも整数オーバーフローをpanicさせる


Rustで次のように整数オーバーフローしてしまう式を書いた場合、Debugビルドではpanicを起こしますが、 Releaseビルドでは無視して桁あふれします。

```rust
fn main() {
    // 10と数値リテラルで書くとコンパイル時にオーバーフローを
    // 検知してエラーになってしまうので、検証用に回避
    let ten: u8 = (0..10).len() as u8;
    
    let u8_overflow: u8 = u8::MAX + ten;
    
    println!("{}", u8_overflow);
}
```

```shell:Debugビルド時の実行結果
thread 'main' panicked at 'attempt to add with overflow', src/main.rs:5:27
```


```shell:Releaseビルド時の実行結果
9
```


[Playgroundで確認](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7286d77958da7ad0fb74ef8541941047)

  
実行時のオーバーフローのチェックにはコストがかかるため、パフォーマンスを最大化したいReleaseビルド時にチェックが取り除かれるのは理に適っています。

しかし、要件によってはそこまでシビアなパフォーマンスを要求しておらず、むしろ誤動作防止のためにReleaseビルド時も整数オーバーフローをpanicさせてほしいというケースもあるかと思います。

このようなニーズを満たしたい場合は、`Cargo.toml`でReleaseプロファイルの`overflow-checks`を`true`に設定します。

```toml:Cargo.toml
[profile.release]
overflow-checks = true
```
参考: https://doc.rust-lang.org/cargo/reference/profiles.html#overflow-checks

こうすることで Releaseビルド時もDebugビルド時と同様、実行時にオーバーフローのチェックが入るようになり、オーバーフローした場合はpanicを起こします。

```shell:overflow-checksをtrueにした際の、Releaseビルド時の実行結果
thread 'main' panicked at 'attempt to add with overflow', src/main.rs:5:27
```

パフォーマンスとのトレードオフにはなりますが、使えるケースはそれなりに多いのではないでしょうか。
プロジェクトによっては最初から`overflow-checks = true`で設定しておいて、パフォーマンス上の懸念が出てきたときに初めて検討するくらいでもいいかもしれませんね。

以上。お読みいただきありがとうございました。
Qt+OpenGLでゲーム制作 ～OpenGLを使う

#Qt+OpenGLでゲーム制作
######QtでOpenGLを使いたい
昔はDirectXばかり使っていてOpenGLって面倒だな……と思っていたのですが、今でも面倒です。視覚的に何やってるか分かりにくいですよね。QtではOpenGLのラッパークラスが充実しているのでらくちんです。趣味の開発だと楽さは大事。とは言えデフォルトだと無効になっています。

プロパティを開いて「Qt Modules」の……
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/152cf416-2457-413f-0122-865c4ca52606.png)

OpenGLにチェックを入れて有効にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/548837bb-bc5b-e2c2-1e61-70f317d72788.png)

ヘッダをQWidgetからQOpenGLWidgetに書き換える。

```cpp:GameEngine.h
#pragma once

#include <QOpenGLWidget>

class GameEngine : public QOpenGLWidget
{
    Q_OBJECT
public:
    GameEngine(QWidget *parent = Q_NULLPTR);
};
```

なんて簡単！！
と思ったらビルドエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/fd88b98a-5aa3-123f-5897-9c7f9d982b04.png)

Qt6のマニュアルを見てみるとQOpenGLWidgetのモジュールが変わっている……。ですのでモジュールに手書きでopenglwidgetと追記。スクショには映ってませんが、openglとopenglwidget両方追記したほうが良さそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/38f3036e-0009-fe9a-475d-a5be8eeb0e94.png)

はい、画面真っ黒なOpenGLのウィンドウが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/76d91fc8-8094-f3bc-96d4-59c99d3a0fb5.png)

真っ黒なのであんまり面白くはないですが、これでOpenGLが使えます。
Qt+OpenGLでゲーム制作

#Qt+OpenGLでゲーム制作
######とりあえずウィンドウ表示まで
以前からゲーム制作をしてみたいな、と思ってはいたもののメインのCGツール制作で時間がいっぱいいっぱいなのですが、着手しなければ始まらない。と言う事で隙間時間使いながらやってみようと思います。

開発環境としては

+ Visual Studio Community 2022
+ Qt6

全部無料環境です。Qt6はまだまだメインで使っていないのですが、この機会に少しずつ触ってみようかな、と。VS2022もまだまだメインでは使用していないのですがこの機会に使ってみます。VisualStudioにQtのアドオンを入れてウィザード使うと初期ウィンドウ表示までを勝手にやってくれるので便利です。ただし今回はウィザードが吐いたGUI周りはいらないので消してしまいます。(全部OpenGLで表示しますから)

main.cppがこんな感じ。簡単と言うか簡潔と言うか。Qtのアプリは大規模になってもmain.cppの基本はコレです。QApplicationはアプリのコア部分。GameEngineクラスはただのウィンドウで定義したらshowでh表示して、QApplicationを実行するだけ。

```cpp:main.cpp
#include "GameEngine.h"
#include "stdafx.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    GameEngine w;
    w.show();
    return a.exec();
}

```

これがメインウィンドウのヘッダー。Windowを扱うQWidgetの派生クラスになっています。コンストラクタしかないので実質なにもしてない空っぽのクラスですが、まずはこのクラスをOpenGL向けにいじっていくことになると思います。

```cpp:GameEngine.h
#pragma once

#include <QtWidgets/QWidget>

class GameEngine : public QWidget
{
    Q_OBJECT
public:
    GameEngine(QWidget *parent = Q_NULLPTR);

};
```

cpp部分はこんな感じ。自動生成されただけなのでコンストラクタしかないですね。ui.setupUi(this);でデザイナを使ったボタンとかのレイアウトを勝手にやってくれますがこれも今回は不要です。

```cpp:GameEngine.cpp
#include "GameEngine.h"
#include "stdafx.h"

GameEngine::GameEngine(QWidget *parent)
    : QWidget(parent)
{
}

```
######ビルド＆実行
こんなウィンドウが表示されればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527790/ccdfb89d-d7b8-e747-5847-ccd4c3c7fb93.png)
Ubuntu Server 20.04インストールした後設定した事

# 自分用メモみたいなやつです

## パッケージのアップグレード
```bash
sudo apt update && sudo apt upgrade -y
```

## rootアカウントでのログインを無効化
```bash
sudo passwd -l root
```

## タイムゾーンの変更

```bash
# タイムゾーン変更
sudo timedatectl set-timezone 'Asia/Tokyo'

# 確認
timedatectl | grep Time
```

## 日本語表示

```bash
# パッケージをインストール
sudo apt install -y language-pack-ja

# 設定
sudo localectl set-locale 'LANG=ja_JP.utf8'
```

## ファイアウォール
```bash
# 許可されたもの以外閉鎖
sudo ufw default deny

# ログを有効（/var/log/ufw.log）
sudo ufw logging on

# ログレベル変更
sudo ufw logging medium

# ここで開けるポートを設定
# 例
# 30 秒の間に 6 回以上連続して ssh 接続してくるアクセスを拒否
sudo ufw limit from 192.168.XX.XX to any port 22 proto tcp
# HTTP(80)通信を許可（サイトを公開するときとか）
sudo ufw allow 80/tcp

# ファイアウォールを有効
sudo ufw enable

# ステータス確認
sudo ufw status

# リストで許可されてるのを表示
sudo ufw status numbered

# 削除するときはリスト表示した時書かれてる番号を指定
sudo ufw delete X
```

## Ipv6無効（なんとなく）

参考（と言うかホボそのまま）

https://qiita.com/htshozawa/items/77dd0be079cdf817a5a6

```bash
# コンフィグファイルの作成
sudo vi /etc/sysctl.d/60-ipv6-disable.conf

# 再読み込みして有効に
sudo systemctl restart procps

# 設定ファイルを作成
sudo vi /etc/rc.local

# 権限を変更
sudo chmod 755 /etc/rc.local

# 再起動
sudo reboot
```

```conf:/etc/sysctl.d/60-ipv6-disable.conf
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
```

```bash:/etc/rc.local
#!/bin/bash
systemctl restart procps
exit 0
```



## SSH公開鍵認証

参考

https://webkaru.net/linux/tera-term-ssh-login-public-key/

```bash
# ディレクトリ移動
cd ~/

# フォルダを作成
mkdir .ssh

# フォルダ権限を変更
chmod 700 .ssh

# ホームディレクトリに公開鍵を配置

# 公開鍵の権限を変更
chmod 600 id_rsa.pub

# 公開鍵を移動
mv id_rsa.pub .ssh/authorized_keys

# コンフィグファイルのバックアップ
sudo cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config.bk

# 編集（パスワード認証を禁止）
sudo vi /etc/ssh/sshd_config

# 反映
sudo service ssh restart
```

```diff:/etc/ssh/sshd_config
- PasswordAuthentication yes
+ PasswordAuthentication no
```

## SSHポートの変更（必要な場合）

```bash
# 編集（ポート番号を変更）
sudo vi /etc/ssh/sshd_config

# 反映
service ssh restart
```

```diff:/etc/ssh/sshd_config
- Port 22
+ Port 55327
```


## RKHhunterのインストール（RootKit）

参考

https://kb.linuxlove.xyz/rkhunter.html

```bash
# インストール
sudo apt install -y rkhunter

# 設定ファイルを修正
sudo vi /etc/rkhunter.conf

# 設定ファイルを修正
sudo vi /etc/default/rkhunter

# 設定ファイルのチェック
sudo rkhunter -C

# アップデート
sudo rkhunter --update

# バージョン確認
sudo rkhunter --versioncheck

# データファイルの更新
sudo rkhunter --propupd

# システムチェック
sudo rkhunter --check --sk
```

```diff:/etc/rkhunter.conf
- UPDATE_MIRRORS=0
+ UPDATE_MIRRORS=1
- MIRRORS_MODE=1
+ MIRRORS_MODE=0
- WEB_CMD="/bin/false"
+ WEB_CMD=""
- ALLOW_SSH_PROT_V1=2
+ ALLOW_SSH_PROT_V1=0
```

```diff:/etc/default/rkhunter
CRON_DAILY_RUN="true"
CRON_DB_UPDATE=true"
APT_AUTOGEN="true"
```

## 他何かしないといけない事とかあれば教えてください
[Unity]OcclusionCullingが上手く出来なかった話

#概要
OcclusionCullingを試してみたくて簡単なサンプルを作ってみたのですが、遮蔽物に隠れたオブジェクトが思ったように消えてくれませんでした。その時の事を共有したいと思います。

ちなみにOcclusionCullingとは、壁や建物の裏側に隠れているプレイヤーから見る事の出来ないオブジェクトを描写対象から除外する事で処理の負担を減らす技術です。
#本文
まずこのような環境を用意しました。
カメラの前に遮蔽物（赤い壁）があり、その奥にカメラからは見えない物（青い箱）があります。
![スクリーンショット 2022-02-19 11.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/b0d9128f-95f8-237b-2ead-c5b4c2a316db.png)
2つのオブジェクトにはOccluder StaticとOccludee Staticを設定しました。
(Occluder Staticは遮蔽する側、Occludee Staticは遮蔽される側に設定します。両方つけても大丈夫です)
![スクリーンショット 2022-02-19 11.43.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/283d11fe-8f79-39a3-c985-85871fc2ed72.png)
次にOcclusionCullingの設定画面を表示します
Window > Rendering > Occlusion Culling
![スクリーンショット 2022-02-19 11.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/12ea260b-adb6-0ee6-da63-4d1cc0a8ee18.png)
Bakeタブを選び下にあるBakeボタンを押します。(上手くいかない時はSmallestOccluderを小さい数字にします)
![スクリーンショット 2022-02-19 11.50.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/df173f1a-e165-28f9-8fa3-9bdead2e85a7.png)
OcclusionのVisualizationタブを選ぶとSceneビューの右下にあるOcclusionCullingがVisualizeになり、OcclusionCullingの動作を確認できます。ですが、この段階で青い箱は赤い壁に遮られているのに表示されたままです。
![スクリーンショット 2022-02-19 12.40.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/642102c0-ea7a-e029-891e-934bc35c71c7.png)

![スクリーンショット 2022-02-19 11.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/9271b30f-95b5-3ca3-3bad-d4f6f24b621e.png)
#本題
OcclusionCullingでEditを選ぶとOcclusionAreaを確認する事ができます。OcclusionCulling対象オブジェクトの周囲がワイヤー表示されていますが、遮蔽されたオブジェクトが消える為には `この範囲内にカメラが入る` 必要があります。
![スクリーンショット 2022-02-19 12.01.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/d50a759c-d26c-e699-20b4-8aaad1984fdb.png)
オブジェクトを何も選択していない状態でOcclusionのobjectタブを選ぶとOcclusionAreaを新規で作るボタンが表示されます。ここからOcclusionAreaを追加する事ができます。
（CreateEmptyで空のオブジェクトを作った後OcclusionAreaをAddComponentしても同様の事ができます）
![スクリーンショット 2022-02-19 11.36.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/1df86396-b6ed-ef71-3c6b-f460ecd136a5.png)

OcclusionAreaを適度な大きさにして
![スクリーンショット 2022-02-19 12.11.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/08f5fa8c-9224-30ab-57b3-3a9c2358f527.png)
再度Bakeすると
![スクリーンショット 2022-02-19 12.13.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/701cb591-fea3-5d59-c0a4-3d17b50d5346.png)
今度は遮蔽された青い箱が消えました
![スクリーンショット 2022-02-19 12.14.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/a60ed6d0-6dcd-6784-5e53-c3a2f3c2155a.png)
#補足1
カメラを動かすと赤い壁も消えたりすると思います。これはFrustumCullingというカメラの撮影範囲外（例えばカメラの真後ろとか）のオブジェクトを描写しないようにする機能の影響です（こっちは設定をしなくてもUnityが標準で行ってくれる機能です）
#補足2
OcclusionCullingでオブジェクトが消える様子を確認できるのは右下にOcclusion Cullingが表示されている時だけです。動作が確認できない時はここも確認してみてください！
![スクリーンショット 2022-02-19 16.29.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/4f227c25-d4a7-6826-caf0-cb910bfe3880.png)
Instagram graph api利用までの流れ

## 全体イメージ
![ezgif.com-gif-maker.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536217/3b8c5493-a371-bba3-7c62-71da60e9b1cc.jpeg)

## 具体的な流れ
### Facebookページの作成
- FBアカウント登録
- FBページ作成
- FacebookページとInstagramアカウントの紐付け：左側に表示されているメニューバーから「設定」→「Instagram」を選択、アカウントをリンク」ボタンを押下し、Instagramアカウントを紐つけ。

### Facebook開発者アカウントの作成
Facebook開発者ページにアクセス
https://developers.facebook.com/?locale=ja_JP
↓
右上にある「スタートガイド」ボタンを押下します
↓
Facebookアプリの作成

これでアカウント準備ができました！
AWS CodeBuilde で Cypress を実行する

# やりたいこと
- AWS CodeBuild のビルドプロジェクトで Cypress E2E テストを実施したい
- ビルドプロジェクトの呼び出し元は Jenkins から行いたい
    - 既存の CI/CD に追加する形で実現したかった

既存の CI/CD 資産に追加する形で E2E テストを実現する方法を調査＆お試し。

# 前提
- github 上に Cypress E2E プロジェクトを用意している

# 設定
## AWS IAM
- Jenkins から CodeBuild を実行するためのユーザを作成する
    - アタッチするポリシーは「AWSCodeBuildDeveloperAccess」
        - ※もっと権限を絞った適切なポリシーがあるかも
    - 作成した際の「アクセスキー ID」「シークレットキー」を Jenkins ジョブの AWS Configuration に設定する

## AWS CodeBuild
- Cypress を実行する CodeBuild ビルドプロジェクトを作成する
    - プロジェクトの設定
    - プロジェクト名を記入
        - Jenkins で作成したジョブの Project Configuration に設定する
    - ソース
        - ソースプロバイダで「GitHub」を選択
        - リポジトリの URL に Cypress リポジトリの URL を記入
    - 環境
        - マネージド型イメージを選択
            - Node.js が動けば OK
    - ログ
        - グループ名を記入
    - Buildspec
        - 以下ビルドコマンドを記述

``` buildspec.yml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: latest
    commands:
      # Set COMMIT_INFO variables to send Git specifics to Cypress Dashboard when recording
      # https://docs.cypress.io/guides/continuous-integration/introduction#Git-information
      - export COMMIT_INFO_BRANCH="$(git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g')"
      - export COMMIT_INFO_MESSAGE="$(git log -1 --pretty=%B)"
      - export COMMIT_INFO_EMAIL="$(git log -1 --pretty=%ae)"
      - export COMMIT_INFO_AUTHOR="$(git log -1 --pretty=%an)"
      - export COMMIT_INFO_SHA="$(git log -1 --pretty=%H)"
      - export COMMIT_INFO_REMOTE="$(git config --get remote.origin.url)"
      - npm ci
  pre_build:
    commands:
      - npm run cy:verify
      - npm run cy:info
  build:
    commands:
      - npm run start:ci &
      - npx cypress run
```

## Jenkins
- CodeBuild ビルドプロジェクトを実行する Jenkins のジョブを作成する
    - プラグインに「AWS CodeBuild Plugin」を追加する
    - フリースタイル・プロジェクトのビルドを作成
    - ビルドで「AWS CodeBuild」を選択（プラグインインストール後に選択可能）
    - 設定値
        - AWS Configuration
            - Manually specify access and secret keys を選択
            - AWS Access Key, AWS Secret Key に 作成した IAM ユーザを指定
        - Project Configuration
            - Region, Project Name は 作成したビルドプロジェクトを指定
            - Use Project source を選択

# 参考
- https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/jenkins-plugin.html
- https://docs.cypress.io/guides/continuous-integration/aws-codebuild#Basic-Setup
仮想ターミナルで起動したconda仮想環境でモジュールのimportエラー

# 症状の概略

`GNU Screen`などの仮想端末のなかでconda仮想環境を起動したとき、仮想環境のsite-packagesにPATHが通っておらず、あらゆるモジュールがimportエラー(`ModuleNotFoundError`)してしまう。

# 対処法

仮想端末を起動するときは`conda deactivate`してある状態でセッションを張ること！
つまり、

```shell-session
(base) $ screen -S example-terminal # <- 新しい仮想端末を起動するコマンド
#  example-terminalセッションの中で
(base) $ conda activate hoge
(hoge) $ python text.py
```
はOKで、

```shell-session
(base) $ conda activate fuga # <- あらかじめconda仮想環境を起動してしまっている！！これがダメ！！
(fuga) $ screen -S example-terminal # <- 新しい仮想端末を起動するコマンド
#  example-terminalセッションの中で
(base) $ conda activate hoge
(hoge) $ python text.py
```
は動かない、ということのようです。


# Related Report

ある程度、問題の特定ができたので調べてみると、似たようなissueが見つかりました。

[stack overflow | screen inside the conda environment doesnt work](https://stackoverflow.com/questions/50591901/screen-inside-the-conda-environment-doesnt-work)

読むと「.bashrcにPATHが通ってないからだぞ」という指摘をしている人がいますが、私の環境ではちゃんと通してあります。
最後の人が

> What you can do is start `screen` first, and then activate the conda environment `conda activate my_env`

って言っているように、上記の対処がやはり根本的な解消法かなと思います。




# 症状に気が付いたきっかけ

リモートで作業しているときSSH接続が切れてもプロセスが強制終了しないように、GNU Screenやtmuxを使って作業している人は多いと思います。
（ただし私はscreen派ですのでtmuxのことはほとんど分かりません。）

ところがある日、いつも通りVSCodeのターミナルからpythonスクリプトを実行したら`ModuleNotFoundError`のエラーが！

でもipythonを立ち上げてimportコマンドをベタ打ちしてもエラーにならないし、VSCodeのデバッガーの中でも特にエラーにはなりません。明らかにターミナルの中のscreenセッションが悪さをしてそう、と思っていくつかのケースを試したら判明した、という経緯です。

結構気づきにくい気がしたので、参考になれば嬉しいです。
C++ 他人のために書くコメントの書き方

最近、C++でコーディングする仕事に従事した。開発チームのルールとしてコメントの書き方が定められているが「@briefには短い説明を書く」というような文言しか無い。守りやすくわかりやすいという面では良いルールだが、長い目で見て大切なのは、どんな説明を書くべきか、どんな説明なら良いのか？だと思う。なので、コメントには何を書くべきなのか？あらためて考えてみた。以降はその結果である。

## ソースコードコメントには何を書くと良いのか？

C++でコーディングする時は次のどれかを作っている。
* 他に機能を提供するコンポーネント(※1)
* 他のコンポーネント(※1)を使って機能を実現するコンポーネント(※1)

(※1)ここでは、コンポーネントはクラスや関数を指す。

大抵のコンポーネントはどちらか一方ではなく両方の性質を持つが、ここでポイントにしたいのは、大抵のコンポーネントは他に機能を提供するという点である。特に仕事としてコーディングする場合、何を提供するのか他の人にきちんと説明することが望まれる。
きちんと説明するためには、設計書などの資料を書いたりソースコードのコメントに説明を書いたりする。ここでは、ソースコードのコメントを使って他の人のためになる説明を書く方法についてまとめておきたい。

ソースコードに書く説明は、他の人がどう関わるかによって大きく二つにわけられると思う。

* コンポーネントを利用する人への説明（ここではAPI説明と呼ぶことにする）
* コンポーネントをメンテナンスする人への説明（ここではメンテナンス説明と呼ぶことにする）

## API説明

API説明では、コンポーネントの使い方を正確に適切な量で読みやすく書くことが理想である。説明の量が多いと大切な説明が埋もれてしまったり、読む気をなくさえるかもしれない。これらのうち、二つはdoxygenというツールを使うことで解決させられる。doxygenはソースコードを解析してHTML形式のドキュメントに加工してくれるツールである。正確性と読みやすさがある程度確保できる。

API説明を適切な量に抑えるためには、最初からすべての説明を書ききろうとするのではなく、利用者が最も知りたいことを優先して書き始め、プログラムがバグ修正を経て成長するのと同様に、説明も他人の意見を参考にしながら成長させれば良いと考える。

利用者が最も知りたいことを説明する際、Design by Contrac（契約による設計）とか、Contract programming（契約によるプログラミング）というContractという視点を参考にしたい。

Design by ContracやContract programmingにおけるContractでは、次の三つの観点があるとされている。

* 事前条件：引数やグローバル変数、環境変数、共有メモリ等APIを提供するコンポーネント使用するコンピュータリソースに関する注意事項
* 事後条件：関数の戻り値やAPIを呼び出した後にコンポーネントが変更を加えるコンピュータリソースに関する注意事項
* 不変条件：コンポーネントが設計通りの機能を提供する上での注意事項

例えば、氏名を与えると電話番号を返す電話帳クラスを例に考えてみる。例えばContractは次のようなイメージである。

* 事前条件
	* 引数の氏名は全角漢字ひらがなカタカナでなければならない。
	* 引数の氏名は省略できない
	* 引数の誕生日は省略することができる
* 事後条件
	* 戻り値の電話番号は一人あたり0以上でありひとつだけとは限らない
* 不変条件
	* 電話帳データベースが存在していなければならない

不変条件で「実行する計算機は日本に存在しなければならない」などという、多くの場面で当たり前のことは説明する必要がないが、何を優先して書くか誰が見ても納得の優先順を決めるのは難しく、先述したように一気に完成させると考えるのではなく、他の人の意見を取り入れつつ改善するのが良い。

API説明を書くコツとしては、Contract、事前条件／事後条件／不変条件を念頭に書くのが理想であるが、最初は筆が進まないかもしれない。そこで、「C++のためのAPIデザイン」マーティン・レディ著、ホジソンますみ訳が良いヒントになった。

* クラスは何者か？何を表現するものか？
* 入力値の範囲は？単位は何か？
* 戻り値の範囲は？単位は何か？
* APIが内部でチェックするエラーは何か？
* 例外を投げるか？
* スレッドセーフか？
* 未実装やTODOはあるか？
* メンバ関数の呼び出し順に制約はあるか？
* どのコンピュータリソースを参照・変更するか？

javadocやQtのドキュメントも良いお手本になった。

## メンテナンス説明

コンポーネントを作成したエンジニアがずっと一人でメンテナンスすることはまず無い。コンポーネントは複数の人がメンテナンスするものである。メンテナンスする人たちの間で設計方針や試験方針を共有した上でソースコードに手を加えなければ、潜在的なバグを混入させたりコンポーネントを劣化させてしまう。

ゆえに、ソースコードにはAPI説明だけでなく、コンポーネントの構造やどういう方針の元作られているのか説明しておくことが理想である。メンテナンス説明を書くことにしたら、ソースコードレビューは、主にメンテナンス説明の方だけでよくなる。

決して、API説明にメンテナンス説明を混入させてはならない。この両者は分ける必要がある。そのため、私は宣言ファイル（.h）にAPI説明、定義ファイル（.cpp）にメンテナンス説明を書くようにしている。ただ、これはdoxygenをうまく使えばもっといいやり方があるかもしれない。

メンテナンス説明には次のような観点がある。すべてをソースコードの中に説明するのは難しいかもしれないが、こういう情報を共有して残しておくとコンポーネントのメンテナンスで問題が起きにくい。

* コーディング規約は何を適用しているのか？
* 命名規約は？
* 用語、略称、[ソースコードで使用する英語](https://qiita.com/Ted-HM/items/7dde25dcffae4cdc7923)
* doxygenやgcc等、ツールやコンパイラの使い方は？
* cmakeやmakefileの書き方は？
* 各ディレクトリにはどういうファイルを置くのか？
* 大きな枠組みとしてMVCか？他のアーキテクチャパターンか？
* 使用するライブラリは？ログは自作か？それともサードパーティ製を使用するのか？
* エラーログは？ワーニングログは？デバッグログは？
* レイヤ構造は？コンポーネントのパッケージ化と依存関係は？
* ユニットテストは？CIは？
* Pimplイディオムを積極的に使うか否か

以上
【WSL2+Warden】MySQL Workbench設定方法

#目次
* 手順
* MySQL Workbenchダウンロード
* Visual Studio 2019インストール
* MySQL Workbenchインストール
* 設定


#手順
・MySQL Workbenchダウンロード
・Visual Studio 2019インストール
・MySQL Workbenchインストール
・設定

#MySQL Workbenchダウンロード
MySQLをインストールしていない方は
Go to Download Pageからダウンロードする
既にインストール済みの方は
Other downloadからダウンロードする
[MySQL Workbench]
https://dev.mysql.com/downloads/workbench/

#Visual Studio 2019インストール
MySQL Workbenchのインストーラーを起動すると
<font color=red>Workbench requires the Visual C++ redistributable for Visual Studio 2019 for Redistributable Package to be installed.</font>
というエラーが出るのでVisual C++ Redistributable for Visual Studio 2019をインストールする。
[VisualStudio]
https://visualstudio.microsoft.com/ja/downloads/?q=Visual+Studio+2019+Microsoft+Visual+C%2B%2B+%E5%86%8D%E9%A0%92%E5%B8%83%E5%8F%AF%E8%83%BD%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8
(VisualStudio 2022で問題ない)

#MySQL Workbenchインストール
インストーラーを起動してインストールに進む
[インストール手順参考]
https://it-kyujin.jp/article/detail/1132/

#設定
![2022-02-18 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512649/50815d94-73c5-ddbf-be61-5697cfade310.png)

Connection Method:Standard TCP/IP over SSH
SSH Hostname: 127.0.0.1:2222 
SSh Username: user 
SSh Password: なし 
SSH Key File: \\wsl$\Ubuntu-20.04\home\[USER]\.warden\tunnel\ssh_key
Mysql Hostname: magento_db_1 (プロジェクトのdbコンテナ名) 
Mysql ServerPort:3306 
Username : magento 
Password : magento

SSH Key File:[USER]部分は変えてください
Mysql Hostname:$warden env psを叩くと確認できます。

```
$ warden env ps
Name           　　Command                          State   Ports
-----------------------------------------------------------------------------
magento_db_1       docker-entrypoint.sh mysql ...   Up      3306/tcp
(以下省略)

```

Username : magentoインストール時に設定したもの 
Password : magentoインストール時に設定したもの

その後Test Connectionをクリックして接続できたらOK！
【LGモニタ】HDMI 4Kで30Hzになってしまう現象

# 環境
- windows10
- NVIDIA GeForce GTX 1050 Ti
- LG モニター ディスプレイ 27UL500-W 27インチ/4K/HDR(標準輝度:300cd/㎡)/IPS非光沢/HDMI×2、DisplayPort/FreeSync/ブルーライト低減

# 現象詳細
上記モニタをデュアルモニタにして使用していた。DisplayPortとHDMIで使用していたが、HDMIのほうでリフレッシュレートが30Hzになっていた。

# 解決策
LGモニタでHDMI ULTRA HD Deep ColorをONにしたら、30Hz⇒60HZになった。

# まとめ
モニタは30Hzだとマウスの動きがぎこちなくて使いにくい。
【MySQL】 安全等価演算子

Oracleでデータベースを使う時あまり見ることなかったので
<=>　
普通　等価演算子、非等価演算子だと
= <= >= != <>
こんな感じのイメージじゃないでしょうか。

<=>　
この演算子便利なんです。
右辺が値があるときは
[<]
[=]
[>]
と一緒の挙動をします。
　
右辺がNULLの場合には
　 IS NULLの挙動をしてくれます。

下記のようなtestというテーブルがあったとしましょう。
実際にデータは2行以上存在している前提で考えます。

|id  |name  |bikou1 |bikou2 |
|---|---|---|---|
|1  |Mark  |備考  |備考  |
|2  |Qiita  |NULL  |NULL  |

SQL文
下記の二つのパターンのSQLで挙動は一緒

```
SELECT * FROM test WHERE bikou1 = bikou2
SELECT * FROM test WHERE bikou1 IS NULL AND bikou2 IS NULL
```

```
SELECT * FROM test WHERE bikou1 <=> bikou2
```
NULL値も含めて検査したいときは便利です。
わざわざIS NULLで分けて抽出する必要がないので。