OmniAICreator/Qiita-1.07M huggingface dataset:
TailwindCSSを使っているとKaminariのテンプレートが生成されない

# 起こったこと

Rails7でアプリを作っているときに、TailwindCSSを使っていると、[KaminariのREADME](https://github.com/kaminari/kaminari#customizing-the-pagination-helper)にあるコマンド(`rails g kaminari:views default`)でテンプレートが生成されなかった。(エラーも出ない😢)

```Bash
$ rails g kaminari:views default
$
$ ls app/views
active_storage  users  layouts  shared   #<= kaminariフォルダがない
```

ちなみに、何かthemeを指定すると、tailwindでは使えないよと言われてしまう。

```
$ bin/rails g kaminari:views google
template_engine: tailwindcss is not available for theme: google
```

公式README: https://github.com/kaminari/kaminari#customizing-the-pagination-helper

> To Edit Your Paginator
> Run the generator first,
> % rails g kaminari:views default
> then edit the partials in your app's app/views/kaminari/ directory.

## 起こった環境

- Rails 7.0.3
- TailwindCSS
- Kaminari 1.2.2

# 対応方法

テンプレートエンジンの指定が必要らしい。バグっぽい？のでそのうち直るかもしれない :thought_balloon: 
```
rails g kaminari:views default -e erb
```
refs: https://github.com/kaminari/kaminari/issues/1071#issuecomment-1016004825
Goodnotes5のなげなわ機能について

# はじめに
iPadでpdfに書き込んだりできるのでgoodnotesを愛用してる。論文、資料を読み込んで書き込むか、計算用紙程度にしか使ってなかったが便利な機能が分かったのでメモしておく。

## なげなわ機能
ペン、マーカー、ポインタぐらいしか使っていなかったがなげなわ機能というのが搭載されている。
適当に囲ってその部分を***同一ページ内***で移動させたり、切り取ったりすることができる。
なげなわ機能の欠点として囲った部分の移動が同一ページ内のなので、別のページに移動させたいときは書き直すしか手段がないと思っていたがページをまたいで移動させる手段を見つけた。

## 方法
- 移動させたい箇所を囲う
- その状態でタップしてアクションツールを表示させる。
- 「要素を追加」を選択する
- 新規コレクションに保存する。
- 「要素に追加」から移動させたいページに貼り付ける。
第4週目Github

第4週目Github
1.pullrequestとは何か？
私が作ったコードを他のメンバーが検討してコードの品質を高める
私が作ったブランチを他の人に付ける時に使われる。

二つあるんですが
1.私が作ったブランチを他の人々の助言を聞きたい時
2.オープンソース方式なのに遠隔貯蔵所を複製してきて(フォーク)コピー本で遠隔貯蔵所を改善していく方式私がした方が良ければ私のものを持って行ってくれとフルリクエストする方式オープンソースの方式

一行整理
フルリクエスト=他の人とのコードレビューを通じてコードの品質を高める機能

2.ブランチとマスターブランチ
我々が何らかの機能を新たに追加したりする際には、マスターブランチで使用することを控え、
新しいブランチ（フィーチャーブランチ）を作って繋げるようにした方が捨てやすく管理したい。 集めて見やすい。

一行整理
マスターブランチ
新しいブランチ=根元(ピッチャーブランチ)

3.フルリクエスト作り
私が作った根を木につなげられるよう検討してほしい
レビュアーズやアサインアースにたっぷりかける
コンバーセーション=事件の時間を記録しておいたタブ
コミットとファイルチェンジを見て検討し、最終的に問題がないと判断されれば、コンファーマッジ>併合される。

一行整理
フルリクエスト（連結検討）が終われば、遠く（併合）となる。

4.フルリクエストでコミュニケーションする
私が作ったフルリクエストだけでなく他の人が作ったフルリクエストも併合できなければならない
クリエイトフルリクエストボタンを押して解決
コミットとファイルチェンジで確認

一行整理
フルリクエストで意見等を交換しよう！ コードの品質を高めていこう、フルリクエストの本質的な機能

5.衝突解決
他のブランチで同じものを修正すると衝突が起こる
これを解決してみよう
ウェブエディタを利用したり、
直接併合をすることだ。

一行整理
マスターをトピックブランチに持ってきてトピックブランチを改善し続けていく
それで、すべての作業が終わったらトピックをマスターブランチに併合


CLI(コマンドラインインターフェース)バージョン管理
バージョン管理の開始
gitinit:現在ディレクトリを襟にバージョン管理をさせる。gitというディレクトリ生成
Repository:リポジトリ
Workingtree:ファイルを修正した場所、修正したファイル
Stagingarea:コミットしたいことバージョンを作ろうとするファイル
gitstatus:今襟の状態を調べるのに最も多く使われる。
gitadd:ステージングエリアに上げること（やらないとアントラクトされる）
gitcommit:createcommitバージョンと同じ意味で見れば良い
gitlog:歴史を見たければこれで出る時はqボタン

襟はいくつかのファイルを1つのバージョン作ることができる
gitdiffバージョン管理の違い(変わった点)
gitreset-hard今まで管理したものを捨てたい。

バージョン管理というのは時間を探索することができる。
以前のバージョンを復元することも可能。
gitcheckoutコミットidを行うと、該当コミットバージョンに戻る（headのみ移される）
gitcheckoutmaster最新状態に戻りたいとき
gitadd.現在のディレクトリの下にあるすべてのディレクトリをaddする
gitcommit-amaddとコミットを一緒に進行(ただし最初の一度はaddはしなければならない)
gitcommitだけで入ってコミットメッセージを修正可能

gitreset--hardコミットidこのバージョンでリセットする！
他の人と共有されたバージョンについてはリセットすべきではない！
gitrevertresetとは異なり、削除せずに全バージョンに行くこと、リバートする時は逆順にすればよい。

バージョン管理の核心は比較!! 比較を通じて過去を振り返ることができるということ。
バージョン管理が不要な場合はgitignoreファイルを作ってそれに無視したいファイルを入れる。


githostingによる遠隔貯蔵所管理github、gitlab等

gitではダウンロードという表現の代わりにpullという引っ張ってくるというコマンドを使うpull>push、pull>push
clone遠隔貯蔵所からそのままコピーして地域貯蔵所に移す
他の貯蔵所で同じ資料を管理するのでバックアップの効果
gitremoteの襟から遠隔貯蔵所に接続するには、この命令語を使わなければならない。-v遠隔貯蔵所の内訳を示す。
gitpush地域から遠隔保存にアップロード
git add > git commit > git push

gitclone様々なコンピュータによる同様の作業既にある（遠隔）貯蔵所から地域の場所への複製
gitpull遠隔貯蔵所にあったものをローカルへの同期化（引っ張ってくる）
pull>作業>commit>push

gitfetch=リモートブランチだけをもたらす方法
gitmerge=リモートブランチを地域ブランチと合併させる
git fetch > git merge FETCH_HEAD > commit > push
git pull= git fetch; git merge origin/master

慎重に作業する時に使われる(複雑だと思ったらpull)
Chrome Extension iframeの中でも処理を行う設定

# どんな時？
Extensionを使いたいページで例えば、リンクマウスオーバーでプレビューが出るようなページがあるとする。
そのプレビューがiframeを使って実現されている場合、iframe内でも同様のChrome Extensionを呼んでほしい。
そんな時があるとする。

# 結論
```"all_frames": true```を記述すればOK。


```js:manifest.json

{
  "manifest_version": 3,
  "name": "開発中",
  "version": "3.0.0",
  "description": "説明文",
  "content_scripts":[
    {
      "all_frames": true
    }
  ]
}

```

```js:content.js
$(function(){
  alert('呼んだ？');
});


```
blastengineのNode.js SDKを使って添付ファイル付きメールを送信する

blastengine（ブラストエンジン）はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

現在、Node.js向けに、blastengine SDKを開発しています。この記事では、その使い方を解説します。まずはテキストメールの即時送信についてです。

[blastengine - npm](https://www.npmjs.com/package/blastengine)

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/515541ad-b74e-e1e2-ac34-46d181ee2924.jpeg)

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKは npm コマンドでインストールできます。

```
npm i blastengine
```

## SDKのインポート

まずSDKをインポートします。

```js
import Blastengine, { Transaction } from 'blastengine';
```

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```js
new Blastengine(YOUR_USER_ID, YOUR_API_KEY);
```

## トランザクションオブジェクトの作成

メールを即時配信する際にはトランザクションオブジェクトを使います。

```js
const transaction = new Transaction;
```

## 必要な情報をセットする

続けて、トランザクションオブジェクトに必要なオブジェクトをセットします。

```js
transaction
	.setFrom('info@example.com', 'From Name')
	.setSubject('メールの件名')
	.setTo('to@example.jp')
	.setText('メールの本文');
```

## 添付ファイルをセットする

添付ファイルはファイルへのパスかBlobオブジェクト、またはBufferを適用してください。複数指定可能です。

```js
transaction
	.addAttachment('file.png')
	.addAttachment('another.png')
```

後は `send` メソッドで送信できます。これは非同期メソッドです。

```js
const res = await transaction.send();
```

`res.delivery_id` に数字が入っていれば、送信完了です。

```js
res.delivery_id
// => 18
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-node](https://github.com/blastengineMania/blastengine-node)

## まとめ

blastengineには他にも一括メール配信を行う機能があります。ぜひ皆さんのシステム開発におけるメール配信を素早く実装するのに役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
blastengineのNode.js SDKを使ってメール送信を行う

blastengine（ブラストエンジン）はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先へ届くようになります。

現在、Node.js向けに、blastengine SDKを開発しています。この記事では、その使い方を解説します。まずはテキストメールの即時送信についてです。

[blastengine - npm](https://www.npmjs.com/package/blastengine)

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/515541ad-b74e-e1e2-ac34-46d181ee2924.jpeg)

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKは npm コマンドでインストールできます。

```
npm i blastengine
```

## SDKのインポート

まずSDKをインポートします。

```js
import Blastengine, { Transaction } from 'blastengine';
```

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```js
const client = new Blastengine(YOUR_USER_ID, YOUR_API_KEY);
```

## トランザクションオブジェクトの作成

メールを即時配信する際にはトランザクションオブジェクトを使います。

```js
const transaction = new Transaction;
```

## 必要な情報をセットする

続けて、トランザクションオブジェクトに必要なオブジェクトをセットします。

```js
transaction
	.setFrom('info@example.com', 'Admin')
	.setSubject('メールの件名')
	.setTo('to@example.jp')
	.setText('メールの本文');
```

後は `send` メソッドで送信できます。これは非同期メソッドです。

```js
const res = await transaction.send();
```

`res.delivery_id` に数字が入っていれば、送信完了です。

```
res.delivery_id
// => 18
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-node](https://github.com/blastengineMania/blastengine-node)

## まとめ

blastengineには他にも一括メール配信を行ったり、添付ファイル付きのメール配信機能などもあります。これらの機能も随時実装していきますので、ぜひ皆さんのシステム開発に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
blastengineのNode.js SDKを使ってメールを一斉配信する

blastengineは開発者にとって使いやすいメール配信サービスを提供しています。まだサービスローンチしたばかりでSDKが不足しているのですが、徐々に開発を進めています。

まず最初にNode.js向けにSDK開発を進めていますが、一斉配信に対応しましたので、その使い方を紹介します。

[blastengine - npm](https://www.npmjs.com/package/blastengine)

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/515541ad-b74e-e1e2-ac34-46d181ee2924.jpeg)

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKは npm コマンドでインストールできます。

```
npm i blastengine
```

## SDKのインポート

まずSDKをインポートします。

```js
import Blastengine, { Bulk } from 'blastengine';
```

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```js
new Blastengine(YOUR_USER_ID, YOUR_API_KEY);
```

## 一斉配信オブジェクトを作成する

一斉配信用のオブジェクトを生成します。

```js
const bulk = new Bulk;
```

## 必要な情報をセットする

続けて、一斉配信オブジェクトに必要なオブジェクトをセットします。

```js
bulk
	.setFrom('info@example.com', 'From Name')
	.setSubject('Test subject')
	.setText('__name__さん宛のメール本文');
```

## メール配信内容を登録する

一斉配信内容をblastengineに登録します。

```js
const res = await bulk.register();
```

## 宛先をセットする

次に宛先をセットします。それと一緒に、差し込みコードもセットできます。差し込みコードはキーと値を持っており、そのキーに該当する部分が値に変換されながらメール配信されます。メール本文では `__キー__` のように `__` でキーを囲んでください。

追加したら update メソッドを実行して更新します。

```js
bulk.addTo('example1@example.com', {name: '名前 1'});
bulk.addTo('example2@example.com', {name: '名前 2'});
await bulk.update();
```

この時、送り先が50件を超えるとCSVアップロードを利用する方法に切り替わります。メソッドは同じですが、若干時間がかかる可能性があります。

## 配信を開始する

後は send メソッドで配信を実行します。配信時には任意の時間を設定できます。デフォルトでは1分後としています。

```js
await bulk.send();
// 一日後の場合
const date = new Date;
date.setDate(date.getDate() + 1);
const res = await bulk.send(date);
```

`res.delivery_id` に数字が入っていれば、送信完了です。

```
res.delivery_id
// => 18
```

### 削除する

一斉配信用のオブジェクトを削除する場合には delete メソッドを使ってください。なお、一斉配信用のオブジェクトは10個までしか作成できません。

```js
await bulk.delete();
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-node](https://github.com/blastengineMania/blastengine-node)

## まとめ

blastengineには他にも一括メール配信を行ったり、添付ファイル付きのメール配信機能などもあります。これらの機能もSDKに随時実装していきますので、ぜひ皆さんのシステム開発に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
Docker コンテナ間でssh接続してみよう。

学習用にメモ。
"slave"と"master"の2台のコンテナを立ち上げて、"slave"→"master"にssh接続してみる。

## 準備
・Dockerfileを用意。
```dockerfile
# 使用するOS
FROM ubuntu:21.10

# コマンド準備
RUN apt-get update && \
    apt-get install -y vim && \
    apt-get install -y sudo

# SSHプロトコルを利用するためのソフトウェアをインストール
RUN apt-get install -y openssh-server

# 公開鍵と秘密鍵用
RUN mkdir  ~/.ssh && \
    touch  ~/.ssh/authorized_keys && \
    chmod 600  ~/.ssh/authorized_keys
```

・ネットワークを作成(コンテナ間で通信ができるように。)
```terminal
$ docker network create ssh_network
```

## イメージを作成
```terminal
$ docker build -t sshcontainer:test .
```

## コンテナを起動
```terminal
$ docker run -it --name master -p 2222:22 --network ssh_network sshcontainer/test
$ docker run -it --name slave -p 2233:22 --network ssh_network sshcontainer/test
```
## slave側で公開鍵と秘密鍵を作成
```terminal
# cd ~/.ssh

// 作成
# ssh-keygen
```

## master側で公開鍵のコピー
```terminal
// slave側で先ほど作成した公開鍵(デフォルトなら"id_rsa.pub")をコピー。

# vim ~/.ssh/authorized_keys
// 公開鍵をペースト。
```

## master側コンテナのsshのポート番号を変更
```terminal
# vi /etc/ssh/sshd_config

// 以下のようにデフォルトではなっているので、Portを2222にしてコメントアウトを外す。
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22 ← コメントアウトを外して"Port 2222"に変更する。

ssh-server再起動
# sudo /etc/init.d/ssh restart
```

## ssh接続
```terminal
# ssh root@master
```

※参考にさせていただいたURL(ほぼここ)
[Dockerコンテナ間でssh接続をする](https://qiita.com/neo_fukafukafukka/items/34ece05e14547d847450)
【Unity】選択しているオブジェクトをワイヤー表示する【ギズモ】

下図のように、選択しているオブジェクトのメッシュにワイヤー表示をする場合、「Selection Wire」にチェックを入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/2f55fc4a-d0ce-7040-b29a-4c95102851f8.png)

下図は、「Selection Wire」のチェックを外した状態です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/a85db926-f282-e1c3-4bbb-0f9c024370fe.png)

---

また、「Shading Mode」において、通常は下図のように「Shaded」が選択されていますが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/be108aae-b13c-7d06-bde5-f9efeaf0bc86.png)

下図のように「Shaded Wireframe」を選択することで、オブジェクトそのものをワンやーフレームで表示することも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/aa79af9f-55a5-6fd6-98c1-004eeb75b1ea.png)
Firebase(Firestore) Timestamp型の取得と表示方法

Firestoreに保存されているTimestamp型のデータの取得と表示方法についてまとめます。

## データ構造
- コレクション名：posts
- ドキュメントID：自動(ランダム)
- フィールド
    - title (string)
    - createdAt (timestamp)

## Day.jsインストール
「Day.js」は「Moment.js」とほぼ互換性のあるAPIを提供しており、Moment.jsの代わりとして推奨されている日付操作用ライブラリの1つ。

```
npm install day.js --save

// 確認
npm list --depth=0 | grep dayjs
```

## 日付形式での取得と表示
timestamp型をそのまま取得すると以下のようなオブジェクトになる
```
createdAt: t {seconds: 1618557497, nanoseconds: 367000000}
```

日付形式に変換するには、dayjsの`toData()` メソッドを使う  
また`format()`メソッドで形式を指定する  

```
const [posts, setPosts] = useState([]);

  useEffect(() => {
    const postData = collection(db, "posts");

    onSnapshot(postData, (querySnapshot) => {
      const data = QuerySnapshot.docs.map((doc)=>({
          id: doc.id,
          title: doc.data().title
          // 日付取得
          createdAt: dayjs(doc.data().createdAt.toDate()).format('YYYY/MM/DD'),
      }))
      setPosts(data);
    });
  }, []);

  return (
    <div className="App">
      <div>
        {posts.map((post) => (
          <div key={post.title}>
            <h1 className="title">{post.title}</h1>
            <p>{post.createdAt}</p>
          </div>
        ))}
      </div>
    </div>
 );

// 表示結果例
// 2022/05/31
```
Firebase(バージョン9以降) x React 連携方法

FirebaseとReactを連携させたアプリを作る際のセットアップについてまとめました。  
Firestore からデータ取得できるまでを記載します。  
Firebase バージョン9 以降の記述方法になります。

## React セットアップ
### プロジェクト作成
プロジェクトを作成したいフォルダに移動して以下コマンドを実行
```
npx create-react-app appname
```
カレントディレクトリに作成する場合は`appname` を`.`にする
```
npx create-react-app .
```

### 起動確認
Reactプロジェクトフォルダに移動し、以下コマンド実行。
`localhost:3000`が起動し初期画面が表示されればOK
```
npm start
```

## Firebase セットアップ
予めFirebaseプロジェクトを作成しておく。  
今回は`posts`というコレクションを作成し、`title`と`text`という2つのフィールドをもったドキュメントを作成。

### FirebaseSDK 追加
```
npm install firebase
```

### FirebaseCLI
初回のみ
```
npm install -g firebase-tools
```

### Firebase 初期化
`src/firebase.js` を作成  
Firebaseコンソールの歯車->プロジェクトの設定->SDKの設定と構成 にConfigがあるので以下のようにそれぞれコピペする
そして、`initializeApp()`にわたす

```
// firebase.js
import { initializeApp } from "firebase/app";
const firebaseConfig = {
  apiKey: "xxxxx",
  authDomain: "xxxxx",
  projectId: "xxxxx",
  storageBucket: "xxxxx",
  messagingSenderId: "xxxxx",
  appId: "xxxxx",
};

const app = initializeApp(firebaseConfig);
```

### Cloud Firestore 初期化
`src/firebase.js` に以下を追記  
```
import { getFirestore } from "firebase/firestore";
```
```
const db = getFirestore(app);
export default db;
```

`db`をエクスポートしたので使いたいjsファイルにインポートする
```
// ex. App.js
import db from "./firebase"
```

## 連携確認

```
// App.js
import { collection, onSnapshot, } from "firebase/firestore";
import { useEffect, useState } from "react";
import "./App.css";
import db from "./firebase";

function App() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    const postData = collection(db, "posts"); //第二引数はコレクション名

    onSnapshot(postData, (querySnapshot) => {
      setPosts(querySnapshot.docs.map((doc) => ({ ...doc.data() })));
    });
  }, []);

  return (
    <div className="App">
      <div>
        {posts.map((post) => (
          <div key={post.title}>
            <h1 className="title">{post.title}</h1>
            <p>{post.text}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;
```

Firestoreのデータが取得され、表示できていれば連携完了。

## 参考
[Cloud Firestore スタートガイド](https://firebase.google.com/docs/firestore/quickstart)
【Next.js】Vercelでデプロイしたプロジェクトを削除する

## はじめに
Vercelでデプロイしたプロジェクトを削除する手順について記載します。

## Vercelでデプロイしたプロジェクトを削除する方法
以下の手順で削除することができます。

まず、VercelのDashbordベージにアクセスします。

https://vercel.com/dashboard

![スクリーンショット 2022-06-06 午後5.18.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/b783f2f7-4f54-6463-dc67-72c9b7fcd9bc.png)

削除したいプロジェクトをクリックします。

![スクリーンショット 2022-06-06 午後5.19.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/bd01c19f-9420-0490-c28c-b36d50d64821.png)

`Settings`をクリックします。

![スクリーンショット 2022-06-06 午後5.19.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4c8d4f9d-9cdc-22a8-07a2-425e99dbb92c.png)

下の方にスクロールします。

![スクリーンショット 2022-06-06 午後5.20.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/258a5c4d-97fe-9a3b-41a1-ae9e16df8d18.png)

`Delete`をクリックします。

![スクリーンショット 2022-06-06 午後5.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/b423f75a-ed9d-a649-c3ff-4e04cf8595ec.png)

指示通り太字になっている箇所を入力し、`CONTINUE`をクリックします。
するとプロジェクトが削除されます。

![スクリーンショット 2022-06-06 午後5.29.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/ae93a808-5493-bf18-cf08-d77b1638622e.png)
【基本情報技術者】OSI参照モデルとTCP/IP

基本情報技術者試験の分野「OSI基本参照モデルとTCP/IP」についてご紹介いたします。
## OSI参照モデル
**OSI(Open Systems Interconnection)基本参照モデル**とは、「通信する際に必要な機能を7つ階層に分類してまとめた通信のルール」です。

### OSI参照モデルの7階層
OSI参照モデルでは、通信が相手に届くまでの一連の流れを機能ごとに**7つのステップ7階層**に分けて考えています。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/3d69a992-8478-6a69-974e-754361434244.png)

## TCP/IP
**プロトコル**は、**ネットワーク上でコンピュータ同士が通信するときに使用する手順や約束事**のこと。※「protocol」の単語の意味は、儀礼や議定書、協定や実施要項等「手順」を表す言葉。
**TCP/IP**(Transmission Control Protocol/Internet Protocol)とは、**インターネットなどで標準的に用いられる通信プロトコル（通信手順）**。TCPとIPを含む、インターネット標準のプロトコル群全体の総称。基本参照モデルの各層と対応している。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/0b1c163c-5405-2a4e-dc67-d9d8e4498d3b.png)

### アプリケーション層のプロトコル
| 名前 | 説明 |
|:-------:|:--------|
|**HTTP**|**HTML文章などを送受信**する。Hypertext Transfer Protocol|
|**FTP**|**ファイルを転送**する。File Transfer Protocol|
|**TELNET**|**遠隔地にあるコンピュータにリモート**でログインして操作する。|
|**SNMP**|**ネットワーク上の構成機器や障害時の情報収集**を行う。Simple Network Management Protocol|
|**NTP**|タイムサーバの時刻をもとに在時刻の情報を送受信し、コンピュータの**時刻を合わせる。** Network Time Protocol|
|**SMTP**|**メールを送信するとき**にメールサーバ間でメールを送受信する。Simple Mail Transfer Protocol|
|**POP3**|メールサーバのメールボックスから**メールを受信する。** Post Office Protocol|
|**IMAP**|POP3と違い、メールサーバ上のメールボックスから**必要なものだけ選択して受信する。** Internet Message Access Protocol|

### トランスポート層のプロトコル
| 名前 | 説明 |
|:-------:|:--------|
|**TCP**|**通信相手と通信ができたかを確認し、信頼性の高い**データ転送を提供する。Transmission Control Protocol|
|**UDP**|**信頼性は保証しないが高速**なデータを提供する。User Datagram Protocol|

### インターネット層のプロトコル
| 名前 | 説明 |
|:-------:|:--------|
|**IP**|**IPアドレスを用いてデータを相手まで届ける**。 Internet Protocol|
|**ICP**|通信相手との通信状況をメッセージで返す。Internet Control Message Protocol|
|**ARP**|IPアドレスから※MACアドレスを取得する。Address Resolution Protocol|

※MACアドレスは、PCやネットワーク機器が持つ世界で一つの固有識別番号。機器の住所・宛先というイメージ。

### ネットワークインタフェース層のプロトコル
| 名前 | 説明 |
|:-------:|:--------|
|**PPP**|2地点間を接続して通信する。Point-to-Point Protocol|
|**PPPoE**|LAN(イーサネット）上でPPPを行い、**常時接続**する。PPP over Ethernet|
Python で Tweet の位置情報をヒートマップを用いて可視化しよう！(folium版)

# はじめに
[「Python で Twitter の位置情報収集」](https://qiita.com/ryamamoto0406/items/82e71076af387ee77762)で集めた Tweet の位置情報を可視化していきたい。今回はキーワードを "beer" として 2022年5月23日、24日、25日の間につぶやかれた位置情報を取得し、これを可視化してみる。データの取得方法については上記記事を確認されたし。

cartopy でヒートマップを作る方法は[Python で Tweet の位置情報をヒートマップで可視化しよう！(cartopy版)](https://qiita.com/ryamamoto0406/items/561b45fbcf65af41764c)に記載済み。前半部分は上記記事と全く同じ。

# データの読み込みと結合
まず収集したデータを読み込み、三つのデータフレームを結合する。

```python:データ読み込みと結合
# 必要なモジュールのインポート
import pandas as pd

# データの読み込み
df1 = pd.read_csv("./20220523_beer.csv")
df2 = pd.read_csv("./20220524_beer.csv")
df3 = pd.read_csv("./20220525_beer.csv")

# データ結合
df = pd.concat([df1, df2, df3])

# 結果の表示
df.head()
```

出力は下記の通り。

![cartopy_heatmap_data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1077734/1ddbd79b-ecb7-ddcd-8ef7-1b06d1cf808c.png)

データフレームのサイズを確認してみると、

```python:データセット確認
# サイズ確認
print(df.shape)
```

```python:出力
(5788, 5)
```

約5800行程度の位置情報がある。

# folium でヒートマップを作る
folium にはヒートマップのプラグインがすでに用意されている。以下に参考記事を示す。

- [foliumでヒートマップの作り方をおぼえた](https://hikiniku11029.hatenablog.com/entry/2019/06/18/folium%E3%81%A7%E3%83%92%E3%83%BC%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9%E3%82%92%E3%81%8A%E3%81%BC%E3%81%88%E3%81%9F)
- [【foliumのPlugins】HeatMap(ヒートマップ)の使い方](https://chayarokurokuro.hatenablog.com/entry/2021/08/08/212048)

コードはシンプルで簡単。

```python:ヒートマップの作成
# 必要なモジュールをインポート
from folium import Map
from folium.plugins import HeatMap

# 地図の作成（中心は日本）
m = Map(location=[35.658581, 139.745433], zoom_start = 2)

# ヒートマップの作成
HeatMap(
    df[["lat", "long"]].values, # 緯度・経度のリスト
    radius=4, # ヒートマップの点の半径。
    blur=3 # ぼかしの程度
).add_to(m)

# 図の保存
m.save('heatmap.html')
```

![folium_heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1077734/cb48c33e-d6e1-b908-b717-736205f8b431.png)

やはりアメリカ、ヨーロッパ、日本で多く beer とつぶやかれており、特にロンドン、ニューヨーク付近で色が赤に近くなっているのがわかると思う。folium の html は開くと拡大縮小、移動ができるので、日本なら東京と大阪に beer のつぶやきが多いのがわかる。

# おわりに
folium を使うと簡単にヒートマップを作成することができた。ほかにもいくつかプラグインがあるようなので、時間があればいろいろと試してみたいと思う。
RuntimeError: cuInit failed: no CUDA-capable device is detected

#### RuntimeError: cuInit failed: no CUDA-capable device is detected がGoogle Colabで出たら。

```
import numpy as np
import pycuda.gpuarray as gpuarray
from pycuda.elementwise import ElementwiseKernel
import pycuda.autoinit


-------------------------以下エラー------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-2-be9ea5a5b25e> in <module>()
      2 import pycuda.gpuarray as gpuarray
      3 from pycuda.elementwise import ElementwiseKernel
----> 4 import pycuda.autoinit

/usr/local/lib/python3.7/dist-packages/pycuda/autoinit.py in <module>()
      3 
      4 # Initialize CUDA
----> 5 cuda.init()
      6 
      7 from pycuda.tools import make_default_context  # noqa: E402

RuntimeError: cuInit failed: no CUDA-capable device is detected

```
1. ランタイムのセッションタイプを押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2698384/fc56a27e-7540-6311-ff48-d6028533600a.png)


2.ハードウェア アクセラレータを「GPU」に変える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2698384/bc715b92-6eeb-56ce-a55e-cee6798fda34.png)



3.もう一度実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2698384/eae25687-2f5c-aaf3-9352-9cb4efb841b7.png)

OK！
tfenv で M1 対応の terraform をインストールする

## 動機

この issue のエラーを回避するために、 tfenv で Terraform が `amd64` で入ってくるのを回避したかった。

https://github.com/hashicorp/terraform-provider-aws/issues/20274

以下のように、 `tfenv install ****` をすると amd64 が入ってきてしまう。

```sh
$ tfenv install 1.2.2  
Installing Terraform v1.2.2
Downloading release tarball from https://releases.hashicorp.com/terraform/1.2.2/terraform_1.2.2_darwin_amd64.zip
######################################################################################################################################################################################################################################################### 100.0%
Downloading SHA hash file from https://releases.hashicorp.com/terraform/1.2.2/terraform_1.2.2_SHA256SUMS
No keybase install found, skipping OpenPGP signature verification
Archive:  tfenv_download.WOq4o7/terraform_1.2.2_darwin_amd64.zip
  inflating: /opt/homebrew/Cellar/tfenv/2.2.2/versions/1.2.2/terraform  
Installation of terraform v1.2.2 successful. To make this your default version, run 'tfenv use 1.2.2'
```

## 環境

M1 Macbook Air


## 方法

https://github.com/tfutils/tfenv#tfenv-1

README.md に書いてありました。 `arm64` を渡してあげれば良さそう。

```sh
TFENV_ARCH=arm64
```

```sh
$ TFENV_ARCH=arm64 tfenv install 1.2.2
Installing Terraform v1.2.2
Downloading release tarball from https://releases.hashicorp.com/terraform/1.2.2/terraform_1.2.2_darwin_arm64.zip
######################################################################################################################################################################################################################################################### 100.0%
Downloading SHA hash file from https://releases.hashicorp.com/terraform/1.2.2/terraform_1.2.2_SHA256SUMS
No keybase install found, skipping OpenPGP signature verification
Archive:  tfenv_download.zmM3xS/terraform_1.2.2_darwin_arm64.zip
  inflating: /opt/homebrew/Cellar/tfenv/2.2.2/versions/1.2.2/terraform  
Installation of terraform v1.2.2 successful. To make this your default version, run 'tfenv use 1.2.2'
```

Terraform の公式のダウンロード URL を見に行くみたいで、 `arm` だけだとダメだった。

```sh
TFENV_ARCH=arm tfenv install 1.2.2
Installing Terraform v1.2.2
Downloading release tarball from https://releases.hashicorp.com/terraform/1.2.2/terraform_1.2.2_darwin_arm.zip
#=#=-  #       #
#=O#-     #        #
-#O=- #      #          #
curl: (22) The requested URL returned error: 404

Tarball download failed
```

`.zshrc`, `.bashrc` で常に環境変数がセットされるようにすると良さそう。
もし amd64 で `terraform init` していたら、 arm64 で入れ直した後にもう一度 `terraform init` をする。
【Rails】DBから最新データが取得されていない時の対処法

# 初めに

ポートフォリオのライク機能を作成した際に、`DB`のデータは変更されているのにインスタンスのデータは更新されていなかった。

## 環境

- Rails 6.1.4
- Ruby 2.7.4

## 結論

`SQLキャッシュ`がされていたので、同じ`SQL`を発行した場合キャッシュされたデータ(更新前のデータ)が返ってきた。

# 解決方法

`SQLキャッシュ`は

- 同じクエリが発生すると、データベースへのクエリを実行せずに、キャッシュされた結果を返す
- `SQLキャッシュ`は、アクションの開始時に作成され、アクションの終了時に破棄されるので、アクションの実行中しか保持されない。

なので、`reload`メソッドを利用することでキャッシュを使わずに再取得できます。

```ruby:like_controller.rb
class LikesController < ApplicationController

  def create
    review = Review.find(params[:review_id])
    like = Like.create(user: current_user, review: review)
    review.reload
    respond_to do |format|
      format.js
      format.html {redirect_to root_path}
    end
  end
end

```

これにより、`SQL`が再度発行され最新のデータが`DB`から取得されます。

# 参考

[SQL キャッシュ - Rails ガイド](https://railsguides.jp/caching_with_rails.html#sql%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5)
MVC モデル、フレームワークとは

# MVCの表すもの
以下の３つを指す。

## M(モデル）
データと業務処理に関する部分
## V(ビュー)
結果をユーザーに出力する部分
## C(コントローラ)
ユーザーの命令を受けて各部に指示を出す部分
モデルやビューに伝える役割

# Webアプリケーションの三層構造と似ている。
しかしここには違いがある。
それは階層構造になっているからだ。
この構造は最上層と最下層の直接のデータ層が直接やり取りができないところだ。

# MVCモデルの利点
3つに分かれているために改修や機能追加が容易で、分業で開発を行いやすい。

# 思ったこと
MVCモデルはrailsだけではないんだな。

# フレームワーク（一般的な処理の流れを「ひな型」)
色々な仕様があるんだな。

## フレームワークを使うと
・ひな型に沿う形のプログラムを作ることしかできない。
・プログラム開発の手間の削減
・開発者の力量差による品質のバラつきが出なくなる。

出典 Web技術の基本(SBcreative)
Git コマンド　まとめ２

git resetは間違って入力した場合に戻すための命令であり、属性は
ハード、ソフト、ミックスの3つである。

git fetchはローカルファイルは変更せずにgitの変更内訳だけを確認することであり、
ローカルに変更された内訳は持ってこない。

git stashは作業中だった内容を臨時に保存することだ。

git　reset　-soft　HEAD　:コードは生かしcommitのみ取り消す
git　reset　-merge　:mergeキャンセル
git　reset　-hard　HEAD　&　git　pull　:gitコード強制的に全て受け取る。
git　push　remote_name　-delete branch_name　:遠隔ブランチ削除
git　fetch　:gitサーバーから最新コードを受け取る。MERGEはしない
git　stash　pop　:最後に臨時保存した作業コードを持ってくる
cat readme.md : readme.mdの内容を確認
Databricksワークスペースにログインできなくなった際のトラブルシュート

パスワードを変更していないにもかかわらず、これまでログインできていたワークスペースにログインができなくなった際のトラブルシュートの手順をご説明します。

可能性として最も高いのは、「**自分がアクセスできないワークスペースのURLでログインしようとしている**」ということです。ワークスペースにはワークスペース固有のURLが割り当てられるので、作成したワークスペース、割り当てられたワークスペースのURLはブックマークしておくことをお勧めします。

ご自身がワークスペースを作成した**アカウントオーナー**である場合には、以下の手順でワークスペースのURLを確認することができます。そうでない場合には、ワークスペースを作成したアカウントオーナーにお問合せください。アカウントオーナーが何であるかは、[こちら](https://qiita.com/taka_yayoi/items/4603091dd325c77d577f#databricks%E3%81%AE%E7%99%BB%E5%A0%B4%E4%BA%BA%E7%89%A9%E3%81%A8%E4%B8%BB%E8%A6%81%E6%A9%9F%E8%83%BD%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B)を参照ください。

# アカウントコンソールへのログイン

アカウントコンソール https://accounts.cloud.databricks.com/login にアクセスします。アカウントオーナーのみがアカウントコンソールにログインすることができます。

![Screen Shot 2022-06-06 at 16.44.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c7eac39b-3ee5-2e22-89f3-5b514154e7a0.png)

# ワークスペース一覧へのアクセス

アカウントコンソールにログインするとこれまでに作成したDatabricksワークスペースの一覧が表示されます。

![Screen Shot 2022-06-06 at 16.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f9e04d56-0a46-7131-cb51-6d9a6cf0f529.png)

# ワークスペースへのアクセス

アクセスしたいワークスペースの行の一番右にある**Open**をクリックします。

1. このページをブックマークしておきます。
1. ワークスペースにログインします。
![Screen Shot 2022-06-06 at 16.46.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b5cad3ae-4bc8-e8dd-ee7d-d7d747295d3c.png)
1. これでワークスペースにログインできるはずです。
![Screen Shot 2022-06-06 at 16.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/440ad101-24ab-c561-8ba8-d3821bfbb328.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
M5Paper: I2C アドレスのスキャン

```text:m5paper_i2c_scan.ino
// ---------------------------------------------------------------
//	m5paper_i2c_scan.ino
//
//					Jun/6/2022
// ---------------------------------------------------------------
#include <M5EPD.h>
// I2C (internal) - SDA: 21, SCL: 22
// I2C (external - Port A) - SDA: 25, SCL: 32

M5EPD_Canvas canvas(&M5.EPD);
// ---------------------------------------------------------------
void setup()
{
	M5.begin();
	Wire1.begin(25, 32);

	M5.EPD.Clear(true);
	canvas.createCanvas(960, 540);
	canvas.setTextSize(5);

	canvas.drawString("m5paper_i2c_scan", 30, 100);
	canvas.pushCanvas(0,0,UPDATE_MODE_A2);
}

// ---------------------------------------------------------------
void loop()
{
	int address;
	int error;
	char buf[60];
	int aa[] = {0,0,0,0,0,0,0,0,0,0};

	Serial.println("Scanning internal I2C");
	canvas.drawString("Scanning internal I2C", 30, 150);
	canvas.pushCanvas(0,0,UPDATE_MODE_A2);
	
	for(address = 1; address < 127; address++)
	{
		Wire.beginTransmission(address);
		error = Wire.endTransmission();
		if(error == 0)
			{
			Serial.println(address, HEX);
			}
		delay(10);
	}
	delay(500);

	canvas.drawString("Scanning external I2C (PortA)", 30, 200);
	canvas.pushCanvas(0,0,UPDATE_MODE_A2);

	int nDevices = 0;
	Serial.println("Scanning external I2C (PortA)");
	for(address = 1; address < 127; address++)
	{
		Wire1.beginTransmission(address);
		error = Wire1.endTransmission();
		if(error == 0)
			{
			Serial.println(address, HEX);
			aa[nDevices] = address;
			nDevices++;
			}
		delay(10);
	}

	sprintf(buf, "aa[0] = %x", aa[0] );
	canvas.drawString(buf, 30, 250);
	sprintf(buf, "aa[1] = %x", aa[1] );
	canvas.drawString(buf, 430, 250);

	sprintf(buf, "aa[2] = %x", aa[2] );
	canvas.drawString(buf, 30, 300);
	sprintf(buf, "aa[3] = %x", aa[3] );
	canvas.drawString(buf, 430, 300);

	sprintf(buf, "nDevices = %d", nDevices );
	canvas.drawString(buf, 30, 350);
	canvas.pushCanvas(0,0,UPDATE_MODE_A2);


	delay(5000);
}

// ---------------------------------------------------------------
```

Arduino IDE
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/eda23583-ec99-3c52-8e02-e52fd5955c90.png)

実行結果
>Grove-LCD RGB Backlight を接続
![IMG_20220606_163732.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/b4e9634d-502c-9cdc-45fc-93d1c346a242.jpeg)
ラズパイの特定のUSB機器以外のUSB接続を無効にする

# はじめに
<!-- 概要 -->
ラズパイなどエッジデバイスを工場内IoT等でセキュアに使用したい場合、物理的なUSBアクセス遮断以外に簡単なアクセス制限をする方法を試したので記録しておく
# 目次

1. [特定のUSB機器の素性をチェック](#Chapter1)
1. [特定のUSB機器に名前を付ける](#Chapter2)
1. [USB接続無効化](#Chapter3)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 特定のUSB機器のプロダクトIDを探します
以下のコマンドでUSB機器のプロダクトIDを取得
~~~
lsusb
~~~
以下のようにレスポンスがあります
~~~:例
Bus 001 Device 022: ID 10c4:ea60 Cygnal Integrated Products, Inc.
Bus 002 Device 004: ID 05e3:0626 Genesys Logic, INC
~~~
~~~:出力の意味
BusNo __ DeviceNo __ : ID vendorID:productID 
~~~
vendorIDをチェックして、このVendorIDに対して次の項目で名前を付けます
<a id="#Chapter2"></a>
# 特定のUSB機器に名前を付ける
~~~
echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0666", GROUP:="dialout",  SYMLINK+="ydlidar"' >/etc/udev/rules.d/ydlidar.rules

service udev reload
service udev restart
~~~
ここでは、10c4:ea60のUSB機器に”ydlidar”という名前を付けています。
キーボード等、無効化から除外したい機器があれば登録します。
<a id="#Chapter3"></a>
# USB接続無効化
/lib/udev/rules.d/50-udev-default.rulesに記載されている接続時のルールを書き換える
~~~
sudo vi /lib/udev/rules.d/50-udev-default.rules
~~~
~~~
KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout", MODE="000"
~~~
~~~
service udev reload
service udev restart
~~~
MODE="000"で実行・書き込み・読み込みを許可しないに変更
| シンボル |    数値    |    パーミッションの内容    |
|---:|-------------|------------|
| rwx|     7        |     読み込み・書き込み・実行  を許可     |
| rw-|      6       |      読み込み・書き込み  を許可      |
| r-x|       5      |      読み込み・実行  を許可      |
| r-|         4    |     読み込み  を許可       |
| -wx|         3    |       書き込み・実行を許可     |
| -w-|          2   |      書き込みを許可          |
| -x|            1 |      実行を許可     |
| -|             0|       許可なし     |

|左から1桁目|左から2桁目|左から3桁目|
|--- |----                                  |---|
| オーナー                |       グループ|       その他     |

注:パーミッション設定後にキーボードの操作をする場合はSSH経由でお願いします。

<a id="#reference"></a>
# 参考文献
https://www.server-memo.net/tips/command/chmod/chmod.html

- [リンクテキスト](URL)
Web検索エンジン、Webアプリケーションの三層構造

# Web検索エンジン
Webで情報を探すときはGoogle、Yahoo!、Bingがある。
１９９０年ごろは検索エンジンが検索に使うための情報は人手で管理されていた。
構造はディレクトリ（フォルダ)のように木構造になっている。

２０００年ごろは人手では管理が追いつかなくなった。
そこで```クローラ```、```ロボット```と呼ばれるプログラムが自動的にWeb上の情報を収集し、解析した結果を検索に用いる```ロボット型検索エンジン```が主流となる。

クローラはWebページのリンクをを次々と辿ることによって別のWebページを収集し、データベースに登録していく。またWebページが更新、削除された場合は、データベースの更新削除を行い、最新化されていく。
このようにデータベースの最新化させていくことを```クローリング```という。

Webページの中身を解析し、どのような情報が含まれていくかを抽出し、分析可能な形にするこの変換作業を```スクレピング```という。

スクレピングはDOM(HTMLから要素を取り出す)、HTMLパーサー（HTMLのタグの内容を取り出す）というプログラムで使われている。

検索エンジンはこうして作られたデータとユーザーが送ってきた情報をマッチングさせることでWeb検索を行う。

# Webアプリケーションの三層構造
Webブラウザ上で動作するアプリケーションを```Webアプリケーション```という。
Webアプリケーションは```三層構造(三層アーキテクチャ)となっている。

# その3層構造とは...
## プレゼーテーション層(ユーザーインターフェース）
ユーザーへの表示、ユーザーの操作受付を行う。
クライアントサイド・スクリプト(javascriptなど）

### ユーザーインターフェース（UI）とは
ユーザー（利用者）と製品やサービスとのインターフェース（接点）すべてのこと
WebサイトでいうところのUIは、サイトの見た目や、使いやすさのことを指します。
文字のフォント、メニューやボタンの操作性などユーザーが目にするもの・操作するものすべてが含まれています。

出典 https://www.m-hand.co.jp/design/7161/

## アプリケーション層（業務処理)
アプリケーションサーバー（APサーバー）
ユーザーからの命令実行、表示画面の作成を行う。
サーバーサイド・スクリプト(Ruby,PHPなど)

## データ層(データ処理や保管)
データベースサーバー（DBサーバー）
データの抽出、更新、保管を行う。

# どうして三層の構造にするのか？
・一台だと負担が大きくなるので、３つに分けることでサーバーの負担を減らす
・適した構成にしやすくなる。
・改修するときも部分ごとに行うことができる。
・他のサーバーに影響を及ぼさないようにする。

# 思ったこと
適した構成とはどのようなものか？
やったみたい。

出典　Web技術の基本
PostgreSQLでvaluesからselectした結果をinsertする

忘れるのでメモです。
CSVから一時テーブルへの取込みするときなど、複数行のデータを加工しながら一度に取り込みたいときによく使います。

```sql
insert into "宛先テーブル"
(
    name,
    age
)
select
    t.name,
    t.age
from (
    values
    ('bob', 22),
    ('jane', 19),
    ('mike', 30)
) as t (name, age)
```
VSCode で HSP3 の開発環境を作る [2022年]

- [モダンなHSP環境を構築しよう \[2018年\]](https://qiita.com/YSRKEN/items/449816a7c03e3091e604)
- [VSCode で HSP3 の開発環境を作る \[2019年末\]](https://qiita.com/vain0x/items/1c0be49b3b22142dbfd1)
に継ぐ最新版です。
前提として
- HSP3.6
- VSCode
- node.js
がインストール済みとします。
------

## 拡張機能インストールの準備
[vain0x/hsp3-ginger: HSP3 開発ツールを作るプロジェクト](https://github.com/vain0x/hsp3-ginger)
から__hsp3-ginger-main.zip__をダウンロードして解凍します。
コマンドプロンプトもしくはパワーシェルで
__hsp3-ginger-main\\hsp3-debug-window-adapter\\vscode-ext__
内__install.ps1__を実行して__hsp3-debug-window-adapter.vsix__を作成します。

## hsp3-debug-window-adapter.vsix のインストール
VSCodeの拡張機能を開き
__ビューとその他のアクション__ → __VSIX からのインストール__
と辿り、__hsp3-debug-window-adapter.vsix__をインストールします。

## その他の拡張機能のインストール
HSPで検索をし、
- [HSP3 デバッグ \(標準のデバッグウィンドウを使用\)](https://marketplace.visualstudio.com/items?itemName=vain0x.hsp3-debug-window-adapter)
- [HSP3 構文定義](https://marketplace.visualstudio.com/items?itemName=vain0x.hsp3-vscode-syntax)
- [language-hsp3](https://marketplace.visualstudio.com/items?itemName=honobonosun.language-hsp3)
をインストールします。

## 拡張機能の設定
- language-hsp3.compiler
- language-hsp3.helpman.path.local
- hsp3-debug-window-adapter.hsp3-root
にそれぞれパスを入力します。
-----

以上で環境構築完了です。
VSCodeでF5でのデバッグとUTF8での開発ができるようになりました。
pgAdmin4でCSV出力してみた。あと文字化けした時の対処。

pgAdminといえばPostgreSQLをGUIで管理できるツールで、
PostgreSQLをインストールした時に一緒についてくるやつです。
PostgreSQLを扱う人は大体最初使うことになります。

ではさっそくpgAdmin4でテーブルのデータをCSV出力してみます。
出力したいテーブルを右クリックして「インポート/エクスポート」をクリックします。
![pgAdmin4_csv1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513616/dc36e7c4-ac61-5b5e-2acc-a6d7583737fb.png)
エクスポートを選択
ファイル名を適宜入力
形式をcsv
その他の設定はこだわりあれば自由に
「OK」をクリック
**↓↓↓ここ追記**
エンコーディングをSHIFT_JIS_2004にしてください！
（**※ExcelはShift-JISで開こうとするのでSHIFT_JISで出力しないと文字化けします。**）
![pgAdmin4_csv2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513616/ce4f079f-3a04-ea4c-299f-468f7ea33ba9.png)
Excelで開いてみると.....

できましたーーーー！！
![pgAdmin4_csv3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513616/e04dbc14-2ac4-53d6-f874-80e8d021d58e.png)
SEO対策　メモ

コンバージョン率(CVR)とは

Webマーケティングにおいて、事前に設定した最終的な成果を、ユーザーが達成することを意味する


コンバージョン率＝コンバージョン数÷セッション数×100(%)

ランディングページにおける平均的なCVR（コンバージョン率）は、約2〜3%

organic　広告以外の検索数

最後まで読んでいるかどうか

滞在時間が長いかどうか

キーワードが多い場合、良くない

外部リンクが多いと良くない

ユーザーに役立つ品質の高いコンテンツをつくる
クエリの検索意図を把握する
専門性の高いコンテンツを目指す
ユーザビリティの良い、使いやすいサイトを構築する
クローラビリティを高める

専門性があるページか？
権威があるページか？
信頼できるページか？

1.タイトル
記事の内容をユーザーとクローラーに正しく伝わるよう、キャッチコピーとなる「タイトル」はしっかり考えましょう。少なくとも、タイトルには狙いたいキーワードを入れた方が良いでしょう。そのキーワードで検索したユーザーの目に触れやすくなりますし、ユーザーに読んでもらえれば結果的に検索エンジンからの評価も上昇します。

2.メタディスクリブション
タイトルと同じぐらい重要なのが、メタディスクリプション（記事概要）です。検索結果でタイトルの直下に表示される文章を指し、この内容を読んだユーザーに「この記事なら自分の課題を解決してくれそうだ」と記事に飛んでもらえるような内容にする必要があります。

3.見出しタグ
記事の本文は、「自分が欲しい情報はあるのか」をすぐに判断できるような状態にしておくと良いでしょう。そのためには、見出しを活用するべきです。文章をだらだら羅列するのではなく、H2やH3などの見出しタグを使ってこの章では何について書かれているのかがぱっと見でわかるようにしましょう。ユーザー体験を向上するだけでなく、クローラーへのアピールにもなります。

4.クローラーが読み取りやすい環境を構築する
Webサイトの情報や画像を収集する「クローラー」の対策も必須です。クローラーはコンテンツの更新があると情報を上書きしていきますが、すべてのページを巡回するとは限りません。重要なページをクロールさせるには、クローラビリティの最適化をする必要があります。

主な方法は以下の4つです。

Googleサーチコンソールを使ってサイトマップを送信する
「Fetch as Google」をうまく利用してクロールを促す
ディレクトリ構造の改善を図る
パンくずリストを設定してサイト構成への理解を促す
5.ユーザビリティの考慮
ユーザーが利用しやすいサイトの構成も、重要な内部対策のひとつです。近年はパソコンよりもスマホを使った検索が多いため、スマホへの最適化や、読み込み速度の向上などを意識しましょう。

内部対策の詳細を知りたい方は、以下の記事を確認してみてください。

検索順位が上がるまでの期間
少なくとも3ヶ月〜半年くらいはかかります。

もちろん検索順位が上がるスピードは、上位表示したい検索キーワードにもよります。

珍しい会社名や商品名での上位表示なら、ホームページを公開後すぐにヒットできることも珍しくありません。

一方で、売上に結びつきやすい検索キーワードの場合は、ライバルページも多く順位向上に長く時間がかかります。

リスティング広告

クエリ（検索キーワード）

クローラー
巡回（クローリング）
Googleサーチコンソール　メモ

# Googleサーチコンソール

クリック数
検索キーワードによってサイトのURLが何回クリックされたかを示す
Google からサイトへのリンクがクリックされた頻度


表示回数
サイトへのリンクが Google で閲覧された頻度
検索順位が1位〜10位のリンクが検索結果の1ページ目に表示される

ユーザーがページネーションでページをめくって掲載ページを表示しない限り、表示回数はカウントされない
ページを開きさえすれば、ユーザーがスクロールしなかったとしても表示回数にカウントされる

表示回数のカウント対象はGoogle検索のみ



掲載順位
Google に掲載されているリンクの掲載順位の相対ランキング



CTR(クリック率)
クリック数÷表示回数(インプレッション数)×100
クリック数を表示回数で割った値
SEO対策流れ

## 検索される為の調査　検索前

Googleキーワードプランナー(Google広告)
Googleにおける検索ワードのパフォーマンスを調査
関連キーワード検索、検索ボリューム予測などの機能があり、検索エンジンを対象としたツール

## 検索されてからの結果　検索後
Googleサーチコンソール
Google上に表示されるサイトの情報を調査
Googleでのサイトの検索順位、表示回数、クリック率などの調査が可能で、サイトと検索エンジンの繋がりを調べるためのツール

## サイトに訪れた人の結果　サイト訪問
Googleアナリティクス
サイトに訪問した後の人の行動を調査
ページビュー、離脱率、滞在時間などを測定
サイト内部の動向を知るためのツール
GoogleAnalytics メモ　SEO

アクセス数
・ユーザー数(ユニークユーザー数)
・PV数(ページビュー数)
・セッション数

ユーザー数
Webサイトを訪れたユーザーのうち重複を除いた値
一日に同じユーザーが複数回サイトを訪問したとしても、ユーザー数は1とカウント

PV数
Webサイト内のページが表示された総回数
同ユーザーがサイトを訪れてもPV数はカウントされる
ブラウザバックしてもPV数はカウントされる

セッション数
ユーザーがWebサイトに流入してから離脱するまでの流れを一回としてカウント
離脱したユーザーが一定時間を経てサイトに再訪問した場合や、参照元が変更されたときなどは再度新規セッションとしてカウントされます。


滞在時間
サイトの滞在時間

回遊率
サイト内の他ページを読んで回ることを回遊
1ユーザーがどれだけのページを見て回ったかを示すのが回遊率
PV数÷セッション数＝回遊率

直帰率
ユーザーが最初に訪れたページを見た後に、
その他のページに遷移せずそのままサイトを離脱すること直帰
直帰したユーザーの割合が直帰率
直帰したセッション数÷全セッション数＝直帰率

離脱率
サイトを離脱したユーザーの割合を示す指標
離脱したセッション数÷全PV数＝離脱率

コンバージョン率(CVR)
Webサイトにおける「目標」のこと
サイトに訪れたユーザーにとってもらいたい行動
コンバージョン数（CV数）÷セッション数＝コンバージョン率（CVR）

サイトの訪問者数はどのくらいか
どこからサイトに訪れたか（検索、広告、外部リンクなど）
どのような人が訪れたか（性別、年齢、地域、使用端末など）
どのページにアクセスが多いか
どの時間帯にアクセスが多いか
サイト内をどのくらい回遊してくれたか（閲覧ページ数、滞在時間）
サイトを離脱したページはどこか
GoogleAnalytics 　直帰率とは　SEO

直帰率

直帰率の数字を下げることは、目的ではない。それは単なる数字だ。何の意味もない。

真の目的は、エンゲージメントを高め、満足度を高め、ユーザーをより幸せにすることだ。

1
サイトを高速化すると直帰率は下がる

2
対応する検索意図の幅を広げる
画像、詳細、レビューなど他のリソースにリンクできるように

3
競合分析
検索上位を獲得しているページとの違い

4
質問に答える
しっかりと回答をする

5
関連するリンクを、わかりやすい位置につける

6
CTA
Call To Action　行動喚起
Web上のユーザーに行動を喚起させるするためのテキストや画像に対して使われている用語
リンクできる、文字、画像、ボタン

7
逆ピラミッド
興味→詳細→もっと詳しく→購入

参考
https://webtan.impress.co.jp/e/2021/06/21/40505#moz-section-1
HTMLの構成 progate

# 要素
要素で要素を入れることを```入れ子```

## 親要素
要素を囲む方を```親要素```

## 子要素
要素から囲まれる方を```子要素```

## インデント
親子関係を示すために囲む要素の開始タグからスペースを2つ(一般的に)付ける。
これを```インデント```
tabでつけられる。
【備忘録】HerokuアプリからAWS RDSのデータベースへ接続する

# 何が書いてある記事なのか？
Heroku上に構築したアプリケーションから、AWS RDS上に構築したデータベースへ接続する手順について。

## Heroku→RDS(MySQL)への接続方法
### 前提条件
- AWS RDS上にデータベース(MySQL)を構築済みであること
- GitHubからデプロイされたHerokuアプリケーションが存在すること
- MySQL 5.x にて確認

### 手順

#### 1. Herokuへデプロイ済みのGitHubリポジトリに、AnazonRDS CA証明書(*.pem)ファイルを追加する

```shell
# 対象リポジトリのディレクトリへ移動
$ cd hoge_repo

# リポジトリのconfigディレクトリにCA証明書をダウンロード
$ curl https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem > ./config/amazon-rds-ca-cert.pem

# リポジトリにプッシュする
$ git push origin main
$ git push heroku main
```

#### 2. Herokuアプリの環境変数`DATABASE_URL`にデータベース情報を反映する

```shell
# <username>  DBユーザ名 
# <password>  DBパスワード
# <hostname>  ホスト名(RDSデータベースのエンドポイント名)
# <port>      ポート番号
# <database>  データベース名
# <herokuapp> 対象のHerokuアプリケーション名
$ heroku config:set DATABASE_URL="mysql2://<username>:<password>@<hostname>:<port>/<database>?sslca=config/amazon-rds-ca-cert.pem" -a <herokuapp>
```

#### 3. RDSのセキュリティグループ設定を選択し、インバウンドルールを変更する

RDSのWeb管理画面にて設定する。ここでは、ソースを`0.0.0.0/0`とし、どのIPからでも接続できるように設定する。
ただし、本番環境などでは、セキュリティを考慮した上で正しく設定すること。

#### 4. 必要に応じて、MySQLのデータベースに対して、ユーザーの全接続に対してSSLを求めるように設定する

```sql
# 対象データベースにてSQLクエリを発行
GRANT USAGE ON *.* TO '<username>'@'%' REQUIRE SSL;
```

#### 5. 対象のアプリケーションからデータベースへ接続が可能であることを確認する

## 参考文献
- [Heroku公式ドキュメント(Amazon RDS)](https://devcenter.heroku.com/ja/articles/amazon-rds)
- [amazon-web-services - HerokuアプリケーションをAWSRDSデータベースにポイントする](https://jablogs.com/detail/58149)
【M1Mac】M1でVSCodeのターミナルにRosetta用のzshプロファイルを追加する。【Rosetta】

自分用のメモとして残します。




# やり方

settings.jsonに追加する。
`"terminal.integrated.profiles.osx"`があると思うので、追加。
なければ追加。

```settings.json

 "terminal.integrated.profiles.osx": {
       〜〜〜省略〜〜〜
        "zsh-rosetta": {
            "path": "arch",
            "args": ["-x86_64", "zsh", "-l"],
            "overrideName": true
        }
    },

```
## デフォルトをRosettaZshにしたい場合
同jsonに`terminal.integrated.defaultProfile.osx`下記を追加 

```settings.json
 "terminal.integrated.defaultProfile.osx": "zsh-rosetta",
 "terminal.integrated.profiles.osx": {
       〜〜〜省略〜〜〜
        "zsh-rosetta": {
            "path": "arch",
            "args": ["-x86_64", "zsh", "-l"],
            "overrideName": true
        }
    },

```
GridagramからMagic-Gridにしてみた

おうちモニター(oumon)で使っていた[Gridagram](https://qiita.com/yamori813/items/37d036daae7e451eeb7a)はレスポンシブルではなく、追加したい項目も増えてきたので、[Magic-Grid](https://github.com/e-oj/Magic-Grid)に替えてみました。

とりあえずHTML,JS,CSSを埋め込んでみたところ、メニューがコンテンツの下になり、選択できなくなりました。

![menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/21469d4b-36fd-a7d5-bef3-5685f2bbc6db.png)

JSとかCSSとかあまりよく分かってないので、いろいろ検索したところ下記で直りました。

```html
<ul class="ddmenu" style="position:relative; z-index:10">
```

とりあえずGridagramで使っていたjsonをjQueryで読んでそのまま表示するようにJSを書いて見ました。GridagramはjQueryのプラグインですが、Magic-GridはjQueryを使っていないので、直接getJSONを使います。

![menu2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/a9e0a435-e118-26c4-6250-be5444db658d.png)

Androidでもちゃんと表示できました。やっぱ時代はレスポンシブルですね。

メニューとコンテンツの間にグレーの線が入っているのはGridagramの名残です。
README に開発のセットアップ方法を書こう（書いてくれ）

# READMEに何を書くべきか問題

リポジトリの顔とも言うべきREADMEに何を書くべきかは多くの方が議論されていると思いますが、ここではリポジトリのソースコードを利用して開発を始める時の手順（セットアップ）の記述に関して、自身の体験など踏まえて意見を整理しておきます。

# READMEは誰が見るの？
リポジトリの作者や以前からのコミッターはそのリポジトリの内容に精通しているので、正直READMEなんて見なくても問題ないです。問題なのは初めてリポジトリを見に来た人たちです。ネットの大海原の中から奇跡的にこのリポジトリに辿り着いた通行人たち。リポジトリの目的や内容・特徴を簡潔に説明し、彼らに少しでも興味を持ってもらうための手段がREADMEと言えます。ですから、 **READMEはリポジトリ初見の目線が大事です。** 製作者のメモ書きみたいな暗号文を記載されても困ります。もっとも **数週間もすれば過去の自分はもはや他人です。** 他人のメモ書きなんぞ解読不能です。

# セットアップ方法が分からん
社会人として働く経験から気付かされました。自主開発中心の学生時代とは異なり、他者が作成したリポジトリを利用・コミッターとして参加する機会が増えたため、そのたびに開発環境を新しく用意します。困ったことにリポジトリによってはセットアップ方法の説明が不十分もしくは存在せず、経験者に質問して対応してもらうケースが多々ありました。正直、最初はREADME以外何を見ればいいか分からんし、最低限のセットアップ方法は記載して欲しい。まぁ、業務の場合は開発に必要な文書をREADME以外の方法・サービスで管理している場合もあり、READMEにまとめろ、とは一概に言えなさそうです。

ただし、自主開発などは言い訳できないので、 **README読んでも分からん、となったら誰も見向きもしてくれないです。** かつての自分という他人が遺したリポジトリを修正しようと発掘しても、セットアップ方法が分からず開発が始まらん、とイライラします。リポジトリに対して最も精力的なはずの製作者ですらその有様なのですから、通りがかりの他人なら尚更です。イライラする前に理解を放棄して忘却の彼方です。

# これ書いて欲しかった集
他者のリポジトリに対して、もそうですが過去の自分に対する反省としても経験を遺しておきます。

### バージョン・依存ライブラリ
特にpythonはライブラリも含めバージョン管理が面倒なのでConda環境がほぼ必須。Conda環境の作成から案内してくれ。importエラーのたびに必要なライブラリを探して`pip`叩くのはもう嫌だ。`requirements.txt`にまとめて欲しい。

### 他のリポジトリに依存する場合
いや知らんがな。そっちもローカルにcloneする必要あるなら、最初にそう言ってくれ。

### 認証情報の用意
リモートリポジトリにpushしたくない情報は`.gitignore`で除外することは多いが、開発に必要な情報であることに変わり無い。どこから認証情報を取得して、どのファイル・何の環境変数に書き出すのか指示してくれ。

### 外部サービスに依存する場合
開発するアプリがバックエンドを利用する場合など。デバッグやステージング・プロダクト環境などに応じて別々のエンドポイントだったり、認証情報が違っていたりする。書いてくれ。

### Build方法
開発プラットフォームにスタンダードな方法が明白ならいい。例えばとりあえず`npm run build`と叩けば行ける。そうでないなら、どのスクリプト叩けばいいの？ Build時の設定値はどうする？書いてくれ。

挙げるとキリがないのでここまで。今後、自分が書く時には気をつけようと思います。
LocalJumpError: unexpected return

# 結論

- ブロックの中で早期returnを使うな
- ブロックの中で、returnは呼べないので次の処理へ飛ばす場合はnextを使う

# ブロックとは

- `hoges.each do | hoge | end` や `hoges.each {|hoge| }` のようなもの
- 有名なところだと`map`や`each`などが存在する

参考

https://qiita.com/naotospace/items/3bbef4015c4390182915

# 再現手順

```ruby 
# ブロックの中でreturnを呼び出す

numbers = [1,2,3,4,5]

numbers.each do |num|
   return if num % 2 == 0
end 

```

実行すると、以下のエラーが出る

```
LocalJumpError: unexpected return
```

# 解決策

- returnを使わずに処理しよう
  - returnはそもそも関数の返り値を返すメソッド 
- 特に早期returnなどで利用する場合はnext文で対応しよう
- 例）1-5の値で偶数の値をeven_numbersに入れたい場合

```ruby 

numbers = [1,2,3,4,5]

even_numbers = [] #ここに偶数の値を入れる

# NG　早期リターンを使う

numbers.each do |num|
   return num % 2 != 0
   even_numbers << num
end 

# OK next文で解決する

numbers.each do |num|
   next if num % 2 != 0 
   even_numbers << num
end 

# OK もっときれいにに書く場合
# select: https://qiita.com/shibukk/items/7dded3e74b0f7dbfb633

even_numbers = numbers.select(&:even?)

```



# 参考

- Unexpected Return (LocalJumpError)
   - https://stackoverflow.com/questions/17800629/unexpected-return-localjumperror
- https://zenn.dev/hayaokimura/articles/ruby-block-reintroduction