OmniAICreator/Qiita-1.07M huggingface dataset:
Chrome 拡張機能を作って公開しよう⑤　〜権限多すぎ問題を解決〜

この記事は、先日ブログに投稿したものと同じ内容です。ぜひ、ブログの方もご覧ください。

https://frogapp.net/blog/2021-08/chrome-extension-5/

***



# 権限を少なくする

前回まで書いてきたコードですが、まだ課題があります。

![権限多すぎ](https://user-images.githubusercontent.com/75155258/127963556-97d4558d-cb67-40f7-8ac4-cf119b9a35bc.png)

これは、Chrome の拡張機能の管理画面のスクリーンショットです。権限が、「閲覧履歴の読み取り」と、この拡張機能の機能に対して過大であることがわかります。

今回は、これを修正します。

やり方は簡単です。`manifest.json` の `permissions` を以下のように書き換えてください。

```JSON:manifest.json
"permissions": ["activeTab"],
```

`chrome://extensions` を開き、更新ボタンを押します。

![更新ボタン](https://user-images.githubusercontent.com/75155258/128589985-e072d29d-d87e-4f11-afa6-9d66016b6c7f.png)

「詳細」ボタンをクリックして、「権限」欄を見てください。

![権限](https://user-images.githubusercontent.com/75155258/128590010-5027b476-f5c0-4f95-b410-529b31257a3c.png)

「この拡張機能に特別な権限は必要ありません」と表示されていれば OK です。

# 不具合を修正する

しかし、これだけで今日の記事が終わってしまってはあっけないので、もう一つやります。

`chrome://extension` 画面で拡張機能を開き、Facebook でシェアしてみてください。

![エラー](https://user-images.githubusercontent.com/75155258/128590126-b4a4a56f-6064-4450-ad2a-e6aef655e92c.png)

エラーになります。どうやら、URL に `http://` か `https://` が含まれていないとリクエストを拒否する仕様になっているようです。

そこで、URL にこれらが存在するか調べる機能を実装していきます。

## HTML の修正
「Facebook のシェアボタン」〜「LINE で送るボタン」までを、`<div id="sns">`で囲んでください。

## JavaScript の修正

`popup.js` の `chrome.tabs.query` の中の末尾に以下のコードを追加してください。

```JavaScript:popup.js
if(!/http\:\/\/|https\:\/\//.test(tabUrl)) {
    const element = document.getElementById("sns");
    element.style.marginTop = "1.5em";
    element.textContent = "このページでは SNS を用いたシェア機能をご利用になれません。ご了承ください。";
}
```

このコードに登場する `test` は、とある文字列の中に指定した文字列が含まれているかを、`true` または `false` で返すものです。

`test` の前に検索したい文字列を正規表現で指定します。正規表現について、詳しくは説明しませんが、このコードに関わっているルールを説明します。

1. 正規表現は2つの `/` (スラッシュ)の間に書く
2. `|` は「または」という意味。`/りんご|みかん/` と書いた場合、「りんご」または「みかん」が含まれているか、という意味となる
3. 正規表現の中に登場する `/`(スラッシュ)や`:`(コロン)、`;`(セミコロン)が含まれている場合、これらの文字がプログラムのコマンドと誤認識されないよう、直前に `\`(バッククオート)を入れる。

上記のコードの場合、「`http://` か `https://` が含まれているか」という意味になる。

もし、`http://` も `https://` も含まれていない場合、先程 `popup.html` に追加した`<div id="sns">` の上に余白を追加し、中のテキストを変更するようになっています。

これで、SNS でシェアした際にエラーになるのを防ぐことができます。

今日は以上です！

# まとめ
- `tabs` の代わりに `activeTab` を指定することで、権限が無駄に多くなることが防げる。
- `test` を用いると、文字列を検索することができる。

本日もお疲れさまでした！

次回は Web ストアに出品する予定でしたが、予定を変更してもう一つ機能を実装していきます。

また、今回扱ったコードは、[こちら](https://github.com/r-40021/copy_title-URL/tree/lesson_5)から見られます。


<br><br>
【連載一覧】

1.  [環境構築](https://qiita.com/r-40021/items/8f10798f07c2c2fb0066)
2.  [ポップアップ作成](https://qiita.com/r-40021/items/dbbd0c37ac37d0583108)
3.  [仕様に沿って開発](https://qiita.com/r-40021/items/9ec3aa0363f75924e75f)
4.  [コピー機能実装](https://qiita.com/r-40021/items/133857b9c79468e5facc)
5.  [権限を減らす](https://qiita.com/r-40021/items/6c931cb510ca36934c6f) (←今ココ)
6.  [コンテキストメニューの作成](https://qiita.com/r-40021/items/cd64894721a0e4723047)
7.  [Webストアに公開](https://qiita.com/r-40021/items/8fe23194c56b654f1db2)
Chrome 拡張機能を作って公開しよう①　〜環境構築〜

この記事は、先日ブログに投稿したものと同じ内容です。ぜひ、ブログの方もご覧ください。

https://frogapp.net/blog/2021-07/chrome-extension-1/

***


今回からは、連載企画ということで Chrome の拡張機能を開発していきます。何回分に渡るかはわかりませんが、1回分のボリュームを抑えていくので、物足りなさを感じてしまう方もいらっしゃるかもしれませんが、お付き合いよろしくお願いします。

さて、今回は連載第1回目、ということで環境構築を行っていきます。といっても、普段からプログラミングをされている方は、やることがほぼないです！プログラミングをされていない方も、難易度はそこまで高くありませんので、身構えずに取り組んでみてください。

# 対象
- HTML、JavaScript、CSS の基礎が分かる方 (DOM操作とか...)

これらがわからないという方は、まずは Webアプリを作るところから始めてみましょう！

Chrome 拡張機能開発ではこれら３つの言語が必須になります。

※HTML、CSS はものによっては使わないかも

# 必要なもののインストール
## Google Chrome
当たり前ですが、Google Chrome が必要です。開発した拡張機能をテストするのに用います。

普段から Google Chrome を使われている方は、再度インストールする必要はありません。そのままで OK です。
## エディタ
プログラムを書いていくために必要なエディタをインストールします。これも、普段使われているもので結構です。

ただし、WIndows 標準の「メモ帳」を使われている方は、特にこだわりがないのであれば、今は無料で高機能なものがたくさんあるのでこれを機に是非インストールしましょう。

おすすめは「Visual Studio Code」です。

<a href="https://azure.microsoft.com/ja-jp/products/visual-studio-code/" target="_blank" rel="noopener noreferrer">ダウンロードページ</a>

インストールしたら、デフォルトでは画面が英語なので日本語化します。以下のサイトを参考にすればすぐにできます。

<a href="https://www.fenet.jp/dotnet/column/environment/5400/" target="_blank" rel="noopener noreferrer">Visual Studio Codeを日本語表示にする手順！変更方法も解説
 (.NET Column)</a>
 
 
 
これで環境構築は終了です！あっという間でしたね！
誰でも気軽に開発を始められるところが、Chrome 拡張機能開発の良い点の一つだと思います。
 
 
# 公開するなら...

開発したChrome 拡張機能をウェブストアで公開するには、上のものに加えて以下のものが必要になります。
- Google アカウント (できれば開発用のものを作ったほうが良い)
- 5ドル (ウェブストアにアカウントを登録する際に、**１度だけ**登録料を支払う必要がある)
- クレジットカード or デビットカード (どうしても用意できない場合は、本人確認を済ませたLINEプリペイドカードでも可)

# 開発の流れ

1. 必要なファイルを用意する
2. コードを書く
3. テストする
4. 2.3.を繰り返し、バグをなくしていく
5. 公開！ (これは任意)

では、今回はこれくらいにします。次回からいよいよ本格的に開発を行っていきます！

<br><br>
【連載一覧】

1.  [環境構築](https://qiita.com/r-40021/items/8f10798f07c2c2fb0066) (←今ココ)
2.  [ポップアップ作成](https://qiita.com/r-40021/items/dbbd0c37ac37d0583108)
3.  [仕様に沿って開発](https://qiita.com/r-40021/items/9ec3aa0363f75924e75f)
4.  [コピー機能実装](https://qiita.com/r-40021/items/133857b9c79468e5facc)
5.  [権限を減らす](https://qiita.com/r-40021/items/6c931cb510ca36934c6f)
6.  [コンテキストメニューの作成](https://qiita.com/r-40021/items/cd64894721a0e4723047)
7.  [Webストアに公開](https://qiita.com/r-40021/items/8fe23194c56b654f1db2)
kaggle 30 Days of MLを全くの初学者が受講してみた。

# 動機
kaggleに挑戦しようと同じく全くの初心者の友人に誘われたのが2021年春頃。本を買い集め少しずつ読み進めながらも、7月頃にようやくkaggleとsignateに登録。そろそろコンペに挑戦しようかという矢先に、kaggleから30 Days of MLの連絡がきた。またとない機会と思い、苦手な英語を翻訳しながら進めていく。

# Day 1
## Step 1
### 課題
プロフィールを編集しよう！
### 解答・勉強になったこと
した。

## Step 2
### 課題
Novice, Contributor, Expert, Master, Grandmasterのランクがあるよ！
### 解答・勉強になったこと
なるほど。

## Step 3
### 課題
Titanicにsubmitしてみよう！
### 解答・勉強になったこと
公式のTitanic Tutorialを順にこなしていく。基本的にはボタンを押すだけでプログラミングは無し。

## Step 4
### 課題
コメントをしてみよう！
### 解答・勉強になったこと
した！

## Step 5
### 課題
イイネしてみよう！
### 解答・勉強になったこと
した！

### 今日の成果
Contributorになった！
C言語　readline関数

# はじめに

readline関数はMacのデフォルト環境には入っていません。
以下のコマンドでインストールする必要があります。

```
brew install readline
```

コンパイル時にも lオプションでライブラリを指定する必要があります。

```
gcc main.c -lreadline
```


## readline

ユーザから編集機能付きで一行を受け取ります。

```c
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>

char *readline (char *prompt);
```

readlineは、promptをプロンプトとして使用して、端末から行を読み取り、それを返します。

プロンプトが`NULL`または空の文字列の場合、プロンプトは発行されません。

**返される行はmalloc（3）で割り当てられます。**
**呼び出し元は、終了時にそれを解放する必要があります。**

返された行では最後の改行が削除されているため、**行のテキストのみ**が残ります。

### 返り値

readlineは、読み取った行のテキストを返します。

空白行は空の文字列を返します。行の読み取り中にEOFが検出され、その行が空の場合、`NULL`が返されます。EOFが空でない行で読み取られた場合、それは改行として扱われます。

## コンパイル方法


## サンプルコード

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>

int main()
{
	char *line = NULL;

	while (1)
	{
		line = readline("> ");
		if (line == NULL || strlen(line) == 0)
		{
			free(line);
			break;
		}
		printf("line is '%s'\n", line);
		add_history(line);
		free(line);
	}
	printf("exit\n");
	return 0;
}
```

add_history関数を入れておくと、↑でヒストリーの参照ができます。

## 参考

[readline(3) — Arch manual pages](https://man.archlinux.org/man/readline.3)

[The GNU Readline Libraryを使った - メモの日々(2008-03-19)](http://ogawa.s18.xrea.com/tdiary/20080319p02.html)
chromebookでFlutterの開発環境を作る

とりあえずLinuxを有効にしてFlutterを入れてみた作業メモ
とりあえずまず先にADBデバッグの有効をオンにしておく

#Android Studio のインストール
公式サイトからダウンロード
[https://developer.android.com/studio/?hl=ja](https://developer.android.com/studio/?hl=ja)

ダウンロードしたファイルをクリックし、インストール開始。
![Screenshot 2021-08-06 22.36.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/8d61fd05-290f-098b-d897-f8984be55b7c.png)

PluginsよりFlutterを選択してインストール
![Screenshot 2021-08-06 22.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/691e13b9-40d1-9d7f-39f3-df813949076e.png)

SDK Toolsで以下２つを選択
・google Play Licensing Library
![Screenshot 2021-08-06 23.06.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/9ce56b62-e8c8-1847-af97-81e18bf1c06c.png)

#Flutterのインストール
$HOMEにFlutterをインストール。(stableにしていたかも・・・）

```
$ git clone https://github.com/flutter/flutter.git
```


flutterにパスを通します。.bashrcの最下行に追加。

```
export PATH="$PATH:$HOME/flutter/bin"
```

インストール状況確認。

```
$ flutter doctor
```

![Screenshot 2021-08-06 22.31.55x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/ca5af540-c2f7-2d87-0744-821ba016a815.png)

〆の項目を対応していきます。
まずAndroid SDKの設定

![Screenshot 2021-08-07 10.46.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/eda4a908-fcdf-b6fb-2f58-da911009e3b3.png)

chromeの設定

```
$ sudo apt install chromium
```

.bashrcの最下行に以下を追加。

```
export CHROME_EXECUTABLE=/usr/bin/chromium
```
Androidライセンス

```
$ flutter doctor --android-licenses
```

ここまでで再び「flutter doctor」を実行して〆がないことを確認。


#flutterのブランクプロジェクトを新規作成

android studioを起動してflutterのプロジェクトを新規作成

File→Project StructureでProjectのSDKの設定を指定（初期は未設定状態）
Moduleにも同様に設定

![Screenshot 2021-08-09 13.39.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/549ec36a-9793-bb17-e1a6-0dfdbe32e1f2.png)

![Screenshot 2021-08-09 13.40.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1864453/67358b66-e842-3c95-0f88-a91de563bdec.png)

とりあえずここまで。

ですが、まだ動きませんね。
お名前ドットコムとムームードメインとALBとACM

現状→完成図（一部）
-

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/25db8273-8c69-55ec-25ef-1f104b966f50.png)


作業順
-


:::note info

現状確認
↓
https化するための証明書の作成（要お名前ドットコムでのCNAME登録）
↓
証明書を使ってALBを作成
↓
Route53でサブドメインのAレコードをALBにして登録
↓
お名前ドットコムでのALBのCNAME登録
↓
動作確認

:::

前提
-


|所有ドメイン|ドメイン管理 |現在のネームサーバ|index.htmlの場所|現在|
|:--------|:---------|:-----------|:-----------|:-----------|
|ドメインA |お名前ドットコム | レンタルサーバー RSプラン|レンタルサーバー RSプラン|http://ドメインA|
|ドメインB |お名前ドットコム | レンタルサーバー RSプラン|レンタルサーバー RSプラン|http://ドメインB|
|ドメインC |ムームードメイン |ムームーDNS|置いていない|設定なし|


※レンタルサーバー RSプラン：お名前ドットコムのサービス
※ムームーDNS：ムームードメインのサービス

注意点
-

**★お名前ドットコムやムームードメインのネームサーバで管理します**




ムームードメイン
-

①ムームーDNSを使用する、にします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/fc5113cd-9c07-d1b6-2dc5-ce998c17c54a.png)


② CNAMEにして、ACM証明書のCNAME情報を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/b50dcd5a-0058-726d-30b0-1c0eed293c1d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/2902a7f4-b26a-4dc2-c820-ef1a19148e0c.png)

**ムームードメインは、値の最初の「_」は、あっても認証できました。。**


お名前ドットコム
-

①ムームードメインと同じように、ACM証明書のCNAME情報を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/2902a7f4-b26a-4dc2-c820-ef1a19148e0c.png)

**※値の_は外すこと！！**

②お名前ドットコムは、DNSレコード用ネームサーバを使う設定にします（今回は）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/091f8e5f-8190-ba04-736a-2d40fa39b366.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/40868932-a3be-f31f-9a66-78d2230d80b4.png)

ALBを作成します
-

https://recipe.kc-cloud.jp/archives/11084

を参考に作ります。

EC2の準備をします
-

httpd を有効にして、index.htmlも置きます
EC2のSGで、ALBを指定します。


お名前ドットコムまたはムームードメインにALBを登録します
-

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/adefcdca-d6e9-8e35-4309-0b85877fa44f.png)


ALBがhealthyになっているか確認します
-

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/e88f542b-78e7-62cf-d189-a5c3a22cbc58.png)

curlコマンドで確認します
-

https://speakerdeck.com/cybozuinsideout/http-and-dns-2021

すごくわかりやすかった


ブラウザで確認します
-

手持ちのFireFox,Edge　で確認します

が、chromeはwwwが省略されるようです。（知らなかった）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/240a1757-ddde-5aec-7d82-136fd1e0716e.png)
EC2を置くVPCを間違えた時

https://aws.amazon.com/jp/premiumsupport/knowledge-center/move-ec2-instance/

変更は出来ないので、

>
①当該EC2を停止
②EC2のAMIを作成
③そのAMIから新しくEC2を作成
④EIPを振り直し

します。
ACM証明書がなぜか消えない時


参考
-

https://itnews.org/news_resources/109597

ロードバランサもEC2も消したのになぜ？
と思っていたら、APIGatewayを消していなかった。
EC2ではなく、S3にAPIGatewayをつかってACMでhttps化していたんだった。
訓練データ、検証データ、テストデータは全て違うものである

#はじめに
　機械学習において、モデルの汎化性能を測る方法に、クロスバリデーションやホールド・アウト法、リーブワンアウト法等があることは周知の事実かと思います。

　しかし、これらの方法を単に訓練データとテストデータに分ける手法と勘違いしている言説を（私も含め）非常に多く見かけます。何なら書籍の中ですら、きちんと述べられていないことが多いです。

　この記事では、

・k分割交差検証ってあるけど、k個のモデルのうち結局どれを最終的に使うの？
・k分割交差検証でなんで平均を取るのかわからん
・機械学習って訓練データとテストデータさえあればいいんでしょ？

といった疑問や勘違いを解消することを目標とします。

# 機械学習はテストデータと訓練データだけあればいいのか？
まず、モデルの汎化性能を評価するために、手持ちのデータをテストデータと訓練データに分けなければいけません。
これは確かに間違いではありません。

しかし、十分でもありません。

いま、とりあえずホールド・アウト法で訓練データとテストデータを分けたとします。

　→そして、適当なハイパーパラメータで訓練データで学習を行い、テストデータでこのモデルの性能を評価します。
　→いい感じだけど、別のパラメータでも試したいな。
　→違う値ぶちこんだら性能上がりました、めでたしめでたし。

というのは間違いです。

なぜなら、この実験で分かったことは、ある訓練データによる「テストデータ」への当てはまりの良さを最適化するハイパーパラメータに過ぎないからです。
手持ちのデータを適当に分割した「テストデータ」に対しての当てはまりが良かっただけで、一般のデータに対する性能は保証されていません。従って、この方法では汎化性能を測ることはできません。

##じゃあk分割交差検証をすればいいんじゃね
　→手持ちのデータをk個のセグメントに分けて、、
　→それぞれ異なるハイパーパラメータを設定してk個の異なるモデルを作って、、
　→それぞれテストを行って、、
　→平均を取ったよ、これが汎化性能やで、めでたしめでたし。

も間違いです。

この場合、異なるハイパーパラメータの組み合わせで作ったモデルの性能の平均は意味を持ちません。
また、k個のモデルのどれを選べばいいのか分かりません。
仮に精度が最もいいやつを選んだとて、他のデータも使って学習し直したら違う結果になることは明白です。

では、ホールド・アウト法やk分割交差検証って、結局どう使うのが正しいのでしょうか？

#手持ちのデータを訓練データ、検証データ、テストデータに分ける

実は、手持ちのデータを**訓練データ**と**テストデータ**分けるのが**ホールド・アウト法**で、
**訓練データ**を、**訓練データ**と**検証データ**に分けるのが**ホールド・アウト法**、**k分割交差検証**、**リーブワンアウト**です。

先程はハイパーパラメータの探索にテストデータを使ってはいけないと書きました。
なぜなら、テストデータに最適化されたハイパーパラメータを探索することになるからです。

ではどうやってハイパーパラメータを探索すればいいのか。その答えが訓練データと検証データです。

まず、ホールド・アウト法で手持ちのデータと訓練データを分けます。
テストデータはまず置いておいて、次に訓練データをホールド・アウトなり、k分割交差検証なりで分けます。

|　　　　　　　　訓練データ　　　　　　　　　　|テストデータ｜
　　　　　
　　　　　　　　　　↓↓↓↓↓↓

｜　    　　   訓練データ　　　　　　　｜検証データ｜テストデータ|


そして、訓練データであるハイパーパラメータを試し、その性能を検証データで測れば、テストデータでどれくらいの汎化性能となるか検討をつけることができます（テストデータと訓練データが同じ分布に従うと仮定すれば）。
テストデータはあくまで、訓練データと検証データを使って見つけた最適なパラメータが、未知のデータ（一般データ）に対し、「本当に汎化性能を持つのか」評価するためだけにあるデータです。

#注意
　ここまでハイパーパラメータの探索は、手持ちのデータを訓練データ、検証データ、テストデータに分けて、訓練データとテストデータでイテレーションを回して最適（と思われる）組み合わせを見つけ、最後にテストデータで汎化性能を測る、と説明しました。
　
　しかし、私が見る限り、「テストデータ」と「検証データ」に関してはかなり言葉の意味にゆらぎがあるように感じます。つまり、テストデータと検証データが、ここで述べた意味と反対になったりすることがある、ということです。（「評価データ」などと呼ばれることもあります。）
ですので、この点に関しては注意がいるかもしれません（ここまでに説明したことを頭に入れておけば文脈から推測できるとは思いますが）。

#参考文献
Aurélien Géron (著), 下田 倫大 (監修), 長尾 高弘  (翻訳)「scikit-learnとTensorFlowによる実践機械学習」
『どの駐車場出入口から入ったっけ？』を機械学習を使って解決してみた

#ショッピングセンターの駐車場出入口はたくさんある・・

ショッピングセンターから帰るとき、「あれ？どこに車停めたっけ？」という
経験はありませんか？
GPSから位置情報を検知するアプリや、施設側のサービスで随分わかりやすく
なっていますが、みなさん以下のような経験があるようです。

[「車、どこに停めったっけ！？車の置き場所のアイデア5選」](https://select.mamastar.jp/376389/3)

#インフォメーションスタッフを救いたい

自分でアイデアを出して解決できる人はいいですが、やはりわからなくて
不安となる人も一定います。ショッピングセンター内のインフォメーション
では毎日数件必ず「どこに停めたかわからない」という相談があります。
これが探し当てるまで一苦労・・
今回は、このケースでインフォメーションスタッフが駐車場出入口の画像をを基に駐車場出入口の場所を案内できる仕様を考えてみました。
(お客様が出入口の画像は撮ったものの、場所がわからず、インフォメーションに相談に来た、、ところからスタート！）



#やりたいことのイメージ

![やりたいこと.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/dd091dab-a9c1-69b9-6034-e3ea4add494f.jpeg)

![フロー図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/d1f25ed6-ffdc-634b-48be-6fe777918d5f.jpeg)

利用したツール
[Teacable Machine](https://teachablemachine.withgoogle.com/)
[CodePen](https://codepen.io/)
[Node-RED](https://nodered.org/)
[LINE messagingAPI](https://developers.line.biz/ja/services/messaging-api/)
※LINE Developersに関する記事は[コチラ](https://qiita.com/Matsueda_Junno/items/d08f65e7d225ac28fe70#%EF%BC%93line-developers%E3%81%A7webhook-url%E3%82%92%E4%BD%9C%E6%88%90)


#結論
![wulNMWEJBjTN9ETb5FEt1628443985-1628444013.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/b48292f6-4cd4-d0c0-7d31-9cf0fdf97727.gif)

#Teachable Machineで対象の出入口を記憶させる

![スクリーンショット (195).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/6d82bc77-782d-d549-773f-caa6531898c6.png)

各出入口を様々な角度から撮影します(裏・表・正面・横・・)
※本来はそれぞれ100枚程度サンプルがあるとより精度が上がります


#CodePenで画像から場所を特定する簡単なWebアプリをつくる

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="NWjEOjO" data-user="matsueda-junno" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/matsueda-junno/pen/NWjEOjO">
  出入口判定</a> by Matsueda_Junno (<a href="https://codepen.io/matsueda-junno">@matsueda-junno</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#Node-REDを使って判定した場所ごとの案内方法をLINEで返す

![スクリーンショット (196).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/f11fa918-721f-b0a4-0587-d3ca0ce3c6e4.png)

ノード全体

![IusC8e6aH93lR6Zge36o1628480530-1628480684.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1803233/214a6501-0c07-8530-d2f8-36e2db873c78.gif)

各ノードの設定はコチラから

#やってみての結果

##上手くいったこと
- 様々な角度で画像を認識できたがほぼ特定ができたこと
- 問題なくLINEに案内方法が返せたこと
 
##より工夫したかったこと
- 案内方法がテキストではなく、案内ルート(図)を返せるようにしたいです

##他の方法で駐車場出入口を特定したい
- Webアプリでヒントとなるワードを入力し(アンケートフォーム)そのワードを基にLINEで出入口情報を返したいと思っております
気軽にbitwardenをセルフホストする

最近色々あるので、「パスワードくらいは自分のところにおいておくか。」と思い、セルフホストとするのを決めた。

## 利用したサービスについて
公式については結構リソースが必要になるっぽいので、vaultwardenで。
VPSだと色々心配なので`AWS`でバックアップ含め色々仕込む。

メモリはUbuntuServerを使う限りは500MBあれば足りる。
でも、無料期間があるので`t2.micro`を使ってみる。
来年になったら`t2.nano`に変更する予定。

## 構築手順
構築についてはこちらのページが非常に参考になります。

https://banatech.net/blog/view/22
毎日9時から17時までtcpdumpでパケットキャプチャしてファイルに書き出す方法

# tcpdumpのログをファイルに書き出す
```bash
tcpdump -w /path/to/`date "+%Y%m%d%H%M%S"`.pcap
```
保存するファイル名は日時

https://qiita.com/ngyuki/items/969d1efaddb68acb5313#-w-file

# 指定した時間の間tcpdumpを実行する
```bash
sudo timeout {時間} tcpdump
```
timeoutコマンドを用いて任意の時間の間tcpdumpを実行する。時間はデフォルトで秒。時間の後ろにs（秒）、m（分）、h（時）、d（日）をつけることで単位を指定できる。

https://atmarkit.itmedia.co.jp/ait/articles/1906/27/news008.html

# tcpdumpを定期実行する
```bash
crontab -e
```
crontabコマンドを用いて、定期的にジョブを実行するようスケジュールするcronを設定する


```bash
{分} {時} {日} {月} {曜日} /usr/sbin/tcpdump
```
指定しないなら`*`、例えば毎日AM9:00に実行したいなら、

```bash
0 9 * * * /usr/sbin/tcpdump
```

https://eng-entrance.com/linux-command-crontab


# 毎日9時から17時までパケットキャプチャしてファイルに書き出す
```
0 9 * * * timeout 8h /usr/sbin/tcpdump -w /path/to/`date "+%Y%m%d%H%M%S"`.pcap
```
cronに上記の設定をする

# 参考
- https://qiita.com/ngyuki/items/969d1efaddb68acb5313#-w-file
- https://atmarkit.itmedia.co.jp/ait/articles/1906/27/news008.html
- https://eng-entrance.com/linux-command-crontab
Python - ctypesのwindllでマウスの位置を取得する

まぁpyautoguiを使って取得すればいいだけの話なんですけど、自分の環境だとpyautiguiをインポートしたときに急に高DPI対応になったりして、wxPythonだと高DPI対応にしたときに謎に表示がおかしくなるのが嫌なので今回はそれ以外の方法でマウス位置を取得する方法を紹介します。
(あとpyautoguiインポートするのに少し時間かかる)


※Windowsで実行しないとエラーになる場合があります。

```Python
import ctypes
class POINT(ctypes.Structure):
    _fields_ = [("x", ctypes.c_long),
                ("y", ctypes.c_long)]
def GetPosition():
    cursor = POINT()
    ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
    return (cursor.x, cursor.y)
print(GetPosition())
```

一応このコードで取得できますが、これは高DPIに対応していないときの位置となっています。

そのため、マウスを画面の一番右下において実行してみると、

```
(1535, 863)
```

となってしまいます。
自分みたいに、wxPythonなどで高DPIじゃないソフトをつくるような人ならいいんですけど、そうじゃない場合は以下のようにコードを書くと正確に測れます。

```Python
#高DPI対応にしてから、取得
import ctypes
try:
    ctypes.windll.shcore.SetProcessDpiAwareness(True)
except:
    pass
class POINT(ctypes.Structure):
    _fields_ = [("x", ctypes.c_long),
                ("y", ctypes.c_long)]
def GetPosition():
    cursor = POINT()
    ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
    return (cursor.x, cursor.y)
print(GetPosition())
```



```
(1919, 1079)
```

（なぜか一つずつ下がっていますが、正確に取得できています。）
【Java】二次元Map: キーと値のペアを全て取得する

#Mapとは
Mapとは、***キーと値のペアをリスト形式で保持するコレクションのこと***である。
取り出したい値のキーを指定することでその値を取得することができるが、Mapに格納されている全てのキーと値を取り出すにはどうしたらいいのだろうか

#一次元Map: キーと値のペアを全て取得する

```java:MapSample1.java
package sample;

import java.util.HashMap;
import java.util.Map;

public class MapSample1 {
	public static void main(String[] args) {

		Map<Integer, String> map = new HashMap<>();
		map.put(1, "aaa");
		map.put(6, "bbb");
		map.put(3, "ccc");

		for (Map.Entry<Integer, String> entry : map.entrySet()) {
			System.out.println(entry.getKey() + ":" + entry.getValue());
		}
	}
}


```

```java:結果
1:aaa
3:ccc
6:bbb
```

#二次元Map: キーと値のペアを全て取得する
やり方は一次元Mapのときと同様

```java:MapSample2.java
package sample;

import java.util.HashMap;
import java.util.Map;

public class MapSample2 {
	public static void main(String[] args) {

		Map<Integer, Map<Integer, String>> map_list = new HashMap<Integer, Map<Integer, String>>();

		Map<Integer, String> map1 = new HashMap<>();
		map1.put(11, "aaa");
		map1.put(12, "bbb");
		map1.put(16, "ccc");

		Map<Integer, String> map2 = new HashMap<>();
		map2.put(21, "ddd");
		map2.put(24, "eee");
		map2.put(26, "fff");

		Map<Integer, String> map3 = new HashMap<>();
		map3.put(31, "ggg");
		map3.put(32, "hhh");
		map3.put(36, "iii");

		map_list.put(1, map1);
		map_list.put(2, map2);
		map_list.put(3, map3);

		for (Map.Entry<Integer, Map<Integer, String>> map : map_list.entrySet()) {

			for (Map.Entry<Integer, String> entry : map.getValue().entrySet()) {
				System.out.println(entry.getKey() + ": " + entry.getValue());
			}
			System.out.println();
		}

	}
}

```

```java:結果
16: ccc
11: aaa
12: bbb

21: ddd
24: eee
26: fff

32: hhh
36: iii
31: ggg

```

以上
なぜ拡張for文は普通のfor文より速いのか？

# はじめに
昔書いた記事を眺めていたら、「[JavaでよくつかうCollection実装クラスの仕組みと特性](https://qiita.com/frost_star/items/8a5d711f9090f0e24f51)」の記事が、「[collection型のクラスであるlinkedListに関するランダムアクセスの遅さという課題への取り組み](https://qiita.com/ninoko1995/items/c4e84194f0e48caa6d68)」という記事で参考にされていました。ありがとうございます！
こちらの記事では、LinkedListで作成した処理について、for文と拡張for文で実行時間を比較しており、拡張for文のほうが圧倒的に早いという結果が出ています。
今回は、この拡張for文についてなぜ普通のfor文よりも高速か、というところを解説していきたいと思います。

# 拡張for文とは何ぞや？
そもそも拡張for文とは何か？
コレクション(ListやSetなど)の要素を繰り返し取り出して、何かしらの処理を行うときなどに使用する構文です。
例えば、Listに格納された数値の総和を取るために、for文と拡張for文ではそれぞれ下記のように記述します。

```java:for文
List<Integer> list = Arrays.asList(1,3,5,7);
for(int i = 0;i < list.size(); i++){
   sum += list.get(i);
}
```
```java:拡張for文
List<Integer> list = Arrays.asList(1, 3, 5, 7);
for(Integer i: list){
    sum += i;
}
```

つまり、拡張for文は

```java
for(要素の型 要素を入れる変数: コレクションの変数){
    処理(要素が入った変数を処理に使用できる)
}
```
という構文になっていることがわかります。
普通のfor文と比べてシンプルな記述になっていますね。

# 拡張for文は何をやっているのか？
拡張for文が内部的にどういう動きをしているか、Javaのドキュメントを読んでみましょう。
ちなみに拡張for文と呼ばれることが多いですが、実はJavaのドキュメントではFor-Eachループという項目になっています。

https://docs.oracle.com/javase/jp/8/docs/technotes/guides/language/foreach.html

これによると、下記2つのコードは等価であるとのこと。
その上で、拡張for文のほうがiterator変数を扱わないことから複雑性やエラーの危険性が排除されるのでより推奨されます。

```java:拡張for文
List<Integer> list = Arrays.asList(1, 3, 5, 7);
for(Integer i: list){
    sum += i;
}
```
```java:iterator
List<Integer> list = Arrays.asList(1, 3, 5, 7);
for(Iterator<Integer> i = list.iterator(); i.hasNext();){
    sum += i;
}
```
つまり、拡張for文は内部的にはiteratorによる反復処理を行っているということがわかります。

# なぜLinkedListだと拡張for文が格段に高速なのか？
LinkedListの実装を考えてみましょう。
詳細な説明は「[JavaでよくつかうCollection実装クラスの仕組みと特性](https://qiita.com/frost_star/items/8a5d711f9090f0e24f51)」に記載がありますが、LinkedListは下図の通り、ノードが連結した形の構造になっています(本来は前後にリンクがある二重リンクリストですが、話を簡単にするために片方だけのリンクを持つ構造として説明しています)。
そのため、ノード3を参照するときには、ルートから始まり、ノード1、ノード2、ノード3と順番にノードをたどることになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115996/de2eaaf8-d699-c323-26d0-627158dd57e3.png)

ここで、for文を使った繰り返しで全要素にを参照する場合を考えると、それぞれのノードを参照するときの処理は下記のようになります。

- ノード1：ルート⇒ノード1
- ノード2：ルート⇒ノード1⇒ノード2
- ノード3：ルート⇒ノード1⇒ノード2⇒ノード3

この場合、ノード3を参照するときに再度ルートから順番に辿ることになってしまい、効率が悪くなります。
そこで、LinkedListのIteratorでは、現在位置を保存することで、これを解消して効率よく内部の要素を返しています。
上述したように、拡張for文ではIteratorを使っているので、結果として拡張for文を使うことで効率の良い反復処理が可能になった、ということになります。

# 拡張for文とfor文のどちらを使うべきか？
Iteratorは効率的な反復処理を提供するという前提に基づくならば、基本的に拡張for文を使うことで常に効率のいい反復処理が実行できます。
単純な配列の反復処理では、for文のほうが高速な場合もありますが、ほんの数ms程度なので変更に強いコードにするためにも拡張for文を使いましょう。

# 参考
[for文と拡張for文の速度を比較してみる。](https://qiita.com/aky100200/items/3e6770db3e1fbe1a9d90)
[拡張for文を使う理由](https://soichirooooo5.hatenadiary.org/entry/20080723/1216829964)
Rubyの基本的文法について

#テーマ
今回は、rubyの中で基本となる以下のことについて説明します。

- 出力
- 入力
- 変数

#出力
みなさんお馴染みの"Hello World"を出力してみましょう。Rubyで値を出力する方法は様々ありますが、今回は、print,puts,p,printfについて見ていきましょう。

###printf
printを使うと、改行を入れずに指定した値を出力できます。

###puts
putsを使うと、末尾に改行が入る形で出力されます。

###p
pを使うと、出力する値とともにその値の型情報(文字列型や数値型など)を出力します。改行文字も入るため、出力する値が改行されます。

###printf
printfは書式を設定して出力するものです。これまでとは異なり、()で出力内容をくくります。異なる型の値をまとめて出力するときに便利です。%dは、数値型を代入する引数の型であり、%sは文字列を代入する引数の方です。
>実行例

```ruby
print "Hello "
print "World!"
#出力結果 改行されずに出力されていることがわかります。
#=> Hello World!

puts "Hello "
puts "World!"

#出力結果 今度は、Helloの後ろに改行が入って出力されていることがわかります。
#=> Hello
#=> World!

p "Hello World!"
p 2021

#出力結果 
#=> "Hello World!"
#=> 2021
#Hello World!が,""とともに出力されており、値が文字列型であることがわかります。
#2021はそのまま出力されており、整数型の値であることがわかるかと思います。


printf("今年は%d年で、%s年です.",2021,"丑")

#出力結果
#=> 今年は2021年で、丑年です.
#数値型の2021が%dに、文字列型の%sが"丑"に対応して、出力されていることがわかると思います。

```

#入力
キーボードから入力する代表的なものは、gets(),gets.to_i(),gets.to_f()です。

| 表記方法       |出力内容|
|:-----------------|:------------------|
| gets()           |キーボードから文字列として入力します|
| gets.to_i()      |キーボードで入力した値を整数値に変換します。|
| gets.to_f()      |キーボードで入力した値を小数値に変換します。|

違いがわかるようにコードを書いて見ました。

```ruby
puts "---値の入力---"
num1 = gets()
num2 = gets.to_i()
num3 = gets.to_f()

puts "---出力結果---"
p num1
p num2
p num3
```
以下が出力結果です。それぞれのメソッドに対して、適切な出力がされていることがわかります。

```
---値の入力---
100
100
100
---出力結果---
"100\n"
100
100.0
```

#変数
変数は、値を入れておく箱のようなものです。今回は、変数を文字列の中に埋め込む変数展開を見ていきます。#{変数名}を文字列の中に入れることで、変数を代入している値に置き換えて出力します。
以下のコードをみてみましょう。

```ruby
puts "---値の入力---"
num1 = gets()
num2 = gets.to_i()
num3 = gets.to_f()

puts "---出力結果---"
puts "入力された値:#{num1}"
puts "入力された値:#{num2}"
puts "入力された値:#{num3}"
```

出力結果は以下のようになります。putsの中に#{変数名}を埋め込むことで、キーボードから入力した値が適切に出力されていることがわかると思います。

```
---値の入力---
1
1
1
---出力結果---
入力された値:1
入力された値:1
入力された値:1.0
```

#最後に
今回はここら辺で終わりにしたいと思います。次は、条件分岐や繰り返し構文などを投稿したいと思います。ありがとうございました。
【第10章】Railsチュートリアルでヘルパーについて忘れていたので復習した

[Railsチュートリアル第10章(第6版)](https://railstutorial.jp/chapters/updating_and_deleting_users?version=6.0#code-friendly_forwarding_test)でhelper関連の演習が解けなかったので復習した。

#①ヘルパー
・Railsのビューでは膨大な数の組み込み関数が使える。
・新しく作ることもでき、新しく作成したメソッドのことをカスタムヘルパーという。
・Webサイトのレイアウトで使うコンパクトなヘルパーメソッドでは、メソッド定義、変数割り当て、論理評価、制御フロー、文字列の式展開 など、Rubyの様々な要素が投入されている。
・デフォルトでは、ヘルパーファイルで定義されているメソッドは自動的にすべてのビューで利用できる。
・ヘルパーメソッドはテストから呼び出せない。

#③まとめ
①で忘れていた箇所を思い出せた。
鮮度確認をするAIを作ってみた。（未完成）

今回は画像判定システムを使って牛肉の鮮度を見分けるAIを作ってみました。
すでに鮮度判定ができる画像判定システムがあると思いますが
弊社の予算上、導入することが難しい為、自分で作ってみました。

■検証結果が出やすいように、以下の内容で画像を登録し、実施しました。
①切り立てのお肉と３日間熟成させ変色したお肉を使用。
②お肉の種類は牛肉細切れのみで画像登録。
③同じスーパーで購入。


#完成物

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/b835aa74-7d57-2105-3819-08bfbb3904c7.png)
動画URL　https://youtu.be/-JZT-QnRMww


#作成方法（Node-RED）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/ec8cd192-1cf1-0e61-428a-1d5acac4010e.png)

#CodePen

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="gOWdppB" data-user="nagaharahitomi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/nagaharahitomi/pen/gOWdppB">
  【完成】鮮度チェック</a> by NagaharaHitomi (<a href="https://codepen.io/nagaharahitomi">@nagaharahitomi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


#できなかったこと
Node-REDとの接続はできましたが、LINEに「鮮度が悪いので撤去してください」と判定されたときのみ、
指定された相手に通知が来るように設定したかったのですが、設定することができませんでした。
この設定をすることによって、店舗責任者に売り場に鮮度が悪い商品が陳列されていたことを
認識してもらいたいという意図がありました。

#今後できるようにしたいこと
・豚の細切れなど他のお肉・部位でも検証できるようにしたい。
・お肉だけでなく魚や野菜でも検証できるようにしたい。
（特に野菜・果物は賞味期限がなく担当者の目や感覚が判断基準となるため）
・「これは何時に切ったお肉です」というようなお肉を切ってから何時間経つのかが分かるようにしたい。
・判定結果を音声で確認できるようにしたい。（目が悪い方でも判定結果を確認できるようにしたい。）

#追記
使用したお肉はすべて食べました。



最後まで読んでいただきありがとうございました。
deviseでログイン機能を作成後、本番環境にアップすると新規登録画面に遷移しない

作成したアプリをHerokuにアップしたときに、deviseで作った新規登録画面への遷移で起こったエラーの原因がわかったので、記事を書いていきます。

##環境
<ul>
 <li>MacOS</li>
 <li>Rails 6.0</li>
 <li>ログイン機能にdeviseを使用</li>
</ul>

##本番環境にアップすると新規登録画面に遷移しない
開発環境では正常に動作していたはずのアプリをHerokuにアップすると、下記の画像のように
![IMG_8815.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194218/64455a9e-1f3b-213f-626f-1a2357f4d0a0.png)
![IMG_8816.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194218/2f96922d-40d6-924c-aecb-83eadd588f32.png)
新規登録ページに遷移しない問題が起こっていました。
こちらの原因はとてもシンプルです。
##原因は autofocus:true が複数存在するため

```app/views/devise/registrations/new.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
 <%= render "devise/shared/error_messages", resource: resource %>
 <div class="field form-group form-row">
   <div class="col-2 required-b pt-2"><span class="badge  badge-danger p-1">必須</span></div>
   <%= f.text_field :name, ！！！autofocus: true！！！, placeholder: "ユーザー名", class: "form-control col-10 px-2" %>
 </div>
 <div class="field form-group form-row">
   <div class="col-2 required-b pt-2"><span class="badge  badge-danger p-1">必須</span></div>
   <%= f.email_field :email, ！！！autofocus: true！！！, placeholder: "メールアドレス", class: "form-control col-10 px-2" %>
 </div>
 <div class="field form-group form-row">
   <div class="col-2 required-b pt-2"><span class="badge  badge-danger p-1">必須</span></div>
   <%= f.password_field :password, placeholder: "パスワード", class: "form-control col-10 px-2" %>
 </div>
 <div class="field form-group form-row">
   <div class="col-2 required-b pt-2"><span class="badge  badge-danger p-1">必須</span></div>
   <%= f.password_field :password_confirmation, placeholder: "パスワード確認", class: "form-control col-10 px-2" %>
 </div>
 <div class="actions">
   <%= f.submit "新しいアカウントを作成", class: "btn btn-primary" %>
 </div>
<% end %>
```

上記コードのユーザー名とメールアドレスのコードにそれぞれ autofocus:trueが存在しており、これが原因で画面遷移エラーが出ていました。
autofocus:trueを複数記述しないように削除すればエラーは解決、正常に画面遷移するようになります。
59日後にITパスポートを受けるFラン私大文系既卒(12日目)

# 集中処理
* 集中処理とは?
 * 一台のコンピュータに複数の端末を動かす形態

# ホストコンピュータ
* ホストコンピュータとは?
 * 集中処理の複数の端末を動かすコンピュータ
 
# 分散処理
* 分散処理とは?
 * ネットワークで繋がれた複数のコンピュータが、処理を分担して行うシステム

# クライアントサーバシステム
* クライアントサーバシステムとは?
 * クライアントが出した処理要求を、サーバが処理する分散処理システム
 * 専用のソフトウェアをインストールしておく必要がある

# Webシステム
* Webシステムとは?
 * インターネットとWebブラウザを利用するシステム
 * 専用のソフトウェアをインストールする必要はない

# シンクライアント(Thin Client)
* シンクライアントとは?
 * クライアント側に最低限の機能しか持たせず、サーバ側でアプリケーションソフトウェアを集中管理するシステム形態
 * データはサーバ側に保存され、手元のPCには残らない

# グリッドコンピューティング
* グリッドコンピューティングとは?
 * インターネットで複数のコンピュータを繋ぐことで、スーパーコンピュータ並みの高速処理を実現するシステム

# サーバの仮想化
* サーバの仮想化とは?
 * １つのコンピュータ上で、仮想的に複数のサーバを動作させる技術

# シンプレックスシステム
* シンプレックスシステムとは？
 * 一つのコンピュータだけのシステム構成

# デュプレックスシステム(Duplex：２重の)
* デュプレックスシステムとは? 
 * メインで動作するコンピュータと、故障に備えて待機しているコンピュータの2つのコンピュータからなるシステム構成

# デュアルシステム(Dual：2つの)
*　デュアルシステムとは? 
 *　2つのコンピュータが同じ処理を行い、結果を照合して正しいと確認するシステム
 *　２つのコンピュータが同じ処理をするので、処理能力はシンプレックスシステムと同じ

# RAID(Redundant Array of Inexpensive Disks)
* RAIDとは?
 * 複数のハードディスクを、あたかも1つのハードディスクであるかのように扱う技術
 * データを複数台のハードディスク上に保存する技術

# ストライピング
* ストレイピングとは?
 * RAID0
 * 複数のハードディスクに、データを分散させて書き込む記憶方式
* メリット
 * 処理を高速化できる
* デメリット
 * 可用性が下がる

# ミラーリング
* ミラーリングとは?
　　* RAID1
 * 複数のハードディスクに、、同じデータを書き込むこと
* メリット
 * 可溶性が上が
* デメリット
 * 保存できる量がストライピングの半分になる
 * 処理が遅くなる

# NAS(Network Attached Storage)
* NASとは?
 * ネットワークに接続して使用するファイルサーバ専用機
 * 複数のPCでデータを共有できる

# システムの評価指標
* システムの評価指標(3つ)
 * 性能
 * 経済性
 * 信頼性

# 応答時間(レスポンスタイム)
* 応答時間とは?
 * 処理にかかる時間 

# ベンチマークテスト
* ベンチマークテストとは?
 * システムの性能を比較するために行うテスト

# 初期コスト(イニシャルコスト)
* 初期コストとは?
 * システムの導入にかかるコスト

# 運用コスト(ランニングコスト)
* 運用コストとは? 
 * システムの運用や故障の修理にかかる費用

# TOC(Total Cost of Ownership)

* TCOとは?
 * 初期コストと運用コストを合わせた費用

# MTBF(Mean Time Between Failures：平均故障間隔)
* MTBFとは?
 * システムが故障せずに正しく動いていた時間の平均値
 * 信頼性を表す指標の1つ
* 式 

```math
MTBF = \frac{稼働時間の合計}{故障した回数}
```

# 予防保守
* 予防保守とは　
 * MTBFを高めるメンテナンス

# MTTR(Mean Time To Repair：平均修理時間)
* MTTRとは?
 * システムが稼働してなかった時間の平均値
 * 保守性を表す指標の1つ
* 式

```math
MTTR = \frac{故障時間の合計}{故障回数}
```

# 稼働率
* 稼働率とは?
 * システムが故障せずに動いていた割合
 * 可用性を表す指標の1つ
* 式


```math
稼働率 = \frac{MTBF}{MTBF - MTTR}
```

# フォールトトレラント(Fault Tolerant)
* フォールトトレラントとは?
 * 障害が発生しても、止めないための設計

# フェールソフト(Fail Soft)
* フェールソフトとは?
 * たとえ機能は落ちたとしても、システム全体は動作させる設計

# フェールセーフ(Fail Safe)
* フェールセーフとは?
 * システムを止めてでも安全を優先する設計

# フールプルーフ(foolproof)
* フールプルーフとは?
 * 誤った動作をしても、システムに異常が起こらないようにする設計

# 直列システム
* 直列システムとは?
 * 複数の装置が直列に接続されたシステム
 * 代表例はシンプレックスシステム
* 式

```math
直列システムの稼働率 = 装置Aの稼働率　\times 装置Bの稼働率
```

# 並列システム
* 並列システムとは?
 * 複数の装置が並列に接続されたシステム
 * 代表例は、デュプレックスシステムやデュアルシステム
* 式

```math 
並列システムの稼働率 = 1 - (1 - 装置Aの稼働率) \times (1 - 装置Bの稼働率)
```

# 複合システム
* 複合システムとは?
 * 複数の装置、もしくは複数のシステムを部品として組み合わせてつくる、より大きな1つのシステム

# バスタブ曲線
* バスタブ曲線とは?
 * 装置の故障率と時間経過の関係を表した曲線
スマートホーム目指してラズパイ触ってみた(3) 〜LINE連携＆温度通知編〜

##今回の目標
LINE Notifyを使って、自分のLINEアカウント宛に温度を通知させる

他の記事はこちら
[スマートホーム目指してラズパイ触ってみた(1) 〜ラズパイ４+SenseHatセットアップ編〜（Qiita）](https://qiita.com/keilog/items/78dfb492790997fa16b7)
[スマートホーム目指してラズパイ触ってみた(2) 〜Macからリモートデスクトップ接続編〜（Qiita）]
(https://qiita.com/keilog/items/76117db977ce5096ac19)
[スマートホーム目指してラズパイ触ってみた(4) 〜Amazon S3 (AWS CLI)連携編〜（Qiita）]
(https://qiita.com/keilog/items/a7894275daf151686a86)
[スマートホーム目指してラズパイ触ってみた(5) 〜Amazon S3 + QuickSight連携編〜
（Qiita）]
(https://qiita.com/keilog/items/c1d0b69c3892904e48eb)

##Step１ : LINE Notifyでアクセストークンを取得する

まずアクセストークンを取得するために、LINE Notifyにログインします。
https://notify-bot.line.me/ja/ (LINE公式サイト)
手順は下記記事を参考にしました。

https://qiita.com/iitenkida7/items/576a8226ba6584864d95

※発行したトークンは１度しか表示されないので、テキストメモなどに控えておきます。（うっかり失くした場合は、新たにトークンを再発行できます。）

LINE Notifyをブロックしていたら解除します。
またLINE Notifyが友だちにいない場合は、以下のQRをスマートフォンで読み取って追加可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1863184/08209407-94ad-2d14-c4fd-8cfdb10d2b29.png)

##Step2 : SenseHatで測定した温度をLINEに通知させる
SenseHatで測定した温度は、以下のコードで確認できます。

ラズパイ拡張モジュールのSenseHatについてはこちらの記事をご参考ください。
[スマートホーム目指してラズパイ触ってみた(1) 〜ラズパイ４+SenseHatセットアップ編〜(Qiita)](https://qiita.com/keilog/items/78dfb492790997fa16b7)


```temp_check.py
from sense_hat import SenseHat

sense = SenseHat()
sense.clear()
temp = sense.get_temperature()

msg1 = "現在の温度"
msg2 = "℃です。"
message = "{0}:{1:.1f}{2:}".format(msg1,temp,msg2)

print (message)
```

実行すると結果がShellに出力されます。
```現在の温度：３１.7℃です。
```

この出力結果をLINEに通知させたいので、上記のコードと組み合わせて下記のように記載します。

```temp_line_notify.py
from sense_hat import SenseHat

sense = SenseHat()
sense.clear()
temp = sense.get_temperature()

import requests
url = "https://notify-api.line.me/api/notify"
token = "取得したトークン"
headers = {"Authorization" : "Bearer "+ token} 

msg1 = "現在の温度"
msg2 = "℃です。"
message = "{0}:{1:.1f}{2:}".format(msg1,temp,msg2)

payload = {"message" :  message} 
r = requests.post(url, headers = headers, params=payload)

print (message)
```
「取得したトークン」の箇所にはメモしておいたトークンをコピペします。
実行（Run）すると、実行結果がLINEに通知されるようになります。

##おまけ
温度を定期的に通知させたい場合は、ラズパイのターミナルで下記コマンドを打ちます。

```sudo crontab -e
```

編集モードになるので、以下のように間隔とファイル名を記述します。

■毎分ごとに通知させたい場合
```*/1 * * * * python3 /home/pi/[実行するファイル名]
```
例)*/1 * * * * python3 /home/pi/temp_line_notify.py

■３０分ごとに通知させたい場合
```*/30 * * * * python3 /home/pi/[実行するファイル名]
```

編集したらCommand+Xで終了します。

これを行うと設定した間隔で通知されますが、停止しない限りずっと通知が来るので、停止させたい場合は同じコマンド(#sudo crontab -e)で編集して、該当行をコメントアウト(#)します。

##その他参照記事
[ラズベリーパイ4でcronを動かす(Qiita)]
(https://qiita.com/gdate/items/bdf6c620404679063211)

ITmedia NEWS：名刺サイズの超小型PC「ラズパイ」で遊ぶ
https://www.itmedia.co.jp/news/articles/1912/01/news009.html
https://www.itmedia.co.jp/news/articles/2009/15/news037.html
https://www.itmedia.co.jp/news/articles/2009/16/news021.html
公開鍵認証でクライアントデバイス(鍵ペア)を紛失した時の対処法 【ConoHa VPS】

# 概要
いつもログインに使ってるPCが故障した，誤ってクライアント側の鍵ファイルを削除してしまったなどして，サーバーから締め出されてしまった．．．といった際に使用できる対処法を紹介します．

[公開鍵認証でしかログインできなくする方法はこちら](https://qiita.com/t_asa/items/11ba21eab208afca44cc)

## 環境
 - サーバー(ホスト) : Ubuntu 20.04 LTS (ConoHa VPS)

## 留意事項
 - これからお読みいただくと分かる通り，ConoHa VPSではSSHを使用しなくてもブラウザ上でコンソールが使えます．つまり，ConoHaのパスワードとサーバーのsudoを持ったユーザーのIDとパスワードが割れると乗っ取られます．ConoHaアカウントには二段階認証を設定しておくことをお勧めします．
 - 【事前準備】の作業は，サーバーから締め出された後でも，ConoHaのコントロールパネルからVPS管理画面に進み，ブラウザコンソールを使うことで実施することができます．

# 事前準備: 非常用ユーザーの作成とパスワード認証の例外的許可

公開鍵認証でログインできなくなった際に使うための非常用のユーザーを作成します．

 - sudo権限は持たせない
 - このユーザーのみ例外的にパスワード認証を許可
 - SFTP専用で，自分のホームディレクトリにのみ接続できるようにする．
 - 通常時はこのユーザーを使ったSSH接続を拒否するようにする．

sudo権限を持ったユーザーでサーバーにログインし，非常用のユーザーを作成します．`<username>`は使いたいユーザー名に置き換えてください．

```
sudo adduser <username>
```

パスワードを二回聞かれますので，使いたいパスワードを入力し次へ進んでください．

その後，ユーザーのプロフィールに関する質問(フルネームや電話番号など)を聞いてくる場合がありますが，空欄のまま全部スキップしてください．最後に `Is the information correct?` と聞かれたら，`Yes`と入力して完了です．

次に，サーバー側のSSH設定を変更します．ターミナル上で使えるテキストエディタを，サーバーに用意しておいてください．(ここではVimを使っています)

```
sudo vim /etc/ssh/sshd_config 
```

configファイルの末尾に以下を追加してください．DenyUsersは既に指定している場合は，既存の行に`,<username>`を付け加えてください．DenyUsersを設定することで通常時はログインができないようにします．そうしないと，パスワードが破られた際に，SFTPで大量のファイルをアップロードされサーバーを破壊される可能性があるためです．また，SFTP限定にしているのもsudoを与えてないとはいえ何かしらのコマンドを実行されるのを防ぐためです．

```ssh
Match User <username>
	PasswordAuthentication yes
	ForceCommand internal-sftp

DenyUsers <username>
```

サービスを再起動すると設定が反映されます．

```
sudo systemctl restart sshd
```

# [1] クライアント側で鍵ペアを生成

こちらは省略します．

# [2] 非常用ユーザーのログインを許可

ConoHa コントロールパネルからVPSの管理画面に進み，「コンソール」をクリックしてください．
コンソールに入ると以下のような表示になると思います．

※ブラウザコンソールは，ブラウザのウインドウを最大化するか全画面表示にして利用することをおすすめします．

```
<VPSのIPアドレス> Login: 
```

ここで，sudo権限を持ったユーザー名(いつもログインに使用してるユーザー名)を入力し改行します．パスワードを聞かれるのでログインします．

テキストエディタ(Vim等)で `/etc/ssh/sshd_config` を開き，DenyUsersをコメントアウトします．(もしくはDenyUsersから非常用ユーザーを除外します)

```
#DenyUsers <username>
```

サービスを再起動すると設定が反映されます．

```
sudo systemctl restart sshd
```

ConoHaのコンソールはいったん切断します．`exit`でログアウトしたらウインドウを閉じてください．

# [3] 公開鍵ファイルをアップロード

SFTPに対応したFTPクライアントで，先ほどの非常用ユーザーでログインし，`/home/<username>` に公開鍵ファイルをアップロードします．

# [4] 公開鍵を既存のユーザーに追加

再びConoHaのブラウザコンソールを開き，普段サーバー管理に使っているユーザーでログインします．次に，以下のようなコマンドを実行してください．

```
sudo mv /home/<username>/<公開鍵ファイル> ~/.
cat <公開鍵ファイル> >> .ssh/authorized_keys
rm <公開鍵ファイル>
sudo systemctl restart sshd
```

SSHクライアントから，公開鍵認証でログインできることを確認してください．

# 後始末: 非常用ユーザーのログインを拒否

全ての作業が終了したら，sshd_configファイルを開き，DenyUsersを再度有効化してください．
スマートホーム目指してラズパイ触ってみた(2) 〜Macからリモートデスクトップ接続編〜

##今回の目標
・MacからMicrosoft Remote Desktopを使用してラズパイにアクセスできるようになる

他の記事はこちら
[スマートホーム目指してラズパイ触ってみた(1) 〜ラズパイ４+SenseHatセットアップ編〜(Qiita)](https://qiita.com/keilog/items/78dfb492790997fa16b7)
[スマートホーム目指してラズパイ触ってみた(3) 〜LINE連携＆温度通知編〜（Qiita）]
(https://qiita.com/keilog/items/b0ef6161628c544ed6c3)
[スマートホーム目指してラズパイ触ってみた(4) 〜Amazon S3 (AWS CLI)連携編〜（Qiita）]
(https://qiita.com/keilog/items/a7894275daf151686a86)
[スマートホーム目指してラズパイ触ってみた(5) 〜Amazon S3 + QuickSight連携編〜
（Qiita）]
(https://qiita.com/keilog/items/c1d0b69c3892904e48eb)

##Step１
ラズパイをさわるのに毎回HDMIケーブルやら有線キーボードを接続するのは面倒・・・ということで、MacからRemoteDesktopでアクセスできるようにします。



ラズパイ側でソフトウェアのインストールが必要になるので、ターミナルを起動し、以下のコマンドを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1863184/b88b4aeb-aaa3-7a6d-6a28-fe3019b56ec6.png)

```
sudo apt-get install xrdp
sudo service xrdp restart
```
インストールが完了したら、

ラズパイのターミナルでifconfigを実行し、ラズパイのIPアドレスを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1863184/14aff8e9-c24a-c0aa-2c22-4465d3f8ad90.png)

リモートデスクトップのアプリから、ラズパイのIPアドレスを指定してリモートデスクトップ接続します。
私はMacから接続したかったので、こちら(Mac版のMicrosoft Remote Desktop)を使いました。

https://apps.apple.com/jp/app/microsoft-remote-desktop/id1295203466?mt=12

※ラズパイと自分のPCが同じWifiに接続してないと（所属するネットワークが異なるため）、リモートデスクトップ出来ないので注意です。

```
PC name: ラズパイのIPアドレス（Wifi接続用）
User Account: pi (ラズパイのデフォルトrootユーザー)
Password: ラズパイのパスワード
```

私の設定画面はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1863184/22ba96e5-4860-1d1a-638f-c34da4f4aacc.png)


##参照記事

https://tkrel.com/12222
M1Macでnvramいじっちゃって起動しなくなった場合の復旧

ついさっき、M1Macbookで「蓋を開けても自動起動しない」ように設定しようとしていてnvramをいじったら起動しなくなりました。
大慌てでスマホで色々ググったんだけど「無理。OS再インストールしろ」的な記事しか書いてなかったので自分で復旧できた後取り敢えずメモ流しとこうかと。

# 前提
起動しなくなる前に自分が変更した内容を記憶/記録していること。
# やり方
## リカバリーモードにする
あちこちに書いてあるとおり、「起動オプションを読み込み中」と表示されるまで電源ボタンを長押しします。
（既にエラー画面が表示されてて慌ててる場合はまず電源ボタンを長押しして電源切って、少し待ってから上の操作）
## 復旧アシスタントを起動する
まあこれもあちこちに書かれている通り、「オプション→続ける→復旧アシスタントが起動するまで待つ」です。
## ターミナルを起動する
この復旧アシスタントでアップルマークからターミナルをrootユーザで起動できます。
これに気が付かなかったら泣きながらOS入れ直しているところだった。
## nvramコマンドを打って自分の変更したパラメータを元に戻す。
ここで自分が「何をどう変更していたか」がわかってないと詰むので前提として「自分が変更した内容」がわかってないとダメ、という。。。
ひょっとするとnvramを「初期設定に戻す」コマンドがあるのかもしれないんだけど、自分は基本Windowsユーザでマカーではないのでわかりませんでした。
以上で再起動したら動いたので参考になる方は参考にしてね。
# ちなみに
「自動起動しなくする方法」は結局わかりませんでしたとさ（笑）
あ、あと記事を書いたのも初めてなんでMarkdownうまく使えてません、ゴメンナサイ
[Python]ある人の英語ツイートを検知・自動翻訳してツイート

#目標
こちらが指定した人が英語でツイートをした時、すぐに本文をGoogle翻訳で日本語に翻訳して自分のアカウントでツイートする。

#動機
あるスポーツの最新情報をTwitterで発信しているジャーナリストの方がいる。日本を含む世界中で注目度の高い方だが、ツイートは英語。日本人がもっとパッと読みやすい形でタイムラインに流れてくればいいのに、という思いから。

#必要な準備
###TwitterAPIの取得
Twitterにログインして以下のURLからAPIを取得する。必要なのは「APIキー」「APIシークレットキー」「アクセストークン」「アクセスシークレットトークン」の４つ。
https://developer.twitter.com/en/apps/
###Google翻訳のライブラリのインストール
pipコマンドを以下のように使う。「pip install googletrans」だとバージョンが古く、翻訳の部分でエラーが起きるので注意。

```pip install googletrans==3.1.0a0
```

###tweepy
無ければtweepyもインストールしておく。

#インポート
まずTwitterに関するライブラリ
```import tweepy
```
次にAPI認証の際に使うライブラリ
```from requests_oauthlib import OAuth1Session
```
時間に関するもの
```import time
```
最後に翻訳に使うもの
```from googletrans import Translator
```
#APIの認証
取得したキーとトークンを入れる
```API_KEY = ''
API_SECRET = ''
ACCESS_TOKEN = ''
ACCESS_TOKEN_SECRET = ''
```
認証
```auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
```
#ツイートに必要な関数の定義
ネット上の他の方のものを参考にしました。「translated」が翻訳した文章の入ったリストで、頭に＊をつけることでカッコなど不要なものが外れる。

```py
def main():
    makeAPI().update_status(*translated)

def makeAPI():
    return tweepy.API(auth)
```
#検知の仕組みと事前準備
検知には各ツイートに振られるIDを使う。つまり、１番上のツイートのIDが変わったら「更新された」と考える仕組み。そのためにまず準備として現在の１番上のツイートのIDを知っておく必要がある。

最新のツイートのIDを持ってくる
```state = api.user_timeline(screen_name="相手のツイッターのID(@は不要)")
id_form = state[0].id
```

#実行
```py
while True:
  state = api.user_timeline(screen_name="相手のツイッターのID(@は不要)")
  if state:
    id_now = state[0].id
    if id_now != id_form: 
      new_text = state[0].text 
      translator = Translator()
      translated = [translator.translate(new_text ,dest="ja").text] #翻訳
      if __name__ == "__main__":
        main() #ツイートする
        id_form = id_now #新しいidを設定
  else:
    continue
  time.sleep(60)
```
「while True」 で無限ループ
「if state」でstateに中身があるか確認。たまに空のリストになっている(バグ？)
「dest="ja"」は翻訳先が日本語になるような設定

更新時間は60秒で設定したが、1秒でも回る。

#完成
目的の人が半日経ってもツイートしないので、しびれを切らして別の公式アカウントでテスト。うまくいったものの日本語訳が微妙なため、見やすさの観点では当初の理想は叶わず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1868002/4f8e1208-0277-3384-2192-441c86d368e4.png)
初めてのOSSコントリビュートにおすすめのサイト

OSSにコントリビュートしたい気持ちはあれど、はじめは何から始めたらいいかわからないと思います。

Githubでは、初めてコントリビュートする際に着手しやすいissue用に `good first issues` というラベルが用意されています。
それらのissueをまとめているサイトがいくつかありましたので、自分へのメモとしての意味も含めて以下に記載します。

## 参考サイト一覧
#### :star: おすすめ１
個人的にはデザインが一番好み。プロジェクトや選択可能言語も豊富。

https://good-first-issues.page

#### :star: おすすめ２
選択可能言語は1番目のサイトよりも多くはないが、基本的なものはそろっており、デザインも見やすい。

https://goodfirstissue.dev/

#### :star: おすすめ３
こちらも選択可能な言語は1番目のサイトほど多くはないが、程よくまとめられている。

https://goofi.vercel.app/

#### :star: おすすめ４
こちらは `help wanted` というラベルのissueをまとめている。
他のラベルでの検索も可能。

http://github-help-wanted.com/
【個人開発】エンジニアは全員サーフィンやるべきだと思ったので、サーフィンしながらタイピングできるサービスを作ってみた。

# はじめに

![S5ZHskYu8cDwNqRz9V7n1628473413-1628473421.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990592/a7e04000-a8d4-5abd-4405-dfce6e8d829a.gif)





エンジニアやエンジニア志望の皆さん、最後に海に行ったのはいつですか？

元々インドアで仕事や勉強をしがちで、コロナ禍もありよほど好きな人でなければ1年以上海に行ってないのではないでしょうか？

申し遅れました、りゅうじと申します。

【Twitter】

[https://twitter.com/otokomigakimasu](https://twitter.com/otokomigakimasu)

【今回作ったサービス】

[https://surf-typing.herokuapp.com/](https://surf-typing.herokuapp.com/)

サーフィンが好きでよく海に行く私は、普段インドアで仕事や学習を頑張っていらっしゃる皆さんこそ海に行くべきだと断言できます。もっと言えばサーフィンをやってみるべきです。

いつもPCと向き合っていて心身が受けているストレスは無自覚の内に蓄積されています。

その全てを海が洗い流してくれます。

しかし現実的に海が近い場所にないなら簡単には行けないし、サーフィンを趣味としていなければ真夏以外で海に行く事は少ないかと思います。

いつも通りPCを開いて海を感じられながら視覚的にサーフィン体験ができ、仕事や学習の効率化の為にタイピングも練習できて、心が癒されるものがあったらと思い…。

**作りました。**

[https://surf-typing.herokuapp.com/](https://surf-typing.herokuapp.com/)

![SurfTypingイメージ動画.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990592/c7ef1811-b734-a095-5a2c-03840037c081.jpeg)


# サービス概要

サーフムービーをバックに波の音とアコースティックギターの音色を聴きながらタイピング練習ができます。

![a84ce0c9d4cd448fcd2902053b3f69e2 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990592/8d69d596-c269-c0c2-5a16-38ba8e263059.gif)


問題の言葉は私がこれまでの人生で好きな言葉だったり、誰かに頂いた言葉だったり、自分の中で響いた言葉だったり…を出題しています。

人は普段見聞きしている言葉に影響を受けて生きています。

私はこれまでPCを購入してから既存のタイピングゲームを毎日欠かさず練習しておりました。

その中でタイピングゲームの問題の言葉が自身が想像しているよりも心に影響がある事を体感しています。

なので、問題を前向きな言葉だったり自身の思想を元にすれば、タイピングゲームからでも使っていただいた方を癒したり元気づけたり、私の人柄だったり、共有したい言葉を発信できると考えたからです。

![1a18d31a0b3cfdc0fbe2157bbbf859a4 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990592/ef9f05be-e91f-ca02-59bd-e55071663e8f.gif)


# 使用技術

- Ruby 2.6.6
- Rails 6.0.3
- JavaScript

## 主なGem

- meta-tags
- rubocop
- webpacker

# こだわったポイント

### すべての素材を自分で用意しました

使用した動画はGoProという手ブレ無しで撮影できるビデオカメラを購入して撮影してきました。
![D0D5D2A6-A60D-4A9E-BEED-7554326D4578.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990592/3e15c27a-ac9b-c787-c6c2-b75e36710867.jpeg)


流れる波の音・アコースティックギターの音色・メロディも全て自分で作成し演奏しています。

### エラー音はギターのハーモニクスを使いました

エラー音が不快な音だとゲームをしていてストレスを感じます。

不快ではなく、きちんとエラー音として認識できる音を考えた結果、ギターのハーモニクスという綺麗な音が鳴らせる奏法のものを取り入れました。

### 気軽に使ってほしい想いからユーザー登録機能などを排除

いつものPC作業に入る前だったり、合間の時間に使ってほしいと思ったので、極力必要でないと感じた機能を排除する事を意識しました。

### z派 j派 どちらにも対応

こちらは当初のリリース時は対応しておりませんでした。

私自身、対応させたかったのですが

リリース前の開発段階では実装の方法を模索してもわからなく、必要最低限の機能だと感じなかったので、後回しにしMVPという事でリリースしていました。

しかし

- ji 'と'zi '
- 'ju'と 'zyu'
- 'jo'と'zyo'

をどちらにも対応させてほしいという要望を多数頂きアップデート致しました。

# 今後実装したい事

- ステージを複数用意し選択できるようにする
- タイピングの成績の記録を残せるようにする

# 終わりに

最後まで読んでいただきありがとうございました。

色々書いてきましたが、私は海が…サーフィンが…ギターが好きだから、このアプリを作りました。問題の言葉は私の思想であり想いです。なのでこのアプリは私自身です。

私という人間を通して、皆さんが少しでも気持ちが明るくなったり、癒しになってもらえたり…。その中でタイピングが自然と速くなっていく手助けができたら嬉しいです。

それではまたSurfTypingでお会いしましょう！

【Twitter】

[https://twitter.com/otokomigakimasu](https://twitter.com/otokomigakimasu)

【今回作成したサービス】

[https://surf-typing.herokuapp.com/](https://surf-typing.herokuapp.com/)
PostGraphileとは

[PostGraphile](https://www.graphile.org/)(ポストグラファイル)は、PostgreSQLのスキーマからGraphQL APIを構築するミドルウェアです。

## PostGraphileのメリットは工数削減

PostgreSQLのデータベースをすでに使っているなら、PostGraphileを配置するだけで、GraphQLのAPIが手に入ります。一般的な開発方法でGraphQL APIを作ろうとすると、データベースに問い合わせするコードをApollo Serverなどを利用して、プログラマー自身が実装する必要があります。PostGraphileを使うと、そのようなバックエンドプログラミングの工数を大幅に削減でき、開発時間を節約できます。

## PostGraphileの特徴

### PostgreSQLのスキーマからGraphQL APIを自動生成

PostGraphileはPostgreSQLのスキーマから、GraphQL APIを自動生成します。なので、DBのスキーマとGraphQLのスキーマを二重で管理するといった手間はありません。

テーブルの関連も自動で認識されるので、GraphQLの醍醐味のひとつである、関連データをひとつのGQLで問い合わせるのもすぐにできます。

GraphQLのCRUDミューテーションも自動生成されます。また、特殊な処理を行うミューテーションを作りたい場合は、PostgreSQLのストアドプロシージャーを定義した上で、それをGraphQLのミューテーションにすることもできます。

データベーススキーマが変更した際には、GraphQL APIも自動的に新しいスキーマに追従するように作られています。

### オープンソース

PostGraphileはオープンソースで開発されていて、誰でも無料で使えます。クラウドベンダーロックインのリスクがありません。PostGraphileをホスティングするサーバーは自分で選べます。

### 先読みでN+1問題を回避する

PostgreSQLをバックエンドにしたGraphQLは、しばしばN+1問題が起こります。この問題を回避するために、DataLoaderを使ってリクエストをバッチ処理する方法がありますが、DataLoaderは常に最適な方法ではありません。PostGraphileでも、DataLoaderが使えますが、より最適なSQLを出せるように[先読み](https://www.graphile.org/graphile-build/look-ahead/)機能がPostGraphileにはあります。

PostGraphileのパフォーマンスは、改善が重ねられてきており、[Prismaよりもかなり速くなっています](https://medium.com/graphile/how-i-made-postgraphile-faster-than-prisma-1-year-later-e6bf3a802f58)。

### 認可はPostgreSQLのロールベースgrantや行レベルセキュリティーを用いる

データベースをバックエンドにGraphQL APIを構築するミドルウェアは、PostGraphile以外にもHasuraなどがあります。それらと、PostGraphileの違いは、認可システムにPostgreSQLの認可機能をそのまま用いていることです。なので、認可についてミドルウェア独自のACLを学習する必要がありません。PostgreSQLの伝統的なロールベースgrantや、行レベルセキュリティーを学べばよく、これはデーターベース管理スキルとしても応用できるスキルになるので、学びが無駄になることが避けられます。

### GraphQLのサブスクリプションに対応

チャットアプリやGoogle Docsのようなアプリでは、リアルタイムにデータベースの変更イベントを受信する必要があります。このようなリアルタイム要件を達成するために、GraphQLにはサブスクリプションがあります。PostGraphileはGraphQLのサブスクリプションに対応しています。PostgreSQLの`LISTEN`/`NOTIFY`を用いて実現しています。

### 起動方法がシンプル

PostGraphileはNPMパッケージとして提供されています。そのため、インストールが簡単でDockerなどの環境がなくとも起動できます。NPMがインストールされていれば、次のような1行のコマンドで起動できます:

```
npx postgraphile -c 'postgres://user:pass@localhost/mydb' --watch --enhance-graphiql --dynamic-json
```

もちろん、Docker上で起動することもできます。

### プラグインによる拡張

PostGraphileにはプラグイン機構があります。必要に応じてGraphile Engineに機能を足せます。

## つづき

https://qiita.com/suin/items/55fc2ff9184c303bb4d0
matplotlibで日本語表示ができなくなって困った件

#はじめに
ubuntu20.04 on wsl2にて久々にmatplotlibを使ってグラフのプロットをする際に日本語表示ができなくなって困った際のメモ

#やったこと1
こちらを参考にイチから動作確認
https://pystyle.info/japanize-matplotlib-just-by-copying-and-pasting/#outline__5

ここに書いてある通りに行うと、正しく日本語は表示された。フォントとか環境的には問題ないっぽい

#やったこと2
やったこと1の操作を自分のコードに加えてみると以下のようなメッセージが表示されてNG

```
.... RuntimeWarning: Glyph 27 missing from current font
```

これは自分のコードになにか問題があると確信した。取り急ぎ以下を確認

```
linux$ file myplotsample.py
Python script, ASCII text executable
```

あれ、UTF-8になっていない。これはまずいかも、ということで以下の操作を実行。

```
linux$ nkf -w --overwrite myplotsample.py
linux$ file myplotsample.py
Python script, UTF-8 Unicode text executable
```

これにて問題は解消され、所望の日本語表示ができた。

#まとめ
文字コードは念のため確認すべきと反省。エディタの設定がまずかったのかも…