OmniAICreator/Qiita-1.07M huggingface dataset:
Nginx の Docker コンテナがデフォルトで graceful shutdown になってちょっと幸せ

この記事は [Nginx の公式 Docker Image](https://hub.docker.com/_/nginx?tab=description&page=1&ordering=last_updated) が**コンテナシャットダウン時にデフォルトで graceful shutdown になった**ことが嬉しかったという内容です。(1.19.5 以降)

## 前提条件
以下のような方々に少しでも嬉しさが伝わると幸いです。

* docker stop、docker-compose、kubernetes でコンテナを操作・運用している方々
* コンテナシャットダウン時に 502 エラーが許されないサービスを開発している方々

## graceful shutdown とは
[wiki](https://en.wikipedia.org/wiki/Graceful_exit) によると「プログラムが重大なエラーを検出し、何らかの制御により正常に終了させること」と書いてあります。web サービスをコンテナで提供する場合に限定すると、以下のような要件になると思います。

* コンテナがシャットダウンされる時、既に存在するコネクションやリクエストの処理を完了させること
* コンテナがシャットダウンされる時、新規に接続を受け付けないようにすること

## 今までの Nginx コンテナの挙動
今まで(v1.19.4 以下) の Nginx コンテナを終了すると`SIGTERM シグナル`が送信されていました。(Nginx のエラーログレベルを notice 以下にすると見れます。以下のログは v1.19.3 の場合)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927896/633efd10-4187-9905-5d60-5402566970a3.png)
これは、docker や Kubernetes のデフォルト動作でコンテナ終了時に` SIGTERM シグナル`を送信するためです。
参照：[docker stop](https://docs.docker.jp/engine/reference/commandline/stop.html)、[docker-compose](https://docs.docker.jp/compose/faq.html#id4)、[Kubernetes](https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)

問題は **Nginx が` SIGTERM シグナル`を受信すると、即刻シャットダウン動作に移行すること** です。([Nginx 公式](http://mogile.web.fc2.com/nginx/control.html) より)
そのため、デフォルト設定のまま運用すると場合によっては 502エラーが出てしまうこともありました。

## 今までの回避方法
この現象を避けるためには **Nginx コンテナに` SIGQUIT シグナル `を送信すれば良い** です。([Nginx 公式](http://mogile.web.fc2.com/nginx/control.html) より)
代表的な方法は以下です。

* [Dockerfile で STOPSIGNAL の定義上書き](https://docs.docker.jp/engine/reference/builder.html?highlight=stopsignal#stopsignal)
* [Kubernetes マニフェストの preStop フィールドで SIGQUIT シグナルを送信](https://kubernetes.io/ja/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#poststart%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9%E3%83%BC%E3%81%A8prestop%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9%E3%83%BC%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B)

ちょっとしたことですが、どちらも「そんなの知らなかった！」とか「加工のひと手間が面倒・・・」ということを感じていました。

## これからの回避方法
何もしなくて良いです。
Nginx 1.19.5 以上のイメージは上記の` STIOPSIGNAL `の定義が上書きされ、デフォルトで` SIGQUIT シグナル`が送信されます。(以下は v1.19.5 の場合)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927896/f03b0dfd-eed7-994d-bd3b-16a381bc490c.png)
これにより、graceful shutdown のために Dockerfile をいじったり、preStop を定義したりする必要は無さそうです！
ちょっと嬉しい。

## まとめ
graceful shutdown が要件のサービスで Nginx コンテナを使っている場合、v1.19.5 以上を使うと少し楽かもしれません。
ただし、構成やツールによって Nginx 単体の graceful shutdown では要件を満たさない場合もありますのでご注意ください。
Refactoring Ruby



# はじめに

マルチスケールシミュレーション特論の講義メモです．講義メモのインデックスは[コチラ](<https://qiita.com/e79a93e5b7b1/items/d48ad7b8df544d737a78>)


# Refactoring Ruby

この記事はジェイ・フィールズ，シェーン・ハービー，マーティン・ファウラー 著 / 長尾高弘 訳 の 『リファクタリング:Rubyエディション』（アスキー・メディアワークス，2010年）に沿って refactoring を学んだ学習記録である．講義資料・コードは公開できないため，github の該当フォルダを参考にしていただきたい．


## refactoring

講義内でも度々紹介されていたが， **refactoring** とは何か．再度確認する．

factoring には因数分解という意味があるが，プログラムを class や method に分割していくこと自体がプログラミングにおける因数分解と言えるだろう．re- がつくと振り返りや戻るというイメージになる．refactoring を簡単にいうと出来上がったプログラムを見直し，再度プログラムの構造を組み立て直すイメージになる．

厳密にいうと refactoring は `外部から見た動作を変えずに，プログラムの内部構造を組み立て直す` ということである．見た目を変えずに，中身を美しくしていく．人間もそうであるべき．


## TSUTAYA Project

今回取り組んだのは リファクタリング：Rubyエディション の TSUTAYA Project (正式名称は不明，第 1 章 pp.25 ~ pp.74) である．ビデオのレンタル料金を計算して出力するプログラムで，様々な要素について複数のクラスに分けて表現されている．

編集の対象となるプログラムファイルは movie.rb, rental.rb, customer.rb の 3 つ．それぞれのプログラムにはプログラム名と同様のクラスが定義されており，

-   Movie class: 作品のデータ（料金など）を表すクラス
-   Rental class: レンタル情報（新作や子供料金など）を表すクラス
-   Customer class: 顧客情報 (名前やレンタル作品) を表すクラス

のように構成されている．

はじめのプログラムは実行する上で特に問題はないのだが，プログラミングの書き方に問題があるらしい．冗長な部分を動作を変えずに改変していくのが refactoring の役目なので早速 refactoring していく．

手順としては一つずつ冗長な部分を直していき，テストしていく．プログラムを改変する際は一気に改変するのではなく，たとえ変数が一つ変えるだけだとしても少しずつ直してはテストをするように心がける．

修正すべき点としてあげられれているのは

-   長いメソッドは動作ごとに分割する．
-   各メソッドはそれぞれ適切なクラス下に定義する．
-   変更しやすいようにわかりやすい記述をする

これらの点を refactoring する．

refactoring の第一歩として， **テストセットの作成** が重要視されている．テストセットを作成し，期待する出力と結果の出力は一致するのか・assert が出ていないか・どのようなエラーなのかまでしっかりわかるようにすることでバグに対する作業効率が向上する．講義内の assert\_equal はここに結びつくわけか．

今回は rspec というテストセットを用いてrefactoring に取り組んだ．


## さいごに

プログラムを追って説明することができないので，refactoring に取り組んでみて感じた感想について記述していく．

TSUTAYA Project の refactoring を終えるのに 3 時間近くかかった．単純計算でも 1 プログラム 1 時間くらい．今回は 3 つのプログラムの refactoring だったが，各プログラム間の相関なども考慮しながら進めるのでファイル数が増えれば指数関数的に時間もかかっていくだろう．

refactoring をしているこの感じどこかで味わったことがあるなと思ったが，それは Rails アプリケーションを作成するときの感じだった．複数のファイルを行き来し，この変数は instance 変数にした方が良いとか，この機能は別の class に移した方がいいとか，そういった考え方である．

個人的には refactoring 苦手，というか向いていない．飽き性なので同じプログラミングを睨めっこしたくない．機能追加するなら前のプログラムを踏襲して 1 から作り直したいし，より綺麗にしたい．瞬発力だけで動いていて持久力がない身からするとこの課題でさえも疲弊したのが本音である．

しかしながら改めて refactoring というものを学べる機会を設けていただいてよかった．より良いコードとは何か，より美しいコードとは何か．自分なりの答えを見つけられた気がする．



------
 - **source** ~/grad_members_20f/members/e79a93e5b7b1/posts/class/refactoring_ruby.org
オブジェクト指向はゲームづくりに向かない その５



その１：https://qiita.com/mas-yo/items/43101d2e5ef073a1f3f5
その２：https://qiita.com/mas-yo/items/f802b5a6a6b3f47eed71
その３：https://qiita.com/mas-yo/items/cd0ddfebba3348a98b24
その４：https://qiita.com/mas-yo/items/c10ee3c8939ead6aec71


前回は、ECSで設計した見下ろし型アクションゲームの土台に、「空を飛ぶ敵」を追加で実装する、ということを想定して、設計を考えてみました。

![ecs4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227302/6b6dd388-edc9-45cd-fc18-33f676d2790e.png)


このように、`MoveAttribute`コンポーネントを追加することで、空を飛ぶ状態を表現したのでした。

さて、次に、「羽のアイテムを使うとプレイヤーは空を飛べるようにする」これを設計してみましょう。

### `UseItem`コンポーネント、`MoveAttribute`システム

まず新たなコンポーネントとして、アイテムの使用状態を持つ`UseItem`コンポーネントを考えます。
アイテムを使う、というのは一般にプレイヤーの入力によって決まりますが、ここでは詳細は省略します。

今回の仕様では、`UseItem`に依存して`MoveAttribute`が変わればOK、ということになりますね。
よって、`MoveAttribute`システムを追加し、`UseItem`を参照するようにします。

![ecs5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227302/8f9757d1-f722-73e1-5330-f6c80c4e2225.png)

`MoveAttribute`の更新は、`MoveAttribute`システムが担当します。

前回（詳細は省きましたが）、`MoveAttribute`は何らかのマスターデータを参照して、敵が「空を飛ぶか、地面を歩くか」を決める、ということを想定していました。

今回は、それに加えて、`UseItem`が「羽アイテムを使う」という状態だったときに、`MoveAttribute`を「飛行」に設定します。

この様に、当初は静的な情報により決定される挙動が、動的なものに変えられたとしても、大きな影響なく、実装をすることができます。

オブジェクト指向による設計と比較すると、どうでしょうか。

[その１](https://qiita.com/mas-yo/items/43101d2e5ef073a1f3f5)で、オブジェクト指向で設計した際、「空を飛ぶ」かどうかは、クラスによって決まっていました。よって、後から動的に空を飛べるようになる機能が欲しくなった際に、困ってしまいましたね。

今回はECSの設計によって、それをうまく回避できています。

## まとめ

以上、全５回に渡って、オブジェクト志向による設計の欠点と、それをECSによってどのように克服できるかについて、見てきました。
プログラミングを学ぶとき、多くの方は、手続き型から、オブジェクト指向と学んで来たと思います。

オブジェクト指向による設計は、現実世界に即して考えるのでわかりやすいですが、一度設計したクラスを後から簡単には変えられないため、常に仕様変更・機能追加を繰り返すゲームのプログラミングには、向かない面もあります。

そこに、データ志向設計（＝Entity Component System）が注目されている理由もあります。
ECSによる柔軟でバグを生みにくいプログラム設計をして、みんなで幸せになりましょう。

ECSでゲームをつくるとどんな感じになるのか、
https://github.com/mas-yo/rust-ecs-game
こちらで実験しています。（言語はRustです）
興味のある方はご覧になってください。
minikubeでIngressアドオンを有効化する

## 環境

* Mac OS X 10.15.7
* Docker For Mac 3.0.3
* Kubernetes 1.19.3

## エラー内容

```sh
$ minikube start

$ minikube addons enable ingress
```

を実行すると以下のエラーが出る

```
Exiting due to MK_USAGE: Due to networking limitations of driver docker on darwin, ingress addon is not supported.
Alternatively to use this addon you can use a vm-based driver:

	'minikube start --vm=true'

To track the update on this work in progress feature please check:
https://github.com/kubernetes/minikube/issues/7332
```

上記のエラーメッセージ通り以下で起動する

```sh
$ minikube start --vm=true

$ minikube addons enable ingress
```

するとdocker hubからのimageをpull出来ず...

## 解決方法

```sh
$ minikube start --driver=hyperkit

$ minikube addons enable ingress
```

でhyperkitを使用してingressを有効化するとdocker hubからimageもpull出来て解消
【Laravel】ログインログを指定したファイルに保存する

# ログインログは出力ファイルを分ける

カスタムチャンネルを追加する
storage/logs/login.logに保存されるようにする

``` config/logging.php
    'channels' => [
        …
        'login' => [
            'driver' => 'single',
            'path' => storage_path('logs/login.log'),
        ],
```

キャッシュクリア

```
$ php artisan config:clear
```

ログイン後にログを保存する

``` app/Http/Controllers/LoginController.php
    /**
     * 認証を処理する
     *
     * @param  \Illuminate\Http\Request $request
     * @return Response
     */
    public function login(Request $request)
    {
        $credentials = $request->only('id', 'password');
        $remember = $request->all()['remember'] ?? false;

        if (\Auth::guard('users')->attempt($credentials, $remember)) {
            \Log::channel('login')->info('ログメッセージ'); // ここを追加
            return redirect()->intended('/');
        }
        return view('auth.login');
    }
```


## ついでに、ログローテーションを導入する
.envのLOG_CHANNELを変更することでログローテーションの導入が可能

```
LOG_CHANNEL=stack
 ↓ 以下に変更
LOG_CHANNEL=daily
```

channelの設定は以下のようになっているので、
dailyにすると14日間でローテーションすることになる。保存先はlaravel.log

``` config/logging.php
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single'],
            'ignore_exceptions' => false,
        ],

        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ],

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 14,
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
        ],

        'papertrail' => [
            'driver' => 'monolog',
            'level' => 'debug',
            'handler' => SyslogUdpHandler::class,
            'handler_with' => [
                'host' => env('PAPERTRAIL_URL'),
                'port' => env('PAPERTRAIL_PORT'),
            ],
        ],

        'stderr' => [
            'driver' => 'monolog',
            'handler' => StreamHandler::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with' => [
                'stream' => 'php://stderr',
            ],
        ],

        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],

        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],

        'null' => [
            'driver' => 'monolog',
            'handler' => NullHandler::class,
        ],

        'emergency' => [
            'path' => storage_path('logs/laravel.log'),
        ],
```
Refactoringの感想（ほんとに感想だけ）



# Refactoring


## Refactoringってなんぞ

今回はRefactoringについて学ぶ

Refactoringってなんぞやというと，一言で言うと\*プログラム自体の動きは変えないように気を付けつつ、ソースコードを書き換える作業\*です．

今回は\*リファクタリング：Rubyエディション （ジェイ・フィールズ, シェーン・ハービー, マーティン・ファウラー 著 / 長尾高弘 訳）\*を参考に勉強する．


## 感想と概要

感想と言っても，特にない．

やったことはビデオレンタルのシステムについて，参考資料通りにRefactoringしただけ．

まずは第一にテストセットの作成を行うこと．

リファクタリングの原則は滅多にバグが入らないように組み立てることだが，人間誰しもミスはある．ということで，しっかりとしたテストが必要とのこと．

次に，どの部分から行うか，ターゲットを決めて行っていく．

長いメソッドを分割して，部品をより適切なクラスに移す．論理的にひとかたまりになっているコードを見つけ，「メソッドの抽出」を行う．

変更を加えたら，テストを行う．（リファクタリングでは，プログラムを少しずつ変更すること！）

場合によれば，現在とは違うクラスにメソッドを渡すことも行う．

とまあ，こういうことを，ひたすら行っていくわけである．

興味のある方は書籍を探して実践してみてください．


# 締め

今回はRefactoringについて学んだ．

確かに，わかりやすく，変更の加えやすいCodeとかって大事だよなぁとか思いつつ，実際には，まずは動くものをという思想がこびりついている．



------
 - **source** ~/school/multi/my_ruby/grad_members_20f/members/evendemiaire/post/refactoring.org
Rails チュートリアル 第9章 備忘録

第9章の備忘録です。
いや、難しいよね。。

##目次
[1 第9章で出てくる語句まとめ](#1-第9章で出てくる語句まとめ)
[2 remember me 機能の実装の流れ](#2-remember-me-機能の実装の流れ)


###1 第9章で出てくる語句まとめ
初めて第9章取り組んだ時に、理解を共わない写経状態だったのだが、改めて取り組んでみると内容が入ってきた。
特にこの章から出てくる語句の意味を把握しておかないと厳しいなと感じたため、初めに語句をまとめてみました。

1. **トークン**
パスワードと同様のもの。
この2つの違いは、パスワードはユーザーが作成・管理
トークンはコンピューターが作成・管理するもの

2. **記憶トークン**
有効期限が設定されたトークンのこと。

3. **ダイジェスト**
まず、ダイジェスト認証が、値をハッシュ化してから送受信し認証を行う方法のこと。
前の章で`password_digest`、今回では`remember_digest`属性を使用していることから、データベースにハッシュ化された情報が入る



###2 remember me 機能の実装の流れ

####2.1 永続的セッション作成の流れ
1. 記憶トークンに、ランダムな文字列を生成して代入
2. ブラウザのcookiesにトークンを保存する時、有効期限を設定
3. トークンはハッシュ値に変換してからデータベースに保存
4. ブラウザのcookiesに保存するユーザーIDを暗号化
5. 永続ユーザーIDを含むcookiesを受け取ったら、そのIDでデータベースを検索、記憶トークンのcookiesがデータベース内のハッシュ値と一致することを確認


一旦ここまで💦
後日文章を足そうと思います。
【メモ】VAEにおける画像の再構成ロス

NVAEやVery Deep VAEs(VDVAE)といったVAEベースの画像生成モデルに興味を持ったので，その損失関数についてメモ

## VAE
◯（階層的でないVAEの）損失関数
$$
\mathcal L(x, z) = \mathbb E_{z\sim{q(z\mid x)}}\left[ \log p_\theta(x\mid z)\right] - \mathrm{KL}(q_\phi(z\mid x)\|\|p(z))
$$

- $x\in[0,1]^{C\times W\times H}$は観測値
- $z\in\mathbb R^D$は潜在変数
- $C,W,H,D\in\mathbb N$は，それぞれ，画像のチャネル，幅，高さ，潜在変数の次元


◯モデル
**なんらかの分布**を仮定し，その**パラメータ**を出力する。
（確率分布そのものはNNから出力できないため）

- encoder｜$q_\phi(z\mid x)$
    - 出力｜正規分布のパラメータ（平均・分散）
- decoder｜$p_\theta(x\mid z)$
    - 出力｜**Mixture of Discretized Logistics**のパラメータ


## Mixture of Discretized Logistics
多分初出であるPixelCNN++[2017]を参考にした。それ以前のPixelCNNでは，出力を255次元のカテゴリカルとしていたが，Mixture of Discretized Logisticsは，そのパラメータを減らすモチベで考案された。

◯Mixture of Discretized Logisticsの確率関数

$$
P(x \mid \pi, \mu, s) =\sum_{i=1}^{K}
\pi_{i}\left[\sigma\left(\left(x+0.5-\mu_{i}\right) / s_{i}\right)-\sigma\left(\left(x-0.5-\mu_{i}\right) / s_{i}\right)\right]
$$

- $P(x=a)=P(x\geq a+0.5) - P(x\geq a-0.5)$というCDFとPDFの関係を利用

◯RGBの同時分布のモデル化（混合なしの場合）
$$
p\left(r_{i, j}, g_{i, j}, b_{i, j} \mid C_{i, j}\right)= P\left(r_{i, j} \mid \mu_{r}\left(C_{i, j}\right), s_{r}\left(C_{i, j}\right)\right) \times P\left(g_{i, j} \mid \mu_{g}\left(C_{i, j}, r_{i, j}\right), s_{g}\left(C_{i, j}\right)\right)
\times P\left(b_{i, j} \mid \mu_{b}\left(C_{i, j}, r_{i, j}, g_{i, j}\right), s_{b}\left(C_{i, j}\right)\right)
$$

$$
\mu_{g}\left(C_{i, j}, r_{i, j}\right)=\mu_{g}\left(C_{i, j}\right)+\alpha\left(C_{i, j}\right) r_{i, j}
$$

$$
\mu_{b}\left(C_{i, j}, r_{i, j}, g_{i, j}\right)=\mu_{b}\left(C_{i, j}\right)+\beta\left(C_{i, j}\right) r_{i, j}+\gamma\left(C_{i, j}\right) b_{i, j}
$$

- R→G→Bの順で依存関係があると仮定（RGB各値は独立ではないためらしい）
- $\mu_r, \mu_g, \mu_b, s_r, s_g, s_b, \alpha, \beta, \gamma$の９つのパラメータ per pixel

◯混合ありの場合
上記の9つのパラメータに加えて，混合比率である$\pi$が加わって，計$10K$個のチャネルが必要
$$
p(r_{i,j},g_{i,j},b_{i,j}\mid C_{i,j}) = \sum_{k=1}^K\pi_k p_i(r_{i,j},g_{i,j},b_{i,j}\mid C_{i,j})
$$

※NVAEやVDVAEでは，$K=10$が用いられているため，出力は100チャネルとなる。

## 再構成ロス
上記の確率分布に基づいて，nllを計算するだけ。各実装をコピペすると楽。

- tf(openai)｜https://github.com/openai/pixel-cnn/blob/master/pixel_cnn_pp/nn.py
- torch(nvidia)｜https://github.com/NVlabs/NVAE/blob/master/distributions.py
- torch(openai)｜https://github.com/openai/vdvae/blob/main/vae_helpers.py

## まとめ

- VAEで画像を扱うときは，3チャネルではなく100チャネル出力
- $100=10\times (9 + 1)$で，10が混合数・9がパラメタ数・1が混合比率
- 再構成ロスはnll(著者実装が参考になる)
MacBook Air Early 2014 のFacetime HD(カメラ)をUbuntu 20.04で認識させる。

MacBook Air (11-inch, Early 2014)のスペックではBig surは辛かったのでUbuntu入れた。
Facetime HD(カメラ)が認識してなかったのでいろいろ適当にやって認識させてみた。
多分、13インチモデルやMid 2013でも認識すると思う。

※ 2020/12/29
uvcvideoのロードが不要だったので記載削除
bdc_pciをロードしないようにする設定を追記

#1.なんか必要そうなパッケージをインストールする。
~~~
# apt install -y \
curl \
xz-utils \
cpio \
imagemagick \
fswebcam \
v4l-utils \
git
~~~
※imagemagick、fswebcam、v4l-utilsは何となく動作確認用に入れただけで必須ではない

#2.ファームウェアをインストール
~~~
# mkdir -p ~/git
# cd ~/git
# git clone https://github.com/patjak/facetimehd-firmware.git
# cd facetimehd-firmware
# make && make install
~~~

#3.ドライバをインストール
~~~
# cd ~/git
# git clone https://github.com/patjak/bcwc_pcie.git
# cd bcwc_pcie
# make
# mkdir -p /lib/modules/$(uname -r)/extra
# cp facetimehd.ko /lib/modules/$(uname -r)/extra
~~~

#4.ドライバをロードする。
~~~
# depmod -a
# modprobe -r bdc_pci
# modprobe -r facetimehd
# modprobe facetimehd
~~~

#5.起動時にドライバを自動的にロードするようにする。
~~~
# echo facetimehd > /etc/modules-load.d/facetimehd.conf
# echo blacklist bdc_pci > /etc/modprobe.d/blacklist-bdc_pci.conf 
~~~
顔画像データセット仕分けのためモデル構築-VGG19の転移学習(#2)

#概要

UTKFaceデータセットを下記特徴ごとに仕分けするモデルを構築する。
・問題なし
・グレースケール
・複数人が写っている
・加工処理されている

[前回作成した学習用データ](https://qiita.com/dream88sound/items/34ee5221c09dd4eecdff)を使用しVGG19転移学習に挑戦してみました。
###環境
Google Colaboratory（GPU）

```csharp
from keras.layers import Dense, Dropout, Flatten, Input
from keras.applications.vgg19 import VGG19
from keras.models import Model, Sequential
from keras import optimizers
```

###VGG19の学習済モデルを使用します。
処理に負担がかかりますが正解率を上げる事ができなかったため画素数を増やしました。
学習用データが少なかったのかもしれない。

```csharp

# モデルはvgg19を使用します　im_size=299
input_tensor = Input(shape=(im_size, im_size, 3))
vgg19 = VGG19(include_top=False, weights='imagenet', input_tensor=input_tensor)

# vggのoutputを受け取り、分類する層を定義します
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg19.output_shape[1:]))
top_model.add(Dense(1024, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(4, activation='softmax'))

# vggとtop_modelを連結します
model = Model(inputs=vgg19.input, outputs=top_model(vgg19.output))

# vggの層の重みを変更不能にします
for layer in model.layers[:18]:
    layer.trainable = False

# コンパイルします
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
              metrics=['accuracy'])

# 学習を行います
model.fit(X_train, y_train,epochs=20, validation_data=(X_test, y_test))

# テストデータでの評価を表示します。
model.evaluate(X_test, y_test, verbose=1)

# 学習モデルをマイドライブに保存します。
model.save("/content/drive/My Drive/vggsort_model.h5")
```

###学習の結果
テストデータにて
- loss: 0.4032 - accuracy: 0.8978

うーむ。まだまだやりようはありそうですがひとまずの結果です。
この学習済モデルを用いて画像データをフォルダ毎に仕分けしたいと思います。

[機械学習モデルを用いた顔画像データセット仕分け(#3)](https://qiita.com/dream88sound/items/865fb40744176329d23e)

その後…
ちなみに、今回使用した学習用データは手作業による仕分けが不十分だったため、間違いを学習させてしまうようなデータが混在していました。
今回の学習済モデルでの仕分けも活用しながら、且つ手作業で学習用データをクリーンにして再度モデル学習を行ったところ、正解率が９６％にまで向上しました。
学習用データ作りは手が抜けない事がよく分かりました。
【初心者向】4万円台で作れる自作PC【構成・手順・参考サイトまとめ】

#本記事の目的
自作PC？？何それ？？のレベルから色々調べてなんとか完成したので、初心者目線で参考になりそうな情報を共有。
ちなみに自作PCの作成目的は、コンピュータをハード面から理解したかったけど、机上の勉強だとあまりよく分からなかったから。
やっぱり実際作ってみると断然頭に残るから、やったことない人にはぜひオススメしたい。

#参考にしたサイト

| 分類 | オススメポイント | リンク |
|:-----------|:------------|:------------|
| パーツ選定       | 価格帯や使用用途に合わせた豊富なパーツ構成を記載。        | [https://artjuku.com/pc-make/](https://artjuku.com/pc-make/)         |
| 組み立て方法    | 上記のサイトと同じ運営者のyoutube。手順が分かりやすいので、1回見てみるのがオススメ。      | [https://www.youtube.com/watch?v=2EvI51RVqlw&t=609s](https://www.youtube.com/watch?v=2EvI51RVqlw&t=609s)       |
| 組み立て方法       | マザーボードを周りを組み立てる際の力加減を解説してくれる（初心者には重要）。        | [https://www.youtube.com/watch?v=XybvVV01JKc&t=1453s](https://www.youtube.com/watch?v=XybvVV01JKc&t=1453s)         |
| 組み立て方法         | PCケースの配線が分かりやすい。          | [https://chimolog.co/bto-pubg-selfmade-pc/](https://chimolog.co/bto-pubg-selfmade-pc/)           |
| 無線LANアダプタ      | 自作PCでWifiを使うために必要。       | [https://www.youtube.com/watch?v=Kh7_THfC2m0)](https://www.youtube.com/watch?v=Kh7_THfC2m0)       |
| OS    | UbuntuのUSBインストール方法がまとめてある。     | [https://www.youtube.com/watch?v=mEJ1S-Tw9MM](https://www.youtube.com/watch?v=mEJ1S-Tw9MM)      |

自分は最初マザーボードにCPUファンとかメモリを取り付けるときの力加減がよく分からなかったので、初心者は上記の動画見て確認したほうが良いと思う。意外と押し込む力が必要。

#構成
| パーツ | 購入したもの |価格（購入時）|
|:-----------|:------------|:------------:|
| CPU       | [Ryzen 3 3200G](https://www.amazon.co.jp/gp/product/B07STGHZK8/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1)        | 13,111         |
| マザーボード     | [B450 Steel Legend](https://www.amazon.co.jp/gp/product/B07MV7LR1B/ref=ppx_yo_dt_b_asin_title_o02_s01?ie=UTF8&psc=1)      | 10,881         |
| ストレージ       | [Crucial 480G](https://www.amazon.co.jp/gp/product/B07H5B8734/ref=ppx_yo_dt_b_asin_title_o02_s01?ie=UTF8&psc=1)        | 5,880         |
| メモリ         | [Team DDR4 16GB](https://www.amazon.co.jp/gp/product/B07W5T4B7M/ref=ppx_yo_dt_b_asin_title_o02_s01?ie=UTF8&psc=1)          | 8,780             |
| 電源       | [Thermaltake Smart 500W -STANDARD-](https://www.amazon.co.jp/gp/product/B01ER29BKG/ref=ppx_yo_dt_b_asin_title_o02_s01?ie=UTF8&psc=1)       | 4,756         |
| ケース    | [Thermaltake Versa H26](https://www.amazon.co.jp/gp/product/B076KFGY7J/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)     | 4,159        |
上記で合計48,000円くらい。組み立てに失敗してパーツ破損すると金額的に痛いので、比較的低価格から始めようと思って上記の構成にした。
ただ自分の場合はキーボード・マウス・モニター・無線LANアダプタも購入したので結果的に6万超えた。
[ちなみに購入した無線LANアダプタはこちら](https://www.amazon.co.jp/gp/product/B07X462KRK/ref=ppx_od_dt_b_asin_title_s01?ie=UTF8&psc=1)

#失敗談
・PCケースのサイズ間違えてマザーボードが入らず、返品・再購入した。なぜ参考サイトの記載通りの構成にしなかったのか・・・。
・PCケースのPCIeが折り取り式だと気づかず、無線LANアダプタをセットする箇所しばらく見つからなかった。

#まとめ
分かりやすくまとめられてるYoutubeや個人サイトのおかげで素人でもなんとか完成させることができた。
自分で作るとなんか愛着が湧いてきてどんどん使いたくなってくる。
将来的にはパーツ交換とかしてアップグレードしてみたいな。。
Qiitaを始めてみた

年末のこのタイミングで始めるのはキリが悪いのでいかがなものかとも考えましたが，
普段から研究や趣味の調べごとをするときにお世話になっているQiitaを始めようと思います．

#始める理由
日々の気づきをまとめるため
自身で調べた知識や方法論をまとめるツールの一つとしてゆる～い感じで使えたらなと．

とくにプログラミングに関するまとめを行うときには，コードがきれいに見えるようにしておきたいので
それだったらいつも使っているQiitaがいいかな，と思い始めることにしました．

きれいに，というのはこんな感じ

```python:test.py
print("hello Qiita!")
```

めっちゃきれい．


ちなみに記述する際に言語の指定を行えば自動でハイライトを入れてくれるので
PythonだけでなくC++であればこんな感じ

```C++:test.cpp
printf("hello Qiita!");
```

あー便利(語彙力)

ということで，これからはまとめ用ツールとしてQiitaを利用しようと考えています．

知識の整理は大事！それでは．

#今回参考にした記事
Qiitaの記法についてまとめられているページです．
https://qiita.com/shizuma/items/8616bbe3ebe8ab0b6ca1
https://qiita.com/Nipper1357/items/07eb78a620bb9264f9aa
確認問題の考察

・RNN
RNNを特徴づける、一番大事な中間層から中間層への重みが解答となる。

・BPTT1
ある変数が直接微分できない場合、連鎖律を使うことで解くことができる。
逆伝播法では、これがキーポイントなる。

・BPTT2
出力y1を求める式は重みWoutにS1をかけcを加えて求める
y1=g(Wout・S1+c) 
ここでS1は入力x1にWinを掛けたものに中間層S0に重みWを掛けたものを活性化関数通したものになる
S1=f(Win・x1+W・S0+b)

・勾配消失1
シグモイド関数を微分したものは左右対称の真ん中が山型となる関数となる。最大値0のとき、は0.25となる

・勾配消失2
勾配のノルムが閾値より大きいときは、勾配のノルムを閾値に正規化するので、クリッピングした勾配は、勾配×（閾値／勾配のノルムと計算される。つまりgradient*rateとなる

・LSTM1
「とても」はあってもなくても文として意味が通じるので、忘却ゲートとなる

・LSTM2
output_gateは関係ないので(1),(2)は消える。忘却ゲートからの値を掛けるのはcとなるので(3)が答えとなる

・LSTM3
LSTMが抱える課題は入力ゲート、出力ゲート、忘却ゲート、CECの４つの部品から構成され、パラメータ数が多くなり計算が膨大になる
CECが抱える課題は勾配が１で学習能力がないこと

・GRU
LSTMは入力ゲート、出力ゲート、忘却ゲート、CEC、GRUはCECがなく更新ゲートとリセットーゲートをもつ。LSTMと比べるとパラメータ数が減り、計算量が少なくなる

・双方向RNN
隠れ層２つの特徴量を消すことなく残すには足したり、掛けたりしてはだめである。そこでconcatenateで合体させる。axisにより合体のさせ方が変わる。0は横に並べる。１は縦に並べる。従って答えはaxis=1となる（４）となる。

・Seq2seq1
答えは(2)となる。(1)は双方向RNN（３）は構文木（４）はLSTM

・Seq2seq2
文の意味となるベクトルを作ろうとしているところなので、（１）となる

・HRED
Seq2seqは一文の一問一答について処理できるある時系列データからある時系列データを作り出す
HREDはSeq2seqの機構にそれまでの文脈の意味ベクトルを解釈に加えられるようにすることで、文脈の意味をくみ取った文の変換をできるようにしたもの
VHREDはHREDが当たり障りのない文脈ついてしか解答を作れなくなったことに対しての解決策。VAEの考え方を取り入れて短い当たり障りのない言葉以上の出力を出せるように改良を施したモデル
・VAE
自己符号化器の潜在変数に確率分布を導入したものとなる。

・word2vec,Attention
RNNは時系列データを処理するのに適したニューラルネットワーク
word2vecは単語の分散表現ベクトルを得る手法
Seq2seqは、一つの時系列データから、別の時系列データを得るニューラルネットワーク
AttentionMechanismは時系列データの中身のそれぞれの関連性に重みをつける手法
Linuxコマンドチートシート

## ショートカットキー
カーソルの操作

|キー |実行結果 |
|------|--------|
|Ctrl + b |1文字分先頭方向へ移動  |
|Ctrl + f |1文字分末尾方向へ移動  |
|Ctrl + a |コマンド先頭へ移動  |
|Ctrl + e |コマンド末尾へ移動  |
|Esc + b  |1単語分先頭方向へ移動  |
|Esc + f |1単語分末尾方向へ移動   |

文字の削除

|キー |実行結果 |
|------|--------|
|Ctrl + h |1文字削除  |
|Ctrl + w |先頭方向の次のスペースまで削除 |
|Ctrl + k |カーソルから末尾までカット |
|Ctrl + u |カーソルから先頭までカット |
|Ctrl + y |カットしたコマンドのペースト |

コマンドの補完
|コマンド |実行結果 |
|------|--------|
|tab   |入力している文字列からコマンドを補完  |
|tab > tab |複数候補の一覧表示 |

コマンド履歴の使用
|キー |実行結果 |
|------|--------|
|Ctrl + p または↑ |一つ前に入力したコマンドを表示 |
|Ctrl + n または↓ |一つ後に入力したコマンドを表示 |
|Ctrl + r        |コマンド履歴を検索 |

## コマンド

### ディレクトリの操作

|コマンド |実行結果 |
|------|--------|
|pwd |カレントディレクトリのフルパスを表示  |
|cd |カレントディレクトリの変更  |
|mkdir |新しいディレクトリを作成  |
|rm -rf |ディレクトリの強制削除|
|rm -i |本当に削除するか確認つきでディレクトリを削除。|
|rmdir |空のディレクトリの削除|
|cp -r |ディレクトリのコピー|

### `ls`コマンド
カレントディレクトリ内のファイルを一覧表示

|オプション |実行結果 |
|------|--------|
|-l |詳細情報を追加表示  |
|-a |隠しファイルを含めて表示  |
|-F |ファイルの種類を含めて一覧表示  |
|-w 30 |指定した数字の横幅でファイル名表示。ここでは幅=30桁  |

### ファイル操作

|コマンド |実行結果 |
|------|--------|
|touch |新しいファイルの作成  |
|rm |ファイルの削除  |
|cp |ファイルのコピー（強制上書き）  |
|mv |ファイルの移動、ファイル名変更  |
|ln -s |シンボリックリンク（別名）の作成 |

### ファイルの閲覧

|コマンド |実行結果 |
|------|--------|
|cat |指定したファイルの中身表示。複数指定すると、中身を連結して表示。  |
|less |ファイルを一画面ごとに表示して、上下にスクロール  |

### `less`コマンド
画面表示中の操作

|コマンド |実行結果 |
|------|--------|
|スペースキー |一画面分下にスクロール  |
|b |一画面分上にスクロール  |
|q |画面を閉じる  |
|/ |下方向に検索|
|n|次の検索結果へ移動  |
|N|前の検索結果へ移動  |

### 検索

|コマンド |実行結果 |
|------|--------|
|find -name| 大文字小文字を区別してファイル名を検索 |
|find -iname| 大文字小文字を区別せずファイル名を検索 |
|which |コマンドのパスを表示  |

### プロセスとジョブの操作

|コマンド |実行結果 |
|------|--------|
|ps|プロセスの表示 |
|ps x| 別のターミナルやデーモンで起動しているプロセスも含めて表示 |
|Ctrl + Z |現在のジョブを中断  |
|jobs |現在のジョブを一覧表示  |
|fg %1 |1番目のjobを再開  |
|bg %1 |1番目のjobをバックグラウンドで再開  |
|コマンドラインの末尾に & | バックグラウンドでコマンドを実行 |
|kill %1|1番目のjobを終了 |
|kill プロセスID|プロセスを終了 |

### フィルタ
|コマンド |実行結果 |
|------|--------|
|cat | 入力をそのまま出力 |
|head| 先頭の10行を表示 |
|tail| 末尾の10行を表示 |
|grep |指定した検索パターンに一致する行だけ表示  |
|sort |並べ替え  |
|uniq |重複した行を取り除く  |
|tac | 逆順に出力する |
|wc | 行数、単語数、バイト数を表示 |
|tr <置換前の文字> <置換後の文字>| 文字の置換 |
Sidekiq のベストプラクティス、ActiveJobを使っている場合はその限りではなさそうという話

公式があげている [Sidekiq のベストプラクティス](https://github.com/mperham/sidekiq/wiki/Best-Practices#1-make-your-job-parameters-small-and-simple
)によると、perform メソッドにはオブジェクトではなくオブジェクトの id を渡すようにと書かれていますが、Rails の ActiveJob を使っている場合はその限りではないという話です。

> # MISTAKE
```ruby
quote = Quote.find(quote_id)
SomeWorker.perform_async(quote)
```

> Complex Ruby objects do not convert to JSON, by default it will convert with to_s and look like #<Quote:0x0000000006e57288>. Even if they did serialize correctly, what happens if your queue backs up and that quote object changes in the meantime? Don't save state to Sidekiq, save simple identifiers. Look up the objects once you actually need them in your perform method.

> > 複雑なRubyオブジェクトはJSONに変換することができません。デフォルトでは to_s を使って変換することになり、その結果は #<Quote:0x0000000006e57288> のようになります。

> > たとえシリアライズができたとしても、キューに保存されている間に quoteオブジェクトの値が変更されたらどうでしょうか？ 状態をSidekiqに保存するのではなく、シンプルなIDを保存してください。 そして、performメソッド内で実際に必要になったタイミングで、オブジェクトを find するようにしてください。


しかし、[ActiveJob Style Guide](https://github.com/toptal/active-job-style-guide) によると id を渡すのは bad と書かれていたので紹介します。

```ruby
# bad - passing by id
# Deserialization error is reported, the job *is* scheduled for retry.
class SomeJob < ApplicationJob
  def perform(model_id)
    model = Model.find(model_id)
    do_something_with(model)
  end
end

# bad - model mismatch
class SomeJob < ApplicationJob
  def perform(model_id)
    Model.find(model_id)
    # ...
  end
end

# Will try to fetch a Model using another model class, e.g. User's id.
SomeJob.perform_later(user.id)

# acceptable - passing by id
# Deserialization error is reported, the job is *not* scheduled for retry.
class SomeJob < ApplicationJob
  def perform(model_id)
    model = Model.find(model_id)
    do_something_with(model)
  rescue ActiveRecord::RecordNotFound
    Rollbar.warning('Not found')
  end
end

# good - passing with GlobalID
# Deserialization error is reported, the job is *not* scheduled for retry.
class SomeJob < ApplicationJob
  def perform(model)
    do_something_with(model)
  end
end
```

Active Record Model を引数で渡す場合、[GlobalID](https://github.com/rails/globalid/blob/master/README.md) という仕組みを用いて自動でシリアライズ、デシリアライズするため、手動でデシリアイズする必要がないとのこと。

また、GlobalID があることで、モデルのプロパティのミスマッチを適切に処理することができるそうです。

このような仕組みがない場合は、Sidekiq のベストプラクティスに則った方が良いでしょう。
Gatsby.jsで「source and transform nodes」が永遠に終わらないとき

## 発生したこと
Gatsbyのビルド時のプロセスの一つで、リモートなどから画像を取得してノードを作成するのが「source and transform nodes」です。

私の環境では、画像1300枚程度を`createRemoteFileNode`でリモートからフェッチするのですが、毎回途中でスタックし、永遠に終わらないという症状が発生しました。

スタックするまでの挙動は、だんだんフェッチが遅くなって、最終的にエラー分も出ず停止する感じです。

また、この症状は必ずローカルのみで発生し、Netlifyにデプロイするときは発生しませんでした。ローカルでもたまにビルドがうまくいくこともあり、ビルドがうまく行っても全ての画像がフェッチできていない場合もあって、４日程度悩みました。

![source_error.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/391ff0a3-ce3f-f86b-6f95-734397529f1e.gif)


## 原因

結論を言うと、安いVPSを使っていたこともあり、VPSが処理落ちしてました。

Netlifyビルド時はネットワーク速度とNodeの実行速度が遅いのでVPSが処理落ちしなかったんですが、ローカルだとネットワークとNodeの実行速度が早かったのが原因のようです。

「仮にエラーコード500が帰ってきてもビルドは通るはずだから原因はローカルにある」という思い込みが、早く解決できなかった原因です。反省。

## 解決方法

アセットのサーバをVPSからVercelに変更したら解決しました。CDNのキャッシュも効くので、ローカルでの高頻度のリクエストでも問題なさそうです。
応用情報技術者取得までの記録

2020秋期の試験で合格しました！ヤッター！！

#はじめに
なぜ応用情報技術者試験を受けようと思ったのか？
・幅広いIT知識を学び直したい
　取引先の社内SEさんと対話する事が多く、自分にはサーバやネットワークの基礎知識が足りないと思った。
・経歴書を武装したい
　年齢の割にマネジメント経験が皆無なのでせめて資格を！
・高度試験を少しでも楽に取得したい
　応用を取得すると向こう2年間は一部免除なので何としても欲しい！

#勉強時間
時間：1日1〜2時間
期間：約5ヶ月
恐らくほとんど毎日勉強していたと思います。よくやったな…。
※前日は徹夜(´-ω-｀)zzz

#勉強内容
・キタミ式イラストIT塾 応用情報技術者
　https://www.amazon.co.jp/dp/B07L9QYQ7Z/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
　一通り読破、章毎の問題を1回ずつ解いた。あとは必要に応じて読んだり。
・過去問
　午前過去3年分×2回ずつ
　午後過去3年分×1回ずつ

#成績は？
午前：66.25点
午後：62.00点
ギリギリ〜スレスレ〜良いんですか本当に？という感じですね。
引き続き精進します…！

#勝因は？
［勉強方法］
1に過去問、2に過去問。とにかく過去問。
午前とにかく過去問です。計算系の公式は暗記暗記暗記。英文字略語系も暗記暗記暗記。
午後もとにかく過去問。分野を自分で選択するのでまず1回全分野やってみる。
そして解けそうな分野を4つ選択するわけですが、保険で5つに絞って勉強しました。
私は「データベース、情報システム構築、プロジェクトマネジメント、サービスマネジメント、システム監査」の5つに絞って勉強しました。他分野は無視！苦手分野捨て過ぎですね！

［メンタル＆モチベ］
育休中と言う事もあり孤独だったので、勉強用SNSで応用情報を受験する仲間を探して勉強報告にイイねをし合ったりした。
命（＝睡眠時間）を削って勉強してるし、家族に負担を掛けたくないので何としても1発合格したかったと言うつまりプレッシャー！
※受験日前日と当日は夫に子守をお願いしていた。ありがたや〜

#おわりに
試験日が近付くと当然ながら「絶対に合格しなければ！」と言う思いが強くなっていき、本来の目的である「幅広い知識を身に付ける」がおざなりになり苦手分野を捨て得意分野に絞って勉強するようになってしまった。
身に付けたいスキルがあるなら目的を絞って勉強しなければいけないですね。
あと前日の徹夜はやめておいた方が良いですね！午前中眠くて全然集中出来なかったです。もうしません。
ArgumentException: Object of type 'UnityEngine.Object' cannot be converted to type 'UnityEngine.Collider'. の解決例

## エラーの様子

####エラー文
![スクリーンショット 2020-12-28 14.04.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/7b6f06e4-be7a-c2ea-a3bc-2acb3b31842d.png)


####指定されているファイル
```
using System;
using UnityEngine;
using UnityEngine.Events;

[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
  [SerializeField] private TriggerEvent onTriggerEnter = new TriggerEvent();
  [SerializeField] private TriggerEvent onTriggerStay = new TriggerEvent();

  /// <summary>
  /// Is TriggerがONで他のColliderと重なっているときは、このメソッドが常にコールされる
  /// </summary>
  /// <param name="other"></param>

  private void OnTriggerStay(Collider other)
  {
    onTriggerStay.Invoke(other);
  }

  [Serializable]
  public class TriggerEvent : UnityEvent<Collider>
  {
  }
}
```


## 試行錯誤したこと
ArgumentException. UnityEngine.Object型のオブジェクトをUnityEngine.Collider型に変換できない。とのことで型指定間違ってるのかなと思ってみてみましたが間違っていませんでした。
googleで調べると明示的な記述をすれば直るみたいなアドバイスがありましたが、すでに明示的になっていて対処に詰まりました。
結局検索では解決策に至れなかったので、参考にしていた本を最初から読み直してみたところ指示と違うことをしていることがわかりました。

## 解決方法

下記のように、prefabに付与したcomponentのOntriggerStayの中身を引数なしの関数に変更することで、エラーを解消できました。


#### 修正前
![スクリーンショット 2020-12-28 14.05.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/e5e2f1f3-c689-5dc6-88c0-6f9d5f82c658.png)

#### 修正後
![スクリーンショット 2020-12-28 14.19.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/2c6528fd-9327-3435-384b-3725beec9b43.png)

## 原因
同じ名前だけど引数を指定する関数と指定しない関数があって、今回は引数がないため、指定しない関数にしなければいけなかったのに、指定ありを選んでしまっていたため値が足りずエラーを吐いていました。
勉強メモ11_インフラ現場の運用手順書で見かけたLinuxコマンドメモ

★はじめに★

運用手順書の内容をあさり、手順書で使っていたコマンドをここに書いていきます。

以下コマンド↓↓↓↓↓↓↓↓↓


①カーネルのバージョンを調べる

```shell
uname -a
```

②ユーザーの識別情報を表示する

```shell
id
```

③現在の日時を表示する

```shell
date
```

④mkdirでディレクトリのパーミッションも一緒に設定

```shell
mkdir -m 777
```

⑤CRC チェックサムとバイト数を表示する

```shell
cksum
```

⑥diffで比較したのをSJISで表示

```shell
diff A B | iconv -f utf8 -t sjis
```

⑦readでpassWord変数を作成

```shell
read -sp "パスワードを入力してください。：" passWord;
```
Ubuntu Server から chromium を kiosk mode で実行する

# 環境
Raspberry Pi 2 Model B

# Ubuntu Server をインストールする。
やり方は以下に記述されている。
https://ubuntu.com/tutorials/how-to-install-ubuntu-on-your-raspberry-pi#1-overview


# コンソールで使うキーボードレイアウトの設定

    $ sudo dpkg-reconfigure keyboard-configuration

`Generic 105-key PC (intl.)` → `Japanese` → `Japanese` → `The default for the keyboard layout` → `No compose key` → `Yes` と入力する。
（参照：https://qiita.com/vochicong/items/6452ac54bde56b0e0bb3 ）

# 最新パッケージに更新する。

    $ sudo apt update
    $ sudo apt upgrade

# X window と Chromium をインストールする。
    $ sudo apt install chromium-browser xorg

再起動すると、GUIが立ち上がってしまうので、いったんCUIに戻す

    $ sudo systemctl set-default multi-user.target　
をすれば再起動時はcui起動のテキストモードでlogin:できる。

# chromium を起動する。
    $ startx /usr/bin/chromium-browser —-kiosk <website>


# 問題
このままだと、日本語が豆腐になってしまう。（いろいろやってみたが解決せず）
【Docker】起動中のコンテナを確認してそこに入る

# 2行で

- `docker ps`
- `docker exec -it コンテナ名 bash`

ターミナルでコマンドを打ちます。

## 起動中のコンテナ一覧を確認

```terminal
$ docker ps
```

`NAMES` のところを確認する。これがコンテナ名。

## コンテナに入る

```terminal
$ docker exec -it コンテナ名 bash
```

`-it` というオプションについては `-i` と `-t` の合わせワザなんだけど、詳細は以下の記事。

**Docker exec -it とは**
<https://hacknote.jp/archives/56621/>
AS400メモ

[https://qiita.com/You_name_is_YU/items/8162bf7b2cae700f5c02#comment-533373ddc6e814583543](https://qiita.com/You_name_is_YU/items/8162bf7b2cae700f5c02#comment-533373ddc6e814583543)
にて山口さんに頼ってばかりだとダメなので自分で調査した事もメモらせて頂きます。
Xcode 12 にてエミュレータビルドと実機ビルドが両立できなくなった件

> for architecture arm64

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103475/cb10784d-727b-9b15-27ec-f53997967020.png)

https://stackoverflow.com/a/64136906/8023331
GoogleAppsScriptのUtilities.formatDateが年末にバグった

GoogleAppsScriptで作成したツールを用いてRedmineのチケットを整理しながら仕事をしていますが、
本日(2020/12/28)になって突然そのツールが動かなくなったので調査しました。

## 事象：Utilities.formatDateで日付型を文字列型に変換すると来年の日付に変わってしまう

日付型から文字列に変換を行う際には、一般的に以下のような処理を記述します。

```
Utilities.formatDate(date, timeZone, format);
```

日付には「2020/12/28 10:00:00」を入れて変換をしましたが、
出力された値は「2021/12/28 10:00:00」と来年の日付に変わってしまっていました。


## 検証：2020/12/27(日)～2020/12/31(木)の間で発生する

以下が検証結果です。

* 2020/12/26(土)までは問題なく2020年の日付に変換されました。
* 2020/12/27(日)から2020/12/31(木)までは来年の2021年が表示されました。
* 2021/01/01(金)からは問題なく指定した年の2021年が出力されました。

ここから憶測するに、曜日が関係あるのではないかと思い、追加で検証しました。

* 2021/12/25(土)までは問題なく2121年の日付に変換されました。
* 2021/12/26(日)から2021/12/31(金)までは来年の2022年が表示されました。
* 2021/01/01(土)からは問題なく指定した年の2022年が表示されました。
* 2022/12/31(土)までは問題なく2121年の日付に変換されました。
* 2023/01/01(日)からは問題なく指定した年の2022年が表示されました。

## 考察：指定した日が含まれる週の土曜日の年が返却されている

検証結果から、**指定した日が含まれる週の土曜日の年が返却されている**と思われます。

どちらにせよ、Utilities.formatDateを使用すると年末に機能が動かなくなりますため、
使用することはおすすめできないですね。

## 回避策：getFullYear()を用いる

幸い、日付型の関数である「getFullYear()」は正しい年が取得されました。
少し面倒ではありますが、日付型から文字列に変換する際はgetFullYear()等を用いて整形しましょう。
気持ちの棚卸し

プロジェクトや制作、チームで携わる多くの事。

- 進捗に遅れがでてくる。予定通りに進まない（不確定要素が発生するのは論外）。
- 対応に追われ、予定していたものに着手できない。
- メンバーがどんどん疲弊し、だんだんやっつけ仕事になっていき、品質が低下する。
- 担当者は複雑な事を考えている最中は、単純作業が消化できない。

それらについて、期限が設定されている以上、私はまず**「終わらせること」**を最優先に考える。

今ままでから最速を考えると

- 進捗管理者であっても、自分でできる事は自分がやりメンバーの負担を減らす。メンバーには私が不得意な分野に時間を割いてもらう。
- メンバーに任せる部分の負担を減らすことにより、作業量を減らして専念・注力できる時間を増やす。その分ミスを減らして、高品質なものを提出してもらう。

をポイントに実行するようにした。
今まで、各メンバーの負担が多すぎたように感じていたのと、HTML&CSS制作とJS実装を分けることによって、分担制にしようと決めた。新規作成だとHTML&CSSの作業量多いし。

だが一部視点としては、

- その人のやる気を削いでしまってるのではないか（仕事を奪っている？）。モチベーションを低下させるのではないか。
- 進捗に無理やりそぐわせる為にその人のペースを乱しているのではないか。
- 縛りが多い（コーディングルール・ガイドライン等）
- （長期運用するには低い人のレベルに合わせるので）出来る人の成長を妨げているのではないか。
- そもそもメンバー信用してないんじゃない？管理者としてメンバーの運用出来てないんじゃない？

とこう見えているかもしれない。
内側の人は、本当は不満だけど耐えてるだけかもしれない。
私のやり方は間違っていると思わなければならないのか。そうかもしれない。
人為的な部分、感情・性格性質・精神・生き様・こだわり、そういった部分は管理できないしそもそもしようと思う事が間違っている。

だが、プロジェクトごとにメンバーが変わる場合もあるし、全部が全部各メンバーに一任していたら回らない。
「終わらせること」を第一に考えると、「品質の低下」「やっつけ仕事の容認」を認めざるを得なくなってしまうジレンマ。
全体的に考えると、後々に障害を起こすもの以外で無い限りはスルーして進めてしまう。細かい事を訂正している時間がかさむと良くない事（メンバーのやる気が下がって負のスパイラルを巻き起こす）が起こるので、「どうしてもダメ」という事はスルーする場合がある。cssとか書き方はいろいろあるし。
厳密にレビュワーとしては、いけないのだけど。訂正事項が多すぎる場合は時間を優先してしまう。
それに、そこから訂正をしていたのでは、自分がイチからやっているのと変わりがない。
何を優先するか。私は皆がストレスなく軽減し、上手く全うできるようアシストして、結果的に良いものを作りたい。
やり方進め方、考え方は人それぞれ。私はしばらくこのスタンスは変えないだろうが、運用改善に必要な事や課題は随時気づきを忘れず解決していこうと思う。

HTML&CSSの経験年数＋実績はある、デザイン経験もある、ディレクター経験もある、複数プロジェクトを運用した経験もある、あと商用JSさえ掌握できればもう何も怖くないじゃん！私。
SpringBoot 設定ファイル（application.yml）を参照してみた

# 概要
application.yml の設定値を参照する方法がとても簡単だったので紹介したいと思います。

# サンプルコード
早速サンプルコードをどうぞ

#### application.yml
String、List、Map 型で設定値をそれぞれ定義する

```
yml:
  sample:
    str: abcde
    list:
      - list1
      - list2
      - list3
    map:
      key1: value1
      key2: value2
      key3: value3
```

#### YmlSampleProperties.java
設定ファイルに記載したフィールドを定義するクラス

```java
@Component
@Data
@ConfigurationProperties(prefix = "yml.sample")
public class YmlSampleProperties {
    private String str;
    private List<String> list = new ArrayList<>();
    private Map<String, String> map = new LinkedHashMap<>();
}
```

#### SampleController.java
YmlSampleProperties クラスに定義した内容を取得し、
とりあえず System.out.println で表示確認する

```java
@RestController
public class SampleController {

    @Autowired
    YmlSampleProperties ymlSampleProperties;

    @GetMapping("/ymlSample")
    public void getYmlData() {
        // String 取得
        String sampleStr = ymlSampleProperties.getStr();
        System.out.println(sampleStr);
        // List 取得
        List<String> sampleList = ymlSampleProperties.getList();
        System.out.println(sampleList);
        // Map 取得
        Map<String, String> sampleMap = ymlSampleProperties.getMap();
        System.out.println(sampleMap);
    }
}
```

# 動作確認
GET /ymlSample API をリクエストすると、
それぞれ設定値が標準出力で表示されることが確認できました！
※ jq は JSON 形式のデータを整形するコマンド

```java
curl "http://localhost:8080/ymlSample"  | jq .
```

```
abcde
[list1, list2, list3]
{key1=value1, key2=value2, key3=value3}
```

String 型だけでなく、List や Map も設定ファイルに定義できるなんて便利！
【Rails6】belongs_toによるバリデーション

#はじめに

ポートフォリオ作成中に発生したエラーについて、備忘録のため記述しています。補助金に関する記事の検索・閲覧ができるポートフォリオを作成しています。

#環境

Ruby on Rails '6.0.0'
Ruby '2.6.5'

#エラー内容

バリデーションに関するエラーになります。エラー文は以下の通りです。

```
web_1  |   ↳ (pry):1:in `create'
web_1  |   Article Load (0.8ms)  SELECT `articles`.* FROM `articles` WHERE `articles`.`id` = 4 LIMIT 1
web_1  |   ↳ (pry):1:in `create'
web_1  |   User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
web_1  |   ↳ (pry):1:in `create'
web_1  |    (0.3ms)  ROLLBACK
web_1  |   ↳ (pry):1:in `create'
web_1  | ActiveRecord::RecordInvalid: バリデーションに失敗しました: Companyを入力してください
```

#学んだこと①:Docker環境におけるbinding.pryの方法

開発環境にDockerを導入しており、エラーの詳細を知るためにbinding.pryを活用しました。しかし、Docker環境でコマンド実行するのは初めてでした。今回は[docker上でbinding.pryを実行する](https://qiita.com/hb5kz/items/7c9d266480079910de5c)を参考にさせていただきました。ありがとうございました。

```
% docker-compose up
% docker ps
% docker attach コンテナID or コンテナ名
```

上記コマンドを実行することでデバックモードを起動し、エラーコードを確認することができました。

#学んだこと②：save!メソッドの使用

```ruby:app/controllers/comments_controller.rb
  def create
    @comment = Comment.new(comment_params)
    if @comment.save
      ActionCable.server.broadcast 'comment_channel', content: @comment
    else
      render :new
    end
  end
```

今回は上記に記載した、コメント機能によるcreateアクション部分でエラーが発生しました。当初ログを確認しても、エラー文の詳細が明記されておらず、分からない状態でした。
そこで、[saveメソッドでエラーが発生した時のデバック方法](https://www.ryotaku.com/entry/2019/03/24/%E3%80%90WIP%E3%80%91%E6%9C%AA%E5%AE%9A)の記事を参考にさせていただきました。ありがとうございました。
Railsのsaveメソッドは保存できなかった場合は、「false」を返すのみであり、エラーログは確認できません。「save!」を使用することでエラー内容を把握できるというものでした。

```
8: def create
web_1  |      9:   @comment = Comment.new(comment_params)
web_1  |  => 10:   binding.pry
web_1  |     11:   if @comment.save
web_1  |     12:     ActionCable.server.broadcast 'comment_channel', content: @comment
web_1  |     13:   else
web_1  |     14:     render :new
web_1  |     15:   end
web_1  |     16: end
web_1  | 
[1] pry(#<CommentsController>)> 
[2] pry(#<CommentsController>)> @comment.save!
   (0.6ms)  BEGIN
web_1  |   ↳ (pry):1:in `create'
web_1  |   Article Load (0.8ms)  SELECT `articles`.* FROM `articles` WHERE `articles`.`id` = 4 LIMIT 1
web_1  |   ↳ (pry):1:in `create'
web_1  |   User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
web_1  |   ↳ (pry):1:in `create'
web_1  |    (0.3ms)  ROLLBACK
web_1  |   ↳ (pry):1:in `create'
web_1  | ActiveRecord::RecordInvalid: バリデーションに失敗しました: Companyを入力してください
```

#③学んだこと：belongs_toによるバリデーションについて

ここで、バリデーションに関するエラーであることが、把握できました。ここから確認を行ったこととして
- migrationファイルを確認し、「null: false」の書き換えを行う
- commentモデルを確認し、「presence: true」部分の書き換えを行う

以上の2つを変更し、再度試してみましたが、結果は変わらず。
ということで、 [（個人メモ）Rails5で関連を定義した時はbelongs_toに気をつける](https://qiita.com/junara/items/ca6f65d2f2a27f185f0e)こちらの記事にたどり着きました。

「belongs_to」を使用する場合は、belongs_to関連の外部キーでnilを許可しないようにするために「required:true」がデフォルトで搭載されるということでした。

解決するために

```ruby:app/models/comments
class Comment < ApplicationRecord
  belongs_to :article
  belongs_to :user, optional: true
  belongs_to :company, optional: true

  validates :text, presence: true
end
```

**optional: true**を明記することで、「nil」を許可することができ、無事解決することができました！！！

#おわりに

ご参考にさせていただいた記事の作成者の方々、本当にありがとうございました。
lambdaでS3に格納されたcsvの絵文字を消してみた。

csvの中身

```csvs:utf8mb4.csv
aa,😀,123
bb,😄,456
```

```python:lambda_function.py
import urllib.parse
import boto3
import re

print('Loading function')

s3 = boto3.client('s3')

def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        # 正規表現パターンを構築
        emoji_pattern = re.compile("["
            u"\U0001F600-\U0001F64F"
            u"\U0001F300-\U0001F5FF"
            u"\U0001F680-\U0001F6FF"
            u"\U0001F1E0-\U0001F1FF"
                               "]+", flags=re.UNICODE)
        body = response['Body'].read()
        bodystr = body.decode('utf-8')
        print(bodystr)
        bodystr = emoji_pattern.sub('', bodystr)
        print(bodystr)
        lines = bodystr.split('\r\n')
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
```

## 結果
```
Function logs:
START RequestId: XXXXXXXX
aa,😀,123
bb,😄,456
aa,,123
bb,,456
END RequestId: XXXXXXXX
REPORT RequestId: XXXXXXXX	Duration: 222.76 ms	Billed Duration: 223 ms	Memory Size: 128 MB	Max Memory Used: 80 MB	Init Duration: 452.44 ms
```

### 参考文献
https://gist.github.com/silverskyvicto/73bc1fb870e0c36b4ab6e1fca7cccd24
これまで開発したwebサービス

初めまして！<b>おかか</b>です。

プログラミング初心者がこれまで開発してきたサービスについて。

<h4>医学書専門フリマサイト「タメヨミ 」</h4>
<table><th>PHP</th><th>JavaScript</th></table>
これはPGの友人と二人で開発しました。開発期間は６ヶ月ほど。本業の合間にプログラムを書き、なぜか古物商の許可を取りに行くなど、プログラミング以外にも活動した期間でもある。
会員登録数100名ほど。
このサービスは、購入者がそれなりにいたが、出品者が集まらず、はじめは１００冊ほど自分の書籍を出品しており、それらが大方買われると利用者が激減した。
結局自分の本を処分するような形となった。

次に受託開発の機会をえた。
フリマサイトの利用者から提案を受け共同で運営する形となった。主に開発を担当し、PRなどを提案者が行う形。
<h4>医療特化型動画学習サイト「manabee 」</h4>
<table><th>Laravel</th><th>JavaScript</th><th>AWS</th></table>
開発期間はコロナがあり、自宅待機期間に書き進め３ヶ月ほど。
AWSを初めて利用し、動画投稿、変換、ストリーミング再生など新しい技術も使用。
息詰まることが大方が、Google先生がいればなんとかなる！なんとかなったのか？？
会員登録数はこちらも100名ほど。
こちらも動画投稿者が集まらず、結局サービス開始から終了まで半年の寿命だっった。

 <h4>学んだこと</h4>
プログラムを書いたり、開発をすることは楽しい！！
もっと色々やりたくて絶賛勉強しながら次にやることを考えています。

ご視聴ありがとうございました。
【Vue.js】メニュー機能の実装　Vue.js導入編 rails6

#はじめに

クリックするとメニューが開いたり閉じたりする機能をVue.jsで実装します。

この記事はrails6でのVue.js導入編です。
また、rails6からはwebpackerが標準装備されてるのでこちらでは省略します。

###目次
1.Vue.js導入
2.Vewのインストール
3.ファイルの読む先を指定
4.エラーの解決方法



#開発環境
Vue 2.6.12 
rails 6.0.0
ruby 2.6.5


#実装
それでは実装して行きます〜

#1.Vew導入

###1.1Vewのインストール
まずはVueインストールします。


```:ターミナル
rails webpacker:install:vue
```
![スクリーンショット 2020-12-15 16.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/e3adb60d-29e6-47e8-6082-541adb72c424.png)


`hello_vue.js'`と`app.vue`が自動生成される。


次に、`application.html.erb`に読み込まれる様に追記します。



```html:app/views/layouts/html.erb
<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>

    <% ↓下記の二行を追記 %>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> ←①これを追記する
    <%= javascript_pack_tag 'hello_vue' %> ←②これを追記する

  </body>
</html>

```



①はVue.jsを読み込ますためで、②は`hello_vue`というファイルを読むためにのものです。
両方ともbody内に追記します。

すると下記の様に表示されます。

![スクリーンショット 2020-12-15 16.36.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/0816ffb7-99f5-e488-f189-1b2809a7253e.png)
ひとまずVew.jsが使える様になりました。





###1.2ファイルの読む先を指定

このままではデォルトなので、個別の新しいファイルで扱える様にします。

```html:app/views/layouts/html.erb

<%= javascript_pack_tag 'hello_vue' %>
//下記に変更
<%= javascript_pack_tag 'menu_vue' %>
```

公式では`hello_vue`を読み込む様に指定されますが、これから作るファイル名`menu_vue`に変更します。

新しいファイルを'menu_vue'の名前で作成します。



```js:app/javascript/packs/menu_vue
var app = new Vue({
  el: '#app',
  data: {
    message: 'こんにちは Vue!' //←違いがわかりにくにで日本語に変換
  }
})
```


```html:app/views/menus/index.html.erb
<h1>Menus#index</h1>
<p>Find me in app/views/menus/index.html.erb</p>

<% 下記を追記 %>
  <div id="app">
    <p>{{ message }}</p>
  </div>

```
![スクリーンショット 2020-12-16 5.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/643d6c47-7181-6a5a-7846-4440a88290a3.png)
出来ました！！


ここまでが導入です。
続きはメニューを作成する部分を実装します。

【Veu.js】メニュー機能の実装　実装編 rails6
https://qiita.com/AKI3/items/cd1729a25c9bb83061b9



#エラーの対応

`Webpacker::Manifest::MissingEntryError`

このエラーが出る場合階層が違う場合が多いので、気をつけて新しいファイルを作る必要があります。
場所はpacksの配下です。
![スクリーンショット 2020-12-16 9.50.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/9d90da12-fad3-c47e-e790-41ba8253a82d.png)


それでも解決出来ない場合は、yarnやwebpackerに問題があるかもしれません。
下記の記事も参考にしてみてくださ。
https://qiita.com/masatwork/items/1b5d190cc76f5eeffbb7
https://qiita.com/NaokiIshimura/items/8203f74f8dfd5f6b87a0


####最後に
私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。

それでは、また次回お会いしましょう〜


#参考
【公式】
https://jp.vuejs.org/v2/guide/

https://www.petitmonte.com/ruby/rails-vuejs-project.html

https://off.tokyo/blog/%E6%97%A2%E3%81%AB%E5%8B%95%E3%81%84%E3%81%A6%E3%82%8Brails%E3%81%ABvue-js%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B/
Bootstrapの適応方法

1.gemfileにbootstrapのコードを打ち込む
gem 'bootstrap', '~>4.4.1'
gem 'jquery-rails'

2.application.jsの13～19行目に以下のコードを打ち込む

//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .
//= require jquery3
//= require popper
//= require bootstrap-sprockets

3.application.cssの1行目に以下のコードを打ち込む
@import "bootstrap";

4.application.cssをapplication.scssに変更する

5.@importの下にcssを書いていく

もし、以下のエラーが出たら
RuntimeError in StaticPages#contact
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>

boot.rbフォルダの最後の行に以下のコードを打ち込む
ENV['EXECJS_RUNTIME'] = 'Node'
(テスト自動化) 画像認識に使う画像を入れ子にする

#背景
社内のシステム開発者向けにテスト自動化システムを構築・運用している。(SikuliX + Testablish)
その中で日常的に出てくる技術課題ややりたいことをメモ書き。

Sikuliが楽しい!

#課題
大抵のRPAツールはそうだが、操作シナリオは１つのファイルで閉じてしまう。
それの何が気になるのかというと、シナリオの中に画像を含んでしまっているのを残念に感じる。
画像はちょっとした仕様変更などで変わるので、画像だけを簡単に差し替えられるようなつくりにしておくのが、肝要ではないかと思う。
というわけで、Sikuliの操作シナリオ中の画像を別建てしたWebServiceから引っ張ってこられるような作りを目指してみた。

#対応
Sikuliの操作シナリオにおける画像ファイル部分はWebServiceから引っ張ってくる。

#目的
各システムでファイルアップロードやダウンロード、エクセル操作くらいの単シナリオであれば、画像差し替えで使い回せるようにしたい。

#内容
実装に当たり１つ課題が出た。
それはsikulixがpythonと思いきや、jythonで実装する必要がある点である。
jythonはJVM上で動作するpython言語で、コーディング量の少なさやシンプルさが売りらしいが、WEB上の情報量が少ないのがネックに感じる。
https://www.jython.org/

ただ、新しく覚える言語(まぁほぼpythonとjavaの合いの子だけど)はワクワクするのでレッツトライ。

以下実装で検証し、成功。
>\-----------------------
import java.net.HttpURLConnection
import java.net.URL
import java.io.BufferedReader
import java.io.InputStreamReader
import java.lang.StringBuffer
import json
import base64
import datetime
>
URL = java.net.URL
url = 'RESTURL'
obj = URL(url)
con = obj.openConnection()
con.setRequestMethod("GET")
responseCode = con.getResponseCode()
>
BufferedReader = java.io.BufferedReader
InputStreamReader = java.io.InputStreamReader
>
buf = BufferedReader(InputStreamReader(con.getInputStream()))
response = buf.readLine()
buf.close();
>
dir = os.getcwd()
>＃画像はBase64でasciiにしておいて、REST戻り値はjsonファイルを指定
>＃jython上でデコードする
downloadData = json.loads(response)
fileName = downloadData['fileName']
contentType = downloadData['contentType']
contentDataAscii = downloadData['contentData']
now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
contentData = base64.b64decode(contentDataAscii)
saveFileName = now + fileName
saveFilePath = os.path.join(dir, saveFileName)
with open(saveFilePath, 'wb') as saveFile:
　saveFile.write(contentData)
>
>↓↓画像認識処理↓↓
\-----------------------

#結果 or 気付いた点
python上でjavaライブラリをimportし、ゴリゴリとjavaを記述するイメージ。
import指定形式、インスタンス生成方法さえ分かれば後はスムーズ。

#結論
これで操作シナリオの共通化が進む!
Autoware/ROSでVelodyne VLP-16の設定

# 前提
AutowareのDockerが起動している状態。
https://qiita.com/atsuto/items/a99296bbd687928967bd

# 接続
Velodyneと、PCを直接Etherケーブルで接続。

# ネットワーク設定
PCの有線接続のアドレスを、Velodyneと同じ192.168.0.xx系に設定。
![Screenshot from 2020-12-27 09-40-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80263/06834e77-54e2-bb8a-e2fe-1f938f269425.png)

IPを指定してVelodyneの設定画面を開き、送信先にPCのIPを設定する。
![Screenshot from 2020-12-27 09-26-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80263/58bc13b4-a05e-cd01-58fe-f66fe6887a2d.png)


# Rviz
ポイントクラウドのnodeを立ち上げる。
使い方：$ roslaunch [package] [filename.launch]

参考：
http://wiki.ros.org/velodyne/Tutorials/Getting%20Started%20with%20the%20Velodyne%20VLP16
https://faboplatform.github.io/AutowareDocs/01.Velodyne_VLP-16/01.Ros_rviz/

```
$ roslaunch velodyne_pointcloud VLP16_points.launch &
$ rosnode list
$ rostopic echo /velodyne_points //データが来ているのが分かる
$ rosrun rviz rviz -f velodyne //Rvizの起動
```
Addから「Point Cloud2」を追加し、Topicに「/velodyne_points」を入力すると、下記のように点群が表示される。

![Screenshot from 2020-12-27 09-24-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80263/e93f8831-fc8a-fba7-486c-b8afa0959171.png)