OmniAICreator/Qiita-1.07M huggingface dataset:
[個人メモ][PHP]ドメインのSSL証明書の有効期限の取得（subjectAltNameまで見る）

個人メモとして記事っぽくまとめ。

PHPでドメインのSSL証明書の有効期限を取得するコードは先人たちの英知に学ぶとして大幅に前段を省略しますが、最後はopenssl_x509_parseで返ってきた値の[subject][CN]と対象ドメインを比較して有効期限の取得判断をしています。
この時面倒なのが、例えばwww.yahoo.co.jpでこれを調べてみると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687945/d355e573-197d-e0aa-b5a2-13432bb6bfe1.png)

のように*付きでくるので単純比較では不一致になってしまうことですね。
まぁこれは正規表現でも使ってあげればいいので、脳死コーディングするなら

```php
if( strpos($parsed['subject']['CN'], $domain_name) !== false ||
	preg_match(sprintf('/^.%s$/',$parsed['subject']['CN']), $domain_name) === 1 )
{
	echo '有効期限：' . date('Y/m/d', $parsed['validTo_time_t']);
}
```

とでもしてあげればよいのですが、面倒なものだと、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687945/0358406a-5ebc-d897-d9fc-6c442ae78657.png)

とかあるわけですね。
そんなときは、[extensions]の[subjectAltName]まで見てあげないといけないはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687945/8aed429d-39b8-2484-1e25-6bcf9177f37c.png)

うわっめんどい、と一瞬思いますが、単純なパース処理なので、難しく考えずexplode、foreach、preg_matchあたりを使えばできるかと。余計な空白もあるのでtrimも忘れずに。

まぁここまで厳密に有効期限チェックするような監視よろしくなバリバリの仕組みでなければ、せいぜい*あたりだけ見てあげればいい気はしますね。知らんけど。

とここで終わるのもなんなので、

```php
$arrDomain = [
	'qiita.com',
	'www.youtube.com',
	'www.google.co.jp',
	'www.yahoo.co.jp',
];

foreach($arrDomain as $domain_name) {
	echo '■' . $domain_name . PHP_EOL;

	$stream_context = stream_context_create(array(
		'ssl' => array('capture_peer_cert' => true)
	));

	$resource = stream_socket_client(
		'ssl://' . $domain_name . ':443',
		$errno,
		$errstr,
		30,
		STREAM_CLIENT_CONNECT,
		$stream_context
	);

	$cont = stream_context_get_params($resource);
	$parsed = openssl_x509_parse($cont['options']['ssl']['peer_certificate']);

	$func_chk_domain = function($cn, $domain) {
		return (strpos($cn, $domain) !== false) ||
			(preg_match(sprintf('/^.%s$/',$cn), $domain) === 1);
	};
	
	// 単純にCNで比較(完全一致と*時の正規表現)
	$check_flg = false;
	if( $func_chk_domain($parsed['subject']['CN'], $domain_name) ) {
		echo 'CNで一致' . PHP_EOL;
		$check_flg = true;
	}
	else {
		// CNで一致しない場合はextensionsのsubjectAltNameを精査
		$arrDNS = explode(',', $parsed['extensions']['subjectAltName']);
		
		foreach($arrDNS as $dns) {
			if( $func_chk_domain(str_ireplace(['DNS:',' '],'',$dns), $domain_name) ) {
				echo 'subjectAltNameで一致' . PHP_EOL;
				$check_flg = true;
				break;
			}
		}
	}
	
	if( $check_flg ) {
		echo '有効期限：' . date('Y/m/d', $parsed['validTo_time_t']) . PHP_EOL;
	}
	else {
		echo '取得NG' . PHP_EOL;
	}
}
```

で取れました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687945/8061abac-f954-bbfd-3c74-528c8f5e3727.png)
CSS absolute × transform で上下中央寄せ(コピペ用)

## absolute × transform
コピペして使う用の記事です。
flexやmargin:auto;などで中央寄せも出来ますが、この手法は擬似要素などを中央寄せする際にとても便利です。

```css

.wrapper {
   width: 100%;
   position: relative;
}

.inner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateY(-50%) translateX(-50%); 
  /* transformがセンタリングしたい要素の縦、横幅分を引いてくれるので中央になる */
}
```
wrapperの上下中央にinnerが配置されます。
Laravelでユーザーの生年月日をちゃんと表示する

ユーザーの生年月日をdate型でデータベースに保存するようにします

そのまま表示しようとすると

```
1998-09-25
```

みたいな表示になるので

format関数を使って○月○日みたいな表示を可能にさせます

## モデルの変更
対象となるモデルに記述（ここではUser.php）

```User.php
protected [
  'birthday'
]

##　表示させたいカラムを指定
```

はいこれだけ、
これでformat関数が使えます

---------------

あとは指定すれば

```php
<p>{{ $user->birthday->format(Y年m月d年) }}</p>
```

こう表示される

```php
1998年09月25日
```

モデルに設定を記述しないとエラーが出る
java_アノテーション_メモ_20200807

# アノテーション

　　**１．アノテーションとは**

　　　　アノテーションとは「この部分は警告を出さなくてもよい」という指示をソースコード内に記述できることです。

　　　　アノテーションは"@"から始まる記述でコメント内ではなくソースコードにそのまま記述します。
　　　　以下で標準で準備されている３つのアノテーションを例にどのようなものか実際に確認しましょう。

　　　　＞違う記事で記述済みのためこれくらいの説明にとどめさせていただきます。


　　**２．アノテーションを利用したコード**

![コメント 2020-08-07 105055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687164/9a98b9cb-f582-c2c1-85f9-7b85751cd049.png)



　　**３．@SuppressWarning - 警告を抑制する**

　　　　クラス、メソッド、フィールドなどに対して、一定の種類の警告をしないように指示するのが
　　　　**@SuppressWarningアノテーション**です。

　　　　このアノテーションは、パラメータとして「抑制、制御したい警告の種類」を指定します。
　　　　たとえば、「２．アノテーションを利用したコード」にあった、
　　　　@SuppressWarning("Serial")は、serialVersionUIDを宣言していないことに対する警告を出さないようにします。
　　　　そのほかこのアノテーションには以下の表１のようなパラメータがあります。


　　**表１　@SuppressWarning　で指定可能な代表的なパラメータ**

　　![コメント 2020-08-07 115055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687164/7110317c-97db-929c-70ae-844a78a406fd.png)


　　**４．@Override - オーバーライド宣言**

　　　　メソッド宣言の先頭に、**@Overrideアノテーション**をつけると、そのメソッドが親クラスの同名のメソッドを
　　　　オーバーライドすることを明示的に宣言することができます。

　　　　なんでこんなものが必要なのか？
　　　　　＞「オーバーライドしたつもりで、実はできていない」場合、それに気づくため

　　　　たとえば、親クラスで宣言されたメソッド transfer() をオーバーライドするつもりで、
　　　　子クラスで誤ったスペルのメソッド transfer() を宣言してしまったとしましょう。
　　　　これではオーバーライドになっていないため、何度 transfer() を呼び出しても親クラスの transfer()が
　　　　動作してしまい、子クラスの transfer() は動作しません。
　　　　
　　　　そのため「メソッドは呼びだせて一応動くが、動作内容がおかしい」という原因の特定が難しい不具合が
　　　　発生してしまいます。
　　　　そこで、オーバーライドを行うことを前提としているメソッド宣言の先頭には@Overrideアノテーションを付ける
　　　　ようにすることでコンパイラが警告を出してくれます


　　**５．@Deprecated - 非推奨の宣言**

　　　　クラス、フィールド、メソッドなどの宣言の先頭に**@Deprecatedアノテーション**を付けると、
　　　　それが非推奨であることをコンパイラに伝えることができます。
　　　　たとえば、あるクラスに手を加えてより良いクラスを作成した結果、古いほうのクラスを使ってほしくない
　　　　時などに記述します。



　長々と記載が続きましたが、未来の自分用のメモですのでご一読いただいた中で間違っているところもあると思います。
　間違っているところなどございましたらご指摘願います。
UVミラーリングを使ってテクスチャの表示をする

# 概要

画像を反転してループさせることによって半分に切り取られたリソースを1枚のリソースとして完成させる

これを
![kusa2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/85983a91-cea3-916f-130d-960c1667491f.png)

こう
![kusa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/a5c0d5bf-1670-381e-2d50-d13ddb417e73.png)


## シェーダーを書く

※テクスチャの設定はrepeatであることを前提とする


### テクスチャを通常表示する場合

UV座標は 0 ~ 1 で入力される

```
float2 uv = input.uv;
```

![スクリーンショット 2020-08-07 13.59.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/f07e2ee2-687c-0431-24df-342a155461ff.png)


### テクスチャを反転したい場合

入力されるUV座標を 1 ~ 0 に変換するだけ
今回はUのみ反転させる

```
float2 uv = 1 - input.uv.x;
```

![スクリーンショット 2020-08-07 14.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/b181594d-3544-3fd0-d3ad-78b0823924d8.png)


### 通常表示と反転表示を組み合わせる

半分のリソースを1枚のリソースとして表示したい場合
通常表示のテクスチャと反転表示のテクスチャを組み合わせることで可能になりそう
0 ~ 1 で通常表示
1 ~ 0 で反転表示
ということがわかったので、UV座標をなんとかして 1 ~ 0 ~ 1 という数値にしてあげたい


### まずはUV座標の値を変更する

以下計算式を使うと UV座標が 0 ~ 1 →　-1 ~ 1 に変換できる

```
uv.x = uv.x * 2 - 1
```

これでUV座標は -1 ~ 1 に変換されたが、マイナスの値が出てしまっているためこのままではダメ


### 変更したUVの値から負の数を取り除く

UV座標の変換のタイミングで絶対値を求める関数を使う

```
uv.x = abs(uv.x * 2 - 1)
```
こうすることによって

-1 ~ 1 に変換された値を 1 ~ 0 ~ 1 という値に変換することが可能になる


### 結果

![スクリーンショット 2020-08-07 14.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/2d6514e6-d541-aca6-6098-1e1015f85f4e.png)

あとは画像のサイズを綺麗に調整したりして完成

お　わ　り
Target(目的変数)を使って、Future(説明変数(特徴量))を作成してはいけない

機械学習とは端的に言えば、データを学習して予測するだけのこと。

データを学習するとは何か？原因となるデータを元に結果となるデータを予測できるようになること。

それは、**原因(説明変数)によって結果(目的変数)を予測できるようになること。**



人間世界のテストを考えてみると、問題集と同じ問題がテストにでるようなことがよくあるので、問題集を丸暗記してテストに望むこともあると思う。
しかし、これは応用力が皆無な勉強法で、機械学習でも同じことが言える。

**原因(答え)をつかって結果(答え)の予測ができるのは当然のことである。**

これをOverfiting(過学習もしくは過剰適合)という。

この状態は、**人間でも機械学習でも全くの約立たず**なので気をつける。
VueとFirebaseでWebアプリ開発でハマったこと②: javascriptやnpmなどのエラー

前回[『VueとFirebaseでWebアプリ開発でハマったこと①: Strings must use singlequote, Extra semicolon』](https://qiita.com/gremito/items/33c54254de9487d8f9a1)の続き。

## 概要
firestoreからデータを受け取ってVueで表示し、Vueでデータを送信してfirestoreに保存する一連の流れをInputしたいと思い、[『firestore, vue.jsでリアルタイム同期のチャットを実装してみる [チュートリアル形式]』](https://qiita.com/ryo2132/items/2881d8223eb2ad3050a1)という記事を参考に作業していたところ次の3つのエラーにハマったのでどう解決したのかまとめる。


## エラー1: Uncaught TypeError: Cannot read property 'install' of undefined

　<img width="500" alt="スクリーンショット 2020-08-07 12.29.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82601/0a0510d9-40cd-7ac8-1ee3-ae5e9aa82b3c.png">

上記は、`$ yarn serve`の結果は正常だけどもアクセス後にエラーになるケースでした。
このエラーだけでは状況がわからないので、エラー文３行目に対応箇所であった`firebase.js`が表示されているためこのリンクをクリックするとConsole上にそのソースコードとエラーの箇所まで飛んでくれました。

原因としては、VueがFirebaseの機能を扱う初期化で問題が起きていることが分かります。
ググったところvuefireのissue[『App startup failure with VueFire plugin #286』](https://github.com/vuejs/vuefire/issues/286)を見つけ、次のように対応するとエラーが解消できました。

```js
- import VueFire from 'vuefire'
- Vue.use(VueFire)

+ import { firestorePlugin } from 'vuefire'
+ Vue.use(firestorePlugin)
```


## エラー2: [Vue warn]: Error in beforeCreate hook: "Error: Vuetify is not properly initialized, see https://vuetifyjs.com/ja/getting-started/quick-start/#bootstrapping-the-vuetify-object"

<img width="500" alt="スクリーンショット 2020-08-07 12.32.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82601/289b8e21-69ca-4c1a-7079-c4c40901e39f.png">

正確には他にも複数エラーが出てますが、エラーの解決は基本的に最初のエラーから対応するべきなのでこのエラーに集中しました。

原因は、参考にした記事の[プラグインのインストール](https://qiita.com/ryo2132/items/2881d8223eb2ad3050a1#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)にあたるところで、ただプラグインを入れるだけ解説されてますが、結局はこれだけでは不十分でちゃんと`vuefire`のインストール対応が必要でした。

エラー文にも出ている通り、公式の`vuefire`のクイックスタートにアクセスして「[Nuxtのインストール](https://vuetifyjs.com/ja/getting-started/quick-start/#nuxt-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)」「[Webpackのインストール](https://vuetifyjs.com/ja/getting-started/quick-start/#webpack-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)」の対応が必須でした。


## エラー3: These dependencies were not found

```shell
$ yarn serve

...

ERROR  Failed to compile with 3 errors                                                                                                                                                                                               12:48:50

These dependencies were not found:

* firebase/app in ./src/plugins/firebase.js
* firebase/firestore in ./src/plugins/firebase.js
* vuefire in ./src/plugins/firebase.js

To install them, you can run: npm install --save firebase/app firebase/firestore vuefire
```

色々触っているとたまにこのエラーが出てたんですが、これは単に`./node_modules`を削除して再度`$ npm install`すると直りました。
【ラズパイ】モニタに映らなくなった時の対処法

Raspberry Pi 3B(以下:ラズパイ)を久々にHDMIケーブルでモニタと繋いで、遊ぼうと思った矢先、**Boot画面で止まってしまった**。本トラブルの対処法備忘録を残しておく。

## NOOBSを起動

ラズパイ起動直後のラズパイマーク画面でshiftキー押下してNOOBSを立ち上げます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/81427195-d71b-1476-4c00-e185855568be.png" width=450 />

設定の編集をクリックする。


## hdmi_safe=1にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/85b741f9-090a-8a40-4fbf-ce5b6d43b501.png)

解決した事実のみしか伝えられないが、設定エディタの**hdmi_safe=1**(もともとは0だった)に変更したらモニタに表示された。

## 環境

- Raspberry PI 3B
- Raspbian GNU/Linux 9.8 (stretch)
ROS 之环境变量

# ROS_PACKAGE_PATH相关

包含需要调用的包，没有相关路径的话会出下找不到包的情况。
使用```rospack find {packagename}```会在$ROS_PACKAGE_PATH里面寻找。

1.ros运行前要设置环境变量，不然找不到相应功能包等。

```~/.bashrc
source /opt/ros/medolic/setup.bash
```

2.新建一个工作空间后，编译后需要设置一下环境变量，不然找不到相应功能包等。

```source ~/my_catkin_ws/devel/setup.bash
```
* 连续执行多个工作空间的setup.bash后一部分路径可能会从ROS_PACKAGE_PATH里消失。（https://blog.csdn.net/robinhjwy/article/details/79597095）

3.添加相关路径

```export ROS_PACKAGE_PATH=${ROS_PACKAGE_PATH}:${my_path}/src
```

4.查看路径
```echo ROS_PACKAGE_PATH
```
PC SPEC

#CPU

**Ryzen7 3700X**
8コア16スレッドで4万円台という最強のCPUです
ゲームでも動画編集でも十分な力を持っています
#マザーボード

**ASRock B450SteelLegend**
男心をくすぐる迷彩柄と、ピカピカ光るIOガード
かっこよすぎる。。。
#メモリ

**Corsair VENGENCE 2666 16GBx2**
Ryzenはメモリが命といいますが、迷ったらこれ。
予算の都合で3200は買えず。。。
いずれ3600とかにします！
#GPU

**ZOTAC RTX2080SUPER**
Amazonで何故か76kになっていて即買いしました（笑）
キャンセルにもならず無事に届きました！
勝利！！！
#電源

**Thermaltake 850W GOLD RGB**
やっぱり光るのは良いですね（笑）
見えないんですけど。
#ケース

**CoolerMaster MC500**
ずっしりとしたケースです
サイドは強化ガラス、さらにスモークもしてあってすごくRGBが映えますｗ
#CPUクーラー

**DeepCool GAMMAX L240**
7000円の水冷にしてはよく冷えます
がんばってくれてます
「実践Node-RED活用マニュアル」書籍出版記念イベント参加してきた。


# 今回参加したイベント

タイトルにもある通りに`「実践Node-RED活用マニュアル」書籍出版記念イベント`です。

執筆者の方々のお話やLTを聞くようなイベントです。
Youtubeにイベント動画上がっています。

イベントページはこちら
https://node-red.connpass.com/event/181754/
イベント動画はこちら
https://www.youtube.com/watch?v=_aeI8auXZQE

# イベント概要
| 使用時間 | 内容 |
|---|---|
| 10分 | 書籍紹介&オープニング |
| 30分 | 執筆者LT |
| 10分 | Node-RED Conに登壇してみよう的な|

前二つについてを以下で書きます。
最後の`Node-RED Conに登壇してみよう的な`は、上記の動画から見てください。

## 書籍紹介&オープニング

ここでは、執筆者の紹介や執筆担当をした部分の簡易な説明を行っていただけました。
担当した部分の説明とか思いを説明して貰うことで読む側としてはこういった意図で書いてるんだぁとかがわかるかなぁと思います。

# 執筆者LT

内容としては、本の内容を絡めてより発展的な内容だったり、執筆中との差分など色々でした。


## LT内容

### 電池を使わないEnOceanの環境センサーとNode-REDをつなぐ方法　<br> 中畑さん

中畑さんがご担当された`IoT・デバイスの活用法`部分で利用していたEnOceanに新しくBLEに対応した製品が登場したのでそちらの説明とNode-REDのサンプルフローの紹介でした。

照明用のDMX/DALI/KNXといった規格も知らない自分ですが、
EnOceanとNode-REDのBLE Beacon Scannerを利用することで簡単に実行できることが分かりました。
やっぱり、Node-REDはライブラリ使うと簡単に開発できるなと思いました。

新しいEnOceanだと太陽光電池がついてて電池が不要で、温度、湿度、照度、加速度、マグネットコンタクトが取得可能のようです。

### 実践Node-RED活用マニュアルで電子ペーパーネタを書きました!<br>ポキオさん

ポキオさんが`IoT・デバイスの活用法`で書かれた天気予報を電子ペーパーに表示する仕組みを説明して頂けました。

個人的には、Node-REDと言えば外部APIを叩いて処理するイメージなのでとても入門に良い題材かなと思いました。
(ただ、本で使用していたlivedoor天気予報がサービス終了してしまったらしいww)
現在は、気象庁のデータから実行できるように変更中らしいです。

### Node-REDからメール送信<br>横井さん

Node-REDの開発チームでもある横井さんです。
ご担当された`SendGridを用いたメール送信方法`について説明頂きました。
Node-REDの標準メール送信だと認証系が厳しい場合があるのでSendGridを用いた方が楽に開発できるよ！という内容でした。
また、月刊I/O10月号でLCDの使い方を紹介予定のようです。(是非書いましょう)

個人的には、SendGridは、APIでメールを送る際に受領確認しか行えないのでメールを送れなかった際の処理をするのが少し面倒くさいなぁと思った過去を思い出しました。
(メール送信結果を取得するAPIもきちんとあります。)


## Node-REDで日常会話ボットを作る<br>メイントピック以外の見どころ<br>水津さん

ご担当された`日常会話ボットを作る`のメイントピック以外の見どころを説明頂きました。
(伏線回収ですね)

GCPでNode-REDを利用する際にGKEでの動かし方しか出てこないけれど、本の中ではApp Engineでの動かし方やGitlabのCI/CD機能を用いてGAEへデプロイする方法など実際に役立ちそうなHow-toが紹介されています。


また、水津さんもポキオさんと同様にAPIが停止していたようですw
ですが、別のAPIに簡単に切り替えられたようです。
これもNode-REDの良いところですね。


## 最後に
イベントに参加してみて、Node-REDはやはりアイデアを形にする(プロトタイプ)際にはとても使いやすいものだと再認識しました。
また、執筆者の中にも本番環境で利用している方々もおり、よりNode-REDが一般的に広まり使われていくのかなと思いました。
10月に行われるNode-RED Conも楽しみになりました。
DockerでCentOS7 + Apache2.4環境をサクッと構築してみる。

身の回りでDockerやLinuxの勉強したい！って人がちょいちょいいたので、勉強用にサクッと出来る手順をまとめました。

# 環境
* Docker for Windows
* CentOS7
* Apache2.4

# 手順
（前提）Docker for Windowsは既に準備済みとします。

### 1.CentOS7のイメージを入手する
```
$ docker pull centos:7
```

### 2.CentOS7のイメージからコンテナを作成する
```
$ docker run -d -it --privileged -p 80:80 --name apache-test centos:7 /sbin/init
abe8af3f37a4f3ea1b0dd169b0039bd485b49f5689e4c4a6042a3b5ea5107c6e
````

```
$ docker ps -a
CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS                     PORTS                               NAMES
b570f5458b41        centos:7                             "/bin/bash"              4 seconds ago       Exited (0) 3 seconds ago                                       apahce-test
```
作成できてますね。

### 3.Apacheの準備・動作確認を行う。
コンテナの中に入って、Apache2.4のインストール→動作確認を行います。

```
$ docker exec -it apache-test /bin/bash
[root@80f5725a647a /]#
```
無事入ることができましたので、 ` yum update`を行い、httpdをインストールしていきます。

```
# yum update -y
# yum install -y httpd
# httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built:   Apr  2 2020 13:13:23
```
バージョン情報が出たので無事にインストール出来たことが確認できました。
ではhttpdプロセスを立ち上げ、実際にアクセスしてみます。

```
# systemctl start httpd
```

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268946/77d96175-3dc9-f5a4-a45e-de59169fecfc.png)
http://[Docker for Windowsを起動した時に出てくる赤枠のIPアドレス]にアクセスします。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268946/49ba743e-fdf8-c0c6-0058-ae2ac9855f2d.png)
無事にアクセスすることができました。


# 余談
CentOS7+Apache2.4の環境ではないですが、さっくりWebサーバを立てたいだけであれば、Docker公式Hubからイメージをpullして動かすのが最速です。

```
$ docker pull httpd
$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
httpd                                latest              a6ea92c35c43        29 hours ago        166MB
$ docker run -d -p 80:80 httpd-test httpd
$ docker start httpd-test
```
systemdを時間帯で管理したい！！

はいはいはいはい、皆さんこんにちは、○○です。
ええ、自粛期間中はYoutubeが捗りますね、いつも面白い動画をありがとうございます。

`systemd`を用いてデーモンを特定の時間帯だけ起動させる方法についてです。
意外と需要ありそうなのですが関連する記事が見当たらなかったので備忘録的に試行錯誤を記しておこうと思います。

##やりたいこと
8時から23時の間だけデーモン（以下ダエモンさんことMr.daemon）を起動しておきたい。
その他の時間は消費電力削減のために停止しておきたい。
ちなみに、操作したいデーモンは自作のもので、起動中に`ffmpeg`でHLSを用いて音声をストリーミング配信し続けるというものです。
余談ですがサービスとデーモンの何が違うのか調べたら、どちらも常駐プログラムで、サービスはWindows系で使われデーモンはUnix系で使われるそうです。

#まず思いついた方法
後ほど問題点を記しますがとりあえず。

##起動編
`systemd`を用いたダエモンさんの起動方法は主に二つ挙げられると思います。

- **自動起動** `systemctl enable {Mr.daemon}`
- **手動起動** `systemctl start {Mr.daemon}`

ですが、これらの方法では時間を指定することはできません。
自動起動ではいつ何時も問答無用で起動してしまいますし、手動起動は言わずもがなです。
そこで時間を指定するためには以下の方法を使えるかと思います。

- **タイマー** `{Mr.daemon}.timer`
- **cron** `0 8 * * * systemctl start {Mr.daemon}`

###`systemd`のタイマー
`systemd`のタイマー機能を利用して特定の時間にダエモンさんを起動できます。

```bash:{Mr.daemon}.timer
[Unit]
#任意の説明
Description=Run {Mr.daemon}.service

[Timer]
#起動したい時刻
OnCalendar=*-*-* 8:00:00 #year-month-date hour:minute:second
#OnCalenderで指定した時刻にOSが寝ていた場合、次回起動時にデーモンを起動
Persistent=true 

[Install]
WantedBy=timers.target
```

このようにユニットファイルを記したら`sudo systemctl enable {Mr.daemon}.timer`でタイマーを有効にします。

###管理者権限`cron`
管理者権限の`cron`でも時間を指定して`systemctl start`を走らせることで同様のことができます。

1. `sudo crontab -e`
2. 右を追記 `0 8 * * * systemctl start {Mr.daemon}`

##停止編
systemdのタイマーでは起動することはできても停止することはできないそうです。
ですので停止するためにはいずれにせよ`cron`を使います。
管理者権限の`cron`に以下のように追記すればよいです。

```
0 23 * * * systemctl stop {Mr.daemon}
```

##上記方法の問題点
さて、上の方法で実装したところ幾つか不都合がありました。
それは8時から23時の間に再起動した後デーモンが起動しないという点です。
当然ですが始まりと終わりのトリガーしか設定していないので、例えばメンテナンス等で9時に再起動した場合は手動で起動しないと翌8時までダエモンさんは眠ったままです。
これでは特定の時間帯だけ稼働するデーモンとしては不十分です。

#ではどうするか
デーモンの起動スクリプトをいじることにしました。

```bash:stream.sh
###追記部分
NOW=`date +%H` #現在時刻の取得
if [ $NOW -ge 23 -o $NOW -lt 8 ]; then #現在時刻が23時~翌8時の間なら
    systemctl stop {Mr.daemon} #デーモンを停止
    exit 0 #正常終了
fi
###

function fork() {
    #処理
}
fork > /dev/null 2>&1 </dev/null &
echo $! > /run/{Mr.daemon}.pid
```

追記部分で23時から翌8時の間にこのスクリプトが走ると処理から抜けるようにしてあります。
この状態で`sudo systemctl enable {Mr.daemon}`として、常に自動起動するようにします。
8時から23時の間では自動起動しますが、23時から翌8時の間は自動起動がキャンセルされるのでダエモンさんは眠ったままです。
最初に試した`systemd`のタイマーとデーモンを停止する`cron`と組み合わせれば特定の時間帯に起動しているダエモンさんの出来上がりです。

##解説
当初`if`の中は`exit`だけでしたが、その状態だと起動が失敗したとエラーが吐かれてしまいました。
`exit 0`として正常終了を返しても同じでした。
別に問題ないといえばそれまでなのですが気持ちが悪いので`systemctl stop {Mr.daemon}`を記述したところ起動キャンセル扱いとなりエラーは出なくなりました。
###`cron`では？
試していませんがデーモン起動スクリプトをいじれなければ同様のことを`cron`でも実現できるでしょう。

```bash
@reboot if [ $NOW -lt 23 -a $NOW -ge 8 ]; then systemctl start {Mr.daemon}; fi
```

このように管理者権限`cron`に追記しておけば23時から8時の間にOSが起動された時ダエモンさんも起動します。
無駄に起動させないので`cron`のほうがスマートな気もしますが`After`や依存関係など`systemd`関連の順番を調整するのが面倒だったので`systemd`のほうで自動起動するようにしました。

#最後に
どうも何れのやり方もスマートな感じがしないので良い方法をご存じの方がいらっしゃいましたらご教授ください。
Composite Collider2Dが使えないときの解決方法

#子オブジェクトからRigidbody2Dを外す
Composite Collider2Dを使おうとしたら、親オブジェクトのInspectorに
![CompositeCollider_Comment_Parent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685029/d0398787-c0b7-bef1-7bc4-00a9902ea630.png)
>"Outline geometry is composed of edges and will not preserve the original collider's center-of-mass or rotational inertia.  The CompositeCollider2D is attached to a Dynamic Rigidbody 2D so you may need to explicitly set there if they are required."

という警告のような文章が出てきて、子オブジェクトのInspectorには
![CompositeCollider_Alart_Child.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685029/b0077279-de46-6a1e-d682-27265f15961f.png)
>"This collider will not function with a composite until there is a CompositeCollider2D on the GameObject that attached Rigidbody2D is on."

という警告が出てきたときの解決法は、
**`「子オブジェクトからRigidbody2Dを外す」`**こと
です。
親オブジェクトにRigidbody2Dがすでにあるはずなので子オブジェクトにはRigidbody2Dは要らないということですね。

#おわりに
子オブジェクトのRigidbody2Dをはずしていなかったことが原因でComposite Collider2Dが使えずに挫折した人も多いかもしれません。この記事が少しでもそういう人たちに読んでもらえたらとても嬉しいです。
私も最初は挫折したうちの一人でした。ですが、ゲーム制作をしている途中でどうしてもComposite Collider2Dを使いたい場面が出てきて、そこで色々と試してこの問題を解決することができました。
最初はInspector内に出てきた警告文をGoogle翻訳で解読しようとしましたが、意味不明な文章にしかならず、翻訳せずに直接検索してみても欲しい答えが見つからず、とても苦労した思い出があります。
誰かにきけばすぐに分かったかもしれませんが、私にはそんな当ても勇気もなくただただ一人で抱え込んでいました。
そんな人のために私はこの記事を書きました。

もしここまで読んで、何か文句があるなら、ここまで読んだ自分自身を責めてください。
もしここまで読んで、共感してくださったなら、ありがとうございます。
[.NET] Angularチュートリアル Tour of Heroes を Blazor で再実装する

Angularの[チュートリアル: Tour of Heroes](https://angular.jp/tutorial) をBlazorを使って再実装してみます。

# Angularチュートリアル Tour of Heroes を Blazor で再実装する 目次

1. [新規プロジェクトの作成](https://qiita.com/sengoku/items/9f4c149f92c3c53772d7)
1. [ヒーローエディタ](https://qiita.com/sengoku/items/81c58a37aeef5899df9f)
1. [リストを表示する](https://qiita.com/sengoku/items/0c5a1d62a73c2c7c91dc)
1. [機能コンポーネントを作成する](https://qiita.com/sengoku/items/08bd0aa23adf88a6bdb8)
1. [サービスを追加](https://qiita.com/sengoku/items/639db14058c82b3310d4)
1. [ルーティングを用いたアプリ内での画面遷移](https://qiita.com/sengoku/items/c5c4b68e23ac87147413)
1. [番外. C#ソースコードとRazorの分離](https://qiita.com/sengoku/items/f3c7006b5709eeead438)
1. サーバからデータを取得する
1. 番外. Blazorコンポーネントのユニットテスト
旧OpenSiv3D(0.4.?)を新バージョンVisualStudio2019(16.6.3以降)で使うときのエラー対策

前回にちょっと書いたが、理由やその他の説明追加

#エラーになる理由
簡単に言うと、昔の命令（STL）の名称が変わり、以前のものが未定義なるといったもの。
それゆえ、ビルドエラーになる
これは OpenSiv3Dライブラリ が新型C++20に対応したため。

#直し方
旧OpenSiv3Dライブラリファイルを以下に変更する。
以下の表に該当する<B> resolt~ </B>ビルドエラーが出たら直す

| エラー例 |
|:--------------------------------------------------------------------------:|
| エラー	C2039	'result_of': 'std' のメンバーではありません	|
が出て、そのメッセージをダブルクリックして飛んで変更してしまえばOK。
ライブラリ本体を変更するので、他で同じバージョンのエラーはすべて消える。
うまく置換を使えば楽に変更できるかもしれません。

| OpenSiv(0.4.2以下) Project(C++11) | VisualStudio2019(16.6.3以降)|
|:-----------------:|:------------------:|
|  変更前|        変更後        |
|             std::result_of|       <B>std::invoke_result</B>|
| std::result_of_t|              <B>std::invoke_result_t</B>|

#ちょっと愚痴
例えばUnityのC#だと、
「この命令は古いです。消える可能性があります」（大意）
となり、使えるけど、もしくはソースコードを新しく書き直す機能ありその場で
変更してくれる（もちろんうまくいかない場合あり）

C言語(SDLエラーで引っかかる命令)では、
「このマクロ使ってね、もしくはこっちの命令を使ってね」（大意）
C++STLで命令名称が変わるなら、
せめてアサートいれて「こっちの命令使ってね」とか、メッセージ出すのは物理的に可能？

GCCがらみや他の開発環境は分かりません。
以前から非推奨となっていたから知ってて当然というC++ならではの高飛車姿勢？

#理想は・・・
前回の記事のように、VisualStudio2019 のバージョンによりビルド振り分けがいいと思いますが、
ちょっと面倒なのと、
バージョンによって該当命令がどこのファイルにあるかわからないのでその辺の手間もあったりします。
古いライブラリのプロジェクトが多くあったりしてちょっとビルドしたいとか動作確認したい場合は、
この辺を直接書き換えた方がいいかとは思います。

しかし、たまたまうまくいっただけで、他にもいろいろあるかもしれません。

やり方が分かれば、ビルド設定を C++11 に変更したらもっとも楽なんですが・・・

現状

| OpenSiv3D バージョン | VisualStudio2019(16.6.3以降)|
|:-----------------:|:------------------:|
| 0.4.1 |   うまくいってない・・・が実はポカミス ※            |
| 0.4.2 |   幾つかプロジェクトを試したが全く問題なしうまくいく|

<font color="DeepPink">※ポカミス</font>
0.4.1 で スペルミス、result  >>  resolt にしてしまい、気が付かず変なところまで
変更してしまい収拾がつかなくなる。

あまり生産性がない作業なのでまあこの辺にして終了にすることにした。

-------------------

もっと作業効率がいい方法を閃いたのでもうちょっとやってみました。

別記事で書いています。
【VSCode】もっとカラーカスタムしたい！

#ココに全てのっている
https://code.visualstudio.com/api/references/theme-color
setting.jsonに`workbench.colorCustomizations`を足そう

例えばTabをカスタマイズしたい場合、tab.**を追加

```json:setting.json
  "workbench.colorCustomizations": {
    "tab.activeBackground": "#7ea7a7",
    "tab.activeBorder": "#FFFFFF",
    "tab.inactiveForeground": "#FFFFFF",
  }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187150/a31d5a73-b189-a1c9-4e11-8593d7850507.png)
Route 53でのサブドメイン管理パターン

つい先日ひょんなことから、自分のサブドメインの切り方が普通のパターンじゃないことに指摘されて初めて気付きました。
忘れない様にメモとして残します。

# 普通のサブドメイン作成方法
https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/dns-routing-traffic-for-subdomains.html
ここに書かれている通り、通常サブドメインを切るときには、ネイキッドドメインのホストゾーンにレコードを作成しルーティングします。
Https通信を許可したい場合には、ACM等を利用して証明書を発行しますが、こちらもワイルドカード指定で証明書を取得しておけば、追加でサブドメイン用の証明書を逐一取得する必要はありません。

<img width="885" alt="スクリーンショット 2020-08-07 12.01.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/82d3142a-b1fa-29e0-62e2-b52cfc3b7871.png">
ネイキッドドメインのホストゾーンを選択
<img width="870" alt="スクリーンショット 2020-08-07 12.03.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/d1862614-2fce-427e-3581-4b92b2e7c808.png">
サブドメインのレコード作成
<img width="610" alt="スクリーンショット 2020-08-07 12.06.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/8fc1e17b-d1fd-b06c-08ea-aa285418ce4b.png">
使用したい名前、ルーティングでレコード作成
ALBに繋げたいときは、エイリアスで指定するなど
<img width="904" alt="スクリーンショット 2020-08-07 12.09.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/f64545f7-e4e7-15ac-f844-bb1fa0b623b2.png">
ネイキッドドメインのホストゾーンにサブドメインレコードを作成していくときに、あらかじめワイルドカード証明書を取得しておくと、新しいレコードに対して追加で証明書が必要なくなる。

# サブドメインをネイキッドドメインとして作成する方法
僕が特に理由もなく普段やってしまっていた方法はこちらでした。どうしてもこのサブドメインは別個のネイキッドドメインとして扱う必要がある場合などの明確な理由がある場合を除いて通常の作成パターンで作成した方が管理しやすいと思います。

このケースにおいては、新たにサブドメインのホストゾーンを作成します。作成したサブドメインのホストゾーンからNSレコードのバリューを取得し、元のドメイン(example.com)のレコードにサブドメインのNSレコードを追加します。その上で、新たに作成したサブドメインのホストゾーン内部で、ルーティングの設定を行います。

<img width="885" alt="スクリーンショット 2020-08-07 12.01.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/82d3142a-b1fa-29e0-62e2-b52cfc3b7871.png">
サブドメインのホストゾーン作成
<img width="890" alt="スクリーンショット 2020-08-07 12.29.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/709b8eee-a84d-c62b-ef51-4326ffc75160.png">
サブドメインのホストゾーン(sub.example.com)のNSレコードの値を取得し、ネイキッドドメイン（example.com）のホストゾーンにサブドメインのNSレコードを作成する
あとは新規に作成したサブドメインのホストゾーンにおいてルーティングの設定をする。

以上
写真にお化粧できる。BeautyGANを手元で試してみました！

![result (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/ed8cf777-9213-d0d3-c9a3-773d249efc73.jpeg)
学習させたお化粧（上の行）を、入力顔にほどこせるというもの。

クローンしてくる。

```shell
git clone https://github.com/Honlan/BeautyGAN.git
```

TesorflowとTensorBoardの1.９が必要なので、インストールする。

```
pip uninstall -y tensorflow
pip install tensorflow==1.9
pip uninstall tensorboard
pip install tensorboard==1.9
```

[リポジトリのリンクから](https://github.com/Honlan/BeautyGAN)トレーニング済みのモデルをダウンロード。
プロジェクトディレクトリ配下にmodelディレクトリを作ってトレーニング済みモデルを入れる。

変換したい画像を指定して実行すると、resultとして出力される。

```
python main.py --no_makeup 'imgs/no_makeup/inputImage.png'
```

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。
[Twitter](https://twitter.com/JackdeS11)
[MLBoysチャンネル]
(https://www.youtube.com/channel/UCbHff-wfjTnB3rtXIP6y0xg)
[Medium](https://medium.com/@rockyshikoku)

[相棒](https://twitter.com/oka_yuuji)
[note](https://note.com/oka_yuuji)
デバッグ用の小ネタを動作確認して車輪を再発明

#環境
Ubuntu20.04LTS on VMWare Player
Core i7 4770 / RAM4GB割り当て
g++/clang++
リポジトリ [https://github.com/pff01632/EnterLeave](https://github.com/pff01632/EnterLeave)
#何をするものか？
関数の先頭で TRACE(); と一行書いておくだけで、その関数への突入と離脱のログが取れる。std::coutに出力しているが、任意のログ出力ライブラリに置き換えてもよい。これを使うメリットとしては、

- いちいち離脱時のログ出力を書かなくて良い
- 途中離脱でも正しくログ出力してくれる
- 関数名を自分で書く必要がない
- オーバーロードやC関数との名前の競合も正しく判断する

といったところ。関数先頭に TRACE() マクロを定義すると、EnterLeaveクラスの自動変数を暗黙的に定義する。変数は自動的に初期化され、Enterを出力する。関数の途中を含む任意のポイントで関数から離脱すると、自動変数であるEnterLeaveクラスのデストラクタが走り、Leaveを出力してくれる。
#コード
```EnterLeave.h
#ifndef     _ENTER_LEAVE_H_
#define     _ENTER_LEAVE_H_
#include    <bits/stdc++.h>

class EnterLeave {
    public:
        EnterLeave(std::string name)
        {
            nm = name;
            std::cout << nm << " Enter." << std::endl;
        };
        ~EnterLeave()
        {
            std::cout << nm << " Leave." << std::endl;
        };
    private:
        std::string nm;
};
#define     TRACE()     EnterLeave  trace_instance(__PRETTY_FUNCTION__)

#endif  //  _ENTER_LEAVE_H_
```

```main.cpp
#include	"EnterLeave.h"

class testclass
{
public:
	testclass()
	{
		TRACE();
	};
	~testclass()
	{
		TRACE();
	};
	void testfunc()
	{
		TRACE();
	};
};

void testfunc()
{
	TRACE();
}

int main(int argc, char *argv[])
{
	TRACE();
	testfunc();
	testclass tst;
	tst.testfunc();
	return	0;
}
```
https://dl.eff.org/certbot-autoからインストールしたcertbot-autoとSELinux

#certbot-autoが自動更新後にPermission denied

##対象っぽいかんじ

CentOS8での話だけど他でも該当すると思います。

* certbot-autoをwgetとかで/usr/local/bin/certbot-autoにインストールしているパターン
* SELinux有効
* 自動更新有効(特にオプションを指定していないので)
* systemd timerで回している(これは関係ないか)

##現象
certbot-autoが自身を自動アップデートする場合があり、その後SELinuxに怒られて動かない。

```console:
certbot-renew.service: Failed at step EXEC spawning /usr/local/bin/certbot-auto: Permission denied

SELinux is preventing (bot-auto) from execute_no_trans access on the file /usr/local/bin/certbot-auto.
If you want to fix the label. /usr/local/bin/certbot-auto default label should be bin_t.
```

えー。

```console:
# ls /usr/local/bin/certbot-auto -Z
-rwxr-xr-x. 1 root root system_u:object_r:tmp_t:s0 79656  03:39 /usr/local/bin/certbot-auto
```

`bin_t`だったはずが`tmp_t`になってますね。

## hook試したけどダメだった

hookにrestorecon仕込んでみたけど鍵再発行タイミングではなくcertbotの自動更新だけだとhook対象外みたい...

##てゆーか、なんでやねん

```shell:
cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
```

`$TEMPDIR`はmktempしているみたい。
元を`-p`でコピーしておいてファイル更新してもどしてるらしい。
ここに`--preserve=context`つければいけそう...?
でもSELinuxない環境だとこのオプションなかったりするのかな。

#結局

良策思いつけませんでした。`certbot-auto --no-self-upgrade`つければ済むっぽいけど残念な感じですね。
CentOS8ではepelに入荷してました。

```shell:
dnf --enablerepo epel info certbot
```
【Vue】Computed, Methods, Watchの使い分けをざっくりと

初学時にちがいがわからなかったこの３つをざっくりと分別すると、

#Computed
リアクティブに再評価される
必ずreturnする必要がある

#Watch
特定のプロパティの変更によって処理を行いたい時に使う

#Method
function全般
必ずしもreturnする必要はない
WSL2のメモリ枯渇問題にcronで毎分キャッシュドロップして対処する話

# はじめに
Always Onデバイスで問題を起こし、長らくアップデートを止められていたWindows 10 2004がようやく僕のSurface Laptop3にも降りてきました。

早速WSL2をと思ったところで、メイン機で発生したメモリ枯渇問題を思い出したのでcronを使って頻繁にキャッシュをドロップして対処してみました。

# 設定
Ubuntuを使用していますが、インストールしたデフォルトではcronが動いていないので動かします。

```
sudo service cron start
```

キャッシュを落とすコマンドはsudoして動かすので、（ごちゃごちゃやるのが面倒なので）rootのcrontabを使います。

```
sudo su
```
crontabでcronの設定を行います。初回は以後どのエディタを使うか聞かれますがお好みで。僕はVimを選択しました。

```
crontab -e
```

毎分キャッシュを落とすコマンド[^1]を書きます。

```
* * * * * sh -c "echo 3 >'/proc/sys/vm/drop_caches' && swapoff -a && swapon -a"
```

ちなみに5分毎が良ければ以下のような感じになります。

```
*/5 * * * * sh -c "echo 3 >'/proc/sys/vm/drop_caches' && swapoff -a && swapon -a"
```

保存するとcronjobが有効になり、設定した時間間隔でコマンドが走ります。

# 様子

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359618/e86e9510-494a-94e4-649d-477c9b51fffa.png)



タスクマネージャーを観察していると1分後にVmmemのメモリ使用量が約1.1GBから666MBまで減少したので、きちんと動いているようです。

キャッシュを大量に必要とするような何かしらをWSL上で動かすときに惨事が発生しそうな気もするのですが、開発系のアプリケーション以外にも（主にTeamsとかOutlookとかのメモリ食い虫を）開いておかないといけない環境ですので、.wslconfigを触ってメモリ上限を決めるやり方よりは常にメモリが空いてくれている方が何かとうれしいのでこのやり方にしました。問題が起きるようならまた別の対策を考えます。

メインマシンならメモリが64GBあるので迷わず.wslconfigに上限32GBとか設定するのですが、Surface Laptop3は16GBしかないので……。


[^1]: https://qiita.com/yoichiwo7/items/e3e13b6fe2f32c4c6120
RUSTチュートリアルをとにかくわかりやすくまとめる会 in Zerobillbank

# 本会について

本会はZerobillbank Japan内の有志で結成したRUSTコミュニティで、
**RUST初学者達が同じ初学者向けにRUSTをわかりやすく伝える**
会となっております。

基本的には[RUST公式チュートリアル(2nd Edition)](https://doc.rust-jp.rs/book/second-edition/)をベースに進めております。
動作確認については[こちら](https://play.rust-lang.org/)のPlaygroundを利用させていただいています。


# お品書き

1. [RUST環境構築](https://qiita.com/Veritas666777/items/c01a0df0c9b97f6b2a95)
2. [変数束縛と可変性](https://qiita.com/shushutochako/items/c272f7a60d5e1edf8d30)
3. [Rustのデータ型について](https://qiita.com/shushutochako/items/efa4427f9750e69a6a05)
4. [RUSTの構造体の型定義とインスタンス化のおはなし](https://qiita.com/Veritas666777/items/d6ac38b4220275257e86)
5. [所有権という概念](https://qiita.com/issei_k/items/03f04620610fe997aebf)
6. [参照と借用](https://qiita.com/issei_k/items/3c8f5733546ce1971837)
7. [モジュールの読み込み方と使い方](https://qiita.com/issei_k/items/f55f9e929831efc88244)
8. [モジュールとファイルシステム](https://qiita.com/issei_k/items/9570de4d5c75fc1cb694)
9. and more...

*and more以降は随時更新予定です。*
Pillowで透過画像を合成したら背景画像の一部も透明になってしまうときの対処法

# まえがき
Pillowを使って大きさの違うPNG画像を`img.paste`で重ねたら、上レイヤーの透過が下レイヤーまで貫通して背景が一部分なくなってしまうという現象が発生したので、その対処法のメモ。

# 環境
Python 3.8.2
Pillow 7.2
Ubuntu 20.04 on WSL2

# 背景と重ねたい画像
背景(bg_cloudy.png)
![bg_cloudy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687640/d2a3c66f-2ffe-e2e2-135d-fbb2fbf33884.png)

重ねたい画像(cloudy.png)
![cloudy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687640/f6938879-0d25-2843-7e92-8b1a48d1ece3.png)

# これは背景に不具合が出る
ただ`bg.paste`で`img`を重ねるようとすると切れる

```python
from PIL import Image

#背景画像をオープンしてRGBAに変換
bg = Image.open('bg_cloudy.png').convert('RGBA')
img = Image.open('cloudy.png').convert('RGBA')

#ペースト
bg.paste(img, (232, 412))

bg.save('fail.png')
```

## 結果
雲のアイコンの透過部分で背景も透過されてしまっている
![fail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687640/f0c875fe-ec74-b22b-4b0c-0ab8d3a6ae2c.png)

# 対処法
`Image.alpha_composite(bg, img)`を使うことで回避できる。ただし第一引数と第二引数の画像のサイズが一致している必要があるので、一旦背景と大きさを揃えた何もないの透過画像の上の指定位置に貼り付けてから重ねて合成をする。

```python
from PIL import Image

bg = Image.open('bg_cloudy.png').convert('RGBA')
img = Image.open('cloudy.png').convert('RGBA')

#背景と同サイズの透明な画像を生成
img_clear = Image.new("RGBA", bg.size, (255, 255, 255, 0))

#透明画像の上にペースト
img_clear.paste(img, (232, 412))

#重ね合わせる
bg = Image.alpha_composite(bg, img_clear)

bg.save('success.png')
```

## 結果
透過部分に不具合出ることなく狙い通りに合成できた。
![success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687640/5c464e1e-b617-948d-405c-843894182f57.png)

# 参考
[https://www.it-swarm.dev/](https://www.it-swarm.dev/ja/python/pil%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E9%80%8F%E6%98%8E%E3%81%AApng%E7%94%BB%E5%83%8F%E3%82%92%E5%88%A5%E3%81%AE%E7%94%BB%E5%83%8F%E3%81%A8%E3%83%9E%E3%83%BC%E3%82%B8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/971486727/)

# 画像の出典
背景の雲の画像
https://www.priga.jp/
アイコンの雲の画像
https://github.com/twitter/twemoji
編集、削除の権限を投稿者だけにしたい 

## バージョン
・ruby 2.5.7
・Rails 5.2.4.3

## 編集、削除の権限を投稿者だけにしたい 
CRUD処理は出来た！
けど、このままだと全ての投稿を編集や削除が出来てしまう状態。

編集、削除の権限を投稿者だけの機能にしたい。



```ruby:tasks_controller.rb

class TasksController < ApplicationController

  def index
    @tasks = Task.all
  end

  def new
    @task = Task.new
  end

  def create
    Task.create(task_params)
  end

  def show
    @task = Task.find(params[:id])
  end
  
  def edit
    @task = Task.find(params[:id])
  end

  def destroy
    task = Task.find(params[:id])
    task.delete
end

  def update
    task = Task.find(params[:id])
    task.update(task_params)
  end

  private
    def task_params
        params.require(:task).permit(:title, :content)
    end
end


```

## ユーザーの投稿を守る為に下記のメソッドを使う
unlessはもし〜でなかったらと言う意味。下記でいうと、

もし受け取ったユーザーのIDが、ログインしているユーザー(current_user)のIDと一致しなければ
処理を実行せずリダイレクトで戻しますよっていう意味です。

```ruby:tasks_controller.rb
  private
    def task_params
        params.require(:task).permit(:title, :content)
    end
    ##以下を追加
   def baria_user
  	unless Task.find(params[:id]).user.id.to_i == current_user.id
  		redirect_to tasks_path(current_user)
  	end
   end
end
```


##before_actionでメソッドを呼び出して、完成！！！
before_actionはコントローラーの全てのアクションが実行される前に実行されるものです。

今回は編集と削除のみの場合で行いたいので、editとupdateとdestroyのみにしています。

```ruby:tasks_controller.rb

class TasksController < ApplicationController
before_action :baria_user, only: [:edit, :destroy, :update]

  def index
    @tasks = Task.all
  end
```
コマンドラインから、git logで見れる最新commitのハッシュを取得する

git logで以下のようなログが表示されることを前提としたとき、

```
$ git log
commit 1413718bb40c9a1ebd4ffe037f934076df4c70eb (HEAD -> master, origin/master, origin/HEAD)
...
```

以下のようにして最新commitのハッシュを取得する

```
$ git log | head -1 | cut -d' ' -f 2
1413718bb40c9a1ebd4ffe037f934076df4c70eb
```

# 備考
何かもっと良い方法があるような気もする
Django　非ログインユーザはlogin.htmlへ遷移させたい時

#クラスの場合　LoginRequiredMixin　を使う

```.py
from django.contrib.auth.mixins import LoginRequiredMixin
# 略
 
class Top(LoginRequiredMixin, generic.TemplateView):
    template_name = 'hogehogeapp/index.html'　　　☛☛☛hogehogeappの部分はアプリケーション名を入力する
```

#関数の場合　login_requiredデコレータを使う

```.py
from django.contrib.auth.decorators import login_required

@login_required
def hogehoge(request, pk):
    hogehoge
```
Puppeteer 文字列で 特定の要素を選択したい時、またその文字列の近くの要素をクリックしたい時

#Puppeteer 文字列で 特定の要素を選択したい時、
またその文字列の近くの要素をクリックしたい時

##なぜ文字列で選択したいか

・Xpath脳死コピペ
・HTMLタグ
・クラス名やID名
では**限定しきれない時**があるから

例えば
Yahoo!広告アカウントに送られてくる特定の名前のレポートのみをクリックしたい時
**(あくまで抽象化するための例)**


##ポイントは２点

**①文字列で選択する方法**
**②その文字列自体をクリック・抽出しても意味がない
aタグまでパスを渡す**

#結論：Xpathあんま理解してなかったのが俺が悪い


```app.js
const reportPath =
    "//span[contains(text(), 'hogehoge')]/../..//a";

await page.waitForXPath(reportPath);
const reportClick = await page.$x(reportPath);
await reportClick[0].click();

```

``
nuxt(spa)でrollbarにsource mapをuploadする

```sh:upload_sourcemap.sh
#!/bin/sh

# Save a short git hash, must be run from a git
# repository (or a child directory)
version=$(git rev-parse --short HEAD)

# Use the post_server_time access token, you can
# find one in your project access token settings
post_server_item=$ROLLBAR_CLIENT_KEY

echo "Uploading source maps for version $version!"

# We upload a source map for each resulting JavaScript
# file; the path depends on your build config
for path in $(find dist/_nuxt -name "*.js"); do
  # URL of the JavaScript file on the web server
  js_file=$(basename $path)
  url=https://$1/_nuxt/$js_file

  # a path to a corresponding source map file
  source_map="@$path.map"

  echo "Uploading source map for $url"

  curl --silent --show-error https://api.rollbar.com/api/1/sourcemap \
    -F access_token=$post_server_item \
    -F version=$version \
    -F minified_url=$url \
    -F source_map=$source_map \
    > /dev/null
done
```

ciでbuildした後に以下を実行

`./upload_sourcemap.sh example.com(運用しているドメイン)`
docker をキャッシュを使わないでビルドする

docker build時に参照ファイルを更新したにもかかわらず、docker build時に反映されない場合はキャッシュクリアすると良い。

```
docker build . --no-cache
```

docker-composeを使う場合は以下

```
docker-compose build --no-cache
```

# 参考
[Dockerのビルド時にGithubのプライベートリポジトリをcloneする](https://blog.leko.jp/post/how-to-clone-private-repository-in-docker-build/)
[頭の体操] 逆ポーランド記法の列挙とその計算

# 列挙

`[1, 2, 3, 4]`を与えられた時に四則演算ですべてのパターンを列挙する

```rb
require "set"
NUMBERS = [1, 2, 3, 4]
SIGNS = %i[+ - / *]

results =
  NUMBERS.permutation(4).uniq.each.with_object(Set.new) do |numbers, results|
    (SIGNS * 3).permutation(3).uniq.each do |signs|
      a, b, c, d = numbers
      x, y, z = signs

      [c, d, x, y].permutation(4).uniq.each do |combination|
        next if combination.join.match(/\A([^\d]{2})/)

        results << ([a, b, *combination, z]).join(" ")
      end
    end
  end

# results.size => 7680
```

# その計算

`1 2 3 4 + - /`を与えられた場合、-0.2を返す


```rb
require 'active_support/core_ext/object/blank'

class Rpn
  SIGNS = %i[+ - / *]

  class << self
    def calc(rpn_text)
      rpn = new(rpn_text)
      rpn.calc
    end
  end

  def initialize(rpn_text)
    @stack = notation_to_a(rpn_text)
  end

  def calc(this_stack = stack)
    return this_stack.first if this_stack.size == 1

    operator_at = this_stack.index{|x| SIGNS.include? x }
    operator = this_stack[operator_at]
    value = this_stack[operator_at - 2].send(operator, this_stack[operator_at - 1])
    this_stack[(operator_at - 2)..operator_at] = value

    return calc(this_stack)
  end

  private

  attr_reader :stack

  def notation_to_a(rpn_text)
    rpn_text.chars.select(&:present?).collect do |x|
      SIGNS.include?(x.to_sym) ? x.to_sym : x.to_f
    end
  end
end

Rpn.calc("1 2 3 4 + - /") # => -0.2
```
UnityのTouchScriptでシングルタップとダブルタップを取得する

#概要
Unityで高機能なタッチ処理を提供してくれる[TouchScript](https://github.com/TouchScript)で、シングルタップとダブルタップを取得する設定です。
別オブジェクトに設定するのは簡単ですが、同じオブジェクトがシングルタップとダブルタップの両方に対応するのは少し厄介だったので紹介します。
(公式のサンプルも別オブジェクトに設定していた・・・)

#環境
Unity 2019.2.16.f1
TouchScript 9.0

#設定方法
###Inspector設定
今回はuGUIでImageを作り、Imageがシングルタップされた時とダブルタップされた時で別の処理をします。
![inspector1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687803/866de1c8-1eb8-a6ff-f316-f77abb700ecd.png)
RectTransformの値は適当

![inspector2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687803/fba39265-e6c2-e177-7321-630e45bc1910.png)
TapGestureの詳細
シングルタップ用とダブルタップ用で2つのTapGestureをアタッチします。

- シングルタップ用TapGestureの設定
    - Number of Taps RequiredをOneにする
    - Require Other Gesture to FailのチェックをONにして、Valueにダブルタップ用のTapGestureを指定する
        - ※自分の環境だとONにしてすぐコンポーネントをドラッグしてもセット出来ない謎現象が起きました
        - ※自分自身のオブジェクトをHierarchyからドラッグ、ゲームを再生してすぐ停止、コンポーネントをドラッグという謎点順で行けました・・・
- ダブルタップ用TapGestureの設定
    - Number of Taps RequiredをTwoにする
    - Limit Timeを0.5にする
        - ダブルタップと判定するしきい値なので、ご自由に調整下さい

###スクリプト
```C#
using TouchScript.Gestures;
using UnityEngine;

// シングルタップとダブルタップの両方を取得する
public class TouchTest : MonoBehaviour
{
    [SerializeField]
    private GameObject image; // Inspectorで自分自身をセットしておく

    private TapGesture m_tapGesture;
    private TapGesture m_doubleTapGesture;

    // Awake→OnEnable→Startなので、Awakeで設定する
    // そもそもSerializeFieldでそれぞれのコンポーネントを持っててもOK
    private void Awake()
    {
        // 1つめがシングルタップ、2つめがダブルタップに反応する
        var tapGestures = image.GetComponents<TapGesture>();
        m_tapGesture = tapGestures[0];
        m_doubleTapGesture = tapGestures[1];
    }

    // メモリリークを避けるために、OnEnableで有効化してOnDisableで無効化
    private void OnEnable()
    {
        m_tapGesture.StateChanged += HandleTap;
        m_doubleTapGesture.StateChanged += HandleDoubleTap;
    }

    private void OnDisable()
    {
        m_tapGesture.StateChanged -= HandleTap;
        m_doubleTapGesture.StateChanged -= HandleDoubleTap;
    }

    // シングルタップ時のイベント
    private void HandleTap(object sender, System.EventArgs e)
    {
        if (m_tapGesture.State != Gesture.GestureState.Recognized)
        {
            return;
        }

        Debug.Log("tap");
    }

    // ダブルタップ時のイベント
    private void HandleDoubleTap(object sender, System.EventArgs e)
    {
        if (m_doubleTapGesture.State != Gesture.GestureState.Recognized)
        {
            return;
        }

        Debug.Log("doubletap");
    }
}
```

このスクリプトをImageオブジェクトにアタッチして、SerializeFieldにImageオブジェクト自身をセットすれば、タップとダブルタップを取得出来ると思います。

- 一回目のタップから[Limit Time]秒経過→シングルタップイベント
- 一回目のタップから[Limit Time]秒経過前に二回目のタップ→ダブルップイベント

になるので、Limit Timeは使いやすいと思う値に設定して下さい。

#参考文献
https://github.com/TouchScript/TouchScript/issues/217
RUSTの環境構築とHello,world!について

# まえがき
この記事はRUSTチュートリアルをZerobillbank社内メンバー（有志）で勉強がてら、可能な限りわかりやすく内容を書き出す企画の一部です。

なお、初学者のため（略）という免責を打ちつつ間違いなどあればコメントで教えていただけますと一同嬉しく思います！

# 概要
rustの環境構築とHello, world!をやるよ
<b>項目的にコマンドの羅列</b>だよ

# 環境構築
### rustupのインストール
#### Mac,Linuxの場合
rustupツールのインストール
`$ curl https://sh.rustup.rs -sSf | sh`

pathの追加
`$ source $HOME/.cargo/env`
`$ export PATH="$HOME/.cargo/bin:$PATH"`

#### Windowsの場合
下記のURLでインストーラーをダウンロードして実行する
`https://www.rust-lang.org/install.html`

### その他のrustコマンド
#### アップデート
`$ rustup update`

#### アンインストール
`$ rustup self uninstall`

#### バージョン確認
`$ rustc --version`

#### ドキュメンテーションの起動
`$ rustup doc`


## Hello, world!をやっちゃうぜ

### ディレクトリ作成
もちろんディレクトリの場所は任意でOK

```
$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world
```

### プログラム作成
`main.rs`を作る

ターミナル上なら`vim main.rs`

```rust
fn main() {
    // 世界よ、こんにちは
    println!("Hello, world!");
}
```

### プログラムの実行

```
$ rustc main.rs
$ ./main
Hello, world!
```

### Rustプログラムの解剖

#### メイン関数
メイン関数は最初に実行される特別な関数だよ

```
fn main() {

}
```

#### コードの書き方
```
println!("Hello, world!");
```

ポイント
1. タブではなくスペース4つでインデントする
2. `println!`は関数ではなくマクロを呼び出してる 
3. `"Hello, world!"`の文字列を引数として,`println!`が画面に表示している
4. 行の最後を`;`で終える

### コンパイルと実行
プログラムを実行するには、ソースファイルをコンパイラに渡してコンパイルする必要があるよ。

```
$ rustc main.rs
```
コンパイルに成功すると、実行可能ファイルが出力されるよ。

```
$ ls
main  main.rs
```

ファイル名を指定することで実行するよ。

```
$ ./main
Hello, world!
```

# Cargo
#### 主な機能  
・ Rustのビルドシステム
・ パッケージマネージャ
・ プロジェクトの管理
コードのビルドや依存しているライブラリのダウンロード等をしてくれるため便利

#### バージョン確認
```
$ cargo --version
```

### プロジェクトの作成
`hello_cargo`というバイナリ形式の実行可能ファイルを作成する

```
$ cargo new hello_cargo --bin
$ cd hello_cargo
```

```
├── Cargo.toml
├── src
│   └── main.rs
```

Cargo.tomlのなかみ
[toml](src="https://github.com/toml-lang/toml")はCargoの設定フォーマット

```
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]

[dependencies]
```
`[package]`
パッケージ設定していることを示すセクションヘッダー

`[dependencies]`
プロジェクトの依存を列挙するセクションの始まり
パッケージのコードはクレートとして参照される

### Cargoでのビルドと実行
#### チェック
```
$ cargo check
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
```
#### ビルド
```
$ cargo build
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
```
#### 実行
```
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_cargo`
Hello, world!
```
JavaScript: 「エラトステネスの篩」を読んで関数にしてみた

とくに必要というわけではないのですが、最近、素数づいてるので書きます。

[「エラトステネスの篩」の説明の記事](https://qiita.com/Ryo-N-cell/items/69af363597b0a6fd7e1b)を読んで、全然頭に入ってこなくてもやっとしてしまったので。
(記事のせいではないです。だんだん理解力が...)

...困ったときのwikipedia。
[エラトステネスの篩](https://ja.wikipedia.org/wiki/エラトステネスの篩)

> アルゴリズム
(中略)
ステップ 1
探索リストに2からxまでの整数を昇順で入れる。
ステップ 2
探索リストの先頭の数を素数リストに移動し、その倍数を探索リストから篩い落とす。
ステップ 3
上記の篩い落とし操作を探索リストの先頭値がxの平方根に達するまで行う。
ステップ 4
探索リストに残った数を素数リストに移動して処理終了。

だそうな。

やってみます。
たぶん末尾再帰案件だとあたりをつけました。

```js
const primesInner = primes => sieveds =>
  sieveds[0] > Math.sqrt(sieveds[sieveds.length-1]) ? [...primes, ...sieveds] //ステップ3>>4
  : primesInner( [...primes, sieveds[0]] )(
      sieveds.slice(1).filter( e => e % sieveds[0] != 0 )
    )  //ステップ2

const primesUpTo = n =>
  primesInner( [] )( [ ...Array(n + 1).keys() ].slice(2) ) //ステップ1

primesUpTo(100)
/*
[
   2,  3,  5,  7, 11, 13, 17, 19,
  23, 29, 31, 37, 41, 43, 47, 53,
  59, 61, 67, 71, 73, 79, 83, 89,
  97
]
*/
```
ああ、こういうことね。これだったらわかるわ...
Laravelのタスクスケジュールが動かない(24時設定）

昨日まで動いていたのに、今日は動かない・・・
昨日のリリースが悪いのかしら。。でも何も悪いことしていないのに・・・

# スケジュール定義を見直そう
スケジュールタスクは全部```App\Console\Kernel```クラスの```schedule```メソッドの中に定義します。
この定義でミスしていました。
毎日２４時に実行したいからって

```php
$schedule->command('cms:update-article-point')->dailyAt('24:00');
```

と書くと落ちます。こんなログを吐いて死にます。

```
In CronExpression.php line 155:
  Invalid CRON field value 24 at position 1
```

このように書きましょう。

```php
$schedule->command('cms:update-article-point')->dailyAt('00:00');
```
502エラーで困った話

# 502(Bad Gateway)嫌い
フロントのフレームワークの勉強をしていてバック側で作成したapiを叩いてみたら502エラー

### エラー内容

```
502(Bad Gateway)
upstream sent too big header while reading response header from upstream
```

## 問題：
> chromeからurl直打ちでgetすると正常に表示される*のですが、
vue側でaxios.getを行うと502(bad gateway)エラーになります。

エラーが発生した環境

* docker仮想環境
* フロントエンド：Vue.js  2.6
* バックエンド　：Laravel  7
* dockerコンテナ：nginx, php-fpm


## 原因：
1. upstream sent too big header while reading response header from upstream
2. PCのスペック不足による仮想サーバのダウン

## 解決：
> 1.  upstream sent too big header while reading response header from upstream

簡単な通信を行っているのでバッファを大きくする必要はなさそう。。
(一応言われたとおりにnginxとphp-fpmのレスポンスヘッダのためのバッファサイズを[この記事](https://oxynotes.com/?p=12011)を参考に大きく確保しました。)
### →これでは解決せず
<br>
> 2. PCのスペック不足による仮想サーバのダウン

これが一番ありそうだったのでPCを再起動後もう一度検証してみたらエラー出ませんでした。
### →解決（？）

## 他に原因かもしれないこと
* ```⌘ + shift + R``` (リソースから直接読み込み)だと100%502エラーになる<br>
   →　複数リクエストが原因？
Rotrics DexArmを使ってみた #1

仕事で[Rotrics DexArm](https://rotrics.com)を触る機会があったのでメモ。素人丸出しなところだらけですので、ご指摘頂けると嬉しいです m(_ _)m

まずは、Macに[Rotrics Studio](https://www.rotrics.com/pages/download)をダウンロードして使おうとしたのですが、どうしてもUSB接続した本体を認識しません。[VCPドライバ](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)が必要なのかも？と思ってインストールしてみましたが、これも有効化できず断念（私のMacBook Proの問題）。Linux版のStudioはまだ無さそうです。[SDK](https://manual.rotrics.com/api-and-sdk/untitled)もどうもまだ開発中のようで何も無い…。

付属のコントローラからは動かせるので、一応遊べるのですが、これではタダの高価なラジコン…。

ということで少し路線を変更して、シリアル通信でGCodeを流し込む作戦。今回、Linux機としてRaspberryPiを用意していました。付属のUSBコードを接続して、`lsusb`コマンドで見てみると、デバイスが認識されています！

```
STMicroelectronics Virtual COM Port
```

- 参考: [LinuxのUSB](https://qiita.com/propella/items/66eb1e93cc71ebea3829)

Screenコマンドで、以下のように接続が可能です。

```bash
screen /dev/ttyACM0 115200
```

エコーバックがないので、ちょっと使いづらいです（設定方法がある？？）。

まとめて動かすには、Pythonのserialモジュールが便利です。

```python
#!/usr/bin/env python3
import serial, time

s = serial.Serial("/dev/ttyACM0",115200)

def w(gcode):
    s.write(gcode.encode('utf-8')+b'\r\n')
    while (not s.read()): pass

#main function
def main():
    # アームを初期位置に
    w("M1111")
    time.sleep(1)
    # 動作速度の設定(8000が最大？？)
    w("G0 F8000")
    # アームを指定した座標まで動かす
    w("G0 X150Y0Z100")
    w('G0 X0Y300Z0')
    w('G0 X0Y-300Z0')
    w('G0 X150Y150Z0')
    w('G0 X150Y-150Z0')
    w('G0 X300Y0Z0')
    w('G0 X200Y0Z50')

if __name__ == '__main__':
    main()
```

（2020.09.08更新）gcodeを書き込んだ後、serial.readを挟むと安定して動くようになりました。

めっちゃ魅力的な製品なんですが、もう少しお手軽に制御できるライブラリなどが出てくると良いかな、と思いました。

続き: [Rotrics DexArmを使ってみた #2](https://qiita.com/lumbermill/items/0bca8e32235d9d00bb1e)
Vue.jsでcssのカスタムプロパティーを使って背景画像を動的に変更する

# 概要
vue.jsでコンポーネントを作成した際に、cssで指定する背景画像を指定したいことってあると思うんですが、その方法についてハマったので共有します。


# 作ったもの
※ compostionAPIを使っていますが、必要に合わせてお使いのものにしてください。

```vuejs
<template>
  <section :style="styles">
   <h2>タイトル的な何か</h2>     // ここで使う背景画像を動的に変更したいとする
  </section>
</template>

<script lang="ts">
import { defineComponent, PropType, computed } from '@vue/composition-api'

type ContentType = 'hoge' | 'fuga'

const iconUrl: { [key in ContentType]: NodeRequire } = {
  hoge: require('@/assets/images/hoge.png'),
  fuga: require('@/assets/images/fuga.png')
}

type Props = {
  contentType: ContentType
}
export default defineComponent({
  name: 'custom-component',
  props: {
    contentType: {
      type: String as PropType<ContentType>,
      required: true
    }
  },
  setup(props: Props) {
    const styles = computed(() => {
      return {
        '--url': `url(${iconUrl[props.contentType]})`
      }
    })
    return {
      styles
    }
  }
})
</script>

<style lang="scss" scoped>
 section {
   h2 {
     background: var(--url)
   }
 }
</style>
```

## 説明
* Vue.jsでCSSのカスタムプロパティを動的に追加するにはコンポーネントに `<:style="style">` でデータを渡して上げることで使えます。
    * こうすることで `root.element` の中にカスタムプロパティが登録されます。
* 画像データのパスはそのまま渡しても、assetsのデータはバイナリで展開されるので、 `require('画像パス')` で読み込んだ状態のものを `url()` に貼り付けた状態のものを渡して上げることでCSS内で動的に画像が変更されます。
    * ここが結構トラップなので注意




## 使う時
```vuejs

<custom-component contentType="hoge"/>

or

<custom-component contentType="fuga"/>
```

使うときは、`contentType` に指定したtypeを指定してあげるだけです。
※ ここのtypeはunionで指定していますが、コンパイルエラーにはならないけど...



# さいごに
画像が展開されたものになっていることを忘れていて、結構時間がかかってしまいました。
普段CSSをメインに触っていないので、 `url()` がどんな動作をしているのかとか理解が少なかったのでなれないことをやると時間かかりますね。