OmniAICreator/Qiita-1.07M huggingface dataset:
手書き数字認識(k-nn)

# やったこと

今回、機械学習のアルゴリズムk近傍法(k-nn)を用いて手書き数字認識を行った。

## データの読み込み
```python
from sklearn.datasets import fetch_openml

mnist = fetch_openml("mnist_784")
```
sklearnのメソッドfetch_openmkでMNISTから手書き数字データmnist_784を取得する。
mnist_784は
* 訓練データ6万枚、テストデータ1万枚の計7万枚の画像量
* 28(縦)×28(幅)ピクセル
* 8bitグレースケール＝（白黒画像）白「0」～黒「255」

の画像データである。今回は学習時間を短縮するために
(訓練データ,テストデータ)=(500,100),(5000,1000)で学習させた。

## データの分割
MNISTより取得した画像データを訓練データとテストデータに分割する。割合は8:2とした。
```python
from sklearn.model_selection import train_test_split
import numpy as np
train_size = 5000 #訓練データ
test_size = 1000 #テストデータ

X_train, X_test, y_train, y_test = \
    train_test_split(mnist.data, mnist.target, stratify=mnist.target,random_state=66,train_size=train_size,test_size=test_size)
```
* `train_test_split`はnp配列をランダムに2分割する。
  * `mnist.data`はデータ数×特徴量の2次元配列である。
  * `mnist.target`はmnist.dataに対応するラベルを表す。(mnist.data[0]のラベルはmnist.target.[0])
  * `stratify`は層化抽出を行う（同じ割合データを分割）。
  * `random_state`は乱数シードを固定できる。固定することで常に同じように分割することが出来る。毎回ランダムに分割されると学習モデル同士の比較が正しく行えなくなる。

参考：https://note.nkmk.me/python-sklearn-train-test-split/


## 学習
```python
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

training_accuracy = []
test_accuracy = []

n_neighbors_settings = range(1,11)

for n_neighbors in n_neighbors_settings:
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    clf.fit(X_train,y_train)

    training_accuracy.append(clf.score(X_train, y_train))
    test_accuracy.append(clf.score(X_test,y_test))
```
`skelearn`から`KNeighborsClassfier`をインポートする。今回はk=1,2,...,10としてk近傍法アルゴリズムを適用する。`training_accuracy`は各kに対する訓練データの正解率の配列を表し、`test_accuracy`は各kに対するテストデータの正解率の配列表す。学習結果をその配列に加えていく。

## 実行結果

* train_size=500,test_size=100の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627192/50787a3a-79b7-e3cd-c8d4-2209401fb669.png)
スイートスポットはk=7のときである。また、全体的に精度が悪い。
次にtrain_size=5000,test_size=1000として学習させる。

* train_size=5000,test_size=1000の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627192/b29f508b-57a1-b0d4-7bde-a498521bb33a.png)
スイートスポットはk=5のときである。また、training_size=500,test_size=100のときと比べて精度が全体的に良い。k=5のときテストデータに対する精度は95%であるから十分な精度といえるだろう。

## 予測する様子
* train_size=5000,test_size=1000のデータセットで学習させたk=5のとしたk-nnである。
```python
#n_neighbor=5としたknnの学習モデル
plt.imshow(X_test[0].reshape(28,28),cmap="gray")
print(f"実際の値：{y_test[0]}")
print(f"予測した値：{clf2.predict(X_test)[0]}")
```
以上のようにコードを書いて予測しているか見てみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627192/b9e40997-f9e8-533f-8161-f7798f20faea.png)
結果は以上のようになり正しく予測できているといえる。

## おまけ
* matplotlibでのグラフの描画の方法
```python
plt.tick_params(colors="white")
plt.plot(n_neighbors_settings,training_accuracy,label="training_accuracy")
plt.xticks(np.arange(0,11,step=1))
plt.plot(n_neighbors_settings,test_accuracy,label="test_accuracy")
plt.ylabel("accuracy",color="white")
plt.xlabel("n_neighbors",color="white")
plt.legend()
plt.grid()
```
`plt.xticks`はx軸の範囲を指定し、ステップ数を決める
`plt.ylabel`はy軸の名前を決め、文字の色を指定
`plt.xlabel`はx軸の名前を決め、文字の色を指定
`plt.legend`は各グラフの説明を追加
`plt.grid`はグリッドを追加（目盛り）
【Rails】loggerの出力をminitestでテストする方法

コントローラのテストをする際に、logger出力のテスト方法につまったので、備忘録として残します。他にいい方法があれば教えていただけると幸いです。

## バージョン

Rails 6.1.5

## 実装方法

適当なアクションに遷移した時にlogを吐く場面を想定します。

```ruby
class XXXController < ApplicationController

  def index
    logger.info "通ったで"  #ここを検出したい
  end

end
```

ログの内容をテストします。

```ruby
# stubを使用するために必要
require 'minitest/mock'

# 略

test 'logger.info を出力' do
  http_method = lambda { get staffs_path }
  logs = get_logs(http_method)
  expected_message = "通ったで"

  # logsのなかに期待するlogがあるかどうかでassert
  assert(logs.includes?(expected_message))
end

# 略

# アクション内で発生した複数のlogを配列として返す
# ①アクション内でinfoが呼ばれる
# ②infoがstackに置き換わる
# ③log_arrayにloggerの内容が格納される。
# ①-③の繰り返し
def get_logs(http_method)
  log_array= []
  stack= proc { |log_arg|
  log_array.push(log_arg)
    }
# stubメソッドにより、infoが呼び出される際に、処理がstackに置き換わる
  Rails.logger.stub(:info, stack) do
    http_method.call
  end
  log_array
end
```

## 備考

railsではアクションに遷移した際に以下のように複数のlogを吐いているため、「想定されるlogがあればテストに成功」という方法をとりました。

```ruby
nil
"Processing by XXXController#index as HTML"
nil
"通ったで"
nil

```

また、`http_method`の中身は以下のように`params`を渡すことデータの更新時のテストにも使えそうです。
```ruby
lambda { post login_path, params: { session:
                                          { email: 'sample@sample.com_1',
                                            password: 'password' }}
    }
```

## 参考

[minitestでloggerの出力内容をテスト](https://qiita.com/inocof/items/f13e04c195cf2a62d109)
EC2上のLaravelプロジェクトでmbstringが使えない

# エラー内容
EC2上にデプロイしたらパスワード変更メール送信時に以下のエラーが出た。
```
Call to undefined function mb_strcut()
```

# 原因
ローカルで開発していた時にはデフォルトでmbstringがインストールされていたが、EC2上ではmbstringをインストールしないといけないらしい。

# 対策
①php-mbstringをインストール
②php.iniを編集
③php-fpmを再起動

### ①php-mbstringをインストール
```
sudo yum install php-mbstring
```

### ②php.iniを編集
php.iniは記述量が多いので/mbstringで探す。
```/etc/php.ini
;mbstring.language = Japanese
↓
mbstring.language = Japanese

;mbstring.internal_encoding = 
↓
mbstring.internal_encoding = UTF-8

;mbstring.http_input =
↓
mbstring.http_input = auto

;mbstring.http_output = 
↓
mbstring.http_output = UTF-8

;mbstring.encoding_translation = OFF
↓
mbstring.encoding_translation = On

;mbstring.detect_order =
↓
mbstring.detect_order = auto
```

### ③php-fpmを再起動
```
sudo systemctl restart php-fpm
```

これでメールが正常に送信された。
logの設計がなぜ後回しになるか自分なりにまとめてみた

# 概要
最近、エンジニアとして働く中で、logの重要性について痛いほど思い知らされたので、ここにlogの重要性をまとめてみることにしました。
今までは、正常に動くことを目的とした基礎設計にばかり目を奪われ、アプリケーションを長く、安全に運用していくという視点が完全に抜け落ちていました。logは、大きく分けると「正常系」と「異常系」に分けられますが、その中でどのようなlogを残すべきなのか、どうやってlogを観察するのか、自分なりに調べまとめておきます。もし興味があったら最後までお付き合いください。

# logの分析が後回しになる３つの理由
近年になって、webアプリケーションが数多くの企業に生産、そして、運用される中でlogはとても重要な位置を占めています。その重要性は大きく分けると二つあると考えられます。
一つ目は、「**分析のためのlog**。」これは、アプリケーションが多くのユーザーに使用されればされるほど重要性が増します。amazonショッピングなどでは、各ユーザーのlogを取得、分析し、精度の高いレコメンデーションを行ってくれています。
二つ目が、「**不正アクセスを検知するためのlog**。」これは、サイバー攻撃の検知をいち早く行い、エンドユーザーを守るために使用されます。
このような重要性を持つlogですが、logの取得・分析は後回しにされがちです。では、なぜlogの取得・分析は、後回しにされがちなのか。私の経験上、３つの理由があると考えています。

- アプリケーションの要件定義段階で異常系の設計が抜け落ちてしまっている
- アプリケーションの仕様を満たすために用意されたエンジニアリソースが少なく、開発時間が限られてしまっている
- 膨大に記録されたlogを分析するには、忍耐が求められる

以上の理由となります。
以下でそれぞれについて自分なりに考察していきます。

# アプリケーションの要件定義段階で異常系の設計が抜け落ちてしまっている
これは、アプリケーションを開発する前段階です。アプリケーションに求める要求が高く、仕様を設計する人数も限られているときに起こりやすいです。顧客が求める要求がシンプルだということはほぼありません。基本的には、複雑でシステム設計者がシンプルにしていくことを強く求められます。また、顧客はアプリケーションが正常に動くことを前提に話を進めます。どのようなバグが起きるかを想定して対話することは、顧客が熟練のシステム設計者でない限りは難しいでしょう。

# アプリケーションの仕様を満たすために用意されたエンジニアリソースが少なく、開発時間が限られてしまっている
これは、アプリケーションを開発段階です。短納期なweb開発を求めらた時に起こりやすいです。競合が増えやすい状況下で、ビジネスサイドの要求は高く、かつ、スピードが求められます。新人エンジニアは特にですが、正常系の動作に気を取られてしまいます。これは、ＱＡエンジニアの話しの中でよく話題に上がることですが、「**開発者は、成功させることをモットーに、テスターは、失敗させることをモットーに設計を行う**」と言われてます。短納期であることは、この格言をさらに強調させるでしょう。

# 膨大に記録されたlogを分析するには、忍耐が求められる
これは、開発後のことです。膨大なlogを分析することは、時に人間の認識能力を凌駕することさえあるでしょう。logを取得することに成功したとて、膨大に取得されたlogをいつ、だれだ、どこで、どのように分析するのかが、はたまたそのリソースはあるのか。この問題に取り組めるほどの人的リソースの余裕と思考を持ち合わせることは非常に難しいでしょう。

# ではどうすればよいのか
結論から言うと、ログの設計をする時間をとれるように交渉する、以外に解決策はないように思っています。
元も子もない結論ですが、アプリケーションの設計は開発工程における最重要ポイントです。
ウォーターフォールであろうとアジャイルであろうと、（それは設計の粒度と速度の問題であって）設計をしなくて言い訳ではありません。
ログの設計もその例外ではないと思っています。

# まとめ
備忘録含めて僕の考えをまとめておきました。
今度はどうやったら良いログの設計ができるかコーディング含めてまとめてみようと思います。
いろいろな考えがあるとは思いますが、何か良い考えがあればご教授いただきたいです。
よろしくおねがいいたします。
【🔴エラー対応】Herokuデプロイ時に「Webpaker::Manifest::MissingEntryError」【javascript_pack_tag】

# 🔷注意
- 本エラーは、「Bootstrap5」+「Rails6」の環境で発生する模様

# ✅当方の環境
- 開発環境 : Docker
- 本番環境 : heroku
- Gemfileの内容
  - ruby 2.7.5
  - rails 6.1.5
  - webpacker 5.0

# ✅関連キーワード
- %= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
- Bootstrap導入したらエラーが発生
- Webpaker::Manifest::MissingEntryError
- status=500
- 「application.html.erb」でエラーが発生
- Herokuデプロイ時のエラー

# ✅エラー内容
- Herokuのログの内容（heroku logs -t -a アプリ名）※一部抜粋
```
Started GET "/" for at 2022-04-12 07:59:45 +0000
 Processing by TopController#index as HTML
 Rendered top/index.html.erb within layouts/application (Duration: 0.7ms | Allocations: 292)
 Rendered layout layouts/application.html.erb (Duration: 1.8ms | Allocations:

 Completed 500 Internal Server Error in 7ms (Allocations: 2415)

 ActionView::Template::Error (Webpacker can't find application.css in /app/public/packs/manifest.json. Possible causes:
 1. You want to set webpacker.yml value of compile to true for your environment
 unless you are using the `webpack -w` or the webpack-dev-server.
 2. webpack has not yet re-run to reflect updates.
 3. You have misconfigured Webpacker's config/webpacker.yml file.
 4. Your webpack configuration is not creating a manifest.
 Your manifest contains:
```

# ✅エラー箇所

```言語:app\views\layouts\application.html.erb
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> #この行でエラーが発生している
```

# ✅エラー発生状況/経緯
- Herokuのみでエラーが発生
- ローカル（Docker）では、エラーは発生していない
- BootstrapのCSSをWebpackerで導入(yarnで実施)してからエラーが発生
- BootstrapをCDNで導入した場合は、Herokuではエラーが発生していない

# ✅エラー原因
- Webpackerの動作が、ローカル環境(development)と本番環境（production）で違うから

# ✅エラー対応
-  Webpackerの動作を、ローカル環境(development)と本番環境（production）共に一緒にする
```言語:config\webpacker.yml
production:
 <<: *default

　　compile: true
　　extract_css: false
　　cache_manifest: false

```
:::note alert
「production」の下部にある設定を修正してください
:::

## 🔴補足：上記3つの説明
| オプション | true| false |
|:---------------|:------------|:------------|
| compile | Railsページが読み込まれると必要に応じて自動的にコンパイル|手動でコンパイルが必要 |
| extract_css | linkを出力| JavaScriptを使って動的にCSSを読み込む|
| cache_manifest | manifest.json の読み込み| manifest.json の読み込まない|




# ✅エラー参考資料
- [herokuへデプロイする際のWebpaker::Manifest::MissingEntryErrorというエラーの対処法まとめ]( https://qiita.com/ArakawaYukihiro/items/bb9d548c9887fcfba019)
- [Railsのstylesheet_link_tagとstylehseet_pack_tagの違いや使い所ついて調べてみた](https://zenn.dev/ryouzi/articles/da8a77accc221e)
PHPのパスを変更

# バージョンを確認
PHPのバージョンを確認するには

```php
taro@MacBook-Pro % php -v
PHP 8.1.4 (cli) (built: Mar 18 2022 09:46:02) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.4, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.4, Copyright (c), by Zend Technologies
```

使用する PHP を確認するには

```php
taro@MacBook-Pro ~ % which php
/usr/local/bin/php
```

# .bash_profile の変更
MAMPのPHP にパスを通すには、次のコマンドを実行するみたいです。

```
$ export PATH=/Applications/MAMP/bin/php/php*.*.*/bin:$PATH
```
1点注意点で　```*.*.*``` は使用するバージョン番号を入れるみたいです。

***.から始まる場合は隠しファイル***です。
```
$ ls  -a
```
で隠しファイルまで見れます。

Laravelを使う場合のバージョンはPHPのバージョンが7以上じゃないといけないみたいです。
Laravel6ではPHP7.2以上、Laravel8ではPHP7.3.0以上が必要みたいです。

ターミナルで常にMAMPのPHPを優先的に使うとき、
ユーザーのホームディレクトリーの .bash_profile ファイルにこのコマンドを追記するみたいです
.bash_profile ファイルがない場合は作成します。

.bash_profile への追記が終わったら、次のコマンドで反映させます。
```
$ source  .bash_profile
```
これでバージョンが変わるはずです。










# 参考資料
https://www.konetacho.com/post/151.html
rsyncしてみる

## rsync とは

ネットワークを通じて、ファイルやディレクトリをsyncするものです。
もちろんlocalでの使用もできます。

### やってみる

#### 構成

- 構成

構成のイメージとしては以下になります。
サーバをまたいであるディレクトリ配下が同期される感じです。

![12022-04-12 rsyncコマンド使ってみる - diagrams.net - Google.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/f8f4d3fe-d69c-cbb9-a7c4-4302697b0775.png)


- 設定

```
- 同期元 : 192.168.156.121 : /var/tmp/test
- 同期先 : 192.168.156.122 : /var/tmp/test_dir
```

#### 同期元サーバの設定

- 同期ディレクトリの作成

```
mkdir /var/tmp/test
```

- rsyncのインストール

```
yum -y install rsync
```

#### 同期先サーバの設定

- 同期ディレクトリの作成

```
mkdir /var/tmp/test_dir
```

- rsyncのインストール

```
yum -y install rsync
```

- rsyncの設定

`[testdir]` : 名前をつけました。なんでもいいです。
`path` : 同期先のディレクトリを指定
`hosts allow` : 同期元のサーバを指定

```
vi /etc/rsyncd.conf
==========
[testdir]
path = /var/tmp/test_dir
hosts allow = 192.168.156.121
hosts deny = *
list = true
uid = root
gid = root
read only = false
==========
```

- 起動・自動起動設定

```
service rsyncd start
service rsyncd enable
```

#### 同期元サーバから同期をかける

- あらかじめファイル置いておく

```
touch /var/tmp/test/a.txt
```

- 同期を行う

`rsync [オプション] 同期元ディレクトリ 同期先サーバ::任意の名前` で同期できます。

オプションは以下になります。
`-a` : アーカイブモード
`-v` : 動作内容の表示
`-z` : 転送中のデータを圧縮
`--delete` : 同期元にないファイルを同期先から削除する

```
rsync -avz --delete /var/tmp/test/ 192.168.156.122::testdir
```

```
sending incremental file list
./
a.txt

sent 107 bytes  received 45 bytes  304.00 bytes/sec
total size is 0  speedup is 0.00
```

## 勉強後イメージ

どっかでやったような気もするけど、ちょっと残したかったので書いてみた。
思ったよりオプションが豊富だった。

## 参考

- [Rsync : ファイル/ディレクトリの同期](https://www.server-world.info/query?os=CentOS_7&p=rsync)
- [リアルタイムミラーリングツール導入(Lsync+Rsync)(CentOS7)](https://sudachi.jp/wiki/%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%9F%E3%83%A9%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%84%E3%83%BC%E3%83%AB%E5%B0%8E%E5%85%A5(Lsync%2BRsync)(CentOS7))
Power Queryでプロ野球の歴代最高打者を決める



NPBのサイトからデータを引っ張って以下の計算をします。

（安打数÷年数）×（打率）

適当に思いついたので、この計算がイミフだったらだれかおしえてください

https://npb.jp/bis/history/ltb_avg.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/1c8936a2-fdb2-2e6a-f528-fc00ecad56f6.png)


ExcelでWebのクエリを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/eafc75e5-d8f9-b6c1-8e58-ceb796a3430a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/dc7a7c7a-e192-ed44-3d68-954fe09e96a1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/0eb7a671-08e2-045d-8c9b-4a11a630aa1f.png)

年数を分割
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/da5d0819-dcc7-5ae8-decf-0d3b982ee0c8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/71060ff5-ff8d-101e-68dc-1c39140fe27d.png)

トリミングして数値に変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/ec890655-f168-c18f-aaf9-37e20b2bcc6a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/e0ca9f01-9bf5-415b-b12a-b1bd375b56ae.png)

現役年数を計算
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/5251f29d-9841-de82-e2be-483e0ef9f9b9.png)

安打数を年数で割る（実効率その1）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/c6a9d139-50df-cb62-ec95-4d726d3849a4.png)

打率を整数に変換（実行率その2）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/fac13151-085d-259c-9e90-8d04c5e4865c.png)

実効率1と2を掛け算
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/c9e3644e-7db1-a2b8-af78-b31aed7055c9.png)

実効率の結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/57eb885b-6f8e-4ff9-0b0e-bb7b09a5b009.png)

Excelシートに書き出し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593011/498fbe0e-ac62-8192-4066-46fa66dd1959.png)

というわけで秋山選手が歴代1位でした。あと外国人選手がなぜか高い

「記憶に残る選手」として有名な長嶋とマツイが上位なのは、関係あるのでしょうか？面白い

あとeffectivenessじゃなくてefficiencyのほうがよかったですがどうでもいいですね
PHP、Laravelのbladeファイルの中でプルダウン形式を使用した

select文の中にif文を記述して、
プルダウン形式を記述したときの内容をまとめます。


行いたい処理。
3種類の会員(無料会員 id=1、トライアル会員 id =2、プラミアム会員 id=4)
がコントーローラーから配列渡せれてきて、
プルダウン方式で選択し更新できるようにしたい。

結果のコード。

```show.blade.php
<form id="edit" action="{{ route('memberlist.update', ['id'=>$user['id']]) }}" method="post" class="contents-memberdetails-remarks">

<select name="user_type">
<option></option>
@if ($user['user_type'] == 1)
<option value="1" name="user_type" selected>無料会員</option>
<option value="2" name="user_type" >トライアル会員</option>
<option value="4" name="user_type" >プレミアム会員</option>
@elseif($user['user_type'] == 2)
<option value="1" name="user_type" selected>無料会員</option>
<option value="2" name="user_type" >トライアル会員</option>
<option value="4" name="user_type" >プレミアム会員</option>
@else
<option value="1" name="user_type" selected>無料会員</option>
<option value="2" name="user_type" >トライアル会員</option>
<option value="4" name="user_type" >プレミアム会員</option>
@endif
</select>
```

記述内容説明。
@if文で
ユーザータイプ１なら無料会員。
ユーザータイプ２ならトライアル会員。
ユーザータイプ４ならプレミアム会員。
を表示させる記述。

selectedの記述は、デフォルトで表示させたい項目を指定できるので、
ユーザータイプ１の項目は無料会員の欄に記述。
ユーザータイプ２の項目はトライアル会員の欄に記述。
ユーザータイプ４の項目はプレミアム会員の欄に記述。
しました。
Slackでの会話で絶対にしてはいけない3点

リモートワークの普及により、社内コミュニケーションにはメールではなくチャットツールを使っている会社も多いと思います。

Teams,Chatwork,LINE Works…数あるチャットツールのなかでも、特にエンジニアに親しみのあるのがSlackかと思います。

もちろん私も公私ともにSlackユーザなのですが、今回はそのSlackを使うにあたって、実際に自分が気を付けている3点についてご紹介します。
（異論・反論あるかと思いますが、個人的見解なのであしからず）

# 「??」で相手を煽る
「〜でしょうか。」と句読点で終わるよりもクエスチョンマークを付けることで、視覚的に「**ここは質問なんだな**」と相手に伝えることができると思います。
しかしこれを付けすぎると、この文章は質問である、という文脈を超えて**相手への非難**という余計な意味合いまで付けてしまうような気がします。
```
ここは〜という意味なんですか???
```
特にこれが数十の返信が飛び交うスレッドみたく、西部戦線のようなバチバチの膠着状態に放り込まれるとアブナイ。
オフラインでの仲に影響する恐れも…

チャットではどうしても非言語情報を付けづらく、思わぬ印象を相手に与えてしまうことがあるので、文章が与えるニュアンスには注意が必要だと思います。
それに付随して、私はあえて句読点の代わりに「!」などの抑揚や、ソフトな絵文字を使うこともあります。😄😊😅
「。」だけで終わると、なんだかクールな、ちょっと怒っているような？ニュアンスが付いてしまうような気がしますので…

上司にこのあたりうまく使い分けている人がいらっしゃるので、ぜひ真似したい。


# リンクのプレビューでタイムラインを埋める
これは技術ブログなどリンクを相手に共有する際の注意です。
「これを参考にこう書きました！」「こんな技術があります」「これを参考に書いたんですけどうまくいきません…」と、リンクを先輩や上司に送る機会はたくさんあると思います。

ただ、このリンクに付随するプレビュー、これが結構画面上を支配するんですね。特に2個も3個も貼ると、13インチノートPCならすぐに画面が一杯。
人って、自分宛てに送られてきた画面いっぱいの文字を見るとドッと疲れませんでしょうか。

プレビューは左上の✗を押すことで簡単に消せるので、文章をスッキリとさせたいときに便利かと思います。
また、Slackは文章にリンクを付けることもできるので、URLをベタ打ちするよりはスマートに文章を見せることも出来ます。

# 「何をしてほしいか」分かりにくい文章を送る
結局、「堅苦しい」「仰々しい」と散々バカにされているメールって、実はよく出来ているんです。
メールにあって、チャットにないもの。それは「**件名**」です！
この件名という短いサマリー文を読むことによって、一昔前の多くのビジネスマンはメール本文を読む前に「この文章はいまからこういうことを自分にしてほしいと伝えるんだな」というマインドセットを作ることが出来ていたのだと思います。

これについては昨年9月に見た、若くしてIT企業のPMを担っているYouTuber「ぴろり」さんから学んだので、こちらもぜひ視聴いただければなと思います。

https://www.youtube.com/watch?v=5JCGIpO_Suc&t=477s

この方が実践されているのは、部下に対してSlackでの依頼に使うテンプレートを用意したことなんですね。
```
【依頼】hogehogeしてください（期限：XX/XX AM○時まで）
```
的な。
ここの【依頼】のところは【お願い】でも、【質問】でも、【相談】でも、何でもいいと思います。
**相手に何をしてほしいか、1行目で伝えているのがポイント。**

よくやりがちなレスで、こんなものがあるかと思います
```
〇〇をしたく、XXをしてみました。
でも結局うまく行かず、次に▲▲をしてみようと思いました。

〜〜
（ここから100行くらい事情説明）
〜〜
でも最終的にうまくいきませんでした。締め切りが明日です。どうすればいいですか？
```
こんなSlackが来たら、誰もが「知るか！」と答えたくなるはず。
コミュニケーションとはいえ、相手の時間を使うという意識が大切である気がします。

さらに言えば、ぴろりさんのテンプレートは期限や（予想の）所要時間を設けているのがすごい。
期限を決めてしまうのは相手の忙しさを考えてしまうと少し気が引けて、とはいえこちらも早く処理してほしいので、あえて明言しない「**なるはやで**」になってしまいがちですが、明確な期限がないと相手もやる気を出しづらいはず。
スケジュール的に無理であれば相手から「その期日までには出来ません」とレスが来るはずなので、恐れずに期限を書いたほうがいいかと思います。
これは自戒も含めて…

正確ではないかもしれないですが、自分で考えた上での所要時間も記載することで、相手はそのタスクのウェイトを図ることができると思います。
特に激務な先輩エンジニアは差し込み案件の数も相当あると思いますので、この情報があるだけで差し込み案件の優先順位付けにかなり役立つのではないかと思います。
CustomEditorで変数を表示しているラベルがマウスオーバーしないと更新されない問題

# 問題
以下のコードは値を保持してChangeValue()が呼ばれた時だけ値を変更するシンプルなスクリプトと、それを表示するEditor拡張です。
```HaveValue.cs
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

internal class HaveValue : MonoBehaviour
{
    private string value = "";

    public void ChangeValue(string value)
    {
        this.value = value;
    }

#if UNITY_EDITOR
    [CustomEditor(typeof(HaveValue), true)]
    public class HaveValueEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            var _target = target as HaveValue;
            EditorGUILayout.LabelField($"{_target.value}");
        }
    }
#endif
}
```
これでも確かに値は表示されますが、マウスオーバーしないと表示を更新してくれないという欠点があります。

# 解決法
以下の一行を追加するだけです。
```Add.cs
public override bool RequiresConstantRepaint() => true;
```
Repaint、つまり再描画がEditor拡張なりEditorWindowを作る時に度々問題になるようです。
(頭の片隅に入れておこう、またこの単語は検索する気がする)
幾つか描画を更新できそうな方法は見つけましたが、
今回はシンプル故、ボタン操作のタイミングで再描画をするといった対応が出来ないため、
RequiresConstantRepaint()が最も目的に合っていると思います。

# 最終コード

```HaveValue.cs
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

internal class HaveValue : MonoBehaviour
{
    private string value = "";

    public void ChangeValue(string value)
    {
        this.value = value;
    }

#if UNITY_EDITOR
    [CustomEditor(typeof(HaveValue), true)]
    public class HaveValueEditor : Editor
    {
        public override bool RequiresConstantRepaint() => true;

        public override void OnInspectorGUI()
        {
            var _target = target as HaveValue;
            EditorGUILayout.LabelField($"{_target.value}");
        }
    }
#endif
}
```

# 参考
こちらの記事を見つけて解決しました。感謝です。

https://qiita.com/Rijicho_nl/items/467458decdd119577245

Qiita上だとRequiresConstantRepaint()が書かれた記事はこれしか見つけられませんでしたが、
実装例までは書かれていなかったので本記事を書きました。
こちらの記事はその一歩先の話をされています。
MudBlazorを使ってBlazor ServerのCRUDアプリのサンプルを作ってみた

この記事では、Blazorで簡単なCRUDアプリケーションのサンプルを公開したいと思います。Blazorではスキャフォールディングで簡単にCRUDを作成するような機能がないため、簡単なデータの一覧画面や編集を行う画面のサンプルを作成しました。

実際にアプリケーションを作成していただく際に、少しでも参考になれば幸いです。  
汎用的に利用できればと思い、自社（インフラジスティックス・ジャパン）のコンポーネントは使用せず、MudBlazorを利用しております。  

# MudBlazorとは
Blazor用のMaterial DesignなUIコンポーネントライブラリのひとつです。
MudBlazorを含め、その他のコンポーネントについても以下で紹介されておりますので、ご参考ください。

https://qiita.com/jsakamoto/items/da7f978e1281fabb6093

# MudBlazorの導入

公式サイトではコマンドで導入して行く手順も掲載されておりますが、テンプレートを導入すれば、Visual Studioの新しいプロジェクトの作成画面で選択できるようになります。

以下のコマンドで、MudBlazorのテンプレートが追加されます。※Visual Studio 2022及び.NET6が導入済みの前提で進めます。
```
dotnet new --install MudBlazor.Templates
```

Visual Studioで新しいプロジェクトを作成しようとすると、MudBlazorのテンプレートが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158398/5aadd5c7-d462-1992-4b77-0906c6f85d9c.png)

こちらのテンプレートを使用することにより、最初からMudBlazorが導入済みのプロジェクトを作成できます。

# サンプルアプリケーション

ユーザー情報を管理できる簡単なCRUD機能を実装しております。

### 一覧画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158398/6bdcbb34-f750-ae45-342f-0df318f70717.png)

### 新規画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158398/898385f7-7536-ccc5-e83b-cb287bfcf9b2.png)

### 編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158398/92cbcdbd-8564-9edf-9348-199881480c11.png)

### 削除画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158398/1e631463-b350-a1ca-ae1f-e4a59bc16a4b.png)

## サンプルプログラムのソースコード
https://github.com/yoshi1220/BlazorServerCRUDSample

# まとめ

DBアクセスやビジネスロジックなどについても基本的な部分は実装しております。これからBlazorで開発されるかたの参考になれば幸いです。
プログラミングノート（モダンJavaScript）

# はじめに
Udemyの[【世界で7万人が受講】Understanding TypeScript 日本語版](https://www.udemy.com/course/understanding-typescript-jp)を参考に一部JavaScriptを学習したので、プログラミングノート（カンペ用ノート）をします。

# letとvar
letを使うべき(ベストは全部const)
```js
// varはグローバルスコープまたは関数スコープ
function add(a: number, b: number) {
  var result; // これは関数スコープ
  result = a + b;
  return result;
}

if (age >= 20) {
  var isAdult = true; // これはグローバルスコープ
}
console.log(isAdult); // undefined

// letはブロックスコープ
if (age >= 20) {
  let isAdult = true; // ブロックスコープ
}
console.log(isAdult); // エラーになる
```
※以前記載の誤りを指摘いただいていましたが、下書きに戻せなかったので、一旦削除して修正後再投稿しました。
　ご指摘いただいた方ありがとうございました。

# アロー関数

## 基本的なアロー関数
```js
const add1 = (a: number, b: number) => {
  return a + b;
};
console.log(add1(2, 5));

```
## 右側の中括弧に式が一つの場合は省略可能
```js
const add2 = (a: number, b: number) => a + b;
console.log(add2(2, 5));
```
## パラメータが一つの場合は左の（）が不要
```js
const printOutput: (output: string | number) => void = output => {
  console.log(output);
};
printOutput(add1(2, 5));
```
※ 「string|number型の引数とvoidの戻り値を定義した関数型」という型定義を最初に入れている

# デフォルト値
一番右の引数だけ設定が可能。
```js
const add = (a: number, b: number = 1) => {
  return a + b;
};
console.log(add(2));
```

# スプレッド演算子
```js
const hobbies = ["Sports", "Cooking"];
const activeHobbies = ["Hiking", ...hobbies]; 
activeHobbies.push(...hobbies); 
```
##  （おまけ）アドレス渡しと値渡し
```js
const person = {
  name: "Max",
  age: 30,
};

const copiedPerson_address = person; // アドレス渡し。値はコピーしていない。
const copiedPerson_value = {
  ...person,
}; //値渡し

```

# レストパラメータ
任意の数を受け取る
```js
const add3 = (...numbers: number[]) => {
  return numbers.reduce((curResult, curValue) => {
    return curResult + curValue;
  }, 0);
};
const addedNumbers = add3(5, 10, 2, 3.7);
console.log(addedNumbers);
```

# 分割代入
配列やオブジェクトを分割して取り出す
```js
const hobbies = ["Sports", "Cooking"];
const activeHobbies = ["Hiking", ...hobbies];

const [hobby1, hobby2, ...remainingHobbies] = hobbies;
```
## オブジェクトの場合
```js
const person = {
  firstName: "Max",
  age: 30,
};

const { firstName: userName, age } = person; //キーをuserNameで上書き 
```
Pythonで標準化、分散、偏差値を求めるなど

```Python
#!/usr/bin/env python
# coding: utf-8

# In[3]:


import pandas as pd
df = pd.read_csv("../../data/hensachi.csv")


# In[4]:


df.head()


# In[6]:


Amean = df['pointA'].mean()
Bmean = df['pointB'].mean()
print(Amean)
print(Bmean)


# In[7]:


def bunsan(array):
	""" データの配列から分散を求める """
    S = 0
    for i in array:
        S += (i - array.mean()) ** 2
        return S
    
bunsanA = bunsan(df['pointA'])
bunsanB = bunsan(df['pointB'])

hyoujyunhensaA = bunsanA ** 1/2
hyoujyunhensaB = bunsanB ** 1/2

print(bunsanA)
print(bunsanB)
print(hyoujyunhensaA)
print(hyoujyunhensaB)

        


# In[9]:


# 標準化

def standardize(array):
	""" 標準化を行う """
    s = bunsan(array) ** 1/2
    result = [(i - array.mean()) / s for i in array]
    return result

stanA = standardize(df['pointA'])
stanB = standardize(df['pointB'])

print(stanA)
print(stanB)


# In[10]:


# 偏差値
def deviation(array):
	""" 偏差値を求める """
    return [i * 10 + 50 for i in array]

hensachiA = deviation(stanA)
hensachiB = deviation(stanB)

print(hensachiA)
print(hensachiB)


# In[ ]:

```

　Twitterで、「100人のうち、99人が50点で自分だけ100点の場合と、99人が0点で自分だけ5点の場合について、どちらが自分の偏差値が高くなるか」というツイートがあったそうなので、このようなデータで分析してみました。

![hensachi1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475646/13c5b347-7d09-991e-28a3-1274443db1ad.png)

　公式に当てはめて関数を作ってみたところ、このような結果になりました。

![hensachi2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475646/6c345e90-4299-913f-1225-2aa2bffc957c.png)

　すみません、これは偏差値ではなくて、標準化した値ですね。偏差値はこれに10倍して50を足します。

![hensachi3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475646/a1a690e5-c6b1-aa2b-4077-e505b8a3ad73.png)

　はい、私の方がはるかに偏差値高いですね。30くらいは上ですね。当然ですね。
　分かりづらいですが、どちらも自分の偏差値が50.4040404040....となっています。

# まとめ
・僕の方が偏差値が高い
Gem 名の命名規則について

ユーザに Gem の読み込み方針を提示するために、命名規則が推奨されている

https://guides.rubygems.org/name-your-gem/

実際には、↑ の命名になっていない Gem もあるけど、デファクトスタンダードとして知っておく

# ① クラス・モジュール名に複数単語が含まれる場合
単語を `_` 区切りにする
 
require 先と同じ表記になるので、ユーザーフレンドリー

例えば、

- Gem 名は `ruby_parser`
- require 先は `〃`
- クラス・モジュール名は `RubyParser`


# ② 別の Gem を拡張する場合
拡張元を `-` 区切りにする

[require先は `/` 区切りとなり](https://ruby.studio-kingdom.com/bundler/guides/bundler_setup#:~:text=%E9%8B%AD%E3%81%84%E8%AA%AD%E8%80%85%E3%81%A7%E3%81%82%E3%82%8C%E3%81%B0%E3%80%81rack%2Dcache%E3%81%AEGem%E3%82%92require%E3%81%99%E3%82%8B%E6%AD%A3%E3%81%97%E3%81%84%E6%96%B9%E6%B3%95%E3%81%AF%E3%80%81require%20%27rack%2Dcache%27%E3%81%A7%E3%81%AF%E7%84%A1%E3%81%8F%E3%80%81%20require%20%27rack/cache%27%E3%81%A7%E3%81%82%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E3%81%8A%E6%B0%97%E3%81%A5%E3%81%8D%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%80%82%20Bunlder%E3%81%ABrequire%20%27rack/cache%27%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E4%BC%9D%E3%81%88%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E3%80%81Gemfile%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%97%E3%81%A6%E4%B8%8B%E3%81%95%E3%81%84%E3%80%82)、クラス・モジュール名は `::` 区切りにする

例えば、`net/http` に `persistent` 機能を追加する場合

- Gem 名は `net-http-persistent`
- require 先は `net/http/persistent`
- クラス・モジュール名は `Net::HTTP::Persistent`

# ③ ①と②の場合
例えば、`net/http` に `digest authentication` 機能を追加する場合

- Gem 名は `net-http-digest_auth`
- require 先は `net/http/digest_auth`
- クラス・モジュール名は `Net::HTTP::DigestAuth`

# ※ 大文字は使わない（小文字で統一する）
OS によって、小文字や大文字を区別しない場合があり、意図せず Gem を読み込んでしまう可能性があるため
MacOSのアップデートでHomebrewがOS Version Errorを吐いた


環境：
MacOS Catalina→Monterey
bash 5.1.8

OSをMontereyにアップデートし、ターミナルを起動したらHomebrewがエラーを吐いた。

```
Traceback (most recent call last):
	11: from /usr/local/Homebrew/Library/Homebrew/brew.rb:31:in `<main>'
	10: from /usr/local/Homebrew/Library/Homebrew/brew.rb:31:in `require_relative'
	 9: from /usr/local/Homebrew/Library/Homebrew/global.rb:80:in `<top (required)>'
	 8: from /usr/local/Homebrew/Library/Homebrew/vendor/portable-ruby/2.6.3_2/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
	 7: from /usr/local/Homebrew/Library/Homebrew/vendor/portable-ruby/2.6.3_2/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
	 6: from /usr/local/Homebrew/Library/Homebrew/os.rb:7:in `<top (required)>'
	 5: from /usr/local/Homebrew/Library/Homebrew/os.rb:43:in `<module:OS>'
	 4: from /usr/local/Homebrew/Library/Homebrew/os/mac.rb:60:in `prerelease?'
	 3: from /usr/local/Homebrew/Library/Homebrew/os/mac.rb:28:in `version'
	 2: from /usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:32:in `from_symbol'
	 1: from /usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:32:in `fetch'
/usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:32:in `block in from_symbol': unknown or unsupported macOS version: :dunno (MacOSVersionError)
```

下記で解決した。
```bash
$ brew update-reset
```

公式ドキュメントによると
[brew(1) – The Missing Package Manager for macOS (or Linux) — Homebrew Documentation](https://docs.brew.sh/Manpage#update-reset-repository-)

>update-reset [repository …]
Fetch and reset Homebrew and all tap repositories (or any specified repository) using git(1) to their latest origin/HEAD.
>
>Note: this will destroy all your uncommitted or committed changes.
- 訳
> gitを使用し、Homebrewと全てのタップリポジトリ(または指定のリポジトリ)を最新のorigin/HEADにフェッチ・リセットする。
>
>注意：未コミットやコミット済みの変更を全て破棄する。

コマンドでリポジトリを指定しなければ、GitHubからHomebrewとタップリポジトリの最新版（origin/HEAD）を取ってきます。
Effective Java 第3版まとめ（項目3）

# 項目3.privateのコンストラクタかenum型でシングルトン特性を強制する

## はじめに

* シングルトンは一度しかインスタンスが作成されないクラス
* シングルトンにすることでテストを困難にする

## 実装方法

### その1

コンストラクタをprivateにし、インスタンスへのアクセスを提供するためのpublic static finalなメンバーを公開する

* 長所
    * クラスがシングルトンであることがAPIから明らか
    * 単純である
* 短所
    * リフレクションによりprivateコンストラクタを呼び出せてしまう
    * シリアライズ可能にするには、Serializableを実装するだけでなく、インスタンスフィールドをtransientと宣言し、readResolveメソッドを提供しなければならない

### その2

コンストラクタをprivateにし、publicなstaticファクトリメソッドを公開する

* 長所
    * APIを変更せずに振る舞いこを変えることができる
    * ジェネリックのシングルトンファクトリを書ける
    * サプライヤとしてメソッド参照を使える
* 短所
    * リフレクションによりprivateコンストラクタを呼び出せてしまう
    * シリアライズ可能にするには、Serializableを実装するだけでなく、インスタンスフィールドをtransientと宣言し、readResolveメソッドを提供しなければならない

### その３

単一要素を持つenumを宣言する

* 長所
    * 何もしなくてもシリアライズやリフレクションへ対応できる
rails6 systemdの書き方について

# はじめに
初めてsystemdを書いた時の自分への戒めとして、こちらを書こうと思います。

# 環境
ruby 3.0.2
rails 6.1.4
puma 5.4

# 参考URL
https://www.rochefort.dev/posts/puma-systemd/

# エラー
```
$ sudo journalctl -fp err
systemd：Failed at step CHDIR spawning /home/ec2-user/.rbenv/shims/bundle: No such file or directory
```
単純に「bundleのファイルかディレクトリがありません」と思い確認してみた所、存在しています。
# 対象コード
```
[Unit]
Description=Puma HTTP Server
After=network.target

[Service]

Type=notify

WatchdogSec=10

User=tomo

WorkingDirectory=/var/www/my_app/current

Environment=RAILS_ENV=production
Environment=RAILS_SERVE_STATIC_FILES=1

ExecStart=/home/ec2-user/.rbenv/shims/bundle exec puma -C /var/www/my_app/current/config/puma.rb

Restart=always

[Install]
WantedBy=multi-user.target
```
参考URLのコードを確認してみましたが、スペルミスもなく間違えがないと思いました。

# CHDIR
CHDIRが何かというと
「自分の今いるディレクトリを移動するときに使うコマンド」みたいです。

# 原因
WorkingDirectoryが
アプリケーションコードのルートディレクトリへのパスになるのですが、
本来は、WorkingDirectory=/var/www/my_appになる所を間違えてmy_appの後に存在しないcurrentを付け加えていました。

# 反省
今回みたいに、WorkingDirectoryなどコードの意味を理解してないとエラーでハマることを改めて再認識しました。
感情推定についてメモ

感情推定技術についてのメモ。知り合いにヒアリングする前にちょっと検索してみた程度の情報。

## User Localの感情推定使ってみた
UserLocalに顔のイメージを送ると、resultが返ってくる。
個人で遊ぶ分にはよさそう。推定アルゴやモデルを自分で作った後、ベンチマークとして比較する対象にはなるかも。

```python
#!/usr/bin/env python
# coding: utf-8

# 依存ライブラリのインストールが必要です
# $ pip install requests

import requests
import json

image_path = '/path/to/image'
image =  open(image_path, 'rb').read()
url = "https://ai-api.userlocal.jp/face"
res = requests.post(url, files={"image_data": image})
data = json.loads(res.content)
result = data['result']
for r in result:
    print(f"""
    年齢: {r['age']}
    感情: {r['emotion']}
    性別: {r['gender']}
    顔の向き: {r['head_pose']}
    顔の位置: {r['location']}
    """)
      
```
↓こうなった↓
| 元画像 (実際はモザイク無しでやりました)                                          | 結果                                                                                                                                                                                                  |
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/7d4d5fc9-46de-9439-d15f-d7e3592ffa45.png) | 年齢    : 37.19<br>感情    : happy<br>性別    : Male<br>顔の向き: {'pitch': -11.44, 'roll': -1.33, 'yaw': -23.23}<br>顔の位置: {'height': 151, 'width': 146, 'x1': 15, 'x2': 161, 'y1': 29, 'y2': 180} |
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/351d5773-14b0-7475-6272-e753e8fc863d.png)                                                  |年齢    : 19.83<br>感情    : surprise<br>性別    : Male<br>顔の向き: {'pitch': -3.04, 'roll': 7.61, 'yaw': -6.77}<br>顔の位置: {'height': 173, 'width': 134, 'x1': 16, 'x2': 150, 'y1': 7, 'y2': 180}<br>
                                                                                                                     
                                                                                                                     
元画像の切り抜きは[OpenCV顔検出](別途リンク予定)の内容をもとに、Googleフォトの自分の画像から切り抜いて適当に持ってきた。
20代半ばから後半の人の写真だったが、推定された年齢はばらつきあり。その他、感情や顔の向き、位置についてはそれっぽい。

顔認識させて感情に合わせてリアクションさせたり、しゃべらせたりするBOT作ったりして遊べそう。怒りを検出したら「6秒我慢だ」ってGoogleHomeにしゃべらせるとか。

最近はもっと高精度でフリーの物もありそう。

## 情報メモ
- [Cloud Vision API](https://syncer.jp/cloud-vision-api) :Googleが提供しているらしい
- [【AI】User Localの表情推定AIで遊んでみた](https://www.techblogchan.com/entry/2019/12/26/010000)
- Affdex: https://affectiva.jp/

- OKI:https://prtimes.jp/main/html/rd/p/000000005.000027192.html
- 筑波大学　延原 肇 氏, 視線特徴量の計測と関心・感情の関係について: http://nobuharaken.com/theme/3321.html
【Visual studio code】Live Serverを使ってリアルタイムで実機確認する方法

html,css,jsを使ってWEBページを制作する際、検証ツールを使ってSP表示を確認するとばっちり表示出来ているのに実機確認をすると表示が崩れている……なんてこと、ありませんか？
私はよくあります！！
……(´・ω・`)

SPの表示を確認する時は検証ツールでざざっと確認→git hub pageやサーバーにアップロード→実機（iPhone12）で確認を行ってました。
もっと楽な方法がある事を知ってめちゃくちゃ感動したので共有です！

# 使用するもの
- Visual studio code（以下VSコード）
- Live server（VSコードのプラグイン）
- 確認用の実機

## Live serverとは
VSコードのプラグイン。
簡易的なローカルサーバーを立ち上げられる。
htmlファイルやcssファイルを編集して保存する度に自動でブラウザに反映してくれる（リロードしなくてもコードを保存すると更新される）

## Live Serverのページを実機（スマホ）で確認する方法
1. PCとSP、同じWi-Fiに接続する。
2. PCでIPアドレスを確認する。
3. 実機からブラウザを開き、確認したIPアドレスに接続する

以上になります。詳しく解説していきます。

1. PCとSP、同じWi-Fiに接続する。
-必ず同じWi-Fiに接続してください。違うWi-Fiに接続してしまうと表示されません。

2. PCでIPアドレスを確認する。
 -VSコードを開き、上部のメニューからターミナルを開く
 -「ipconfig」のコマンドを入力し、IPアドレスを確認
3. 実機からブラウザを開き、確認したIPアドレスに接続する

あとはいつも通り、PCでの操作と同じくVSコード上でソースを編集し保存をすると実機で開いたブラウザ上でも自動でコードが反映されます！

***
ただしこの方法だと毎回コマンドを叩いてIPアドレスを確認しなければいけないのでちょっと面倒…
なので、IPアドレスを固定してしまいます。
***

1. VSコードの左下にある歯車マークの管理をクリックし、設定を選択
2. 表示されるメニューの中からLive Server Configを選択
3. Settings:Use Local Ipの項目のところに「Use local IP as host」にチェックを入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/05ec4efc-f40a-500c-beae-c84f1fcd302b.png)

4. PCでの画面を確認し、IPアドレス＋ポート番号の部分をスマホ実機のブラウザのURL入力欄に入力してアクセスする。
※この時、`https://`は入力しない。
画像で言う所の黄色の部分だけを実機（スマホ）で入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/d0f155cc-4571-16ae-5e43-4ab8faeacb61.png)
私の例でいくと「192.168.3.13:5500」を実機（スマホ）のブラウザで開くとこんな感じになります。
![iOS の画像 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/3c885894-ebbb-1a0e-e464-3e2192ad9254.png)

viewをクリックするとPC同様の画面になります！
![iOS の画像 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/0a36cd50-fc72-6380-6843-1b008ac4f970.png)



これで実機（スマホ）で表示の崩れがないかの確認をしながらのコーディングがめちゃくちゃ楽になるので、是非お試しください！！!
知らなきゃヤバい。メタバース


作成中（2022/04/12）


---

<iframe src="https://www.slideshare.net/slideshow/embed_code/key/1YXRDzcwdKgl9p?hostedIn=slideshare&page=upload" width="476" height="400" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>


以下に投稿（2022/04/16）
https://qiita.com/takuan_22/items/6826a70c1424dd3c346e
M1 MacでPuTTYgenが使える方法

PuTTY形式の秘密鍵からOpenSSH形式の秘密鍵へ変換する必要があったので、
手持ちのM1 Macでの変換方法を調べた。

## 1. homebrew（パッケージマネージャー）のインストール

ターミナルを開き、以下のコマンドでhomebrewをインストールする。

```shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

## 2. homebrewのPATH追加

M1 Macだと、homebrewは以下のディレクトリにインストールされる。

```shell
/opt/homebrew
```

ホームディレクトリにある.zshenvファイルを開き、以下の行を追加する。

```
export PATH=/opt/homebrew/bin:$PATH
```

## 3. puttyのインストール

以下のコマンドで　puttyをインストールする。

```shell
brew install putty
```

## 4. PuTTYgenを使用した変換

PuTTYgenを使用し、PuTTY形式の秘密鍵からOpenSSH形式の秘密鍵へ変換する。

```shell
puttygen privatekey.ppk -O private-openssh -o privatekey.key
```

以上で目的の変換ができた。

## 参考情報

* [PuTTYgen Download Guide for Windows, Linux and Mac](https://www.puttygen.com/#Download_PuTTYgen_for_Mac)
【Go, go-cmp】子インスタンスで持つ値の並びを気にせずに比較したい

SortSlicesだと子インスタンスで持つ値がバラバラの場合、無視することが出来ないが[Transformer](https://pkg.go.dev/github.com/google/go-cmp/cmp?utm_source=godoc#Transformer)だと出来る。


NumSlice構造体で持つNumsの順番がバラバラな構造体を作る。

```golang
func TestSortSlice5(t *testing.T) {

	type NumSlice struct {
		Id   int
		Nums []int
	}

	type Compare struct {
		NumSlice NumSlice
	}

	v1 := &Compare{
		NumSlice: NumSlice{Id: 1, Nums: []int{1, 2, 3, 4, 5}}, // 昇順
	}
	v2 := &Compare{
		NumSlice: NumSlice{Id: 1, Nums: []int{5, 4, 3, 2, 1}}, // 降順
	}

	opts := []cmp.Option{
		cmp.Transformer("NumSlice", func(in []int) []int {
			out := append([]int(nil), in...) // Copy input to avoid mutating it
			sort.Ints(out)
			return out
		}),
	}

	if diff := cmp.Diff(v1, v2, opts...); diff != "" {
		t.Errorf("Compare value is mismatch (-v1 +v2):%s\n", diff)
	}
}
```

親構造体に文字列のスライスを追加してみる
```golang
func TestSortSlice(t *testing.T) {

	type NumSlice struct {
		Id   int
		Nums []int
	}

	type Compare struct {
		NumSlice    NumSlice
		StringSlice []string
	}

	v1 := &Compare{
		NumSlice:    NumSlice{Id: 1, Nums: []int{1, 2, 3, 4, 5}}, // 昇順
		StringSlice: []string{"1", "2", "3"}, // 昇順
	}
	v2 := &Compare{
		NumSlice:    NumSlice{Id: 1, Nums: []int{5, 4, 3, 2, 1}}, // 降順
		StringSlice: []string{"3", "2", "1"}, // 降順
	}

    // 文字列スライス用を追加
	opts := []cmp.Option{
		cmp.Transformer("NumSlice", func(in []int) []int {
			out := append([]int(nil), in...) // Copy input to avoid mutating it
			sort.Ints(out)
			return out
		}),
		cmp.Transformer("StringSlice", func(in []string) []string {
			out := append([]string(nil), in...) // Copy input to avoid mutating it
			sort.Strings(out)
			return out
		}),
	}

	if diff := cmp.Diff(v1, v2, opts...); diff != "" {
		t.Errorf("Compare value is mismatch (-v1 +v2):%s\n", diff)
	}
}
```


正しく比較がされているか、異なる値を入れてみる。
```golang
func TestSortSlice(t *testing.T) {

	type NumSlice struct {
		Id   int
		Nums []int
	}

	type Compare struct {
		NumSlice    NumSlice
		StringSlice []string
	}

	v1 := &Compare{
		NumSlice:    NumSlice{Id: 1, Nums: []int{1, 2, 3, 4, 5}},
		StringSlice: []string{"1", "2", "3", "4"}, // 3番目に"4"を追加
	}
	v2 := &Compare{
		NumSlice:    NumSlice{Id: 1, Nums: []int{5, 4, 3, 2, 1}},
		StringSlice: []string{"5", "3", "2", "1"}, // 0番目に"5"を追加
	}

	opts := []cmp.Option{
		cmp.Transformer("NumSlice", func(in []int) []int {
			out := append([]int(nil), in...)
			sort.Ints(out)
			return out
		}),
		cmp.Transformer("StringSlice", func(in []string) []string {
			out := append([]string(nil), in...)
			sort.Strings(out)
			return out
		}),
	}

	if diff := cmp.Diff(v1, v2, opts...); diff != "" {
		t.Errorf("Compare value is mismatch (-v1 +v2):%s\n", diff)
	}
}
```

ちゃんと比較してくれる
```
=== RUN   TestSortSlice
    sort_test.go:1774: Compare value is mismatch (-v1 +v2):  &http.Compare{
          	NumSlice: {Id: 1, Nums: Inverse(NumSlice, []int{1, 2, 3, 4, ...})},
          	StringSlice: []string(Inverse(StringSlice, []string{
          		"1",
          		"2",
          		"3",
        - 		"4",
        + 		"5",
          	})),
          }
```


SortSlicesのやり方があれば教えてください。
[OutSystems]アクセス修飾子Protectedを擬似的に実現する方法

# 確認環境
Personal Environment(Version 11.14.0 (Build 33133))
Service Studio(Version 11.14.12)
Forgeコンポーネント：[Action Info](https://www.outsystems.com/forge/component-overview/3046/action-info)(Version 3.0.6)

# 背景
OutSystemsでは、ある要素を他のモジュールに使わせるとき、Publicにする（Publicプロパティ=Yes）かしない（No）かのいずれかしか選択肢がない。

単体テストや同じチームの他の要素で利用するために、ある要素をPublicにすると、そのモジュールにアクセス権を持つユーザーが自由にその要素への参照を追加できてしまう。

モジュール・アプリケーション構成とITユーザーの権限を適切に設定することで解決できる問題だが、アーキテクチャ設計とITユーザの管理が面倒になってしまう。

そこで、Server Actionの作りを工夫することで、特定のモジュール以外からアクセスできないようにしたい。

# Action Info
Extension。.NET FrameworkのSystem.Diagnosisにある[StackTrace クラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.stacktrace?view=netframework-4.7.2)を利用して、スタックトレースからActionの呼出情報を取得する。

> StackTrace デバッグ ビルド構成では、情報が最も有益です。 既定では、デバッグ ビルドにはデバッグ シンボルが含まれますが、リリース ビルドには含め "されません"。 デバッグ シンボルには、 オブジェクトと オブジェクトの構築に使用されるファイル、メソッド名、行番号、および列情報のほとんどが StackFrame 含 StackTrace まれています。

とあるように、リリースビルド（本番はおそらくこっち）だと情報が完全ではないらしい。

> StackTrace は、最適化中にコード変換が行われるので、予想される数のメソッド呼び出しを報告しない場合があります。

また、最適化によってメソッド呼出が省略されることもあるとのこと。実際にはOutSystemsを間に挟んでいるので、きちんと出るかもしれないが、当てにしきるのはためらわれる。

# 実装例
以下のように実装してみる。

1. GetActionInfoをDepthパラメータ=1で呼び出す（パラメータ=1は直前の呼び出し元を示す）
1. GetActionInfoのOutput ParameterにあるEspaceNameが想定通りであるかをチェック（ここでは、AllowedConsumerという名前のモジュールでチェック）
1. AllowedConsumerなら通常通り処理を行う（下向きのパス）。AllowedConsumer以外なら例外をThrowして終わる

許可されていないモジュールからの呼出があると、開発環境内で例外になるため本番には到達しない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/9f2109dd-107d-d3c5-a570-ecce7f7a48fd.png)

# 欠点
Action Infoの部分に書いたように、Action Infoは当てにしきることはできない。
また、簡単な処理とはいえ、業務ロジックに無関係な処理を挟んでしまうとパフォーマンスに影響するかもしれない。

よって、この方法を実際に利用するときは

- 本番まで含めてAction Infoの動作を綿密にテストして問題がないことを確認する
- 開発以外の環境では、Action Infoを利用する部分のロジックはそもそも動作させないようにする（Site Property等を利用して）

といったことを検討したい。
仮想シリアルポートの作成および動作確認方法

仮想シリアルポートを作成して動作確認する方法

# はじめに

環境

```:bash
cat /etc/system-release
Amazon Linux release 2 (Karoo)
```

プログラムはpython

```:bash
bash-4.2# python3 --version
Python 3.7.10
```

port:9600を使用して通信します

# 仮想シリアルポート作成

socatという便利コマンド

## socatとは

https://linux.die.net/man/1/socat

> 2つの双方向バイトストリームを確立し、それらの間でデータを転送するコマンドラインベースのユーティリティです。

### socat install
```
yum install -y socat
```

### コマンド

```
socat -d -d pty,raw,echo=0 pty,raw,echo=0
```

#### 構文
```
socat [options] <address> <address>
```

##### オプション

```
[options]: -d -d: fatal/error/warning/info のメッセージを表示
<address>: pty,raw,echo=0: ptyの入力値をそのまま出力します
<address>: pty,raw,echo=0: ptyの入力値をそのまま出力します
```

##### ptyとは

https://ja.wikipedia.org/wiki/%E6%93%AC%E4%BC%BC%E7%AB%AF%E6%9C%AB

> 擬似端末セッションの役割をソフトウェア（プロセス）が代用する

sshした際などに生成され、各コマンドプロンプトがこちらに該当します

* ssh セッション1
```
bash-4.2# ps -a
  PID TTY          TIME CMD
  225 pts/1    00:00:00 ps
```

* ssh セッション2
```
bash-4.2# ps -a
  PID TTY          TIME CMD
  225 pts/2    00:00:00 ps
```

TTYのところが異なっています

### 実行結果
```
bash-4.2# socat -d -d pty,raw,echo=0 pty,raw,echo=0
2022/04/12 10:52:53 socat[226] N PTY is /dev/pts/2
2022/04/12 10:52:53 socat[226] N PTY is /dev/pts/3
2022/04/12 10:52:53 socat[226] N starting data transfer loop with FDs [5,5] and [7,7]
```
※各環境にて`/dev/pts/2`・`/dev/pts/3`の内容は異なります
※コマンドを終了するとバイトストリームも閉じられます

# スクリプト
送受信ともに`pyserial`を利用します

## pyserial install
```
pip3 install pyserial
```

## 送信スクリプト

```:Sender/main.py
import serial

if __name__ == "__main__":
    # /dev/pts/2 はsocatの実行結果に合わせて書き換える
    ser = serial.Serial('/dev/pts/2', 9600, timeout = None)

    message = 'test\n'

    ser.write(message.encode('ascii'))

    ser.close()
```

## 受信スクリプト

```:Reciver/main.py
import serial

if __name__ == "__main__":
    # /dev/pts/3 はsocatの実行結果に合わせて書き換える
    ser = serial.Serial('/dev/pts/3', 9600, timeout = None)

    while 1: 
        line = ser.readline()

        print(line.decode('utf-8'), end='')
```

## 実行結果

### 送信スクリプト

```
bash-4.2# python3 Sender/main.py
```

### 受信スクリプト

```
bash-4.2# python3 Reciver/main.py
test
test
test
test
test
test
test
test
test
test
```

送信した内容が受信されてプロンプトに表示されています

# さいごに
割と簡単に仮想シリアルポートの作成・動作確認が実施できました
FastAPI: Systemd で使う

プログラムは、
/home/samples/tmp/api_mariadb.py
です

## 設定ファイル

```text:/etc/systemd/system/uvicorn.service
[Unit]
Description=The uvicorn process
Before=nginx.service
After=network.target remote-fs.target nss-lookup.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/samples/tmp


ExecStart=/usr/local/bin/uvicorn api_mariadb:app --reload
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target
```

## 起動

```bash
sudo systemctl start uvicorn
```

## 起動の確認

```bash
sudo systemctl status uvicorn
```
【備忘録】Railsリレーション検索・作成総集

- ユーザー VS 性別（１：多）
- ユーザー VS スキル （多：多）

## １:多(検索)
```
User.find_by(sex_id: 1)
```

## 多:多(検索)
```
User.includes(:skills).where(user_skills: { skill_id: 1 })
```
※user_skillsは中間テーブル

## 多:多(作成)
```
User.new(skills: [Skill.find(1)])
```
FastAPI: CORS の使い方

プログラム

```py:main_cors.py
# ------------------------------------------------------------------
#	main_cors.py
#
#					Apr/12/2022
# ------------------------------------------------------------------
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

# ------------------------------------------------------------------
app = FastAPI()

origins = [
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# ------------------------------------------------------------------
@app.get("/")
def read_root():
    return {"Hello": "World"}


# ------------------------------------------------------------------
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

# ------------------------------------------------------------------
```

サーバーの実行

```bash
uvicorn main_cors:app --reload
```

CORS の設定が出来ていないと次のようなエラーが出ます。

```text
from origin 'https://example.com' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present 
on the requested resource.
```
PostgreSQL でクライアント証明書認証を行うには

PostgreSQL でクライアント証明書認証を行う手順は以下のとおりです。

1. 自己署名でサーバ証明書を作成します。

   ```shell-session
   $ openssl req -new -x509 -days 3650 -nodes -text -out $PGDATA/server.crt \
       -keyout $PGDATA/server.key -subj /CN=node-1
   Generating a RSA private key
   .......................................................+++++
   .....................+++++
   writing new private key to '/var/lib/pgsql/14/data/server.key'
   -----
   ```

   `-days` には証明書の有効期間 (日)、`-subj` の `CN` にはサーバ接続時のホスト名を指定します。

1. サーバ証明書をルート証明書としてコピーします。

   ```shell-session
   $ cp $PGDATA/server.crt $PGDATA/root.crt
   ```

1. `postgresql.conf` を編集します。

   ```config:$PGDATA/postgresql.conf
   listen_addresses = '*'
   ssl = on
   ssl_ca_file = 'root.crt
   ```

   `listen_addresses = '*'` で別ホストからの接続、`ssl = on` で SSL 接続を有効にし、`ssl_ca_file` にはルート証明書を指定します。

1. `pg_hba.conf` を編集します。

   ```config:$PGDATA/pg_hba.conf
   # TYPE  DATABASE        USER            ADDRESS                 METHOD
   hostssl all             all             172.28.128.0/24         cert
   ```

   `TYPE` には SSL 接続の `hostssl`、`METHOD` には `cert` か、任意の認証方式とオプションとして `clientcert` に `verify-full` か、`verify-ca` を指定します。`verify-ca` は証明書のみ、`verify-full` と `cert` はユーザ名の一致も検証します。バージョン 11 以前は `verify-ca` 相当の `1` と `cert` にしか対応していません。

1. 設定変更を反映するため、サーバを再起動します。

   ```shell-session
   $ /usr/pgsql-14/bin/pg_ctl restart
   サーバー停止処理の完了を待っています....完了
   サーバーは停止しました
   サーバーの起動完了を待っています....2022-04-12 20:50:25.622 JST [9785] LOG:  redirecting log output to logging collector process
   2022-04-12 20:50:25.622 JST [9785] HINT:  Future log output will appear in directory "log".
   完了
   サーバー起動完了
   ```

1. クライアント証明書の格納先を作成します。

   ```shell-session
   $ mkdir ~/.postgresql
   ```

1. クライアント証明書を作成します。

   ```shell-session
   $ openssl req -new -nodes -text -out ~/.postgresql/postgresql.csr \
       -keyout ~/.postgresql/postgresql.key -subj /CN=postgres
   Generating a RSA private key
   ...............+++++
   .....................+++++
   writing new private key to '/var/lib/pgsql/.postgresql/postgresql.key'
   -----
   ```

   `-subj` の `CN` にはサーバ接続時のユーザ名を指定します。

1. ルート証明書の代わりにサーバ証明書でクライアント証明書に署名します。

   ```shell-session
   $ openssl x509 -req -in ~/.postgresql/postgresql.csr -text -days 3650 \
       -CA $PGDATA/server.crt -CAkey $PGDATA/server.key -CAcreateserial \
       -out ~/.postgresql/postgresql.crt
   Signature ok
   subject=CN = postgres
   Getting CA Private Key
   ```

   `-days` には証明書の有効期間 (日) を指定します。

1. クライアント証明書の署名要求を削除します。

   ```shell-session
   $ rm -f ~/.postgresql/postgresql.csr
   ```

1. ルート証明書をコピーします。

   ```shell-session
   $ cp $PGDATA/root.crt ~/.postgresql
   ```

1. サーバに接続できるかを確認します。

   ```shell-session
   $ psql -h node-1
   psql (14.2)
   SSL 接続 (プロトコル: TLSv1.3、暗号化方式: TLS_AES_256_GCM_SHA384、ビット長: 256、圧縮: オフ)
   "help"でヘルプを表示します。
   
   postgres=# \q
   ```

   `~/.postgresql` ディレクトリを別ホストにコピーすれば、別ホストからでも接続できます。