OmniAICreator/Qiita-1.07M huggingface dataset:
rubyのDockerイメージでseleniumを使えるようにするメモ

# 概要
- CircleCIで `circleci/ruby:X.Y.Z-node-browsers` の最新のrubyに対応したものがなかった
    - 最新rubyの `ruby:X.Y.Z-buster`　にしたらseleniumが動かない
- `ruby:X.Y.Z-buster`　でseleniumを使えるようにした
- とりあえず動くように差分のメモ

# .circleci/config.ymlの差分

## imageを変更する
before
```yml
- image: circleci/ruby:X.Y.Z-node-browsers
```

after
```yml
- image: ruby:X.Y.Z-buster
```

## 環境設定を追加
上で設定したrubyイメージのenvironmentにSELENIUM_DRIVERを追加。

after
```yml
environment:
  SELENIUM_DRIVER: selenium_driver
```


## Chromeを入れる
Chromeの導入だけでなく関連パッケージがさらに必要になる。

before
```yml
- run:
  command: |
    sudo apt-get update --allow-releaseinfo-change
    sudo apt-get install -y libappindicator1 fonts-liberation
    export CHROME_BIN=/usr/bin/google-chrome
    wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    sudo dpkg -i google-chrome*.deb
```

after
```yml
- run:
  command: |
    apt-get update --allow-releaseinfo-change
    apt-get install -y sudo unzip --no-install-recommends
    sudo apt-get update --allow-releaseinfo-change
    CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
    wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \
    unzip ~/chromedriver_linux64.zip -d ~/ && \
    rm ~/chromedriver_linux64.zip && \
    chown root:root ~/chromedriver && \
    chmod 755 ~/chromedriver && \
    mv ~/chromedriver /usr/bin/chromedriver && \
    sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \
    sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
    apt-get update && apt-get install -y google-chrome-stable
```

## Node.jsを入れる
元々のイメージに入っていたものがないので、config.ymlに追加する。
Chromeの設定の下にでも追加。
`command` の最初URLの `setup_16.x` は使用しているNode.jsのバージョンによって変更する。

after
```yml
- run:
  command: |
    curl -sL https://deb.nodesource.com/setup_16.x | bash - \
        && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
        && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
        && apt-get update -qq \
        && apt-get install -y nodejs yarn --no-install-recommends
```

ここまで書けばCI上でseleniumを使ったテストが実行できるはず。
[CLion] scanfがEOFを吐かなくて詰まった話

大学の課題でCLionを使っていたところ、EOFで詰まったのでメモ書き。
解決法は最後に書いているので飛ばしたい人は飛ばしてください。

# 起こった問題

## 問題の概要

```c
//(大分省略して書きます)
while(Scanf("%d",&i)!=EOF){
    printf("%d",i);
}
```

本来このコードを実行して`ctrl+d`または`ctrl+Z`キーを入力すると、`scanf()`が`EOF(通常は-1)`を返して上記のwhile文が終了するはず。

しかし、**CLion**のコンソール上で実行すると、`scanf()`が**EOFではなく0を返す**という謎現象に悩まされた。

外部からコマンドプロンプトでEXEファイルを実行した時には問題は発生しなかった。



## 環境

> OS: Windows 11
> エディター: CLion 2022.1.1 Build #CL-221.5591.52 (JetaBrains)
> コンパイル設定:
> ​		Configuration: CMake Application
> ​		CMakeでMinGWを指定し、MinGWでビルド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/39a3cedb-a435-385e-0b36-1bcd63b9678d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/ec0a54a0-9e44-9fb0-a5a3-b2b0203633f5.png)

## 問題の詳細

```c
#include <stdio.h>

int main() {
    int x;
    int r;
    while ((r = scanf("%d", &x)) != EOF) {
        printf("INPUT: %d\n", x);
        printf("scanf returned %d\n", r);
    }
    printf("END");
}
```

このコードを実行して`Ctrl+D`を入力した結果がこちら。
キーを入力した直後から、`scanf`が0を吐いて暴走をし始めたことが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/7ac14a6d-7157-2ee9-0295-b42a2c59316e.png)

ちなみに、`Ctrl+Z`では何も反応なく。Keymapを確認したところ、EOFを送るショートカットは`Ctrl+D`に割り振られていたのでキーは間違えてはなさそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/934d8304-8c7f-6bd5-da9a-baddb94a7d48.png)

生成されたexeファイルをコマンドプロンプトから実行すると、`Ctrl+Z`で問題なく正常に`scanf()`がEOFを吐いた。

エディター外のコンソールを呼び出しても良いが極力CLionで完結させたい、ということで試行錯誤した。



# 解決法: MinGWからCygwinへ切り替えた

見出しの通りです。ビルドツールをMinGWからCygwinに切り替えたところ、しっかり`Ctrl+D`でEOFを吐いてくれました。行ったCygwinの設定は以下の通り。

Cygwinのインストールについては[➣公式ヘルプ](https://www.jetbrains.com/help/clion/quick-tutorial-on-configuring-clion-on-windows.html#Cygwin)を参照のこと。以下のパッケージを追加しておくと良いかと思います。

- gcc-g++
- gdb
- gdb-debuginfo (Tutorialには載っていないが、Debuggerを有効にするらしい[➣StackOverflowの記事](https://stackoverflow.com/questions/1779247/how-do-i-to-add-gdb-to-cygwin))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/045c236d-dcde-a173-3e71-1d6a17444289.png)

CMake設定がCygwinに切り替わっているか確認することを忘れずに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136916/6a1ad5a1-d400-0c59-8761-91feefc81bee.png)

# 結局問題なのは?

CLionのバグかと。コンソールがMinGWに対応しきれていなかったという話なのでしょうか..?わからん。

# 独り言

まさか大学の課題で2年ぶり(?)にQiitaに投稿するとは思わなかったが、意外とすぐに書けちゃうなって思いました。今後投稿回数を増やせるように心がけます..!
iPadのSwift Playgroundsだけでswift初心者の高校教師がアプリの開発に挑戦してみる　＜その5＞

https://qiita.com/kerikerijy/items/6cceec47f4a877cfa624

# プレイグラウンド「Appを続ける」について

5月17日のSwift Playgroundsのアップデートで新たに3つのプレイグラウンドが追加されました。

![19960047-0B85-49B2-890F-0AB1FFF5C8E8.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661763/6e259427-9032-f496-5801-ee16ead771a9.jpeg)
![39934880-82AF-4187-81F0-061C1F0B4611.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661763/90d0278f-1244-3b8e-aea3-b3df216b1e0b.jpeg)

特に、「Appを続ける」は初心者のアプリ開発の参考になりそうで、早速学んでみたので感じたことを書き残しておきます。

このプレイグラウンドでは、ユーザが絵文字の生き物を追加、削除、または変更できる、完全に機能するAppを作成するチュートリアルです。

![5A83DF6D-4560-4967-8217-3458FC4C8AF4.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661763/7b4fa798-36e5-25d3-8f0e-b7b876f29bfa.jpeg)
![11ECBA94-2B90-401A-BC0D-A9D8ED5F9377.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661763/5dbfdf8b-35cb-1b9b-d293-55dabc631d3e.jpeg)

チュートリアルの最後には情報を詳細表示するビューを自分で作成することで学んだスキルをテストするような構成になっており、最初から最後まで一気に取り組むことができました。

## 身に付けることができる知識

1. ビュー間を移動する方法
2. ローカルの状態変化を管理する方法
3. App全体でデータを共有する方法（オブザーバルオブジェクトを用いたデータモデルの作成方法）
4. さまざまな内臓SwiftUIビューを使用する方法

これまで、「グリッドを使った整理」、「グリッドの編集」、「イメージギャラリー」などのプレイグラウンドで何となく学んできた事を体系的な知識として整理することができました。

以下に理解が深まったキーワードを示しておきます。これらのキーワードについてよく理解できていないSwift初心者にはプレイグラウンド「Appを続ける」は大変有用であると思います。
これが無料なのですからやっぱりAppleはすごいですよね。

### キーワード

- 状態
- データフロー
- 状態の変化
- 監視
- 状態プロパティ
- プロパティラッパー
- @State
- コールバック
- 3項条件演算子
- バインディング
- アニメート
- .animation(_:value:)修飾子
- ColorPicker
- Slider
- データモデル
- NavigationView
- NavigationLink
- ナビゲーションリンク
- ナビゲーションバー
- Section
- オブザーバルオブジェクト
- List
- .resizebleFont()修飾子
- カスタム修飾子
- ForEachビュー
- 環境オブジェクト
- エンバイロメント
- .onTapGesture修飾子
- コールバック
- .onDelete修飾子
- Form
- 環境変数dismiss

以下のキーワードは検索してもヒットせず、珍しいこともあるものです。

- SPCAssessableWindowGroup
- SPCAssessableGroup

![8C84A7F0-E6EE-45CC-BFE8-BAEB11432CB9.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661763/e96cd7b5-b8ba-af91-c49e-bb501b0e15a0.jpeg)

## まとめ

ということで、Swift Playgroundsのプレイグラウンドを色々と試してきて、ある程度知識が付いてきたように感じます。

振り返ってみて、私の意見として、効率的に学習するために取り組んだ方が良い順番を示しておきます。

1. コードを学ぼう1
2. コードを学ぼう2
3. Appの作成を始めよう
4. プロフィール
5. Appで続ける　← この記事で紹介しているプレイグラウンド
6. グリッドを使った整理
7. グリッドの編集
8. イメージギャラリー

「ジェスチャの認識」、「図形をアニメートする」も気になってはいるんですが、今はこのぐらいにしてそろそろ「席替えアプリ」の開発に挑みたいと思います。

https://qiita.com/kerikerijy/items/83ff1c7fb3f4311813a5
[Azure] Application Insightsで指定した情報を確認する

今日はApplication Insightsの活用方法を記載します。

過去にもApplication Insightsのことを書きましたが、とてもベーシックな内容でしたので、今日は具体的にApplication Insights で指定した内容を確認する方法をみてみます。

下記は参考ドキュメントです

- <a href="https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/app-insights-overview" target="_blank">Application Insights の概要</a>
- <a href="https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/azure-web-apps-net-core?tabs=Windows%2Cwindows" target="_blank">Azure App Service と ASP.NET Core のアプリケーション監視</a>
- <a href="https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/asp-net-core">Application Insights for ASP.NET Core アプリケーション</a>
- <a href="https://qiita.com/syantien/items/f730ec974bc31b771598">[Application Insights] プロジェクトに追加する</a>

下記のライブラリーが必要となります。

```csharp
using Microsoft.ApplicationInsights;
```

下記のようにインジェクトして、アクション中で呼ぶことによってログを記録することができます。

```csharp
private readonly TelemetryClient _telemetry;

public ExampleController(TelemetryClient telemetry)
{
　　　_telemetry = telemetry;
}

public async IActionResult Example({SOME OBJECT HERE})
{
   var log = new Dictionary<string, string>();
   log.Add("value1",JsonConvert.SerializeObject({SOME OBJECT HERE}));
   log.Add("vakue2", {SOME VALUE HERE});
   _telemetry.TrackEvent("{YOUR EVENT NAME HERE}", log);

   return View();
}
```

ここで記録したログはApplication Insights のLive Metricsで確認することができます。


こちらにさらに詳しい内容がまとめてありましたのでご参照ください。

<a href="https://tech-lab.sios.jp/archives/23948" target="_blank">世界一わかりみの深いAPM 〜Application Insightsでアプリケーションパフォーマンス管理に全集中！！〜</a>
Ubuntuのディストリビューションを確認する

# やりたい事
Ubuntuでディストリビューションを確認したい
# コマンド
```
cat /etc/*release*
```
# 実行結果
```
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.4 LTS"
# R34 (release), REVISION: 1.0, GCID: 30102743, BOARD: t186ref, EABI: aarch64, DATE: Wed Apr  6 19:11:41 UTC 2022
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal


```
PHPStanで定数のエラーが出力されるとき

## コマンド入力
```
composer stan
```
Stanチェックするためコマンド入力すると、あるエラーが出力される。
```
Constant DEL_FLG_OFF not found.
💡 Learn more at https://phpstan.org/user-guide/discovering-symbols
```
定数として定義したDEL_FLG_OFFが見つからないとのこと。

## 原因は？
定数を定義したファイルがStanチェックのときに、読み込まれていないためです。
親切にエラー文にURLが載せてあるため、参照すると下記のように書いています。

#### [Global constants](https://phpstan.org/user-guide/discovering-symbols)
Global constants used in the analysed code need to be defined in bootstrap files.
Create a file that looks like this:
```php:constants.php
define('MY_CONSTANT', 1);
And add it to your configuration file:
```
```:phpstan.neon
parameters:
    bootstrapFiles:
        - constants.php
```
Please note that bootstrap files will actually be executed by the PHP runtime.

## 要約すると
グローバル定数を定義する場合は、
phpstan.neonにbootstrapFilesとして定義してくださいとのこと。
[VRChat]人が見えなくなるバグをU#で検出したい

# TL; DR
この問題は未解決です、今後も新たな情報が分かり次第追記していきます

# 人が見えなくなるバグ？
VRChatで時々発生する「同じインスタンスにいるのにその人が見えない」という現象が発生することがあります。（もちろんブロックしていない状況での話です）

症状としては、（A,B,Cのプレイヤーがいるとして）

- AからはBのアバターが見えるし声も聞こえるが、BからはAのネームプレートすら見えず声も聞こえない
- Cからは両方とも見えているし声も聞こえる
- Aがワールドのグローバルなモノを掴むとBからはそのオブジェクトが見えなくなっている

というもので、ブロック並みに厄介です。
これは経験則なのですが、このバグは同じインスタンスにほぼ同時に2人(A,B)が入ったときに起きやすいです。また、今のところ正常に表示された後しばらくしてから消えるといったことはありません。

# 環境
VRChat Client (Steam build 11946)
VRChat SDK 2022.04.20.16.26
UdonSharp v0.20.3

# 試したこと
- プレイヤー一覧を取得→表示されないプレイヤーもプレイヤー一覧は正しく取得できている
- VRCPlayerAPIにあるIsValid関数→現象発生の有無に関係なくtrueを返す
- VRC.SDKBase.UtilitiesにあるIsValid関数→同上

# これから試すこと
- VRCPlayerAPIにあるGetTrackingDataでトラッキング位置を取得し失敗しないか検証
    - 失敗の検知にtry-catchが使えないので他のUdonBehaviourからenabledを取得してチェックするのがいいと思う
- カメラを使ってそのプレイヤーが表示されるかチェック
    - アバターが0polyでも正しく取得できるようネームプレートを使う？
error /node_modules/node-sass: Command failed.の対処法

mac OS バージョン11.6
エディタ…VScode
Rails 6.0.4

# やりたいこと
yarnコマンドがエラーなく通るようにしたい。

# エラー内容
```
% yarn add jquery
（省略）
error /node_modules/node-sass: Command failed.
```

yarn installや他のyarnコマンドも試しましたが、全部同じエラー。

# 原因
nodejsのバージョンもしくはnode-sassバージョンに原因があるみたい。
これからバージョンを正しく指定していきます。

# 解決策
初めに　```% nodebrew install v14.15.0```　を試すがエラーが出る。

まずはNodebrewをインストールする必要があるみたい。



<br>
・インストール

```% brew install nodebrew```

・確認
```nodebrew -v```
バージョンが表示されればOK。

・環境変数を追加
ターミナルで以下を実行。

```
export PATH=$HOME/.nodebrew/current/bin:$PATH
```

・```bash_profile```を更新して設定を反映させる。

```source ~/.bash_profile```

・セットアップ。これやらないとインストールできない。
```nodebrew setup```


<br>
<br>
<br>
あとはバージョンを指定してインストールしていきます。

```
% nodebrew install v14.15.0

% nodebrew use v14.15.0


% yarn add node-sass@4.14.0
yarn add v1.22.17
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 5 new dependencies.
info Direct dependencies
└─ node-sass@4.14.0
info All dependencies
├─ invert-kv@1.0.0
├─ lcid@1.0.0
├─ node-sass@4.14.0
├─ os-locale@1.4.0
└─ sass-graph@2.2.6
✨  Done in 30.25s.
```

この後　```% yarn add jquery```も試しましたが無事実行できました！


# 参考
https://qiita.com/ashketcham/items/70763df042db23947728
https://qiita.com/mame_daifuku/items/373daf5f49ee585ea498
121 答え

まずは試しに単純な　for loop　のネスト。

# Brute Force
```Java
public int maxProfit(int[] prices) {
		int maxProfit = 0;
		
		for(int i = 0; i < prices.length -1; i++) {
			for(int j = i + 1; j < prices.length; j++) {
				int tempProfit = prices[j] - prices[i];
				maxProfit = Math.max(maxProfit, tempProfit);
			}
		}
		return maxProfit;
	}

```
結果：　TLE

# 解答
## Window Sliding Technique
次はWindow Sliding Technique をつかう。
参考: 
[GeeksForGeeks](https://www.geeksforgeeks.org/window-sliding-technique/)
[Kindson The Tech Pro](https://www.youtube.com/watch?v=_u_egBMlP-M)

この方法は
loopの長さが固定されていることで計算量を減らせる。

詳しいことはURLに掲載されている。このサイトは、灰色Coderの自分でも結構わかりやすかった。

1. （買値の）最小値
1. 　利益
の値を用意。

```Java
	public int maxProfit(int[] prices) {
		int minimumPrice = Integer.MAX_VALUE;
		int maxProfit = 0;

		for (int i = 0; i < prices.length; i++) {
			if (prices[i] < minimumPrice) { //　minimumPriceを更新する
				minimumPrice = prices[i];

			} else {//prices[i]の値がminimumPriceではないとき
				int profit = prices[i] - minimumPrice;// profitを出す
				maxProfit = Math.max(maxProfit, profit); //max関数で最大のprofitを求める
			}
		}
		return maxProfit;
	}
```
うーん難しい。
解説を見る限り大体はBrute Forceを試してからDP?を使っている印象があるので、まずはBrute Forceを試すのが吉かと思う。

## 間違えたほう
こっちは間違っていたが記録として残しておく。
最小値が最後に来た場合に間違える。
```Java
public int maxProfit(int[] prices) {
		int minimumPrice = Integer.MAX_VALUE;
		int maxProfit = 0;
		int minimumIndex = 0;

		for (int i = 0; i < prices.length; i++) {
			if (prices[i] < minimumPrice) {
				minimumIndex = i;
			}
			minimumPrice = Math.min(minimumPrice, prices[i]);
		}

		for (int i = minimumIndex; i < prices.length; i++) {
			maxProfit = Math.max(maxProfit, prices[i] - prices[minimumIndex]);
		}
		return maxProfit;

	}

```
Django  HTMLファイルの表示と変数の渡し方

前の記事の確認は[こちら](https://qiita.com/__chicken__/items/2fd4f52ae80d8929eb50)
## 必要なフォルダを作成後、htmlファイル作成

1. migrationsと同じ階層に【templates】フォルダを作成
2. templatesフォルダの下に【好きな名称（今回はappとする）】フォルダ作成
3. app内に【index.html】を作成

```
app名フォルダ
｜
｜- migrations
｜
｜- templates - app - index.html
```

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Django練習</title>
</head>
<body>
    <h1>Hello Django</h1>
</body>
</html>
```

## views.pyの編集

```views.py
# renderのインポート
from django.shortcuts import render

# render関数で、さっき作ったappフォルダにあるinde.htmlを指定
def index(request):
    return render(request, 'app/index.html')

```

## runserverで確認
```
python manage.py runserver
```
(URLは http://127.0.0.1:8000/app/)
![スクリーンショット 2022-05-19 7.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482906/059ab8fd-e092-2298-f1d7-7506ceff107b.png)

## htmlファイルに変数を渡す

### views.pyにデータをセット

views.pyに辞書でデータをセット（context部分）
returnの第３引数にセットしたcontextを渡す

```diff
from django.shortcuts import render

def index(request):
+    context = {
+        "name": "Yamada",
+        "age": 12
+    }
-    return render(request, 'app/index.html')
+    return render(request, 'app/index.html', context)
```

### index.htmlにデータをセット

データを表示させるには、
{{ }}で使用したいデータにセットしたキーを指定する

index.htmlファイル↓
```diff
<body>
    <h1>Hello Django</h1>
+    <p>私は{{ name }}です。</p>
+    <p>{{ age }}になりました。</p>
</body>

```
![スクリーンショット 2022-05-19 7.47.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482906/c22bb9d6-9ba2-cd04-c409-f2920b535719.png)
【30歳から目指すwebエンジニア学習録】Rails6でjQueryの導入につまずいた話

# エラーの発見
- 「いいね」ボタンをAjaxで作ろうとしていた
- jQueryを仕込んでも変化せず、、、
- ターミナルを見るとjs.erbファイルには到達している。
- ブラウザのコンソールを見ると`$ is not define`のエラーログが。

# 解決策
- `$ is not define` で検索するとrails6ではjQueryの導入方法が変わったとの記事があった。
https://qiita.com/RIN_HM/items/bdbd76f5015b3c15bfe9
- こちらの海外の記事の指示に従って直していく。
https://www.botreetechnologies.com/blog/introducing-jquery-in-rails-6-using-webpacker/

# 手順1　application.jsファイルを移動する
1. assetsの`application.js`ファイルを
1. app/javascript/packsフォルダに移動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530541/73a3c805-b62e-6b2a-1fe1-c8d2e9e4408d.png)

# 手順2　gem jquery-rails から置き換える
1. views/layouts/application.html.erbの`javascript_include_tag` を `javascript_pack_tag` に置き換える
1. `gem　jquery-rails` はもう使わないらしいのでGemファイルから削除して`bundle install`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530541/e5be755f-dd23-e5a0-4fed-d320ad96f6ea.png)

# 手順3　yarnからjqueryを導入
1. `yarn add jquery` を実行
1. installされているか確認
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530541/00838e4d-0fee-e23b-2ab1-b0d7bca60df2.png)
1. config/webpack/environment.jsを画像のようになるように追加
```
const { environment } = require('@rails/webpacker')

//　ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)
//　ここまで追加 

module.exports = evironment
```


# 手順4　application.jsファイルに追加
1. 手順1で移動しさせたapp/javascripts/packsのapplication.jsファイルに`require("jquery")`を追加
```
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")　　　　 <= こいつを追加
```

# 以上！お疲れさまでした！
- 調べている感じ初学者の方(自分含めて)が躓いているよう。
- こうやってアウトプットしながら学び合うなんてステキな文化だなあ。
SwiftでMeCabを使う方法

MeCabはよく使われている形態素解析器ですが，Swiftで開発するiOSアプリに導入する方法についての情報は少なかったので導入までの手順を紹介します．

# MeCabを使おうとする前に

MeCabをローカルで動作させる最大の問題点はディクショナリのサイズが大きいことです．例えば，新語に強いというmecab-ipadic-NEologdは900MB近くあるので，これを使ってアプリを作ったところアプリのサイズは1GBを超えてしまいました．

単に単語に分解したいだけの場合は標準のNaturalLanguageフレームワークを使うこともできます．なお，NSLinguisticTaggerはNaturalLanguageに置き換えられDeprecatedになっています．

単語の品詞を知ることが目的の場合には上記の方法では間に合いません．その場合はMeCab等を使うことになりますが，まずはクラウドサービス等を検討するのが良いでしょう．筆者が今回のシステムでローカルのMeCabを採用した理由は以下の通りです．

- クラウドの利用料を払いたくない
- そこまで多くのユーザへの展開を考えていない
- 膨大な文を分析する必要があり通信に時間をかけたくない
- センシティブなデータを入力して解析するため生データをエッジにとどめたい
- 単語の分析自体が目的のアプリなのでユーザの理解を得られる


# 1. MeCabのインストール
`https://github.com/landonepps/mecab`からSwift Package Managerでmecabをインストールします．このrepositoryのReadmeに書いてある通りですが以下でも説明します．

- SPMのインストール
- Targets  -> Build Phases -> Link BinaryWith Librariesに追加する．
![スクリーンショット 2022-05-19 6.35.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/c99faa46-1463-faa6-37dc-ca471b5f8906.png)

- Targets -> General -> Frameworks, Libraries, and Embedded Contentに追加し`Embed & Sign`を選択．この操作はReadmeにありませんでしたが忘れているとエラーになりました．
![スクリーンショット 2022-05-19 6.37.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/b8526dec-bf95-8b96-6589-c8685dc6dd2c.png)

- `mecabrc`ファイルをプロジェクトのルートに追加．ファイルの中見は下の感じ．セミコロンはコメントだと思うので実質`dicdir = ./`だけあればいいかも．
![スクリーンショット 2022-05-19 6.39.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/05fc0c81-85cc-857c-488d-f767e128abb3.png)

```code:mecabrc
;
; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
dicdir =  ./

; userdic = /home/foo/bar/user.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n

```

# 辞書の追加

辞書はmacなどでMeCabを動かすときと同じ物を使えます．macでMeCabが動くならどこかに辞書フォルダがあるはずなのでそれをコピーするだけでOKです．改めて辞書を作る場合は[こちら]( https://zenn.dev/sinozu/articles/44f58dddb25c03f8f05e )を参照してください．辞書の生成方法と辞書のインストール先の探し方について記述がありました．


![スクリーンショット 2022-05-19 6.42.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/5e3a1477-7383-9bef-ceae-30cb10978fc1.png)

![スクリーンショット 2022-05-19 6.43.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/832ef924-6bd2-8978-49ee-35a7b99fc769.png)

# Swiftラッパーの追加

ここまでの要領で追加したMeCabはC++のライブラリでありSwiftからいじるのは少々面倒です．そこでSwiftのラッパーが必要になります．

この辺りのプログラムについても前述ライブラリの作者がデモ( https://github.com/landonepps/MecabDemo )を用意しているので参考にします．ラッパーと言っても3つのファイルだけなので以下をコピーします．

- MeCabDemo/Tokenizer 以下のファイル
- MeCabDemo/Collection+SafeSubscript.swift

# 構文解析のコード

以下のコードで構文解析を実行できます。

```swift:sample.swift
let tokenizer = Tokenizer()
let tokens = tokenizer.parse("すもももももももものうち")
print(tokens)

```
Nuxt.js 三目並べ (tic-tac-toe) をNetlifyにデプロイするまで

## 三目並べ (tic-tac-toe) 

[三目並べ - Wikipedia](https://ja.wikipedia.org/wiki/%E4%B8%89%E7%9B%AE%E4%B8%A6%E3%81%B9)
ふと思い立ってNuxt.jsの手習いにゲームでも触りたいなと思った。
この記事のゴール: [practice-nuxt-tic-tac-toe](https://e99h2121-nuxt-tictactoe.netlify.app/)

## 材料

https://github.com/sudoist/practice-nuxt-tic-tac-toe

上記を発見。感謝。

`npm install`
`npm run dev`
`http://localhost:3030/`

途中以下エラーが出た。

```
 ERROR  in ./store/index.js                                                                   friendly-errors 04:19:19

Module Error (from ./node_modules/eslint-loader/dist/cjs.js):                                 friendly-errors 04:19:19

C:\git\practice-nuxt-tic-tac-toe\store\index.js
   1:24  error  Delete `␍`  prettier/prettier
   2:26  error  Delete `␍`  prettier/prettier
   3:1   error  Delete `␍`  prettier/prettier
   4:28  error  Delete `␍`  prettier/prettier
   5:26  error  Delete `␍`  prettier/prettier
   6:13  error  Delete `␍`  prettier/prettier
   7:19  error  Delete `␍`  prettier/prettier
   8:7   error  Delete `␍`  prettier/prettier
   9:17  error  Delete `␍`  prettier/prettier
  10:29  error  Delete `␍`  prettier/prettier
  11:29  error  Delete `␍`  prettier/prettier
```

package.json について `--fix` を付加した。

```package.json
    "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore . --fix",
```

[参考](https://qiita.com/RYO_nami/items/c3c089d72cba4cb96fd2)
> prettier の End of Line のデフォルト値が lf なのに対して、コード内に crlf が含まれているため。

`npm run lint`

なるほど。これで手元の `http://localhost:3030/` にて動作する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/0193f839-f3ed-86ef-a029-c35beb35c893.png)

## デプロイ

折角なのでnetlifyにデプロイしてみる。
Page Not Found が出現したがリダイレクトの設定を施す。[参考](https://monmon.hatenablog.com/entry/nuxtjs-404-redirection)

## Completed

[practice-nuxt-tic-tac-toe](https://e99h2121-nuxt-tictactoe.netlify.app/)


## 参考

[【エラー解決方法】Delete `␍` eslint(prettier/prettier) - Qiita](https://qiita.com/RYO_nami/items/c3c089d72cba4cb96fd2)
[STRIP](https://strip.koatech.info/articles/nuxt-generate-fallback/)
[Nuxt.js + Netlifyで404 Not Foundをトップページにリダイレクト - モンモンブログ](https://monmon.hatenablog.com/entry/nuxtjs-404-redirection)

本題とずれるが、これも便利そう: [commitlint - Lint commit messages](https://commitlint.js.org/#/)
とほほさん: https://www.tohoho-web.com/ex/vuejs.html

以上です～
neosでlogix その80

# 概要
neosでlogixやってみる。
練習問題、やってみた。

# 練習問題
乗り物を作れ。

# 方針

アンカーに、入って、一緒にジャンプする。

CharacterControllerコンポーネント
AvatarAnchorコンポーネント
AvatarAnchorTouchTriggerコンポーネントを使う。
Write Refノード
Local Userノード
Key Heldノード
Fire On Trueノード
Set Character Velocityノードを使う。


# 写真

![2022-05-18 20.40.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b21db0d4-7dbe-58e3-75c2-49e539039235.jpeg)


# 手順

- devtooltipを装着。
- 新規->3d->box
- インスペクターを開き、コンポーネントを追加
- Users>Anchors>AvatarAnchor
- Users>Anchors>AvatarAnchorTouchTrigger
- Physics>CharacterController
- logixtooltipを装着。
- インターフェースを取り出す。
- ノードブラウザを表示。
- Actions>Write Refをスポーン。
- Users>Local Userをスポーン。
- Input Devices>Keyboard>Key Heldをスポーン。
- Flow>Fire On Trueをスポーン。
- Physics>Set Character Velocityをスポーン。
- つなぐ
- インスペクターを表示。
- ☆を使って子スロットを作り、それをlogixという名前にする。
- logixtooltipを装着
- logixスロットをグラブして、リングメニューからSet Packing Rootを選ぶ
- ノードをクリックして、rでパッキング
- 親のスロット名を変更 (box->jump)
- それをグラブして、ctrl + sで、インベントリーに保存

# 成果物

```
neosrec:///U-ohisama/R-0ee1ec21-db19-425b-ba63-9a699caff48e
```

以上。
MSI X570 Gaming plus + Ryzen3600にProxmoxで仮想環境を作る

２年ほどメインを担った自作デスクトップが控え選手になったのでホームラボ用仮想環境にしてみた。

# 機材
Ryzen5 3600
MSI X570 Gaming plus
MSI GeForce GTX 1660 AERO ITX 6G
メモリ 32GB
M.2 SSD 512GB(WD Blue SN570 NVMe SSD) x 2 ※この作業のために追加

※グラボはダウングレードしても良いんだろうな、と思いつつもとりあえずそのまま。
※初めての自作PCで大活躍してくれたがM1 Mac Macbook pro購入により役目を終えた(ﾎﾛﾘ
※他に１TB SATA SSDが刺さっていて、そちらにはWindowsが残っているデュアルブート状態。仮想環境が落ち着いたらP2Vで仮想化する。

# ハードウェアRAID設定
なんとなくM.2 SSDをRAID化。
Proxmoxの記事だがここが山場である（私の場合は一番手間取った）

１．電源投入後DELキーを押しっぱなしにしてBIOS画面を開く
２．Fn7をクリック、または画面上部のボタンからアドバンスモードに切り替え
３．Integrated Peripherals　>  SATA Mode で RAID Modeに設定
4. Windows OS Configuration > BIOS UEFI > CSM Mode → UEFIに設定
5. RAIDXpert2 Configuration Utility > Initializing Disks > Creation Arraysでドライブを指定
　　※私の場合はいつの間にかArrayができていたにも関わらず、Createできない！と１時間くらい悩んでしまった。Createができない場合はDeleteしてみましょう。

![PXL_20220512_111055199.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/761224/0284b994-43a0-083e-06b4-6e9b6186211e.jpeg)

![PXL_20220512_111230668.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/761224/82c1b8c2-a0ef-0005-c77b-3f49258611f0.jpeg)

だいたいこんな感じです。

[まるむしアンテナ「マザーボードのRAIDを設定してみた　MSI MPG B550 GAMING PLUS」](https://antenna.infomixer.net/2021/01/31/%E3%83%9E%E3%82%B6%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%81%AEraid%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F%E3%80%80msi-mpg-b550-gaming-plus/) の記事が一番参考になりました。多謝。

# Proxmoxインストール用USBを作る
このRAIDにWindowsをインストールする場合にはマザーボードに適したRAID認識用のドライバが必要になるのですが、Proxmoxには関係ありません。

公式サイトからProxmox VEのISOをダウンロードします。
[Proxmox Virtual Environment](https://www.proxmox.com/en/proxmox-ve)
Bit torrentでのダウンロードもありますが、全然落ちてこなかった。普通にISOダウンロードで良いでしょう。

私の場合はMacでISOをダウンロードしたので、USB作成にはPVE推奨のbalenaEtcherを使った。
（Windowsの場合Rufasでもできるらしいけど試していない）

別に難しいことはない。

# USBを起動ドライブに指定
BIOS画面からメモリを起動ドライブに指定して、起動。あとは適当にインストールしてゆく。
ESXiと違って気難しくない。

# Proxmox設定に関する参考動画
英語に抵抗がなければこちらのチャンネルが丁寧に解説されてます。英語も聴き取りやすいです。
[LearnLinuxTV - Youtube](https://www.youtube.com/playlist?list=PLT98CRl2KxKHnlbYhtABg6cF50bYa8Ulo)
2022/5/19主にITとかセキュリティの記事

クラウド利用機器にサイバー攻撃、脆弱性公表から3日後に - 富士通
https://www.security-next.com/136577

ファイルサーバへのサイバー攻撃、海外子会社経由で - 沖電気
https://www.security-next.com/136559

採用関連情報がネットより閲覧可能、権限設定ミスで - エイチーム
https://www.security-next.com/136528

Emotet攻撃、日本が突出して狙われると仏セキュリティ企業が発表(5/17)
https://cybersecurity-jp.com/news/66795

サイバー攻撃の動向　脅威増す標的型攻撃重要情報狙う攻撃集団確認、トレンドマイクロが注意喚起(5/17)
https://dempa-digital.com/article/314326

未知の欠陥、サイバー攻撃倍増
中ロのハッカー集団が関与か(5/17)
https://nordot.app/899179430402949120?c=39546741839462401

ゼットスケーラー、フィッシング攻撃に関する2022年版レポートを発表　〜小売・卸売業界へのフィッシング攻撃が400％以上増加(5/17)
https://securityinsight.jp/news/13-inbrief/5038-220517-1

ソフォス、「ランサムウェアの現状2022年版」を発表(5/17)
https://www.nikkei.com/article/DGXZRSP632419_X10C22A5000000/

NVIDIA製GPUディスプレイドライバーに複数の脆弱性 ～GeForceユーザーはv512.77への更新を【16:00追記】
「CVSS v3.1」のベーススコアは最大で「8.5」(5/17)
https://forest.watch.impress.co.jp/docs/news/1409736.html

米、北朝鮮IT技術者の「隠れ出稼ぎ」に警告　国や企業に呼びかけ(5/17)
https://mainichi.jp/articles/20220517/k00/00m/030/042000c

年次クラウドインフラ報告を発表＝米ネットアップ〔ＢＷ〕(5/17)
https://www.jiji.com/sp/article?k=2022051700269&g=bnw

「脆弱性」対策で世界を駆ける女性ホワイトハッカー14歳の読書体験が拓いたセキュリティーの世界(5/17)
https://project.nikkeibp.co.jp/onestep/keyperson/00014/

米、北朝鮮のＩＴ人材雇用回避を　兵器開発の資金稼ぎと警告(5/17)
https://www.tokyo-np.co.jp/article/177843

Apache TomcatにおけるWebSocket接続の実装に関する問題(5/17)
https://jvn.jp/vu/JVNVU94243578/

鍵なしのテスラ車「ハッキングで盗める」専門家が実演(5/17)
https://www.appbank.net/2022/05/17/technology/2236783.php

ZyxelファイアウォールとVMware製品の脆弱性悪用を確認、更新を(5/17)
https://news.mynavi.jp/techplus/article/20220517-2346739/

ブロックチェーンで即時決済、マネーのくびき解く
解剖フィンテック　始まった金融革新㊥(5/17)
https://www.nikkei.com/article/DGXZQOUB041G20U2A500C2000000/

米司法省、仮想通貨を使って制裁回避を企てた米国人を告発(5/17)
https://japan.cnet.com/article/35187570/

日本のデジタル人材育成に危機感　AWSジャパン社長(5/17)
https://www.nikkei.com/article/DGXZQOUC226DU0S2A420C2000000/

Privacy Shield 2.0とは何か？ EU・米国間の新プライバシー保護の枠組みを解説する(5/17)
https://www.sbbit.jp/article/cont1/86801?ref=rss

iOS 16では「プライベートリレー」がデフォルト設定に？：「プライバシーサンドボックスのようなアプローチを強化するだろう」(5/18)
https://gunosy.com/articles/em462

マイナカードのデジタル対応に遅れる役所の窓口に怒り(5/17)
https://agora-web.jp/archives/220515212206.html

AIの精度を左右する3技術　4ギルドで体制づくり(5/18)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/051600292/051600001/

ツール活用でリアルを超える運用を　テレワークだからこそ観察鋭く(5/18)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/031700284/051600003/

18カ月間「業務メール」が盗まれ続けた、企業の検知を回避した恐るべき手口とは(5/18)
https://xtech.nikkei.com/atcl/nxt/column/18/00676/051400106/

無線LAN製品の仕様や認定試験を提供し相互接続性を確保、「Wi-Fi Alliance」とは(5/18)
https://xtech.nikkei.com/atcl/nxt/column/18/01842/042200012/

小田急電鉄が情報サイトの更新を3倍速に、「ヘッドレスCMS」を徹底活用(5/18)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/06829/
LeetCodeのRoman to Integer を解いてみた

## LeetCodeを解いた動機
最近転職活動をしているのですが、面接のコーディング試験の出来が良くなくLeetCodeを解くように勧められました。
また個人の課題として開発進捗が遅いことがあって、LeetCodeの答えには擬似プログラミングがあるので合わせて練習したいなと思いました。
## 問題内容
こちら参照
https://leetcode.com/problems/roman-to-integer
## 自分で書いた擬似プログラミング
今回メモを消してしまったため、次回以降記載

## 自分で書いたコード

```golang.go
func romanToInt(s string) int {
	symbolArray := map[string]int{
		"I": 1,
		"V": 5,
		"X": 10,
		"L": 50,
		"C": 100,
		"D": 500,
		"M": 1000,
	}
	var splitS = strings.Split(s, ",")
	returnInt := 0

	isSkip := false
	for i, _ := range splitS {
		if isSkip {
			isSkip = false
			continue
		}

		if symbolArray[i] > symbolArray[i+1] {
			returnInt = returnInt + symbolArray[i+1] - symbolArray[i]
			isSkip = true
		} else {
			returnInt = returnInt + symbolArray[i]
		}
	}

	return returnInt
}

```

## 答え

大きく間違っている点に関しては、問題を参照していただきたいのですがrangeの中で文字を二つ使う場合はboolで定義している`isSkip`をtrueに変更して if で飛ばずようにしている。

⇨ここは　`isSkip`の代わりに`i := 0`のint型を事前に定義して

```
// isSkip = true
i += 2
// isSkip = false
i += 1
```
の方が好ましいようです。
確かにfor文の中でif文を毎回通過させるのは処理が重くなりそう。

## 最後に
初めてやったが、普段やっているAPIの開発とは毛色が違って面白かった。
今後も続けていくとともに、qiitaの記事をわかりやすくできるよう工夫していきたい。
【Prettier】VSCodeで自動整形できない時の対処法【VSCode】

## VSCodeの設定を確認する
### `Format On Save`を確認
`Format On Save`がオンになっているか確認する。
VSCodeの設定画面を開き、`Editor:Format On Save`を検索します。
`Editor:Format On Save`がオンになっているか確認します。
![スクリーンショット 2022-05-19 午前3.15.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4a9fde87-0894-586a-c431-2aedaefa3a7f.png)

### `Editor:Default Formatter`を確認
次に`Editor:Default Formatter`を検索し、`Editor:Default Formatter`が`Prettier - Code formatter`になっているか確認します。
![スクリーンショット 2022-05-19 午前3.18.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/22765ba7-ea71-5c04-9763-321c345ff7c9.png)

### `setting.json`で確認する
`.vscode/settings.json`に以下のように記述することで上記2点を確認することができます。
```.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true
}
```

### `prettier-plugin-tailwindcss`を使用している場合
`prettier-plugin-tailwindcss`を使用していて、かつ、yarn2以降を使用している場合には`.prettierrc.js`または`prettier.config.js`を作成し、以下のように記述する必要があります。
```prettier.config.js:prettier.config.js or .prettierrc.js
module.exports = {
  plugins: [require('prettier-plugin-tailwindcss')],
}
```
`.prettierrc.json`ではコマンドで整形できるもののVSCodeでの自動整形は動作しませんでした。
```.prettierrc.json
{
  "plugins": ["prettier-plugin-tailwindcss"]
}
```
【Vite】Vanilla TS、React × TypeScriptプロジェクトを作成してみる

# 概要
最近話題のViteを使用したところ、スムーズに各プロジェクトの作成ができたので、その過程について記録する。

# 前提
* MacBookを使用
* `Node.js >=12.2.0` のバージョンが必要(2022/05時点)
  ※Vite公式ドキュメント情報
* 当記事では`npm`を用いる

# Vanilla TSプロジェクトを作成する
* Viteでプロジェクトを作成する方法として、`対話形式`で使用可能なテンプレートを選択、もしくはテンプレートを`直接指定`する方法がある。
* 『[こちらのREADME](https://github.com/vitejs/vite/tree/main/packages/create-vite)』に指定できるテンプレートが記載されている。
```sh
# 任意のディレクトリで以下を実行
npm create vite@latest

# 以下、対話モードで各種設定、表示された例
✔ Project name: … vanilla-ts-project
✔ Select a framework: › vanilla
✔ Select a variant: › vanilla-ts

Scaffolding project in {任意のあなたのディレクトリパス}/vanilla-ts-project...

Done. Now run:
  # あとは下記コマンド群を実行すると開発サーバまで起動、確認ができる
  cd vanilla-ts-project
  npm install
  npm run dev
```

```sh
# 直接テンプレートを指定する場合
npm create vite@latest {プロジェクト名} --template {テンプレート名}

# npm 6.x
npm create vite@latest vanilla-ts-project --template vanilla-ts

# npm 7+ (プロジェクト名の後に--が追加で必要)
npm create vite@latest vanilla-ts-project -- --template vanilla-ts

Scaffolding project in {任意のあなたのディレクトリパス}/vanilla-ts-project...

Done. Now run:

  cd vanilla-ts-project
  npm install
  npm run dev
```

# (参考)React × TypeScriptプロジェクトを作成する
```sh
# 対話モード
npm create vite@latest
✔ Project name: … react-ts-project
✔ Select a framework: › react
✔ Select a variant: › react-ts

Scaffolding project in {任意のあなたのディレクトリパス}/react-ts-project...

Done. Now run:

  cd react-ts-project
  npm install
  npm run dev
```

```sh
# 直接テンプレートを指定する場合
# npm 6.x
npm create vite@latest react-ts-project -- --template react-ts

# npm 7+ (プロジェクト名の後に--が追加で必要)
npm create vite@latest react-ts-project -- --template react-ts
```
プロセスがあるか調べる

すっかり `ansible` でやるようになったものの、必要になったときにすぐ出て来ないと困ったりするやつ

```bash
chk_proc(){
    if pgrep "$1" > /dev/null ; then
        printf "\033[32m%s\033[m\n" "running: ${1}"
    else
        printf "\033[31m%s\033[m\n" "stopped: ${1}"
    fi
}
```

`systemctl` の場合

```bash
chk_svc(){
    if [ $(systemctl is-active "$1") == "active" ] ; then
       printf "\033[32m%s\033[m\n" "running: ${1}"
    else
       printf "\033[31m%s\033[m\n" "stopped: ${1}"
    fi
}
```
この植物の名前は何？→AIカメラに聞いてみよう！

おはようございます。
某大型ショッピングモールに勤務してます、Nakamuraです。

今回はTeachable MachineとCodePenを使って様々な植物を識別してくれる機能を作ってみました。

※参考画像
![23953124_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/706758af-cf7e-b6ec-7610-ba3710e966df.jpeg)

なぜ今回このような機能を作ろうと思ったかというと、母の日に花屋にレジ応援をしに行った事がきっかけでした。
母の日はプレゼントでお花を渡すお客さまが多く、様々な売場から花屋に応援が集まります。私もその一人でした。
レジで花を精算する際、通常の商品のように花にバーコードがついていれば特に問題ないのですがバーコードや値段がついていない花が多数あります。
そうなるとブーケ作り等で忙しくしている花屋担当の店員の所まで行って「この花は何円ですか？」「何ていう名前の花ですか？」といちいち聞きにいかなければなりません。
しかも応援者はだいたい1時間ごとに変わるので、また次の、さらに次の応援者も同様に聞きにいかなければなりません。
そうなると応援者もそうですが、聞かれる花屋担当の方々も大変です。
そこで今回は花屋担当の負担を減らすためAIカメラに頑張ってもらおうと思いました。

完成イメージはこんな感じです↓
<iframe width="560" height="315" src="https://www.youtube.com/embed/icBAFILCAs0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# 作り方
Teachable Machineの画像プロジェクト（標準の画像モデル）を開きます
![写真① 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/3bf595c9-0392-baa1-f09a-b3b2f7beafcc.png)
ウェブカメラをクリックして覚えさせたい植物の画像を読み込ませます。
私は試験的に自宅で育てている3種類の植物を読み込ませてみました。
![写真2 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/7e05cfc9-11e4-a3e3-271b-72cc0de17cd9.png)
こんな感じです。
あとはモデルをトレーニングするをクリックして、トレーニングし終わったらちゃんと動作するかテストしてみましょう。
![写真3 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/2a47b22e-dc8f-9f23-3888-b66b9cca5ab3.png)
パキラを映すとしっかりパキラだと読み取ってくれました。
そうしたら
モデルをエクスポートする→モデルをアップロード
をしてURLやコードをコピーできるようにしましょう。
この時p5.jsのコードをコピーしておきましょう。
![写真4 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/e35db77b-5801-9e53-0cf7-e12cd910c789.png)

続きましてCodePenを開きます。
左上のPenをクリックしてページを開き、HTMLに先ほどコピーしたp5.jsのコードを貼り付けます。
![写真5 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/23c23689-602b-46d9-7001-70c5b23bfd69.png)
![写真6 1032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/13d463be-f765-70ae-feaf-ea036c659eaa.png)
うまくいくとこのように識別してくれます。
![植物動画_Moment1+.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/68492439-7445-048f-ecbc-a44597d36dc0.jpeg)
![植物動画_Moment2+.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/3aafd251-d251-0582-7058-06abd5562a25.jpeg)
![植物動画_Moment3+.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613598/9d432875-dbf2-d420-c5be-b41137b41e64.jpeg)
## 作ってみた感想
今回植物を読み取るというコンセプトで作りましたが、割としっかりと識別してくれたので驚きました。
ただ今回は3種類だけでありこれが10種類、20種類と増えていったときにしっかりと識別してくれるか、確認が必要だと思いました。

そして今回は名前のみ表示でしたが、金額や花言葉等を補足的に表示させることができればより実用性が増すのかなと思いました。

それでは最後まで読んで下さりありがとうございました。
NoSQLの基礎知識

# NoSQLとは

NoSQLは、Not Only SQL（ = SQL DBだけでない）の略。

NoSQLはデータベースの分類を指し、**RDB以外のDB**のことである。

近年、扱うデータ量の増加（ビッグデータ）とともに、NoSQLが使われるようになった。

一般的に、ビッグデータは数十テラバイトから数ペタバイト以上のデータを指す。

ビッグデータを扱うためには、RDBは不向き。

補足：

NoSQLは2000年以前から存在し、ビッグデータの流行とともに用途が見出されて、使われるようになる。

# NoSQLのデータモデル例

NoSQLは**RDBのようにテーブル構造に固定することなく、さまざまな形式**のデータをそのまま格納可能。

- **キーバリュー型**：キーとバリューをペアにして格納するデータモデル。
    - バリューは単一の値だけでなく、 リストやセットなど**複数の値**を持つことが可能。
    - プロダクト例：Redis、Amazon DynamoDB、Riak など
- **ドキュメント型**：JSONやXML形式で記述されたドキュメントの形で管理するモデル。
    - JSONをRDBで格納する場合、スキーマ定義が複雑になるが、ドキュメント型の場合JSONを直接格納できる。
    - プロダクト例：MongoDB、CouchDB、MarkLogic、Cloud Firestoreなど。← MangoDBは世界で最も使われているNoSQL。
- **カラム型（列指向型）**：キーバリュー型にカラム（列）の概念をもたせたモデル。
    - RDBはロー（行）単位で処理するが、カラム型DBはカラム（列）で処理する。列単位でまとまった処理があるシステムではRDBよりも高速に処理可能。
    - 行単位で集計する処理が多い、情報分析システムなどで活用。ビッグデータ分析用のミドルウェアと併用されることが多い。
    - プロダクト例：Google Big Table、Cassandra など
- **グラフ型**：データとデータ間のつながりを管理するモデル
    - グラフ理論を元にしたデータベースで、データをグラフ構造で格納。
    - FacebookなどのSNSのユーザー同士のつながりなど、ネットワーク状のデータを格納するのに向く。
    - プロダクト例：Neo4j など

括弧はプロダクト例。

# RDBに対するNoSQLのメリット

## 1. 高速処理

RDBに対して、NoSQLは高速。

**RDBはデータ量が増えすぎすると、低速になる。**そのため、RDBはビッグデータを扱うのに向いていない。

対して、**NoSQLはシンプルな作りにより処理が高速というメリットあり。**例えば、RDBではテーブル間の整合性を保つためにトランザクションを行っているが、NoSQLではトランザクションが存在しない。

## 2. システムの拡張・分散性

RDBのシステムは、原則として一台のサーバーで動作するように設計される。

近年、データ量の増加により、**RDBのような1台のデータベースサーバーだけでは処理性能が足りない。**

データベースのシステムの処理を高速化させるためには、対応するサーバーの数を増やせば良い（＝ スケールアウト）。

**NoSQLはスケールアウトしやすく、システムの拡張・分散性が高いというメリットあり**。

# RDBに対するNoSQLのデメリット

## 1. **機能が豊富ではない**

SQLが集合論に基づいている完成度の高いデータベース言語であるのと同時にRDBMSは豊富な機能を備えている。一方でNOSQLは主に「書き込み」「読み込み」のシンプルな動作をするにすぎない。「結合(Join)」をはじめとする様々な演算子も通常はサポートされていない。

## 2. **データの整合性が緩い**

RDBMSはデータの更新をかける際には「排他制御」の仕組みを備えている。しかしNOSQLはこの考え方を緩めている。

ビッグデータの環境では多数の人が同時にアクセスを行う都度に排他制御を実施していては大量に速く処理するのは難しくなってしまう。速さを優先するために「データの整合性は、全てのアプリケーションにおいて必ずしも必要であるわけではない」とする考え方である。一時的にデータの整合性が保持されない状態を許容するが結果的に整合性が取れていればいいという考えである。

# NoSQLの活用例

- 追加処理やデータ参照が多いシステム（ゲームやIoTシステムなど）
- 将来的な拡張が見込まれるデータベース
- 非構造データのデータベース
    - NoSQLデータベースは、スキーマレスな性質のため、半構造化データ（JSONなど）および非構造化データ（テキスト、画像、音声データなど）に向く。
    

# 補足：世界のデータベースエンジンランキング（2022/5 時点）
|Rank  |DBMS  |DB Model  |Score  |
|---|---|---|---|
|1  |Oracle  |Relational  |1262  |
|2  |MySQL  |Relational  |1202  |
|3 |Microsoft SQL Server |Relational |941 |
|4 |PostgresSQL |Relational |615 |
|5 |MangoDB |Document |478 |
|6 |Redis |Key-value |179 |
|7 |IBM Db2 |Relational |160 |

引用：[https://db-engines.com/en/ranking](https://db-engines.com/en/ranking)

# 参考

- [https://products.sint.co.jp/topsic/blog/nosql](https://products.sint.co.jp/topsic/blog/nosql)
- [https://tracpath.com/works/development/nosql_overview/](https://tracpath.com/works/development/nosql_overview/)
- [https://qiita.com/shuyann/items/ca3e62cb417c0e214613](https://qiita.com/shuyann/items/ca3e62cb417c0e214613)
- [https://db-engines.com/en/ranking](https://db-engines.com/en/ranking)
RuboCop  v1.28 から追加された "Style/FetchEnvVar" について


## これはなに

- RuboCop のバージョンアップを行った際に、新しいルール "Style/FetchEnvVar" が追加されており、仕様について調べ適用を行いました
- 適用した "Style/FetchEnvVar" のルールについて簡単にまとめました

## Style/FetchEnvVar について

簡単に記載すると、 `ENV['FOO']` ではなく `ENV.fetch('FOO')` を利用しましょうというルールです

通常 `ENV['FOO']` とプログラムを記述し、実行した際に環境変数 `FOO` が未定義だった場合 `nil` を返却します

`nil` が返ること自体は明らかなため、 `nil` で返る可能性を考慮しプログラムを組むべきと言われればその通りです
しかし、手法は文化や慣習によって対応方法は複数存在することは容易に想像できます

- 環境変数参照後にエラーを発生させたい人
- デフォルト値を定義し何事もなかったかのように処理を継続させたい人
- あえて `nil` のまま処理を継続する人
- `nil` が渡されることを考慮し忘れてしまった人

"Style/FetchEnvVar" を使用することで記述を統一するだけでなく、エラーを発生させる箇所を「環境変数を読み込んだタイミング」または、「デフォルト値を定義した状態」のいずれかに統一することが出来ます

### 記述方法について

下記に簡単な記述例を記載します
"Style/FetchEnvVar" ルールは自動修正にも対応しているため、個人的には積極的な "Style/FetchEnvVar" ルールの適用をおすすめします

#### NG

```ruby
ENV['FOO']
ENV['FOO'] || 'bar'
```

#### OK

```ruby
ENV.fetch('FOO')
ENV.fetch('FOO', 'bar')
```

他にも記述例はありますが、続きはドキュメントを参照してください

## Reference

https://github.com/rubocop/rubocop/releases/tag/v1.28.0

https://docs.rubocop.org/rubocop/cops_style.html#stylefetchenvvar

https://github.com/rubocop/rubocop/pull/10502
ユークリッドの互除法をbatで書いてみた。

実行時には、引数として最大公約数を求めたい2つの自然数(%1,%2)を指定する。

```bat:EuclideanAlgorithm.bat

@echo off
setlocal enabledelayedexpansion

if %1==%2 (
    call :commentary
    echo %1 と %2 の最大公約数は「%1」
    echo.
    goto :EOF
)

set a=%1
set b=%2
set /a r=%a% %% %b%

:LOOP
    set /a a=%b%
    set /a b=%r%
    set /a r=%a% %% %b%
    if %r%==0 (
    	call :commentary
        echo %1 と %2 の最大公約数は「%b%」
        echo.
        goto :EOF
    )
goto :LOOP

:commentary
echo.
echo ユークリッドの互除法は、2 つの自然数の最大公約数を求める手法の一つである。
echo 2 つの自然数 a, b について、a の b による剰余を r とすると
echo a と b との最大公約数は b と r との最大公約数に等しいという性質が成り立つ。
echo.

```

<br>
実行例：

```
EuclideanAlgorithm 1274 975
```
<br>

実行結果：
```
ユークリッドの互除法は、2 つの自然数の最大公約数を求める手法の一つである。
2 つの自然数 a, b について、a の b による剰余を r とすると
a と b との最大公約数は b と r との最大公約数に等しいという性質が成り立つ。

1274 と 975 の最大公約数は「13」
```

<br>
同じ値の自然数を引数として渡した際の処理や、デザイン等を排除した最小のスクリプトはこちら。

```bat:EuclideanAlgorithm.bat

@echo off

set a=%1
set b=%2
set /a r=%a% %% %b%

:LOOP
    set /a a=%b%
    set /a b=%r%
    set /a r=%a% %% %b%
    if %r%==0 (
        echo %1 と %2 の最大公約数は「%b%」
        goto :EOF
    )
goto :LOOP

```
【EC2/Amazon Linux2】puma5系でRailsアプリケーションを起動した際にはまったこと

# はじめに
Gemの更新作業にあたりpumaのバージョンを5.6.4にアップデートを行いました。
開発環境では問題なかったのですが、テスト環境でアプリケーションが起動しない現象が発生したため、
対応した内容を記述しています。

# 環境
- Ruby: 2.7.3
- Rails: 6.1.5
- puma: 5.6.4

# 発生していた問題
今までは、 `puma -C config/puma.rb -d` のコマンドで起動していました。
issuesを見るとDaemonizationが廃止されていたたようです。

https://github.com/puma/puma/issues/1983

### じゃあどうするか
issuesのコメントでは ↓のように systemd、upstartもしくはsupervisorを使ってくださいと記載されていました。
今回はsystemdを選択しました。
>Use systemd/upstart/a process supervisor instead.


# 設定内容

### Sysconfigに環境変数を記述
```shell
$ vim /etc/sysconfig/puma

# 環境変数を記述
DATABASE_USERNAME=''
DATABASE_PASSWORD=''
DATABASE_HOST=''
DATABASE_NAME=''
DATABASE_PORT=''
```

### Unitファイルの構成

```shell
$ vim /etc/systemd/system/puma.service

[Unit]
# Unitの説明
Description=Puma App Server
# Unitより先に起動するUnit
After=network.target

[Service]
Type=notify
# 実行ユーザー
User=ec2-user
# サービスを定期的に監視して稼働状態をチェック
WatchdogSec=10
# プロセスの実行ディレクトリ
WorkingDirectory=/var/www/app/
# 環境変数の読み込み
EnvironmentFile=/etc/sysconfig/puma
# 実行コマンド
ExecStart=/bin/bash -lc "bundle exec puma -C config/puma.rb -e staging"
# プロセス停止時の再起動
Restart=always

[Install]
WantedBy=sockets.target
```

### Unitファイルの反映

```shell
sudo chmod +x /etc/systemd/system/puma.service
sudo systemctl daemon-reload
sudo systemctl restart puma.service
```
### 自動起動設定
```shell
sudo systemctl enable puma.service
```

# 参考URL

https://rainbow-engine.com/linux-daemon-useful-commands/

https://www.karakaram.com/how-to-use-systemctl-journalctl/#systemctl

https://www.kanzennirikaisita.com/posts/why-puma-daemonization-removed

https://zenn.dev/ymasutani/articles/ce42131f0e7b1a

https://github.com/puma/puma/issues/1983

https://postd.cc/why-systemd/
external-secrets-operatorのwebhookに使う証明書をcert-managerで賄う時のポイント

# 環境

external-secrets-operator v0.5.0 から v0.5.3 それ以降もかも

---

# 前置き

https://github.com/external-secrets/external-secrets/

kubernetes-external-secretsが非推奨となって、external-secrets-operator（以下ESO）を使用し始めている人もそろそろ増えてきているのではないでしょうか
そんなESOですが、v0.5がリリースされてvalidationとconversionのwebhookが実装されました

webhookのサーバはESOで用意されたものを起動するのですが、k8sの決まり（だったような）でクライアントがwebhookサーバにアクセスするのにTLS接続が必須とのことです（ちょっとこのへんの知識は怪しい）
それに対応するため、ESOはこれに使う証明書を諸々勝手にやってくれるcertcontrollerというものも用意していてくれて、これも別で起動する流れになっています
よって、ESO v0.5を動作させるのに、本体、webhook、certcontrollerの3つが起動する流れとなっています

で、この辺のwebhookの仕組みというのはもちろんESO以外でもよく使われるもので、そのへんの証明書をどうにかするのにcert-managerというものがよく使われています

https://github.com/cert-manager/cert-manager

私が管理する環境も他で既に必要になっていてこのcert-managerがクラスタにありました
せっかくcert-managerがもうあるんだから証明書管理はそっちに寄せたい…ということで対応をしました
大体の対応方法の流れはESOのgithubのissueでも言及されているのですが

https://github.com/external-secrets/external-secrets/issues/885#issuecomment-1098068902

最後までハマって今のとこ前例の記事が見当たらなかった部分を書いておきます

# 証明書の期限に注意

cert-managerで証明書を作る場合、certificateリソースに設定がなければ90日後を期限にして生成され、その期限の2/3が経過すると更新されます

https://cert-manager.io/docs/usage/certificate/#renewal

一方、ESOのwebhookは一定時間ごとにサーバ証明書をチェックしていて

https://github.com/external-secrets/external-secrets/blob/v0.5.3/cmd/webhook.go#L86

このへんのfunctionやconstを追うと、証明書の期限チェックに現在時刻+90日の時刻を使用していることがわかります
なんで90日も足しているのかはわかりませんが、大きく余裕を持ったんでしょうか

で、既に述べたように、cert-managerはデフォルトで90日が期限の証明書を作るので、90日後で期限チェックすると、証明書は期限切れということになります

なので、そのあたり余裕を持って期限を設定した証明書をcert-managerに作ってもらう必要があります
具体的には、Certificateリソースの `spec.duration` と `spec.renewBefore` を設定するのですが、詳細はドキュメントを見てください

# 愚痴

上で紹介したESOのコードの部分で `CheckCerts` がエラーを返す（つまり証明書のチェックに失敗する）と、直後にcontextをcancel()するだけで、結果何の手がかりも残さずにプロセスが終了します…
これがなんもわからなくてだいぶ苦労しました

なもんで、なぜかESOのwebhookコンテナが定期的に正常終了するんだよな…という場合はこのあたり（証明書周りのミス）を疑ってみてください

この辺りはログが出るように改善されていくとありがたいですね
issue上げてcontributeしていきたい気持ちもあるけど度胸がない
未経験が読む「コンピュータシステムの理論と実装」#2

# はじめに
本記事は前回の記事の続きとなります。
私は現在非エンジニアであり、コンピュータシステムの理論と実装の2章を読み終えて、初見ではスッキリしない部分がありました。一方で同じところまで読み進めたエンジニアさんはいたく感動していました。
この記事では「2章の何が感動ポイントなのか」ということを書いていきます。
実装については前記事と同様、私が詰まった部分をヒントとして残していきます。

# 2章を読み終えた私の疑問
2.2仕様を読み進めると、半加算器、全加算器、加算器、インクリメンタと来て、突然"ALU"が現れたように感じました。
「ここまで２進数の加算について論じてきて、なぜよくわからない複雑な機能がついたALUを作るのか？」と思ったのです。
一方で、一緒に勉強しているエンジニアさんはALUの登場に「なるほどー！」ととても感動している様子でした。

### エンジニアさんはなぜ感動したのか？
<b>「今までの回路を使えば、ALUという画期的な回路を実装できてしまうから」</b>だったようです。

#### では、そもそもALUとは？
今までの回路は、1つの機能に特化した回路でした。下記はAnd回路です。

```
x y | out
0 0 |  0
0 1 |  0
1 0 |  0
1 1 |  1
```
一方で（厳密さに欠けますが）ALUのイメージとしては1章のマルチプレクサのセレクタのような入力によって、Andを含む<b>18種類の関数を選択してこなせる回路</b>だと考えられそうです。（※機能について正確には図2-5が参考になると思います）

#### それの何がすごいのか？
例えば、今までAnd演算をしたければ、私たち自身でAnd回路を設置しなければならなかったのに、ALUを置いておけば入力を変えるだけでAnd演算ができるんです！

これって結構すごい進化だと思いませんか？
今は仮想的にチップを組み立てているから「回路の設置なんて楽ちんじゃん」と思うかもしれませんが、現実だったら、以前使っていた回路を基盤から取り除いてAnd回路を設置し直さなければいけない。その手間がALU回路一個で省けるようになった、ということですよね。

そういう超便利アイテムが、1章で作った回路と2章の加算器を使えば、すでに我々は実装できる、（そしてこれを発明した人は天才だ！）というのが感動ポイントだったようです。

私も"ALUが今までの回路とどう違うのか"、そして"それが今までの回路で実装できる"ということを聞いて、「なるほど〜〜！」と感動させてもらえました。

(追記：ただ、これを使うのは5章のようです)

# 2章実装のヒント
作成順序
HalfAdder
FullAdder
Add16
Inc16
ALU

私がつまずいたものだけですが、考え方のヒントを残しておきます。
<details><summary>Inc16</summary><div>
1行で実装できますが、文法を知っておく必要があります。<br>
下のbの部分に注目してください。このような書き方があります。

```
Or16(a=in, b[0..7]=true, b[8..15]=false, out=out)
```

</div></details>

<details><summary>ALU</summary><div>
この章最大の壁です。<br>
まず図2-6の理解が重要です。<br>


<details><summary>ヒント1:zx,nxの意味は？</summary><div>
zxとはzero x（xを0にする）<br>
nxとはnegative x（xを反転する）<br>
これをxだけでなく、yにもoutにも適用して実装しました。
nは正準表現から実装しました。
</div></details>

<details><summary>ヒント２:「fの真偽によってAndかAddか選択する」方法？</summary><div>
この思考に囚われて苦しみました。<br>
最終的に私は、fによらずAndもAddも計算しておいて、fの真偽によって出力する方を選ぶ方法にしました。
</div></details>

</div></details>
Rails DM機能その１

## 開発環境
Mac
Ruby 2.6.5
Rails 6.1.3.2
# モデル作成
```
$ rails g model room name:string  //roomモデル作成
```
```
$ rails g model entry user:references room:references  //entryモデル作成
```
```
$ rails g model message user:references room:references content:text //messageモデル作成
```


# messagesコントローラーの作成
```message_controller.rb
class MessagesController < ApplicationController
  before_action :authenticate_user!

  def create
    message = Message.new(message_params)・・１
    message.user_id = current_user.id
    if message.save・・2
      redirect_to room_path(message.room)
    else
      redirect_back(fallback_location: root_path)
    end
  end

  private

  def message_params・・3
    params.require(:message).permit(:room_id, :body)
  end
end
```
## コードの解説
１・・インスタンスを作成しています。message_paramsというメソッドを引数で呼び出しています。
2・・「保存する」処理を行うメソッドです。
3・・paramsに:messageがあるはず。なければ例外に。そしてpermitの部分では、params[:message]から取り出していい情報は、:room_idと:bodyだけで他の情報を無視する。

# 参考記事
[RailsでややこしいDM機能を1万字でくわしく解説してみた](https://qiita.com/bindingpry/items/6790c91f374acc25bea2)
[RailsでDM(ダイレクトメッセージ)を送れるようにしよう](https://qiita.com/ki_87/items/a344ea566c88b10b950c)