OmniAICreator/Qiita-1.07M huggingface dataset:
ubuntu16.04でkeras-yoloを使用し動画を読み込む

# 目的

前回、darknet_rosをインストールしてROS上でyoloを使用してみました。

今度は動画を読みこませたいと思います。

なぜかというと、物体認識をする現場にいるわけじゃないので、
現場で動画を撮影してきてテストしたいと思い…

本家のyolov3は静止画かwebカメラにしか対応していないので、
撮影した動画にたいして物体認識できるようにkeras-yoloをインストールします。
そしてyolov3で学習させた自前のデータを使って認識してみます

# 環境
ubuntu16.04
Nvidia 384.183
CUDA 9.0
python2.7.12
python3.5.2

# 必要なもの
TensorFlow-gpu 
Keras
Keras版YOLOv3

# TensorFlowのインストール

python3系を使っていくので、pip3でpython3にインストールします。
またデフォルトはpython2.7のため、pythonを実行するときには**python3**と指定していきます。

```
sudo pip3 install tensorflow-gpu
```

# Kerasのインストール

```
sudo pip3 install keras
```

# Keras版yoloのインストール

```
git clone  https://github.com/qqwweee/keras-yolo3.git
```

# 自前データのコピー＆変換

今回私は自前データを使いたいと思いますので、
darknetで学習とテストをするときに作成した以下のファイルをさっきcloneしてきたkeras-yolo3フォルダの直下に置きます。
piyopiyo_test.cfg
piyopiyo.weights

さらに、自前の学習データのclasses.txtをmodel_data/以下に置きます。


そして重みをkeras用に変換します。

```
cd keras-yolo3
python3 convert.py piyopiyo_test.cfg piyopiyo.weights model_data/piyopiyo.h5
```

# yolo.pyを修正

```
class YOLO(object):
    _defaults = {
        "model_path": 'model_data/piyopiyo.h5',　　#ココ
        "anchors_path": 'model_data/yolo_anchors.txt',#ココは変えなくてもうまくいきました。何かよくわからん。
        "classes_path": 'model_data/classes.txt',　#ココ
        "score" : 0.3,
        "iou" : 0.45,
        "model_image_size" : (416, 416),
        "gpu_num" : 0,
    }
```

anchorって何なんだろう…と調べてみたら、bouding boxのアスペクト比のことみたいです。
何種類か定義されているので探索に使う時のって意味なのでしょうか…
これを変えるとうまくいかなかった、という記事もあったりしたのでデフォルトのまま使うことにします。



# 実行

画像の場合は

```
python3 yolo_video.py --image
```
動画の場合は

```
python3 yolo_video.py --input hogeohoge.MOV
```

画像の場合は後でInput image filenameを求められます。


しかしエラーが…

```
ImportError: /opt/ros/kinetic/lib/python2.7/dist-packages/cv2.so: undefined symbol: PyCObject_Type
```
なぜかrosのpython2.7からcv2を探していて、opencvがimportできていない模様

# 解決策
https://qiita.com/ReoNagai/items/112c3a8b6cd55c3e5380
神のような記事!!ありがとうございます:bow:


>
```
python3
import sys
print(sys.path)
```

>を実行すると

>
```
['', '/home/nvidia/catkin_ws/devel/lib/python2.7/dist-packages', '/opt/ros/kinetic/lib/python2.7/dist-packages', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-aarch64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.5/dist-packages/IPython/extensions', '/home/nvidia/.ipython', '../']
```
>
のように追加されているパスが出力される。
よく見ると、その中に

>
```
'/opt/ros/kinetic/lib/python2.7/dist-packages'
が含まれていることが分かる
```
>
こいつが邪魔をしてOpenCVをimportできなくしているので、消してやれば良い
具体的には

>
```
sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
```

と、いうことでyolo_video.pyの上らへんに`sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')`を追記。
そしたら無事に動きました！

# おわり
無事keras版yoloを実行できましたがモッサリしてました。
これなら動画をディスプレイに写して本家YOLOのdemoで認識させてもいいかもしれません。


# 参考サイト
ubuntu16.04に tensorflow, keras　のインストール
https://qiita.com/konosuke-k/items/5adeb9f38ce6f579ed91
keras版yoloのインストール
https://qiita.com/yokoponzoo/items/64137ef45208b12ce501
rosによるcv2のimportエラー
https://qiita.com/ReoNagai/items/112c3a8b6cd55c3e5380
LaravelでRedisにキャッシュしたキー一覧を取得する

## 環境
- Laravel Framework 6.0.3
- Redis 4.0.14 （非クラスタモード）

## 背景
Laravelの[Cache](https://laravel.com/docs/6.x/cache)APIではRedisを利用できますが、全てのRedisのコマンドが実装されているわけではありません。

どんなキーをキャッシュしたかキー一覧を取得したくても、[KEYSコマンド](http://redis.shibu.jp/commandreference/alldata.html#command-KEYS)が実装されていないため、GETコマンド等のように直感的に呼び出すことはできません。

```
>>> use Illuminate\Support\Facades\Cache;
>>> Cache::put('key','value');
=> true
>>> Cache::get('key');
=> "value"
>>> Cache::keys('*');
PHP Error:  Call to undefined method Illuminate/Cache/RedisStore::keys() in /var/www/vendor/laravel/framework/src/Illuminate/Cache/Repository.php on line 636
```

## 方法
- [Redisインスタンス](https://laravel.com/api/5.8/Illuminate/Cache/RedisStore.html#method_getRedis)経由でKEYSコマンドを叩きます

```php
## キーを複数登録
>>> Cache::put('key1','value');
=> true
>>> Cache::put('key2','value');
=> true
>>> Cache::put('key3','value');
=> true

## Redisインスタンス経由でKEYSコマンドを叩く
>>> $redis = Cache::getRedis();
=> Illuminate\Redis\RedisManager {#493}
>>> $redis->keys('*');
=> [
     "key2",
     "key1",
     "key3",
   ]
>>>
>>> $redis->keys('*3');
=> [
     "key3",
   ]
>>>
```

## 補足
- 他のコマンドにも応用可です

## 参考記事
https://blog.csdn.net/ljwaheng/article/details/84138910
Compare Toの戻り値について

CompareToは
左-右という風に覚えたらいい。

実行した結果は3パターンしかない。

- 1
- -1
- 0

のどれかになる。

```c#

 string num1 = "50";
 string num2 = "60";

 var result = num1.Compare(num2);
 System.Console.WriteLine(result);
```

結果 -1

```c#
 var result = num2.Compare(num1);
 System.Console.WriteLine(result);
```

結果 1


- 文字列は文字コードで大きさが決まっている。

```
"a".Compare("b");
```
結果は-1

z>y>x .....a
ミニマムな開発チームを立ち上げる時に気を付けていること

# ミニマムな開発チームの立ち上げ
会社を作ったりサービスを思いついたり、いろんなタイミングでシステム開発が始まり、開発チームが立ち上がります。
初期構築の時はなるべくコストを抑えつつ早く成果を出していく必要があるので
チームの運用もスタートアップならではの~~雑さ~~潔さとスピード感が出てきます。
ぼっち開発からふたり、3人と人数が増えてきて、チームが5人になるまでに気を付けている事を書き出していこうと思います。

## ドキュメントを残す
gitのホスティングのwikiでも良いしGoogleドライブでも良いですが
開発チーム全員が見られるところにドキュメントを残しておかなければなりません。
知識の共有は個の力をチームの力に押し上げる鍵です。
その一瞬を面倒くさがるかどうかが、これからのチームにとって個々の力が足し算になるか掛け算になるかの分岐点になると心得ましょう。
そして最初にやるべき事は「どこにドキュメントを残すか」という事を明示することです。

## プログラムを管理する
今ではほぼ必ずと言っていいほどgitを使っています。
ホスティングされている事も重要ですが、過去のログが追える、ソースの共有が容易である事はとても重要です。
スピード重視で過去のログを重要視しない事も多々ありますが
過去のソースにはこれからのロスを無くす教訓が詰まっていると思った方が良いです。

## 開発環境を作る
決して同じサーバーを複数の開発者で共有したりしてはいけないですし
各開発者が同様の環境で開発が出来なければなりません。
つまり「再現性のある開発環境を共有する」という事がとても重要です。
多くの場合、開発者は開発をするためにプロジェクトに入ってきているはずで
開発環境を構築するために入ってくるわけではありません。
そして優秀な開発環境は本番環境における環境依存の問題を起こさない事にもつながります。

## ソースレビューをする
ソースレビューにおける目的は複数上がりますが
特に立ち上げ期におけるソースレビューでは「共通認識を作る」という事が重要です。
つまりdebugやtest、あら探しというネガティブな意味合いでのソースレビューではなく
「このプロジェクトにおける最適なソースとはどういう形か」という事を
チームの開発者の中で共有するための作業です。
レビューの結果が実際のプログラムコードとして積みあがってくれば
あとは踏襲して新しいプログラムを書いていく事である程度の品質が担保出来ると思います。
逆に品質の低いコードを使い続ける事はチームの存続をも危うくさせるのでよくよく気を付けた方が良いでしょう。

## 運用ルールを決めて周知する
いよいよチームとしてきちんと動き始めた時に
開発の運用ルールについてドキュメントにし、キックオフのミーティングをし、開発ルーティンとして実践していく必要があります。
定められたルーティンに則って運用されているチームに合流する事は、何もルールの無い集団に混ざって成果を出さないといけない事に比べるとさほど難しくないです。
もちろん運用ルールについても常に良い状態を保てるように、アップデートし続ける必要があると思います。
アップデートの基準についてもルール化されれば良いチームとして成長し続ける可能性がぐっと広がると思います。

# まとめ
開発者が増加していくフェーズで、新しく入ってきた開発者がなるべく短期間に成果を出すためには
本人のポテンシャルに頼るのではなく、成果を出すことに注力できる環境をいかに早く作り上げるかにかかってくると思います。
「開発者を増やす必要がある」という事は、事業として開発力の増強が必要だという判断によるところのはずです。
新しい仲間が増える事に甘んじることなく、新しい仲間と共により大きな成果を目指せる環境を作る事が
先にいた者の務めかなと思ったりします。

要件定義や設計の話になると色んな思想が混じってきそうなので
今回は「開発者が最速で開発者として振る舞うのに必要な環境を整える」という部分にフォーカスして書き出してみました。
まだ他にも色々あると思いますが思い出したら追記したりとかすると思います。
CodeBuild で git-pr-release する

git-pr-release に守破離の離に行ってそうな議論をtwitterで目撃したのですが、足元を見ると git-pr-release を導入すると楽できそうな部分があったので、セットアップしてみました。

# CodeBuild でやってみた

手慣れた CodeBuild にこのようなビルドプロジェクトを作りました。起動トリガーは develop にプッシュされた時。Dockerコンテナイメージは `ruby:latest` 。

```yaml
version: 0.2

env:
  variables:
     GIT_PR_RELEASE_BRANCH_STAGING: "develop"
     GIT_PR_RELEASE_BRANCH_PRODUCTION: "master"
     GIT_PR_RELEASE_VERSION: "0.6.0"
     DEBUG: "error"
  parameter-store:
     GIT_PR_RELEASE_TOKEN: "github-api-token-pr-create"
     SSH_PRIV_KEY: "ssh_private_key_for_codebuild"

phases:
  install:
    commands:
      - gem install git-pr-release -v "${GIT_PR_RELEASE_VERSION}"
      - ruby -v
      - gem -v
      - git-pr-release --help
  pre_build:
    commands:
      - mkdir ~/.ssh
      - echo "${SSH_PRIV_KEY}" > ~/.ssh/id_rsa
      - |
        cat <<EOF > ~/.ssh/config
        Host *
          StrictHostKeyChecking=no
          UserKnownHostsFile=/dev/null
        EOF
      - chmod 0700 ~/.ssh
      - chmod 0600 ~/.ssh/*
      - |
        GITHUB_REMOTE_URL_GIT_PROTO=$(echo "${CODEBUILD_SOURCE_REPO_URL}" | sed -e 's|https://github.com/|git@github.com:|g')
        echo ${GITHUB_REMOTE_URL_GIT_PROTO}
        git remote set-url origin ${GITHUB_REMOTE_URL_GIT_PROTO}
      - git remote -v
  build:
    commands:
      - git-pr-release --no-fetch
```

# 作ってみて

CodeBuildは、CircleCI などと異なり、Remote URL が https になってて、git-pr-release は git な前提なので、

* SSHの設定を仕込む必要がある
    * AWSとGitHubリポジトリに 
        * TravisCIやCircleCIなら勝手にSSH鍵の登録とか済ませてくれる
* remote urlをgit@github.....に変換する必要がある
* git remote set-url してやる必要がある

というのが煩雑でした。これを考えると TravisCI や CircleCI, GitHub Actions にしたらもっと簡素にできたなと。

今回ひとつテンプレとして buildspec.yml を作れたので、他のリポジトリにも展開したらいいのですが、

> GitHub にSSHアクセス必要で、 GitHub Personal access token も必要なら、CodeBuild以外の選択肢を検討してからでよい

という理解を得ました。まる。

# 参考

* https://github.com/motemen/git-pr-release
* [CircleCIでgit-pr-releaseする](https://songmu.jp/riji/entry/2019-07-28-circleci-git-pr-release.html)
* [git-pr-releaseについて](https://qiita.com/fuwamaki/items/364f0956b20869cf17d6)
* [git の develop ブランチは必要なのか、またはリリースtagについて](https://togetter.com/li/1422612)
WSL上にmkcertをインストールし、警告を出ないようにするまで

# 概要

WSLでmkcertをインストールして単純に`mkcert -install`を叩いても、ブラウザで証明書が確認できない旨の警告が出てしまったので、解決するためにやったことをまとめました。

chocolateyなどを使って、Windows上にインストール・作業をした場合、windowsの証明書マネージャにそのまま登録されましたが、WSL上だとそのままでは登録されないようです。

## 手順

証明書の返還までは、WSLのubuntu環境での手順です。

### mkcertのインストールと準備

1. `sudo apt install linuxbrew-wrapper`でbrewをインストールします
1. `~/.bashrc`を開き、末尾の方に`export PATH=/home/linuxbrew/.linuxbrew/bin:$PATH`を追記し、再度bashコマンドを叩いて再読込する
    - brewのためにPATHを通しています。
1. `brew install mkcert`でmkcertをインストール
1. `mkcert -install`を叩く

### ルート証明書の変換

1. `mkcert -CAROOT`でlocal CAの置き場所が出るので、そこへ移動
1. `openssl pkcs12 -export -inkey rootCA-key.pem -in rootCA.pem -out rootCA.pfx`でWindowsで利用できる証明書形式に変換する

### ルート証明書のインストール

1. `explorer.exe .`で現在のワーキングディレクトリをエクスプローラーで開く
1. `rootCA.pfx`を右クリック、PFXのインポートからウィザードに従ってインストールする
    - 証明書ストアのところで、`証明書をすべて次のストアに配置する`→`信頼されたルート証明機関`に指定
    - 上は、非WSLの`mkcert -install`でインポートされる場所と同じところです

## 結果の確認

1. `ユーザー証明書の管理`を開き、`信頼されたルート証明機関`→`証明書`の一覧に、`mkcert～～`があるかを確認。
1. ブラウザで該当のページを開き直し、警告がなくなれば成功です。
    - 単純なリロードだと表示が切り替わらないようなので、新しいタブで確認してください。
Chromeで印刷時にtheadを各ページに出力

```css
thead {
  display: table-header-group;
  break-inside: avoid;
}
```

参考: [Repeating table headers in PDF downloads using headless chrome | berliners blog](http://blog.dev030.com/posts/repeating-table-headers-pdf-downloads-using-headless-chrome)

theadに`display: table-header-group`を指定すると、印刷時にページごとにtheadの内容を出力できます。これははっきり仕様にあるわけではなく、ブラウザーの慣習らしいです。Chromeはこれに対応していませんでしたが、わりと最近、`display: table-header-group`に加えて`break-inside: avoid`があれば、ほかのブラウザーのように動作するよう修正されたそうです。

[CSS 2.1の仕様](https://www.w3.org/TR/CSS2/tables.html#table-display)には次の文があります。**may** とされています。

> Print user agents may repeat header rows on each page spanned by a table. 

[HTML5](https://html.spec.whatwg.org/multipage/tables.html#the-thead-element)と[CSS3](https://www.w3.org/TR/css-display-3/#layout-specific-display)にはtheadの印刷に関する記述は見当たりませんでした。
docker on centos 環境でホストのNW設定を変更したときなどでコンテナが外部通信できなくなる時の対処

### 事象
ホストにstatic routeを追加したとき、ホストとbridge接続したコンテナから外部へ通信できなくなった
コンテナを再起動しても、ホストを再起動しても状況かわらず..こまった


### 環境

```
# cat /etc/system-release
CentOS Linux release 7.7.1908 (Core)

# docker -v
Docker version 19.03.4, build 9013bf583a

# docker-compose -v
docker-compose version 1.25.0-rc2, build 661ac20e
```

### 解決策
一度コンテナを落とし、docker serviceを止めたあとに firewalldを再起動
そのあとに再度 dockerを上げる
これで復活した

```
# docker-compose down
# systemctl stop docker
# systemctl restart firewalld
# systemctl start docker
# docker-compose up
```
strings.xmlの内容をcsvに書き出すためのワンライナー

あまり出番はないと思いますがメモ代わりに残しておきます。

```shell

cat path/to/strings.xml | sed  's/^\ *<string name="\(.*\)">\(.*\)<\/string>/\1,"\2"/g' | sed '1d' | sed '$d' > result.csv
```
Linuxでの自動起動の方法

#はじめに
Raspberry piでarduinoなどと同様に電源ＯＮでプログラム起動できるようにする簡単な方法を調べました。
サーバ用途の場合はサービス化した方がよさそうです。

#方法
/etc/rc.localに起動したいコマンドを書く。
※「exit 0」より上に書く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93459/5ea8aff6-938f-f270-f112-6228b476bfda.png)


#起動されるスクリプト
スクリプトはrootとして実行される。
スクリプト内では「sudo」や「su」は使用できない。（rootで実行されるので不要とは思う）
（スクリプトの例）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93459/f3e31e25-a3a9-66c2-ad48-862f1ecbe1f7.png)

ここも参照
http://hendigi.karaage.xyz/2016/11/auto-boot/
Kerasで作ったモデルをKendryte K210環境で動かす（仮）

#Kerasで学習させたモデルをK210環境（M5StickV）で動作するか試してみます。

モデルの変換は以下の２手順でできるようです。
①Kerasで学習して保存したモデルをTensorflowLiteのモデルに変換する。
②TensorflowLiteのモデルをK210モデルに変換する

#TensorflowLiteのモデルに変換する。
Kerasがインストールされてる（tensorflowがインストールされてる）環境なら以下のような感じでconverterを使って簡単に変換できる。

```Python
import tensorflow as tf

converter = tf.lite.TFLiteConverter.from_keras_model_file("keras_clf_iris_dp.h5")
tflite_model = converter.convert()
open("keras_clf_iris_dp.tflite", "wb").write(tflite_model)
```

#TensorflowLiteのモデルで推論を実行してみる。
以下のような感じでInterpreterのオブジェクトを作ってデータをセットしてinvoke()実行で推論を実行できるようです。
TensorflowLiteはKerasのモデルの1/3以下位のサイズになるようなので、TensorflowLiteの環境を作れる場合にはマイコンの環境等には向いていると思います

```Python
interpreter = tf.lite.Interpreter(model_path="keras_clf_iris_dp.tflite")
interpreter.set_tensor(input_details[0]['index'],np.reshape(X_test[0], (1,4)).astype(np.float32))
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
print(output_data)
```

#K210モデルに変換してみる。
結論としては、使用しているレイヤーが未対応と思われるためうまくいきませんでした。
現在時点（2019/10/29）で他のサイトも同じ結論のようなのでバージョンアップを待つしかなさそうです。
「javascript、サーバー時刻取得できるってよ」

「ふえええ...、javascriptだと、サーバーの時間取れないよぉぉぉ〜〜〜〜〜」と
赤ちゃん返りしていたところに
参考になりそうな記事を発見したので
案件で利用しているaxiosに合わせて書き直してみた。

# サーバーの時刻とクライアントの時刻の違い
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115335/c07771bf-3d13-89a4-a61a-b1c51e51d40a.png)


# 忙しい人のためのソースコード
ajax通信するために[axios](https://github.com/axios/axios)を利用

``` html:index.html
<html>
<body>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</body>
</html>
```

``` javascript:getSevertime.js
// フロント側の時間
let frontSideTime = new Date()
console.log(frontSideTime) // デバイスの時刻

// サーバー側の時間
axios.head(window.location.href).then(res => {
  console.log(new Date(res.headers.date)) // サーバー時刻
})
```

これで海外からのwebページのアクセスでも
サーバーの時間を基準にしているから問題なくデバイスに依存せずに表示することができるようになった

### 参考
[JavaScriptだけでサーバー時間を取得したタイマー作成方法](https://iwb.jp/javascript-server-timer-without-jquery/)
petalinux-config -c kernelで設定画面が開かない時の対処法

#現れるはずの設定画面が開かない
**do_menuconfig**が終わらなかったりエラーが出て終了したり症状は様々

##原因と対処法
sshで繋いでるのがダメだった。
しかもForwardX11がyesになっていた、どうやらこれが悪さをしていた模様。
というわけで`-X`やら`-Y`やらを付けずに`ssh`すれば大丈夫です。
動画や画像ファイルのアップロード時に内容を表示する(Nuxt.js/Vuetify)

# 概要
Web アプリケーションでファイルアップロードを実装する際にファイルの内容を表示したい。

# 適用イメージ
![uplaod-preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517184/4383fb1c-9506-8353-f3e7-95115880cc50.gif)

# サンプルソース
- Nuxt.js で Vuetify の File inputs コンポーネントを使っている
- ファイル選択時にファイルの内容をData URL としてバインディングしている
- アップロードするファイルのサイズが大きすぎるとダメかもしれない

```vuejs:demo.vue
<template>
  <v-row justify="center">
    <v-col sm="12" md="11" lg="9" xl="6">
      <v-sheet class="pa-3">
        <h1>アップロードプレビューデモ</h1>
        <v-form ref="form">
          <video v-if="uploadVideoUrl" controls>
            <source :src="uploadVideoUrl" />
            このブラウザではビデオ表示がサポートされていません
          </video>
          <v-file-input
            v-model="input_video"
            accept="video/*"
            show-size
            label="動画ファイルをアップロードしてください"
            prepend-icon="mdi-video"
            @change="onVideoPicked"
          ></v-file-input>
          <img v-if="uploadImageUrl" :src="uploadImageUrl" />
          <v-file-input
            v-model="input_image"
            accept="image/*"
            show-size
            label="画像ファイルをアップロードしてください"
            prepend-icon="mdi-image"
            @change="onImagePicked"
          ></v-file-input>
        </v-form>
      </v-sheet>
    </v-col>
  </v-row>
</template>

<script>
export default {
  data() {
    return {
      input_video: null,
      input_image: null,
      uploadVideoUrl: '',
      uploadImageUrl: ''
    }
  },
  methods: {
    onVideoPicked(file) {
      if (file !== undefined && file !== null) {
        if (file.name.lastIndexOf('.') <= 0) {
          return
        }
        const fr = new FileReader()
        fr.readAsDataURL(file)
        fr.addEventListener('load', () => {
          this.uploadVideoUrl = fr.result
        })
      } else {
        this.uploadVideoUrl = ''
      }
    },
    onImagePicked(file) {
      if (file !== undefined && file !== null) {
        if (file.name.lastIndexOf('.') <= 0) {
          return
        }
        const fr = new FileReader()
        fr.readAsDataURL(file)
        fr.addEventListener('load', () => {
          this.uploadImageUrl = fr.result
        })
      } else {
        this.uploadImageUrl = ''
      }
    }
  }
}
</script>
```

# 参考サイト
- https://stackoverflow.com/questions/44989162/file-upload-in-vuetify
WordPress ユーザー毎の最新記事のURLをデータベースに保存する

WordPressで、ユーザー毎の最新記事URLをデータベースに保存する方法です。
もちろん、ユーザーを指定して最新の投稿記事を取ってくることは可能ですが、ユーザー数が多くなった場合に、ユーザーのメタ情報に最新記事URLを保存しておいたほうがサーバ負荷を抑えられるかな、という考えです。

## 前提
[「WordPressユーザーのためのPHP入門 はじめから、ていねいに。」] (https://php4wordpress.calculator.jp/)を読了した程度のPHP、WordPressの知識

## コード
以下のようなコードになります。(コードはGPL ver.2 or later)

```PHP
add_action( 'publish_post', 'setup_latest_post_url', 10, 2 );

function setup_latest_post_url( $id, $post ) {
	$permalink = get_permalink( $id );
	$uid = intval($post->post_author);
	update_user_meta( $uid, "latestpermalink", $permalink);
}
```

以下、ざっくりと説明をします。

まず、投稿を公開するときに、ユーザーの情報を更新したいので、publish_postアクションフックを活用します。

publish_postアクションフックでは、投稿IDと、投稿オブジェクトをパラメータとして渡すので、これらを活用します。

get_permalink()は、投稿URLを取得する関数です。また投稿者のユーザーIDは、投稿オブジェクトのpost_authorプロパティで取得します。

ユーザー情報を更新する関数はupdate_user_metaが用意されているので、こちらを使います。

```PHP
//            ↓アクションフック名
add_action( 'publish_post', 'setup_latest_post_url', 10, 2 );
//                              ↑アクションフックで実行する関数名

                              // ↓ 投稿ID
function setup_latest_post_url( $id, $post ) {
                                    // ↑投稿オブジェクト

        //            ↓ 投稿ID → 投稿URL へ変換する
	$permalink = get_permalink( $id );

        //             ↓投稿オブジェクトから投稿者のユーザーIDを取得する
	$uid = intval($post->post_author);

        // ↓ ユーザーのメタ情報を変更する
	update_user_meta( $uid, "latestpermalink", $permalink);
}
```

このようにすると、『ユーザーが投稿を公開したとき、そのユーザーのメタ情報latestpermalinkに、投稿のURLを保存する』という処理が可能になります。

(※予約投稿の場合に期待通りに動くかどうかは未検証※)


今回の記事は、[読書好きが次に読む本を紹介するブックレコメンド](book-recommend.com/)向けに作成したコードを共有しています。
Hello World



Qiitaに記事を投稿する日が来るとは夢にも思わなかった。この質のいい記事が多いQiitaに、僕は勇気を出して、何らかの記事を投稿したい！ただ、テーマがないので、思いついたことを書いて行こうと思う！！みなさんよろしく！！お願いします！！！


# 初めて記事を書いてみるよ！
+ hello 
+ world
+ hello world

# これで僕もQiitaデビュー
さぁ引用だ！
>
「われわれは訊ねる、まだ何が冒険されうるのだろうか、生そのものよりも、すなわち冒険そのものよりも、一体何がより冒険的なのだろうか、つまり何が、存在者の存在よりもより冒険的なのだろうかと」
マルティン・ハイデッガー

### コードってどんな感じになるんだ！

よしコードも書いてみよう！！！

~~~
var ppap = function() {

	let ppap1 = "pen";
	let ppap2 = "apple";
	let ppap3 = "pineapple";

	let defValue = 1
	let setCounter = 3;

	let minValue = 1;
	let maxValue = 2;

	let space = 

	try {

		for(var i = defValue; i <= setCounter; i++) {
		    if(i <= minValue) {
		       console.log(i+" "+ppap2+" "+ ppap1);
		    } else if(i <= maxValue && i >= minValue) {
		       console.log(i+" "+ppap1 +" "+ ppap3 +" "+ ppap2 +" "+ ppap1);
		    }  else {
		       throw new Error('( ﾟдﾟ)');
		    }
		}

	}catch(e) {
	    console.error(e.message);
	}

}

ppap();
~~~
新人エンジニアの私が会社から評価Aを頂けた成長するための行動３つ

#はじめに
婚約を契機に、キャリアを再考してエンジニアに転職したIWAOです。
私の記事へアクセス頂き、ありがとうございます。

この記事を書くのは、「エンジニアはアウトプットを常に」との助言を、１０分前に聞いたので、
即行動ということで、Qiitaアカウントを作成したからです。

先輩からの助言は即行動！
１００％以下のクオリティでも即行動して、その経験から学んでいこうと考えてます。

私が出来る意味ある発信は、新人エンジニアとして成果が出ている勉強方法であったり、
未経験から転職した際に気を付けたことや、新人からの業界への観点等と考え、
まず、入社２か月目に最高評価Aを頂いた働く姿勢を発信します。

それでは、書いていきます。
端的に書いていきます。

## 行動①　出来る限りの明るさでコミュニケーション

**大事ですよ！！コミュ力！！**
第一印象から決まります。仕事も恋も。
はっきり大きな声を出すようにしましょう。
相手の目を見ましょう、ずっと下向きはだめです。

と、お会いする多くの業界の方が言ったので、
心掛け実行しました。
そしてら、やはり好印象です。
いきなりコミュ力を高めるのは難しいですが、
声はすぐに実践できるので、ぜひ新人の皆様は試してください。

同期に声の小さな人がいるのですが、
質問や回答に自信がないような印象になります。
内容は正しくて質がいいのに、もったいないです。

第一印象で評価された印象は覆すのが大変です。
第一印象から勝負していきましょう！

第一印象を失敗している人、
安心してください。
今から、実践すると、
「おっ、なんか変わったなと」
マイナスから振れ幅がでかく好印象を受けてもらえます。

　
## 行動②　勉強の目標設定
遠い先のことは未知で分かりません。
まず、３ヵ月か半年単位で具体的な目標を立てましょう。

エンジニアのスキルは、一生役に立ちます。

勉強して損はないので、ぜひ抽象的ではない具体的な目標を立てて、
それに打ち込んでいる姿勢を見せましょう。

下記のツールを私は活用しました。

[マンダラチャートの使い方・書き方(テンプレ付)](http://u-note.me/note/47502826)

私は下記の目標を公言して実行し。結果を出しています。
公言するとプレッシャーにもなって、周りも姿勢の差を感じてくれるので、
いいと思います。
結果が出なくても、勉強した姿勢は評価されますし、資格を目標にすると、
知識がより定着すると思います。

1. １ヵ月目でITパスポートをとる
2. ３ヵ月目でCCNAをとる
3. さらに上位の資格を目指すことを公言する

勉強時間の捻出は、次項のタイムマネジメントについての記述を参考にしてください。
出来る限り短期で資格所得は目指したほうが、評価は高くなると思います。

ITパスポートを例にあげると、入門レベルの資格ですが、
習得に２ヵ月かかる人と１ヵ月かかる人では、知識の吸収力や、勉強法の工夫に差があるのかなと思われ、短期で習得されている人を評価するのが、当たり前だと考えます。

## 行動③　タイムマネジメントを考える

**時間は有限であり、命＝時間です！！**
時間の使い方が非効率な方は、命を無駄にしていると思います。

私は、自分のために早朝出勤を心がけています。
下記の記事にあるように、早朝出勤を含む朝活は、寿命を延ばします。

私は、満員電車がだーーーーーい嫌いなので、満員電車から解放されたのも、
この手法が好きな理由です。

職場に朝早くいるだけで、評価はうなぎのぼりです。
プライベートの資格勉強やネットサーフィンして勉強しているだけなんですが。

[朝活のすすめ。毎朝4時に起床し、早朝出勤を1年間続けた結果](https://ikesala.com/morning/)

寝不足は寿命を縮めますが、早起きは有限な時間を増やし、寿命を延ばす効果(有効時間を増やす)があります。

下記のリンク先を参考に、睡眠時間を調整して、朝活することを強くお勧めします。

[日本人の9割は「ショートスリーパー」になれる](https://diamond.jp/articles/-/114264)

以上の３点が、評価につながる主な行動です。

その他にも何点もあるのですが、すぐ実行できる行動に絞り共有させていただきました。

#さいごに

「先輩！助言のとおり、即アカウント作り、とりあえずアウトプットの記事を書いたよ！
思いのほか大変だよ！」

さて、感情が独り言で出てしまいましたが、
助言通りアウトプットを始めます。

無理なく継続していきたいと思います。

助言のとおり、『考えが整理できて、次のアイディアに繋がる』という効果が、この１時間程度の記事作成という行動にもありそうなので、今後も頑張ります。
(この記事を書き上げるのに５０分程度かかりました)

**エンジニアならアウトプットしろよって助言を、即実行して、アカウント作成から記事作成までを一時間以内に終えた私に、同情と労いの『いいね』を頂けたら、とても励みになります！**

私と同じく、最近エンジニアになった新人エンジニアの皆様！一緒にQiitaでアウトプットしましょう♪

読んで頂きましてありがとうございます。

お終い
typesafe-actionsをReact.useReducer(Hooks API)で使う

TypeScriptでredux向けのreducerやaction生成関数を作る時、typesafe-actionsを使っているのですが、
reduxを使わない類似のフックAPIであるReact.useReducerを使うときもtypesafe-actionsが提供する型や定義の恩恵が欲しいと思い、やったら上手く行ったのでサンプルコードの形で置いておきます。

```jsx

interface State {
  counter: number;
}

export const increment = createAction("INCREMENT", resolve => {
  return (delta:number) => resolve(delta);
});
export const decrement = createAction("DECREMENT", resolve => {
  return (delta:number) => resolve(delta);
});

type Action = ReturnType<typeof increment> | ReturnType<typeof decrement>;

// ここのinitialStateである `{}` は実際の挙動に影響しないようです。
const baseReducer = createReducer<State, Action>({})
  .handleAction(
    [increment],
    (state, action: ReturnType<typeof increment>): State => ({
      counter: state.counter + action.payload
    })
  )
  .handleAction(
    [decrement],
    (state, action: ReturnType<typeof decrement>): State => ({
      counter: state.counter - action.payload
    })
  )
type Reducer = React.Reducer<State, Action>;

// React.useReducerで使える形式にadoptしたReducer
const reducer: Reducer = (state, action) => {
  // typesafe-actions と React.Reducer では若干違う部分があるので橋渡し
  return baseReducer.handlers[action.type](state, action);
}

const initialState: State = {
  counter: 0
};

const component = ()=> {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    
  );
}
```
AWS Solution Architect Professional受験記

# はじめに

受験から２ヶ月ほど経過していますが(受験:2019/8、執筆:2019/10)、まとめの意味を含めてAWS Solution Architect Professional(以降、SAP)の学習内容を記載したいと思います。

# 学習前の状態

* AWSでの業務経験はなし(個人で触ったことがある程度)
* Solutions Architect Associateは取得済み(2017年)
* メインスキルは、アプリ開発系(インフラではない)

# 学習内容
2019/2 にSAPの試験問題がリニューアルされました。
リニューアル後に日が浅いこともあり、情報が少なかったですが、以下のStepに落ち着きました。
教科書的に1と2を受講し、３の問題集をやりながら分からないことを調べるといった勉強方法でした。

本来は、実機を使って色々やりたかったのですが、試験範囲が広すぎるので、時間的コスパがよくないので断念しました。

1. [AWS公式オンライントレーニング - Exam Readiness: AWS Certified Solutions Architect – Professional](https://www.aws.training/Details/eLearning?id=34737)
1. [AWS公式クラスルームトレーニング　Advanced Architecting on AWS]
(https://www.aws.training/training/schedule?courseId=10000)
1. [Udemy-AWS Certified Solutions Architect Professional Practice Exam](https://www.udemy.com/aws-solutions-architect-professional-practice-exams-2018/)

## AWS公式オンライントレーニング Exam Readiness: AWS Certified Solutions Architect – Professional
無料のオンライントレーニング。
試験ドメイン毎に、数分のビデオ解説、簡単なテキスト、少量のサンプル問題から構成されます。
これを学習したからといって、試験範囲が網羅できる訳ではありませんが、主に問われる内容が把握できます。

受講後の感想は、可用性や耐障害性のようなArchitectingの王道がメインというより、移行、フェデレーション、コスト管理など、実務で悩みそうな内容が多いな、でした。
で、実際の試験もそんな傾向です。

なお、英語。

## AWS公式クラスルームトレーニング Advanced Architecting on AWS

3日間のArchitectingのクラスルームで、講義+演習+ハンズオン形式で、Architectingに関して学ぶことができます。
試験に出題されるサービスも一通り網羅している感じで、AWS社員の方も受講されていました(入社後、間がない方)。

試験対策講座ではありませんが、試験対策としても十分有用です。
なお、受験後、後述するUdemyの問題集のスコアが２０％Upしました(50%->70%)。

## Udemy-AWS Certified Solutions Architect Professional Practice Exam

75問 x 4の問題集です。 英語。
解説もわりと親切で、そこそこ良質な問題です。
これを２周しました。

２周完了した時点で、75％-80%ぐらいの正答率でした。
コース案内にもありますが、本試験を受けるには、90%以上正答が望ましいです。

この問題集をやるにあたり痛感したのは、英語力のなさです。
SAPの問題文は長文なので、英語力がないと、問題解くのに時間もかかるし、集中力も必要で非常に疲れました。

#試験本番

さて、試験本番。受験場所は、歌舞伎座テストセンター。
施設も新しく、東京近辺だともっともおすすめです。
土曜日も受験可能です（ただし、すごく混む）。

試験中は、ビミョーな手応えのまま、残り20分で最終問題に到達。
勉強足りなかったなーと思いながら、見直し後、試験を終了。

結果は、なんとか合格でした (793/1000、 合格ライン:750)

あと、問題文の日本語訳の精度がイマイチで、英語に適宜切り替えました。
AWSに限らず、この手のベンダー試験は、日本語訳が怪しいと思ったら英語で見ましょう。
回答に影響するような、表現違いもちょいちょいあります。


#試験後の感想

正直、勉強不足でした。
自分は、運よく（会社の金で）クラストレーニングを受講できたので、なんとかなった印象です。

まとも構築経験がない人間が合格するには、やはりハードル高い試験です。
Qiitaの特定タグへの新着投稿をRSS受信する

#はじめに
Qiitaの最新記事が通知されれば嬉しいなと思ったので
設定方法を記事にまとめました。
##手順
###Slackをインストール
https://slack.com/intl/ja-jp/help/articles/207677868
###SlackにRSSをインストール
https://slack.com/intl/ja-jp/help/articles/218688467-add-rss-feeds-to-slack
###通知設定方法
チャンネルに以下を入力して送信すると
タグ付けした、記事が投稿されるたびに通知されるようになる。

例1)railsタグが付けられた最新記事を読みたい場合
`/feed https://qiita.com/tags/rails/feed`

例2)javascriptタグが付けられた最新記事を読みたい場合
`/feed https://qiita.com/tags/javascript/feed`

##補足：RSSの管理について
###RSSの登録
/feed 〇〇（URL）
/feed 〇〇（URL）の形で登録。
###RSSの一覧
/feed list
/feed listで一覧が表示される。
こちらは削除する際にもIDの確認で使用する。
###RSSの削除
/feed remove 〇〇（ID）
/feed remove 〇〇（ID）の形でRSSを削除する。
上記の一覧の表示で表示される、RSS登録IDを使用して、削除する。
水平、垂直エッジ

研究で調べていた際に、少し時間がかかったので。
横線、縦線の検出には、Sobelフィルタを用います。

水平方向検出用

```math
\begin{matrix}
1 & 2 & 1 \\
0 & 0 & 0 \\
-1 & -2 & -1
\end{matrix}
```


垂直方向検出用

```math
\begin{matrix}
1 & 0 & -1 \\
2 & 0 & -2 \\
1 & 0 & -1
\end{matrix}
```

これらを画像に適用します。

また、OpenCVには

```python
cv2.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
```
があるので使いましょう。

入力画像srcはグレースケールにします。
ddepthは色深度で、cv2.CV_32Fを入れとけば問題ないです。
(dx, dy) = (0, 1)で水平方向検出、(1, 0)で垂直方向検出です。
例に示したソーベルフィルタのカーネルサイズは3なので、ksizeは3でいいでしょう。

```python
gray = cv2.imread('sample.jpg', 0)

dx = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
dy = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3)

cv2.imwrite('./dx.jpg', dx)
cv2.imwrite('./dy.jpg', dy)
```
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　
テストに使った画像
![Lena.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303950/48a76cdb-e570-1082-b19f-b17da331c66e.jpeg)


dx
![Lenadx.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303950/e3f5eaa5-445a-0665-f8a2-35454ca0be4a.jpeg)


dy
![Lenady.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303950/03cea396-e034-6d8c-4e18-1353c7dbf897.jpeg)


Lenaだとわかりにくいですね。。。
今道路に関しての検出してるのですが、そちらだとわかりやすいです。
Geant4練習

#Geant4の例
[geant4の本家](http://geant4-userdoc.web.cern.ch/geant4-userdoc/Doxygen/examples_doc/html/)の翻訳記事
このモジュールは、ユーザーが自分のシミュレーション設定を定義するためにカスタマイズすることになっているユーザークラスを正しい方法で実装することにより、GEANT4ツールキットを正しく使用する方法をユーザーに示すことを目的とした4セットのユーザー例を収集します。

- 「基本」の例のセットは、ユーザーが初心者ように配向し、シンプルさと使いやすさを保ちながらのGeant4アプリケーションの最も一般的なユースケースをカバーしています。

- 「拡張」の例のセットは、Geant4をのほかにいくつかの追加のライブラリが必要な場合があります。このセットは、実際の検出器シミュレーションの多くの特定のユースケースをカバーしています。

- 「高度」の例の設定は「ツールキット」は、異なるシミュレーション研究のための本当の完全なアプリケーションが提供され、開発、の配向の種類の典型的なユースケースをカバー。追加のサードパーティ製品の構築が必要になる場合があります。

ほとんどの例は、インタラクティブモードとバッチモードの両方で実行でき、入力マクロファイル（* .in）と参照出力ファイル（* .out）が提供されます。基本的な拡張サンプルのほとんどは、GEANT4ツールキットの公式リリースを検証するためのシステムテストスイートの一部と見なされます。基本および拡張および高度な例の一部は、リリースプロセスの「受け入れ」テストとしても使用されます。

各例のカテゴリページで詳細を参照してください。

[基本的な例](http://geant4-userdoc.web.cern.ch/geant4-userdoc/Doxygen/examples_doc/html/README_basic.html)
[拡張例](http://geant4-userdoc.web.cern.ch/geant4-userdoc/Doxygen/examples_doc/html/README_extended.html)
[高度な例](https://twiki.cern.ch/twiki/bin/view/Geant4/AdvancedExamples)

ユーザーを初心者ように配向例の前のセットは、「初心者」、Geant4を10.0の「基本」と「拡張」の例セットにリファクタリングされました。これらの例の元のセットに関する情報は、このページにあります。

そして、すべての例に共通するものの詳細：

サンプルをビルドして実行する方法
マルチスレッドモードでサンプルを実行する方法のヒント
サンプルドキュメントでのナビゲート方法

[geant4の本家](http://geant4-userdoc.web.cern.ch/geant4-userdoc/Doxygen/examples_doc/html/)
【メモ】 Raspberry Pi のデスクトップ画面を恒久的にsleepさせない方法

# lightdm.confを編集する
忘れるので自分用にメモる。

[How to Disable the Blank Screen on Raspberry Pi (Raspbian)](http://www.geeks3d.com/hacklab/20160108/how-to-disable-the-blank-screen-on-raspberry-pi-raspbian/)の通りなんですが。

1) /etc/lightdm/lightdm.conf ファイルを sudo 権限で編集し以下を追加
 
```
xserver-command=X -s 0 -dpms
```
2) Raspberry Pi を再起動
【Android】assetsフォルダから画像を読み込みImageViewで表示する

#事前準備
事前準備として，プロジェクトを立ち上げた時にassetsフォルダはできていないことが多いと思いますので，
<img width="451" alt="スクリーンショット 2019-10-29 13.59.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/eaefab19-cb8d-7d23-0111-c123f3a2d524.png">
このようにmain以下にassetsフォルダを作成し，
<img width="422" alt="スクリーンショット 2019-10-29 14.00.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/211c2eac-ec76-f14a-e471-e1e41f8c3763.png">
好きな画像をぶっこんでください．
そしたら準備完了です．



#さっそく本題
タイトルの通りのことを実装する場合には次のコードでいけます．

```java:MainActivity.java

package com.example.****.***_imageview_test;

import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView = (ImageView)findViewById(R.id.image_view);
        Bitmap image = getBitmapFromAsset("youtube.png");
        imageView.setImageBitmap(image);
    }


    private Bitmap getBitmapFromAsset(String strName)
    {
        AssetManager assetManager = getAssets();
        InputStream istr = null;
        try {
            istr = assetManager.open(strName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Bitmap bitmap = BitmapFactory.decodeStream(istr);
        return bitmap;
    }
}
```

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


<ImageView
    android:id="@+id/image_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:contentDescription="@string/img_description1"
    android:scaleType="centerCrop" />

</android.support.constraint.ConstraintLayout>
```

以上でーす．シンプルですよねー！
    android:id="@+id/image_view"　や
android:contentDescription="@string/img_description1"
の設定は各自でお願い致します！🙇‍♂️
@Component で $refs の補完が効くようにする方法 (Vue.JS 2.0)

```ts
@Component
export default class MyComponent extends Vue {
  $refs!: {
    hoge: HTMLCanvasElement,
    fuga: MySubComponent,
  }

  action1 () {
    // ↓補完が効く
    this.$refs.hoge.width
  }
  ...
}
```
【Unity】【制作】1作目 Seek And Shoot の反省点

## 雑多な感想
[Seek And Shootへのリンク](https://unityroom.com/games/seekandshoot)
 Unity1WeekでSTGゲーを作ったよ。
 やはり期限があると多少なりともモチベーションが上がることに気が付く。
 正直周りのクオリティが高くて禿げそう。

## 面白さ
 - 画面全体を使った動きがないため、見た目が地味。STG本来の躍動感が
 失われてしまったのがマイナスポイント。
 - 似たようなSTGで動きがあるのは「ToTheRight」「サウンドシークショット」など
 どちらも高い評価を得ている。

## 技術面
### 身についた点
 - CSVファイルのロード
 - 画像の分割読み込み
 - 2Dにおけるシェーダを用いたディゾルブの実装
 - BGM,SE再生
 - ベジェ曲線による座標移動
 
### 課題 (不明点，または理解が不十分等)
 - [★リンク★](https://qiita.com/ogawa-to/items/b5cfdbc5fe35e591d09a) : WebGLでフォントの一部が表示されないため、原因調査。
 - Unityではコンポーネント思想というものがあるそうだ。オブジェクト指向との違いを理解することも含め理解を深めたい。
 - 今回はUpdate()が60回呼ばれる=1秒という非常に安直な方法でFPSを扱った。
　　updateとfixedUpdateの違い、およびUnityにおけるFPSの扱いについて。
 - GameObject.Find()は実質グローバル変数の乱用に近しい気がする。これをなるべく使わずに済む実装方法の調査。
 - SetActive()をfalseからtrueに切り替えたとき、数フレームだけ描画更新が遅れる原因の調査。
 - 同フレームにて、DestroyしたオブジェクトがGameObject.Find()の対象になってしまう問題について
 - デフォルトのスプライトシェーダのコードの理解。
 - シェーダをGUI上で操作することができるらしいため、それの導入。
 - 自身をDestroyしてもよいか。
 - SeやBgmを一元管理するクラスの実装
 - 回転移動まとめ
 - [★リンク★](https://qiita.com/ogawa-to/items/be474429b87ad9072e45) : コルーチンの理解。例えばゲーム本編において最初に「Ready」などと表示するためにほかのオブジェクトを一時的に停止させるにはどうするか。
 　合わせて、フェードアウト，フェードインの実装。
 - [★リンク★](https://qiita.com/ogawa-to/items/b9a9d1e142c0ba74373a) : Texture, Sprite, Image2Dあたりの違いの理解
 - [★リンク★](https://qiita.com/ogawa-to/items/e3f33c22358c5006fba4) : C#の文法でフィールドの上行に書く[~~]の意味
 - コルーチンへにおけるUI.textの更新が行われない問題について。
   (デバッグ上で値が書き換わっていることは確認できるのだが・・・)
 - [★リンク★](https://qiita.com/ogawa-to/items/68b93ea3efe885aee5a1) : UnityのプロジェクトをGitHubで管理しようとするが、大量のファイルが作成(主にキャッシュファイル)されるため、無視(ignore)すべきファイルがどれかの調査。
## 雑まとめ
 - 簡単に書きなぐってみたが、恐ろしく不十分な理解のままゲームを作っていたことに戦慄した。
   直近はこれらの課題に取り組みたい。
【Git】特定ファイルのcheckoutに失敗するとき、showのリダイレクトで解決する場合がある


```bash
warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your merge.renamelimit variable to at least 1577 and retry the command.
```
変更差分が異常に多かったり、そもそも別リポジトリのコミット等を無理やり比較しようとしたりしていると、`git diff`(あるいは`merge`, `cherry-pick`)の際に`inexact rename detection was skipped due to too many files`(リネーム対象多すぎ)として怒られることがある。
このとき、手動で確認するために特定ファイルの`checkout`を実行しても失敗する場合がある。

```bash
# ファイル単位でのcheckoutも失敗する
git checkout 123ab45c some/file.cpp
```

しかし、この場合でも`git show <リビジョン>:<ファイル名>`コマンドは機能する。
そして`git show`コマンドはファイルにリダイレクトできる。ということで

```bash
# git showの結果を自分自身にリダイレクトして上書きする
git show 123ab45c:some/file.cpp |> some/file.cpp
```

これで何とかなるようだ。
あとは`HEAD`と`diff`を取ったり、手動で泥臭く修正したりできる。
cronが動かない、rootコマンドが見つからないと表示される

# 起きた問題
MyDNSへIP通知用のcronが動かない

```bash
/bin/bash/: root: コマンドが見つかりません
```

とログに表示される。

# 問題が起きた背景
MyDNSを使っており、IPの通知をしようと、サイトの説明ページを見ながら、cronを設定した

# /etc/cron.every5min/mydns のスクリプト
```vim
#!/bin/sh
#
# send IP address to mydns.jp
#
/usr/bin/wget -O - 'https://mydns〇〇〇〇:〇〇〇〇@ipv4.mydns.jp/login.html'
/usr/bin/wget -O - 'https://mydns〇〇〇〇:〇〇〇〇@ipv6.mydns.jp/login.html'
```
※IPv4とIPv6用に2回通知しています。

# 変更前のcrontab -e の設定

```vim
# crontab -e SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
*/5 * * * * root run-parts /etc/cron.every5min > /var/log/cron.log 2>&1
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
```

# 解決方法
crontab -e の書き方が問題でした。

```vim
変更前
*/5 * * * * root run-parts /etc/cron.every5min
```

↓

```vim
変更後
*/5 * * * * run-parts /etc/cron.every5min
```

※ログ出力部分は省略しています。

# 原因
MyDNS.jpさんのサイトで説明していた「cron設定ファイル」というのは、/etc/crontabのことでした。
「/etc/crontab」と「crontab -e」だと書式が少し違うようです。
/etc/crontabでは、コマンドの前に実行するユーザを指定しますが、
crontab -e だと、時間のあとはすぐコマンドの指定になります。

crontabはユーザごとのcronで、/etc/crontabはシステム全体でのcronという扱いなんですかね。
certbotコマンド

# 自動更新
```:shell
sudo /home/revin/certbot-auto renew --post-hook "sudo service httpd restart"
```

# cron設定例
`sudo su -`で`crontab -e`

```:apache,月の中旬の水曜
15 03 15-21 * 3 sudo /home/revin/certbot-auto renew --post-hook "sudo service httpd restart"
```

```:nginx,月の中旬の水曜
15 03 15-21 * 3 sudo /home/revin/certbot-auto renew --post-hook "sudo service nginx restart"
```
kotlin apply,let,also,run,with,takeIf,takeUnless 使い方

調べてもよく理解できない、覚えられないということで自分でまとめてみる。

早速本題へ

kotlin歴短いので、ご指摘等どうぞ

##apply vs run ##

```apply.kt
 val menuFile = File("text.txt").apply{
        setReadable(true) // this.setReadable(true) と同じ
        setWritable(true) // this == File("text.txt")
 }
```
オブジェクト生成時に使う。
File("text.txt")をapplyの中ではthisとして扱うことができて、もちろん省略もできる。
戻り値はthis

apply使ってないバージョン

```normal.kt
 val menuFile = File("text.txt")
 menuFile.setReadable(true)
 menuFile.setWritable(true)
```

```run.kt
 val hasPath = File("xxx.txt").run{
       readText().contains("hello") // this == File("xxx.txt")
 }
```
applyと同じくrunの中でthisを扱える
applyは呼び出し元を返すのに対し、runはラムダの結果を返す。


##let vs also ##

```let.kt
fun getHello(name :String?):String{
      return  name?.let{
          "hello ${it}"  // nameがmasakiの場合は hello masakiになる
      }?:" hello world"  // nameがnullの場合は hello world
}

```

letの中ではnameをitで扱える。
letの中の最後の文が返り値となる。 

let使ってないバージョン

```normal.kt
fun getHello(name :String?):String{
     return if(name != null){
         "hello ${it}"
      }else{
         "hello world" 
      }
}
```


```also.kt
var fileContents:String?
File("xxx.txt").also{
   plint(it.name)  // xxx.txtが出力される 
}.also{
   fileContents = it.readLine() 
}

```
letと同じくitでFile("xxx.txt")を扱える。
letとの違いはletはラムダの結果を返すが、alsoは呼び出し元（ここではFile("xxx.txt")）を返すので、Chain化可能

##with##

runと同じだけど呼び出し方が違うだけ
他の関数と呼び出し方が違うので使わないほうが良さそう

```with.kt
val len = with("hello"){
    length 
}
```

##takeIf##

```takeIf.kt
val fileContent = File("xxx.txt")
                 .takeIf{it.canRead() && it.canWrite()}
                 ?.readText()
```
Fileをitで受け取り
takeIfがtrueならitを返す。結果としてreadText()がfileContentに入る。
takeIfがfalseならnullを返す


##takeUnless##

```takeUnless.kt
class Status(val error: Boolean){
    fun isError():Boolean{
        return error
    }
}

fun process():Status?{
    val result = Status(false)  //falseの場合は resultを返す。
    //val result = Status(true) //true の場合は nullを返す。
    return  result.takeUnless { it.isError() } 
}
```

takeIfの逆でfalseならならitを返す。
上記の例はisError()がfalseの場合は結果を返し、trueの場合はnullを返す。


***最後に***

基本的にもうちょっとコード量を少なくするための関数だと思います。
覚えないとコードがかけないってのはないけど、
他人が書いたソースを読む際には必要になってくるでしょうね。
【開発日記】薬価検索アプリno.4 〜データベース設計〜

前回の内容はこちら。
[【開発日記】薬価検索アプリno.3 〜設計・画面の設計〜](https://qiita.com/pharma_tech3/items/ec93562bd49b54538da0)

開発背景などはこちら
[【開発日記】薬価検索アプリno.1 〜開発概要→企画〜](https://qiita.com/pharma_tech3/items/51c9a670c605098bc3bf)


##現在の進捗状況
1.必要な機能の洗い出し
2.必要な画面設計
3.データベース設計 ⬅︎今ココ
4.Railsでアプリケーションの雛形作成
5.大きな機能から順に実装
6.テストコードを書いて動作を担保する
7.リファクタリングして整理する
8.デプロイ



#DB設計
どうやって設計するのか、
なぜ、この段階で設計する必要があるのか、
ER図はどうやって書くのか、
これらは他の記事に譲りますね。

###大まかな手順
1.管理するデータ（エンティティ）の決定
2.データ属性を決定
3.エンティティ同士の関係性を決定（リレーション）
4.実際にテーブルとして定義する


#いざ、設計！
と、気合い入れてみましたが、
今回のアプリではDBを検索するだけなので、
薬価収載されている薬剤のデータさえあればOKでした。

今後の拡張機能として、お気に入り薬剤を登録できたり、過去の検索履歴が見れたり、というのはまだ先なので、今回は以下のようなテーブルを作成しようと思います。

#medicationsテーブル
今回使用するデータは公に公開されているデータを使用します。

こちらにある「医薬品マスター」を使用します。
[診療報酬情報提供サービス](http://www.iryohoken.go.jp/shinryohoshu/downloadMenu/)
こちらからCSVファイルがダウンロードできます。
また、CSVのままだとなんのこっちゃわからないので、説明を見てみましょう。
[データ内容に関する説明](http://www.iryohoken.go.jp/shinryohoshu/file/spec/data.pdf)

テーブルの構造を書き出すと以下のようになりました。
使わないよね？ってカラムもありますが、
このデータは、少なくとも２年に一回は薬価改定がありますし、常に新しい医薬品も増え続けます。
逆に、販売がなくなる医薬品もあります。
その時に簡単にアップデートできるように、手をつけない形で運用してみようかと思います。
のちのアップデートも考慮して設計していきたいところです。

書き出してみるとこのようになりました。

|column      |    type |   options    |備考|
|:----------------:|:-----------------:|:------------------:|:------------------:|
| 変更区分 change_category       |  integer   |       ||
| マスター種別 master_type   |   string |       |Y:固定|
| 医薬品コード（医薬品名、規格名）pharmaceutical_code |   integer |    ||
| 漢字有効桁数 kanji_significant_digits    |    integer |      ||
|漢字名称  name  |   string |    index  ||
| カナ有効桁数 kana_significant_digits |   integer |     | |
| カナ名称 kana_name | string  |   ||
| 単位コード unit_code | integer  |   ||
| 単位漢字有効桁数 unit_significant_digits | integer  |   ||
| 単位漢字名称 unit_name | string  |  index ||
| 金額種別 price_type| integer  |   ||
| 新又は現金額 price | integer  |   ||
| 予備 spare | integer  |   |未使用（すべて0）|
| 麻薬・毒薬・覚せい剤原料・向精神薬 n_p_s_p_drugs| integer  |   ||
| 神経破壊剤 nerve_destroyer| integer  |   ||
| 生物学的製剤 biologics| integer  |   ||
| 後発品 generic| integer  |  index ||
| 予備 spare_2|  integer |   |未使用（全て０）|
| 歯科特定薬剤 dental_drugs| integer  |   ||
| 造影（補助）剤 contrast_agent| integer  |   ||
| 注射容量 injection_volume | integer  |   ||
| 収載方式等識別 listing_type| integer  | |  |
| 商品名等関連product_name_relations | integer  |   ||
| 旧金額種別 old_price_type | integer  |   ||
| 旧金額 old_price | integer  |   ||
| 漢字名称変更区分 name_change_category| integer  |   ||
| カナ名称変更区分 kana_name_change_category| integer  |   ||
| 剤形 dosage_form | integer  |   ||
| 予備 spare_3 | integer  |   |未使用(null）|
| 変更年月日 changed_date | integer  |   ||
| 廃止年月日 abolition_date| integer  |   ||
| 薬価基準コード standard_code| string  |   ||
| 公表順序番号 order_number| integer  |   ||
| 経過措置年月日又は商品名医薬品コード使用期限 expiration_date | integer  |   ||
| 基本漢字名称 standard_name| string  |   ||




#まとめ・所感
今回は、DB設計を行いました。
今想定してる機能としてはDBを検索するだけ。なので、DBは１つで事足ります。
しかし、今後、お気に入りの登録や、検索履歴、セット処方での金額表示など、ユーザー登録が必要な機能も考えているので、
その時はER図も使って書いてみようと思います。



次回、[【開発日記】薬価検索アプリno.5 〜Railsでアプリケーションの雛形作成、mySQLエラー、GitHubの設定まで〜](https://qiita.com/pharma_tech3/items/0d6f14e889a40dffee3b)に続きます。
forkしたrepositoryをcomposer requireでインストールする

## 背景

- 使用していたライブラリがアーカイブされてしまった😭
- 代替パッケージへの乗り換えはコスト高くて難しい🤔
- いつ削除されるか分からなくて怖い😱
- ライブラリをメンテナンスしたい💪

## フォークしていれば、リポジトリは残る

アーカイブされたリポジトリは一定期間で削除されてしまう可能性があります。
数年後リポジトリが消えていきなり動かなくなったことを考えるとめちゃ怖い。

https://help.github.com/ja/github/administering-a-repository/deleting-a-repository

> プライベートリポジトリを削除すると、そのフォークもすべて削除されます。
> パブリックリポジトリを削除しても、そのフォークは削除されません。

フォークしとけば、上流リポジトリが消されても安心みたい！
(プライベートリポジトリに変更した上で削除されたらどうなってしまうんやろか...？🤨)

## 手順

例として `package/foo` のパブリックリポジトリをforkして `mycompany/foo` のリポジトリを作った場合の手順になります。

## package/foo をアンインストールする

```
$ composer remove package/foo
```

## composer.json を変更する

```json
{
    "repositories": [
        {
            "name": "package/foo",
            "type": "vcs",
            "url": "https://github.com/mycompany/foo"
        }
    ],
... 省略
}
```

## package/foo をインストールする

```
$ composer require package/foo
```

これでフォークしたリポジトリをインストールできます😆

## 参考

- https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md
- https://barryvanveen.nl/blog/55-installing-a-private-package-with-composer
- https://github.com/composer/composer/issues/3542#issuecomment-67623002
[Python/顔認証]

顔認証をして検出した顔の中心に別の画像の貼り付けをしたい。
画像の貼り付けをするのは、顔を予め登録されている人物の顔と照合した時に一致した1人のみ。

顔の検出、画像の貼り付け、画像貼り付けをしたい顔のtop, right, bottom, leftそれぞれの座標の獲得はできている。

発生している問題：画像の貼り付けの位置が指定できない。ちょうど顔の中心に貼り付けをしたいのに、画像全体の左上にしか貼り付けがされない。
エラーコード：なし

```Python
import numpy as np
import face_recognition
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt

from PIL import Image, ImageDraw, ImageFilter

im1 = Image.open('sannin.jpg')
im2 = Image.open('output_test.jpg')

def draw_face_locations(img, locations):
fig, ax = plt.subplots(figsize=(9, 9))
ax.imshow(img)
ax.set_axis_off()
for i, (top, right, bottom, left) in enumerate(locations):
w, h = right - left, bottom - top

ax.add_patch(mpatches.Rectangle(xy=(left, top), width=w, height=h,ec='orange', lw=3, fill=None))
ax.text(left, top - 30, 'No {}'.format(i), color='k', backgroundcolor='w')
print('face (Top: {}, Left: {}, Bottom: {}, Right: {})'.format(
top, left, bottom, right))

back_im = im1.copy()      
back_im.paste(im2,(left+w/2 in locations[0], bottom+h/2 in locations[0]))
back_im.save('sannin_paste.jpg', quality=95)
plt.show()

img1 = face_recognition.load_image_file('sannin.jpg')# 検出対象の画像
img2 = face_recognition.load_image_file('kao.jpg')# 登録されている人物の画像

# 検出対象の画像から顔検出する。
locations1 = face_recognition.face_locations(img1, model='cnn')
draw_face_locations(img1, locations1)
# 登録されている人物の画像から顔検出する。
locations2 = face_recognition.face_locations(img2, model='cnn')
draw_face_locations(img2, locations2)
# 検出対象の顔から特徴量を抽出する
encodings = face_recognition.face_encodings(img1, locations1)
# 登録されている人物の顔から特徴量を抽出する。
encoding = face_recognition.face_encodings(img2, locations2)
# 登録されている人物の顔の特徴量 encoding[0] と検出対象の各顔の特徴量 encodingsとの距離を計算する。
dist = face_recognition.face_distance(encodings, encoding[0])
print(dist)

# 登録されている人物の顔の特徴量 encoding[0] と最も距離が近い特徴量を持つ顔
print("最も距離が近いNo", np.argmin(dist))# 最も距離が近いNo 0
```

[試したこと]

```Python
back_im.paste(im2,(left+w/2 in locations[0], bottom+h/2 in locations[0]))
```

この部分を色々試している

どなたかお力を貸してください。
ThingWorx カスタムウィジェットでJSONデータを受け取るとき

#はじめに

**対象読者**
この記事は、下記の知識・スキルを持っている人を対象としています。

- ThingWorx 開発の基礎値基礎
- JavaScript の基礎知識

**関連記事**

- [エクステンション開発ガイド（英語）] (https://qiita.com/kanoloa/items/374281b7b6d3536795c9)
- [ThingWorx ウィジェット開発] (https://www.ptc.com/support/-/media/FFF75A096E3245C8BA1E42E1C47C04CD.ashx?sc_lang=en)

**対象バージョン**

この記事は、ThingWorx 8.x で有効です。また、2019年10月に執筆していますので、情報の鮮度にはご注意ください。

#カスタムウィジェットでJSONデータを受け取るとき

たとえば、STRING 型のデータをウィジェットに渡すには、ウィジェットの .runtime.js で updatePropety() 関数を次のように書きます。

```runtime.js
this.updateProperty = function (updatePropertyInfo) {

	// 文字列データを受け取る場合

	var stringData;

	if (updatePropertyInfo.TargetProperty === 'String Data') {
		stringData = updatePropertyInfo.SinglePropertyValue;

	}
}	
```

STRING、NUMBER、DATE 型といった、ThingWorx にとってのプリミティブなデータ型を引数としてウィジェットに渡すにはこれでいいのですが、実際には JSON 形式のデータを渡したいことがあります。

残念なことに、``updatePropertyInfo.SinglePropertyValue`` 経由では、JSON　データは渡せません。JSON データをウィジェットで受け取りたいときには、次のように書きます。

```runtime.js
this.updateProperty = function (updatePropertyInfo) {

	// JSON データを受け取る場合

	var rawData;
	var json;

	if (updatePropertyInfo.TargetProperty === 'JSON Data') {
		rawData = {}
		if (updatePropertyInfo.RawDataFromInvoke != undefined) {
			rawData = updatePropertyInfo.RawDataFromInvoke;
			json = rawData.rows[0].json;

			TW.log.debug(json.stringify());

		}
	}
}	
```

上記のように ``updatePropertyInfo.RawDataFromInvoke``変数経由で JSON データを受け取ります。注意する点は、ウィジェットに渡した JSON データは INFOTABLE に格納され、ウィジェットには INFOTABLE ごと渡されると言う点です。このため、

``json = rawData.rows[0].json;``と、配列の最初の要素に含まれる ``json`` 変数にアクセスします。

上記の処理の後は、変数 json には渡したい JSON がはいってますので、あとは煮るなり焼くなりなんなりと。
「そのAMI、実は罠かも」AMIを選ぶ前には、必ず所有者を確認！

# AWSのAMIリストに潜む闇
AWSマネジメントコンソールからWindows Serverを構築する時、AMIを選びますよね。
今日も、いつもの感覚で、ウィザードを開きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/e58147da-1161-ad45-e44d-75bece75fb43.png)
さて、どのAMIを選ぶのが良いのでしょうか。

なんか、上から2番目が良さそうです。
**「Japanese Language」**で**「Support Include」**と書いてあるので、一見、これが一番良さそうです。

でも、上記のAMIには、他のAMIと違うところがあります。
それは**「provided by Amazon」**とは書いてない点です。

なんか、急に怪しくなってきました。

そこで、AMIの一覧画面で確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/9d61640c-b78d-34ee-5ac7-567f5486f0b3.png)

なんと、**1つだけ所有者が違います。**
他は、AWSの公式AMIのように見えますが、この1つだけは明らかに違います。

もしや、**公式っぽく見せようとしている罠では・・・**などと考えてしまいますが、それは果たして考えすぎなのでしょうか。。。

## 怪しいAMIは、今年の春にも存在していた
以下は、今年の4月頃の画面キャプチャーですが、公式に酷似した名前で、野良AMIと思わしきものがウィザードの1ページ目に出現していた様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/3d56232c-ded6-2c19-6f82-49016aef3146.png)
よく見ないと、間違って選んでしまいそうです。

この時もAMIの一覧画面を見ることで、AMIの怪しさに気づけました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/ece1d55d-83f4-7665-448f-8925dbe54a8f.png)

## AMIって誰でも公開できるんだっけ?
AWSでは、次のドキュメントの手順で、誰でもAMIを公開できます。
今回のAMIも、名前を似せてこの手順に沿ってAMIを公開したと思われます。

**「AMIを一般公開する」**
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/sharingamis-intro.html

>AMI を公開した後、コンソールを使用して同じリージョン内でインスタンスを起動すると、
その AMI が [Community AMIs] に表示されます。AMI は、公開してから [Community AMIs] に表示されるまでに、しばらく時間がかかることもあります。また、AMI を非公開にした場合も、[Community AMIs] から削除されるまでにしばらく時間がかかることがあります。

この他には、有償のマーケットプレイスで販売するという手段があります。


# 結論
**AWSのEC2を構築する際には、必ずAMIの所有者を確認した方が良いです。**

コミュニティAMIは、その仕様上、一般の方が作成されたAMIもあり、どんなソフトウェアがインストールされているか分かりませんので、トラブル防止の為、所有者がAmazonのものを選ぶようにすべきかと思います。(理由があって意図している場合は別ですが。)
AMI一覧からEC2を構築する手順であれば、所有者欄を見ながら気づけますので、トラブル回避できます。
怪しいAMIは、名前はそっくりですが、ソースと所有者が違うのが分かります。

最初の画面キャプチャーで示すウィザードでは、公式と野良を正確には区別できません。(Descriptionが偽装されていても気づかない)
CloudFormationやTerraformで最新のAMIを選択するコードでは、Amazon公式アカウントのID(12桁)または所有者でAMIを絞り込むコードに変更すべきでしょう。
バックアップを取ってファイルを上書き(sedによる処理)

ファイルにsedで処理を施して上書きしたい際に，同時にバックアップを取りたければ，

```sed -i.bak -e {sedによる処理} {ファイル名}```

とすれば良い．
また，ファイルは複数指定可能．

例 : カレントディレクトリ配下のtest1.txtとtest2.txtの2行目のアンダースコアを削除したい

実行前のディレクトリ構成
.
├─ test1.txt
└─ test2.txt

実行コード
```sed -i.bak -e '2s/_//g' test1.txt test2.txt```

実行結果
.
├── test1.txt
├── test1.txt.bak
├── test2.txt
└── test2.txt.bak

.bakファイルの中身は書き換える前のものが入っている．
MacでCLIでYAMLの構文チェックをする方法

# 目的
Mac OSで、YAMLファイルの構文チェッカ(Linter)を、CLI経由で使えるようにする。

# Install
参考： https://formulae.brew.sh/formula/yliamllint

```bash:bash
$ brew install yamllint
```

# 使い方
参考: https://github.com/adrienverge/yamllint

```bash:bash
$ yamllint target-file.yaml
```