OmniAICreator/Qiita-1.07M huggingface dataset:
FLASK,Bootstrap,javascriptの連携プレー

flaskを使ったwebアプリで、画像のサムネイルなどの繰り返しパターンにおいて
ボタンの処理など、どうやったいいのか調べている。

実は、HTML側の情報は、すべてDOMオブジェクトという形で
JAVASCRIPTで中身を追えるということを初めて知った。

前にpython会の集まりのとき、とある人が最近はpythonではなく、
JAVASCRIPTの勉強をしていると言っていた。

最近になって、フロントエンドを触り始めると、JAVASCRIPTがポイントだと言うことが
分かるようになってきた。

しかしながらJAVASCRIPTの場合、jQueryやbootstrapといった、
既成のフレームワークの知識も必要になるので、まるで大海を航海するかのように
何から着手すればいいか分からなくなってくる。

今週の目標は、表題の通りだが、自分のメモ用に記事を書いていくこととする。


# flask
- ルーティングを確認する方法

```
app.url_map

Map([<Rule '/hello' (GET, HEAD, OPTIONS) -> main>,
<Rule '/' (GET, HEAD, OPTIONS) -> main>,
<Rule '/static/<filename>' (GET, HEAD, OPTIONS) -> static>])
```

- ルーティングをパラメータ化

```
@app.route('/')  
def main():
    return redirect(url_for('hello', username='Peter'))          
# Also pass an optional URL variable  

@app.route('/hello/<username>')
def hello(username):
    return 'Hello, {}'.format(username)
```
plunkerでassembler-simulator その3

#概要

plunkerでassembler-simulatorやってみた。
命令コード調べてみた。

#命令コード

||0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|
|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|0|NONE|MOV　REG　TO　REG|MOV　ADDRESS　TO　REG|MOV　REGADDRESS　TO　REG|MOV　REG　TO　ADDRESS|MOV　REG　TO　REGARESS|MOV　NUMBER　TO　REG|MOV　NUMBER　TO　ADDRESS|MOV　NUMBER　TO　REGADDRESS|ADD　REG　TO　REG|ADD　REGADDRESS　TO　REG|ADD　ADDRESS　TO_REG|ADD　NUMBER　TO　REG|SUB　REG　FROM　REG|SUB　REGADDRESS　FROM　REG|SUB　ADDRESS　FROM　REG|
|1|SUB　NUMBER　FROM　REG|INC　REG|DEC　REG|CMP　REG　WITH　REG|CMP　REGADDRESS　WITH　REG|CMP　ADDRESS　WITH　REG|CMP　NUMBER　WITH_REG||||||||JMP　REGADDRESS|JMP　ADDRESS|
|2|JC_REGADDRESS|JC_ADDRESS|JNC_REGADDRESS|JNC_ADDRESS|JZ_REGADDRESS|JZ_ADDRESS|JNZ_REGADDRESS|JNZ_ADDRESS|JA_REGADDRESS|JA_ADDRESS|JNA REGADDRESS|JNA ADDRESS|
|3|||PUSH REG|PUSH REGADDRESS|PUSH ADDRESS|PUSH NUMBER|POP REG|CALL REGADDRESS|CALL ADDRESS|RET|||MUL REG|MUL REGADDRESS|MUL ADDRESS|MUL NUMBER|
|4|DIV REG|DIV REGADDRESS|DIV ADDRESS|DIV NUMBER|||AND REG WITH REG|AND REGADDRESS WITH REG|AND ADDRESS WITH REG|AND NUMBER WITH REG|OR REG WITH REG|OR REGADDRESS WITH REG|OR ADDRESS WITH_REG|OR NUMBER WITH REG|XOR REG WITH REG|XOR REGADDRESS WITH REG|
|5|XOR ADDRESS WITH REG|XOR NUMBER WITH REG|NOT REG|||||||||||
|6|||||||||||SHL REG WITH REG|SHL REGADDRESS WITH REG|SHL ADDRESS WITH REG|SHL NUMBER WITH REG|SHR REG WITH REG|SHR REGADDRESS WITH REG|
|7|SHR ADDRESS WITH REG|SHR NUMBER_ ITH REG||||||||||||||


以上。
flask アップロードでつまずいた件

PYthonでpdfファイルをOPENCVで画像処理させるアプリを書いており
その際にWEBフレームワークのFLASKを使っていて、ネットワーク経由で
データをアップロードしようとしてつまずいたので、ここに書き留めます。

つまずいていた内容としては、下記の3点である。

FLASKのテンプレートのhtmlに書いていた、FORMではファイル名はpostで
送信されるが、その際に絶対パスは送れないこと

これは主に、webブラウザ側の一般仕様になっていて、特にchromeだと
フォルダがfakeになってしまうこと

POSTの際には、pdfファイルはrequestオブジェクトとしてメモリに取り込まれており、
バックエンド側で容易にsaveできるメソッドが実装されている

以上
Railsのトランザクションと例外処理

Railsのトランザクションと例外処理がよく分からなかったので、調べました。


```ruby:app/controllers/user_controller.rb

def create
  ActiveRecode::Base.transaction do
    # createではなく、create!にすると保存できなかったときに例外が発生します。
    @user = User.create!(user_params)
   
  rescue => e 
  # バリデーションエラーだけ拾いたい場合は次の行
  # (ActiveRecord:RecodeInvalid => e) 
    # error処理
  end

end
```

rescueはphpでいうとexceptionみたいな感じでした。

参考サイト

[rails save\! create\! update\!のバリデーション例外を捕捉する \- Qiita](https://qiita.com/metheglin/items/db595d972df99b3849c2)

[【Rails】例外処理の書き方\(begin, rescue, raise,retry, ensure\) \- Qiita](https://qiita.com/ngron/items/4c319ae7340b72c7e566)

[rubyの例外についてまとめてみた \- Qiita](https://qiita.com/kasei-san/items/75ad2bb384fdb7e05941)

[ActiveRecord::Base\.transactionで囲うタイミング \- Qiita](https://qiita.com/shingo-nakanishi/items/63f9b6a461dae0bc850a)
電気の基本

switchの充電ケーブルが欲しくてちょっと調べたことのまとめ。
あとNECの40周年モデルノートPCを非売品のおまけ目的に購入したので、それも充電したいと思ったので。

# 電気の基本
## V(ボルト)
電圧で電気を押す力。
日本は100V。国によっては120～240V。

### 100Vの家庭用コンセント
交流(AC)電源。
直流(DC)：乾電池など。電流が一定。
交流(AC)：電気の流れる方向や大きさが変換。その周波数が東日本(50Hz)と西日本(60Hz)で違う。

## A(アンペア)
電流の量。
自宅のブレーカー見ると30Aだった。

## W(ワット)
電力で消費電力の量。
W=V×Aで計算可能。



# 充電について
高速充電の規格について整理する。

## PD
USB Power Delivery。
「5V/9V/15V/20V」という4段階の電圧を基本に、最大5Aの電流を掛け合わせることで、最大100Wの電力供給を実現。(12Vに対応したものも存在)

以下の記事が詳しい。
これで失敗しない、USB PD充電器選び(解説編)
https://pc.watch.impress.co.jp/docs/topic/feature/1164685.html

## PowerIQ
Ankerが策定した規格。
PowerIQ 3.0からPDとQuick Chargeと互換性あり。

## Quick Charge
Qualcommが策定した規格。
Quick Charge 4からPDとの互換性あり。

## まとめ

# ハードウェア

## 充電器

## USBケーブル
USB PD対応のケーブルは3A対応と5A対応が存在する。
PDの20V以外は3Aにしか対応しない。
USBの規格について別ページで整理する。
[USBについて](https://qiita.com/kero3/items/0cac398f693b44466026)
Railsのhas_oneで関連テーブルの保存

has_oneで関連させて保存させる方法につまったので書いておきます。
他のやり方（createを2回使う）もあったのですが、create!しても例外をキャッチできない？感じだったので、こちらの書き方にしました。


```ruby:app/controllers/users_controller.rb

def create
    @user = User.create(user_params)
    # この行のcreate_articleは状況に応じてprofile部分を読みかえて使います。
    @profile = @user.create_profile(profile_params)
end
```

```ruby:app/models/user.rb
has_one :profile
```

```ruby:app/models/profile.rb
belongs_to :user
```

参考サイト
[Active Record の関連付け \- Rails ガイド](https://railsguides.jp/association_basics.html#has-one%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91%E3%81%AE%E8%A9%B3%E7%B4%B0)
BN-880 を設定する。 Part 2

どうも PSS がちょいちょい狂ったり BME-280 が見えなくなったりするので GPS レシーバの設定を調整する。

[BN-880 を設定する。](https://qiita.com/jp_yen/items/a4a6adb812c8ff9443489) の詳細、リトライ版。

以下、UART1 (1) の入出力設定を変更する。
ちなみに番号とインターフェイスの対応は
0：I2C, 1：UART1, 2：UART2, 3：USB, 4：SPI

Configuration View を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/f085dd2c-ca9b-4d2c-cfda-a8cc05de01f6.png)

CFG (Configuration) を選び設定を初期化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/2214db8b-039d-3565-854a-6fa2119194cc.png)
Revirt to default configuration を選択し右側の Devices の全てを選択。
左下の Send をクリック。
一旦ケーブルを抜いて GPS レシーバをリセット。

受信衛星を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/00ef5101-6a4f-3996-32fa-11fbb12b71b3.png)
GPS (SBAS, QZSS), Galileo, GLONASS を選択。
BeiDou (北斗) は受信しないので Enable を外し 0 にしておく。
IMES は屋内用 (ビルの中、地下街など GPS を受信できないところ向けの信号) の信号なので同じく Enable を外し 0 に。
Galileo の max は 10 に増やしておく。
QZSS の L1S も受信できるのでチェックを入れておく。
左下の Send

MSG (Messages) の 01-30 NAV-SVINFO を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/5cc6fc76-2c77-34b1-47d4-20136b463eb8.png)
UART1 を選択し Send
捕捉した衛星の情報を u-box 形式で送信する (NEMA 形式で送れないものを含む)


GPS レシーバーから送信するメッセージを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/8d3a3de9-7132-bbe5-03cd-2219dc1a2f2d.png)
Protocol: 0 - UBX を選択
Target 0(I2C), 1(UART1), 2(UART2), 3(USB), 4(SPI)
のうち、1 の ALL を選択して Send。 

Protocol: 1 - NEMA を選択
1 の ALL を選択して Send。
※必要でないかも？よく分からない。

なんとなく設定してみた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/6e847564-773c-da52-66e1-613331452c54.png)
良く分からない。


PPS の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/9346b983-5002-e607-cf19-51baa0d1e54f.png)
PPS が同期していない間は 10Hz のデューイ比 1:9 のパルスを出力し、同期すると 1Hz とデューイ比を 1:1 のパルスを出力する。
Rising Edge on TOS のチェックを外す (キャプチャでは入れ忘れました。時刻を立ち上がりにするか、立下りにするか。)

捕捉する衛星の仰角を指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/5c68180c-4f9c-8254-2ccd-03f473ddc8aa.png)
Min SV Elevtion を 25° に。
低いところの衛星の電波は長い距離を伝わってくる (=大気の影響を大きく受ける) & マルチパスになって精度が下がるため低緯度の衛星は排除する。(どの程度衛星を捕捉できるかで調整する)

通信プロトコルと通信速度を設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/0e8b1281-656a-98b3-93ee-6e291c7766e5.png)
Target 1 - UART1
in/out は UBX + NEMA
Baudrate 115200
に設定して Send

PMS (Power Management Setup)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/a10047ff-9cb4-16c2-dba5-dfde0f6fda70.png)
Raspberry Pi は電源環境が厳しいので 0 - Full Powe ではなく 1 - Balanced (デフォルト) に設定する。

RXM (Receiver Manager)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/00d6f068-e73a-ffc6-98e8-a001d2cde5a0.png)
ここにも 1 - Power Save Mode との表示があるのでそうしておく。(デフォルト値　0 - Continuos mode)

保存！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/a07ea680-193b-4af0-86bc-b501000681aa.png)
Save current configuration を選択し send
これで、電源を切っても設定が保存される。(これをするまでは保存されない)
EFSの作成メモ

# 概要
　EFSの作成備忘録です。

## EFS作成
### EFSの設定画面に行って、「ファイルシステムの作成」をクリックします。
![WS000012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/5d6e806b-fffd-0fb0-1642-b657ff3a7d2e.jpeg)

### マウントしたいVPCを選びます。
![WS000014.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/8d01bb75-cd30-e876-eee6-e0adb849e555.jpeg)

### Availability Zoneを選びます。
　VPCを選んだ時点で、自動的に割り当てられますが、そのままにせず、アクセスしたいインスタンスのあるAvailability Zoneとセキュリティグループをしっかり選択します。

![WS000015.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/c621835c-30d8-d0ba-185f-971fcc62a4ef.jpeg)

【注釈】
　Availability ZoneごとにPrivate SubnetとPublic Subnetを選びます。
　つまり、Private SubnetとPublic Subnetの両方からアクセスできるEFSボリュームは作成できません。
　Private SubnetとPublic Subnetでデータを共有したい場合はプライベートアドレスやプライベートDNSを指定してscpやrcyncコマンドでやり取りするか、S3を使いましょう。
　セキュリティグループについても、同様です。

### 「次のステップ」をクリックします。
![WS000023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/f88ebe56-0a37-5b18-71ec-e28051941abe.jpeg)

### タグの追加
　こちらは必要に応じて設定します。
　なくてもいいですが、用途が決まっているのであればしっかり管理の為に設定しておきましょう。
![WS000016.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/aa53cda0-afea-f0f2-7dfe-ff0b35b16c90.jpeg)

### ライフサイクル
　一定期間アクセスのないファイルを、維持費は安いけど、取り出すのに時間のかかる場所に移動するよ、という設定です。
　こちらは、要件に応じてですが、通常は最短で構いません。アクセスを頻繁に行うファイルは移動しない理屈ですので。
　私は14日で設定しました。
![WS000018.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/84eaf3c9-de6a-a085-5a1f-25b50c241a41.jpeg)

### スループットモード
　こちらも要件次第ですが、よほど厳しいスループットが要求される環境でもない限りはデフォルトのままで問題ありません。
![WS000019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/f2fdda9a-429f-5641-36e6-fb45ca3d292e.jpeg)

### パフォーマンスモード
　こちらも要件次第ですが、よほど厳しいスループットが要求される環境でもない限りはデフォルトのままで問題ありません。
![WS000020.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/33823f21-5d13-678f-2c4e-538cf6dbe692.jpeg)

### 暗号化
　大事なものを格納する場合は暗号化した方がいいでしょう。
![WS000021.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/bce8037a-c754-6dcf-a330-61092914c80e.jpeg)

### 「次のステップ」をクリックします。

### 確認と作成
　作成内容を確認して、想定したとおりになっていれば、「ファイルシステムの作成」をクリックします。
![WS000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/22d8d19c-b2ca-c4cc-2f9c-ba014dc51460.jpeg)
![WS000023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/c0c921ee-2b37-2031-ea58-6b986cc37fd9.jpeg)


### 作成完了
![WS000026.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400941/d32a1f3d-2d20-4d08-d27b-df34b2dd5706.jpeg)

## EFSをマウントする。
　以下に記載しています。
　https://qiita.com/SSMU3/items/fe2f6b74ab363b39e2f6
Raspberry PiでOut-Of-Treeのドライバをクロスコンパイルする

Raspberry PiでOut-Of-Treeのデバイスドライバをクロスコンパイルしてみたときの自分用メモです。
WAveshareのWM8960-HATのドライバを例にしてみます。
（https://github.com/waveshare/WM8960-Audio-HAT ）

# 手順
## クロコンパイル環境の準備
こちらのページ（ https://qiita.com/mt08/items/d4e9b9e4953c8fa0abcf ）やラズパイの公式ドキュメントを参考にクロスコンパイル環境を整えます。

## Kernel Sourceの取得
こちら( https://github.com/raspberrypi/linux )からKernel Sourceを取得します。
たとえば現時点(2019/10/13)で最新のものは https://github.com/raspberrypi/linux/archive/raspberrypi-kernel_1.20190925-1.tar.gz から取得できます。
取得したら解凍して展開し、以下のコマンドで.configを作成しておきます。(.configがないと後のドライバのMake実行時にエラーが出ます。)

```
# Raspberry Pi 2/3の場合
make bcm2709_defconfig

# Raspberry Pi Zero/Zero W/B/Aの場合
make bcmrpi_defconfig
```

## デバイスドライバのソースコード取得
こちら( https://github.com/waveshare/WM8960-Audio-HAT ) からデバイスドライバのソースコードを取得します。

## Makefileの作成
クロスコンパイル用のMakefileを作成します。
ここではMakefile_crossという名前で作成します。

```Makefile_cross
KERNELSRCDIR = ../linux-rpi-4.19.y
BUILD_DIR := $(shell pwd)
VERBOSE = 0

# Module name
obj-m := wm8960.o

all:
        make -C $(KERNELSRCDIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules

clean:
        rm -f *.o
        rm -f *.ko
```
KERNELSRCDIRのディレクトリ指定はご自分で配置した構成に合わせて修正する必要があります。
作成したら、WM8960のドライバのソースコードと同じ位置に配置します。

## ビルドの実行
以下のコマンドを実行し、ビルドします。

```
export ARCH=arm 
export CROSS_COMPILE=arm-linux-gnueabihf-
make -f Makefile_cross 
```

これでsnd-soc-wm8960.ko、snd-soc-wm8960-soundcard.koというモジュールができるので、
適切な場所にコピーしてロードすれば使えるようになります。



基本的には他のドライバも同じような方法で行けるはずです。
plunkerでvue その43

#概要

plunkerでvueやってみた。
練習問題やってみた。

#練習問題

canvasを使え。

#成果物

https://embed.plnkr.co/sJ0fpkeUWYC1iossgZyS/

https://embed.plnkr.co/2L2BzPLC8ivlrIIts0ig/

https://embed.plnkr.co/YpMdqlIAqFkdoMljZdla/

以上。
【Rails】form_for の number_field で小数を入力できるようにする

# 問題
小数点第1位まで数字を入れたかったのに、デフォルトだと整数しか入れられずエラーを吐かれてしまう。
<img width="487" alt="スクリーンショット 2019-10-11 22.28.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473251/bbde384b-4faf-d125-1958-d031670de56a.png">


# 解決策

`number_field`のあとに`step: "0.1"`と入れる。

```ruby
<%= form_for @test do |f| %>

  <%= f.label :subject %>
  <%= f.text :subject %>

  <%= f.label :score %>
  <%= f.number_field :score, step: "0.1" %>

  <%= f.submit "送信" %>
<% end %>
```

ちなみに、`step: "１００"`とすると矢印を押したときのカウントが100刻みになったりします。
Linuxで種々のファイルを開くopenコマンドを作る

# 目的
Macのopenコマンド風にLinuxでもファイルを開けるようにします。つまり

```shell
myopen image.png
myopen /dir/doc.txt
```
とファイルパスを入力するだけで拡張子に対応したアプリでファイルを開けるようにするということです。

[Macのopenコマンドでファイルを開く](https://qiita.com/aokiplayer/items/74c7adc3d951a6fbd41f)

# 環境
- Ubuntu 18.04
- zsh

# 方法
シェル起動時に読み込まれるファイルに関数を定義しておく。

- bashなら~/.bashrc
- zshなら~/.zshrc

[zshの設定ファイルの読み込み順序と使い方Tipsまとめ](https://qiita.com/muran001/items/7b104d33f5ea3f75353f)

```shell:~/.zshrc
myopen() {
  # 第一引数は$1
  fpath=$1

  # パターンマッチで拡張子を取り出す
  fext="${fpath##*.}"

  # case文で分岐
  case $fext in
    pdf)
      # 拡張子がpdfのときに実行するコマンド
      evince $fpath & ;;
    png|jpg)
      eog $fpath & ;;
    c|cpp|txt)
      atom $fpath ;;
  esac
}
```

コメントに記載したとおりですが
1. コマンド実行時の引数(ファイルパス)を受け取る
2. 拡張子を取り出す
3. 拡張子ごとに分岐してコマンドを実行する
という流れです。

[シェルスクリプト入門 書き方のまとめ](http://motw.mods.jp/shellscript/tutorial.html#branch)
[パス文字列からファイル名などを抜き出す](https://qiita.com/ktr_type23/items/94747a4b27e8a630ce48)

各ファイルは以下のアプリで開いていますが、もちろん好みのアプリに変更可能です。

- pdf &rarr; evince
- png, jpg &rarr; eog
- c, cpp, txt &rarr; atom

.bashrcや.zshrcを更新したら以下のコマンドで変更を反映させます。

```
exec bash
exec zsh
```

冒頭に記載したように次のコマンドでファイルを開けるようになっているはずです。

```
myopen ファイルパス
```

# おまけ(URLもブラウザで開く)
上記のopen関数に少し追加すればファイルだけでなくURLにも対応可能です。

```shell:~/.zshrc
myopen() {
  # 第一引数は$1
  fpath=$1

  # パターンマッチでURL判定
  if [[ $fpath =~ ^http ]]; then
    firefox $fpath &
    exit 0
  fi

  # パターンマッチで拡張子を取り出す
  fext="${fpath##*.}"

  (以下省略)
}
```

パターンマッチでhttpから始まるかどうかを判定し、trueならfirefoxで開くようにしています。次のように使用可能です。

```
myopen https://www.google.com/
```

[bashでif に正規表現を使った文字列マッチ条件分岐](https://takuya-1st.hatenablog.jp/entry/2016/12/22/175514)

# シェルの補完ができなくなった時
例えば./dirというディレクトリに移動しようとして

```
cd d(tab)
```
と入力してtabでディレクトリ名を補完しようとすると次のようなエラーが出ることがあります。

```shell
function definition file not found
```

これはシェルのキャッシュが不具合を起こしているためで、キャッシュファイルを削除してシェルを再起動すれば治ります。

```shell
rm ~/.zcompdump
exec zsh
```

[zshでvim+Tabでエラーになる時の対処法](https://qiita.com/Asuforce/items/28b287fdb933d1985e15)

# まとめ
.bashrcや.zshrcをカスタマイズすることでシェルを効率的に使えるようになります。関数の他aliasによるカスタマイズも一般的のようなので、自分の好みに合った設定を探してみるといいかもしれません。

[aliasと関数で幸せになろう](https://qiita.com/belion_freee/items/528ff57b920d559abf3d)

また、今回記事を書くに当たって本文中にリンクした多数の文献を参考にさせていただきました。ありがとうございました。
GKEで限定公開クラスタ構築時のtimeoutエラー問題と解決策

# はじめに

GKE(Google Kubernetes Engine)の限定公開クラスタを構築する際に、以下のような接続エラーが起こり`kubectl`コマンドが使えずハマったのでメモ。

```bash
$ kubectl version
Unable to connect to the server: dial tcp <Your Cluster IP>:443: i/o timeout 
```

# やりたかったこと

GKEと連携しているAPIの制約上、外部への通信のIPを固定する必要がありました。Cloud NATと限定公開クラスタ(Nodeに外部IPが付与されない)の構築してオートスケールしてもIPを固定にすることが目的でした。

そのために限定公開クラスタをを構築する必要がありました。現在では限定公開クラスタの作成はコンソール上で可能です。ただし、IngressのLet's Encrypt連携といったkubernetesの詳細な設定は`kubectl`を使わないと出来ません。(←違ってたらすみません)

## 通常のクラスタじゃだめなの？

通常のクラスタはオートスケール時にデフォルトで自動的に新規の外部IPが付与され、クラスタが格納されているネットワークにCloud NATを構築していてもその外部IPで通信してしまいます。ノードのテンプレートを設定、適用することで新規作成ノードに外部IPを付与させないことが可能ですが、私の環境では数ヶ月に一度、**適用しているテンプレートが勝手に更新される**現象が発生しました。そのため、GKEでノードに外部IPが付与できないよう限定公開クラスタを構築しました。

# やったこと

以下の公式ドキュメントに従って限定公開クラスタを作成した。

* <https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters?hl=ja>
* <https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl?hl=ja#cluster_endpoint>

# 原因

ドキュメントのサンプルコマンドに含まれている`--enable-master-authorized-networks`オプションが原因でした。これのオプションは許可されたIP以外からのクラスタへの通信を防ぐオプションです。実行するコマンドのオプションぐらいは最低限把握しとけって話ですね。ちなみに`--master-authorized-networks [CIDR]`オプションで許可するIPを指定します。

# 解決策

限定公開クラスタ作成コマンドから`--enable-master-authorized-networks`オプションを除く。

```bash:example
$ gcloud container clusters create private-cluster-0 \
    --create-subnetwork name=my-subnet-0 \
    --enable-ip-alias \
    --enable-private-nodes \
    --master-ipv4-cidr 172.16.0.0/28 \
    --no-enable-basic-auth \
    --no-issue-client-certificate
```
SoftEther VPNで一部のクライアントに固定IPアドレスを割り振る

# やりたいこと
- とある事業所A（1箇所）にある複数のPCを、遠隔地の社員からリモート操作できるようにしたい。
  - 接続先PCは限定されているので、IPアドレスを固定したい。
- 接続元となる「遠隔地」というのは複数の事業所がある。リソースに余裕のある会社でもないので物理ルータの煩雑な設定などは避けたい。ITスキルに自信ニキが必要な作業は総務だけで吸収したい。
  - なので接続元についてはDHCPで良い。
- Active Directoryなんてありません。
- 接続元も接続先も Windows 10。

# 構成
SoftEther VPNのL2TPとSecureNATを利用。遠隔操作にはリモートデスクトップを使うので割愛。
![vpn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207347/aa3a87fe-41da-e79c-673c-5388136b7987.png)

# VPNサーバのセットアップ
SoftEtherのGUI管理ツールはWindowsでしか動かないので、EC2はWindowsインスタンスにする。
セキュリティグループの設定は、デフォルトで入っているRDPの他`UDP/500`, `UDP/4500`のみ開放する。

SoftEther Download Centerは、t2.microでは非力すぎるのかうまくダウンロードできなかった。が、[Browse the list of all downloadable files (Archives)](https://www.softether-download.com/files/softether/)からダウンロードできる。`*-rtm-*/Windows/SoftEther_VPN_Server_and_VPN_Bridge/`以下のファイルをダウンロード、インストールする。

SoftEtherのConfigure Display Languageで表示言語を日本語に変えておく。（なおWindows側の言語設定は変えなくてもよい）

VPNサーバー管理で下記の設定を行う。

1. 簡易セットアップは「高度な機能を用いたVPN」とする。
1. 下のボタン群のうち「IPsec / L2TP 設定」を開く。
    1. 「L2TP サーバー機能を有効にする (L2TP over IPsec)」のみ有効にする。
    1. IPsec事前共有鍵に適当なパスワードを設定する。これは後でクライアントからの接続に必要なので配布する。
1. 「仮想HUBの管理」を開く。
    1. 右下の「仮想NAT及び仮想DHCPサーバー機能」を開く。
    1. 「SecureNAT機能を有効にする」
    1. デフォルトだと`192.168.30.0/24`がDHCP配布用に確保されているが、配布アドレス帯は`.10`～`.200`まで。そのままでも`.201`～`.254`あたりが固定IPアドレスとして使える。
1. 「ユーザーの管理」を開く。
    1. クライアント（リモートデスクトップ接続元・接続先ともに）のアカウントを作成する。パスワード認証が無難。

# クライアントの設定
リモートデスクトップの接続元・接続先とも概ね同じ。

1. ネットワークとインターネットの設定を開く。
1. 左ペイン「VPN」を選択し、「VPN接続を追加する」。
    1. VPNプロバイダー「Windows（ビルトイン）」。
    1. 接続名はお好みで。
    1. サーバー名またはアドレスにパブリックIPを入力する。
    1. VPNの種類は「事前共有キーを使ったL2TP/IPsec」。
1. 「接続」ボタンを押し、ユーザー名とパスワードを入力して接続する。

## IPアドレスの固定

1. 関連設定にある、「アダプターのオプションを変更する」。
1. 新しいL2TP接続設定を右クリックして「プロパティ」を開く。
1. 「ネットワーク」タブの「～TCP/IPv4」を選択し、その「プロパティ」を開く
1. 「次のIPアドレスを使う」に当該クライアントの固定IPアドレスを入力する。
    1. 前述のとおり、SoftEtherのデフォルトだと`192.168.30.200`～`.254`あたりが空いている。
1. 「優先DNSアドレス」にVPNサーバの**VPN内での**プライベートIPアドレスを入力する。デフォルトのままなら`192.168.30.1`。
1. 一度VPNとの接続を切ってから再接続する。
WordPressをGit管理する方法

## 概要

WordPressのコードをgitで管理することになったためそのメモ。

WordPressはpluginや作成したコンテンツなどGitで管理するのに適さないデータが大量にあります。Gitで管理するべきものはテーマファイルだけだと思うので、今回は自作テーマ（既存テーマをカスタマイズする場合も同様）を管理する場合の手順メモです。

WordPressのあるプロジェクトに移動。

```
cd /var/www/wordpress
```

gitのリポジトリを作る。

```
git init
```

`.gitignore` に対象のテーマファイルのみを管理するように記述する。

```
*
!.gitignore
!/wp-content/themes/{mytheme} 
# {mytheme}にはテーマ名を入れる
```

## おまけ

pluginや作成したコンテンツの管理について、個人的には[SnapUp](https://snapup.jp/)が管理が楽でおすすめです。WordPressのスナップショットやstg環境も簡単に作成できます。
【初心者向き】【読み物】機械学習にPythonを使用する

Pythonはデータサイエンス分野で最もよく利用されているプログラミング言語の1つであるので、便利なアドオンライブラリが大きな開発者・オープンソースコミュニティによって行くつも開発されている。

そのため、いざ機械学習を始めるときに自分で1から機械学習のソースコードを書き始める必要がなく、既存のライブラリを活用できるという点にPythonを使う大きなメリットがある。

Pythonなどのインタープリタ言語のパフォーマンスは、計算主体のタスクでは低水準のプログラミング言語に劣るものの、多次元配列に対して高速にベクトル演算を行うNumpyやScipyといった拡張ライブラリがFortranやC言語の実装に基づいて開発されている。

機械学習のプログラミングタスクでは、主にScikit-learnライブラリを使用することになる。scikit-learnは現時点において最もよく使用されているオープンソースの機械学習ライブラリの一つである。

Python
https://www.python.org


科学計算に特に推奨されているPythonディストリビューションの一つに、continum Analyticsが提供しているAnacondaがある。Anacondaは、営利目的での使用を含め、完全に無償のエンタープライズ向けのPythonディストリビューションである。データサイエンス、数学、工学に不可欠なPythonパッケージが1つのユーザーフレンドリなクロスプラットフォームディストーションにまとめられている。

----------------------------------------------------------
SQL小技集
https://qiita.com/ool/items/75da830e7373138c8125
UTCとJST
https://qiita.com/ool/items/6be9cc290c8ad9e0f5bc
今流行りの量子コンピューター
[量子コンピューター]Qisikitでアダマールゲートを実装する
https://qiita.com/ool/items/1a5041edddc11b14efc0
[Qiskitのアカウント認証の仕方]Qiskit IBMQ プロバイダー
https://qiita.com/ool/items/e80c1266cda68984a103
Qiskitの使い方
https://qiita.com/ool/items/2227d2d515caa5087752
[量子コンピューター]Qiskit Tutorials
https://qiita.com/ool/items/2a5038df1471635d442c
ORDER BYを使わずにfind_eachっぽくデータを処理してメモリを節約する方法

# ActiveRecord::Batches#find_eachについて

ActiveRecordの`find_each`は、メモリを節約しながら大量のデータを処理するためのメソッドです。
ActiveRecordのリファレンスには以下のようなことが書かれています。

> find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
> 
> find_eachはデータベースのレコードをループ処理します。
> 大量のレコードが存在するとき、allを用いては、すべてのオブジェクトを一度にインスタンス化するため、メモリ効率がとても悪いです。
> 一方、find_eachのようなバッチ処理メソッドを使用すると、レコードをバッチで処理するため、メモリ消費が大幅に節約できます。
> find_eachは、デフォルトで:batch_sizeが1000なので、1000件ずつのレコードを分割してループします。
https://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_each

つまり、10,000件のレコードを取得してcsvに加工したりといった処理を行いたいとき、find_eachを用いれば10,000件のレコードがメモリにのらずに済むということです。
find_eachを用いてActiveRecordが生成するクエリは、以下のようになります。

```ruby
User.find_each do |user|
    # do_something
end
```

```sql
SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1000
SELECT  `users`.* FROM `users` WHERE `users`.`id` > 1000 ORDER BY `users`.`id` ASC LIMIT 1000
SELECT  `users`.* FROM `users` WHERE `users`.`id` > 2000 ORDER BY `users`.`id` ASC LIMIT 1000
SELECT  `users`.* FROM `users` WHERE `users`.`id` > 3000 ORDER BY `users`.`id` ASC LIMIT 1000
...
(usersが全件取得できるまで繰り返す。10,000件存在していれば10回)
```

`LIMIT 1000`とレコードを限定して取得し、`WHERE users.id > 1000`のように条件指定することで、漏れ・ダブリなくレコードを取得するようになっています。

LIMITを1000以外にしたい場合は、リファレンスにあるように、`find_eah(batch_size: 2000)`のように呼び出せば良いです。

しかし、上記を見ると、`ORDER BY users.id ASC`という意図しないソートがクエリに含まれています。
リファレンスを確認すると、次のような注意書きがあります。

> NOTE: It's not possible to set the order. That is automatically set to ascending on the primary key (“id ASC”) to make the batch ordering work. This also means that this method only works when the primary key is orderable (e.g. an integer or string).

どうやら、find_eachは主キーでソートしてからLIMITをかけて分割取得することで、漏れ・ダブリなくデータを処理するといった実装になっているようです。

よって、`select(users.id AS user_id)`などと一緒に使うとエラーが出ます(`id`というカラム名である必要がある)。
また、他のカラムでORDERしていると、それは無視されます。

indexによっては、ORDERが入ることでクエリが遅くなってしまうことがあると思います。
ORDERは入れたくないが、分割して処理することでメモリ消費を削減したいとき、どう実現するかを考えてみました。

# 実現方法

単純ですが、`id`をすべて取ってきて、`each_slice`で任意の数ずつ`where`で取ってくることで、ORDERなしでfind_eachっぽく処理するようにしてみました。

```ruby
ids = User.pluck(:id)
ids.each_slice(1000) do |id|
    User.where(id: id).each do |user|
        # do_somethins
    end
end
```

これで発行されるクエリは以下のとおりです。

```sql
SELECT `users`.`id` FROM `users`
SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2, 3, 4, 5, 6, 7, 8, ..., 1000)
...
(全件取得するまで)
```

これでORDERなしで、メモリを節約できました。

# 問題点

find_eachは安全のために`ORDER BY users.id ASC`しているわけで、例えばクエリ実行のたびに取得順序が変わるような場合は当然これは使用できません。
また、`ids = User.pluck(:id)`でidを全件取ってくるため、ここでパフォーマンスが落ちることもあります。
結局、find_eachでORDERが入ってもいいように、indexを適切にできるならそうしたほうが良さそうです。
岩舘電気の中の人が Google Calendar と Cybozu 予定表を Gcal Connection for Cybozu Office を使って同期してみた

　皆さんこんにちは、岩舘電気の中の人です。岩手県では岩手医科大学の転院も終わり、秋を感じる季節になってきました。

　さて、中の人は今までスケジュール管理に Google Calendar を使っており、仕事と家庭両方のスケジュール管理に活用していたのですが、自分のスケジュールを社内に公開する必要が出てきたため、Google Calendar とサイボウズ Office のカレンダーを同期してくれる Gcal Connection for Cybozu Office という有償のソフトウエアを導入しました。

　しかしながら、専用のソフトを導入しても簡単にスケジュール同期ができるわけではなく、各アプリの仕様のために大ハマりしてしまったため、同じような悩みを持っている人のために顛末記事を公開します。Gcal Connection for Cybozu Office はプロプライエタリなソフトウエアですのでここで扱うのは少々気が引けるのですが、本記事はどちらかというと google calendar の tips 的な側面が大きいため、お許しいただければ幸いです。

　まず、現状と理想の状態を確認します。

　現在は自分の google account で１つカレンダーを持っており、これを家庭内で共有しています。家族でのイベントがある場合は、必要に応じて「ゲストを追加」することでプライベートなスケジュールを追加します。

　これを次の図のように変更します。

![プレゼンテーション1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61220/9ae60cee-173a-863a-ab83-1a41c1545db4.png)

　Cybozu のスケジュールを社内に公開する場合は、プライベートな予定は「非公開」に設定したいところです。これを実現するために社内公開用のカレンダーを１個追加します。家庭内の meeting request （ゲストを追加）はデフォルトのカレンダーに入ってきますので、デフォルトのカレンダーを Cybozu の非公開カレンダーに割り当てるのが賢明と思われます。（ただし、PCのブラウザ上でイベントを作成する場合はデフォルトカレンダー上に作ろうとするため、会社のイベントを作成する場合はカレンダーの割り当てを変更するひと手間が増えます。モバイルアプリの場合は直前にイベントを追加したカレンダー上にイベントを追加しようとするためこの限りではありません。）

さて、これだけ見ると簡単に見えますが、Gcal Connection for Cybozu Office は、初回の同期時は同期先の google calendar にイベントが一つもない「まっさら」な状態である必要があるという悪夢のような仕様があります。つまり・・・

![000013.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61220/dc97e39a-7bec-4220-c0c0-482487fa19f4.jpeg)



　というわけで、まずは Default Calendar の複製を作ります。ぐぐってもらうとわかるのですが、通常は既存のカレンダーをエクスポートし、新しく作ったカレンダーにインポートすれば終わります。終わるはずなんですが、Google Calendar の場合は非常にダメダメな仕様があり、インポートする iCal ファイルはおよそ 1MB以下でないとインポートに失敗することがある、インポートするファイルに含まれる件数が多すぎても失敗するなどの制約があります。おまけに、同じファイルでも、インポートに成功するときと失敗するときがあります。部分的にインポートされることもありました。なお中の人の場合、エクスポートしたファイルが11MBあったため、試行錯誤して13分割しました。なお iCal を分割できるツールの類は存在しないようなので、テキストエディタで分割することになります。

　なお、エクスポート・インポートを行っても、まったく同じカレンダーが生成されるわけではありません。次の情報は消えてしまいます。

・主催者、参加者情報
・google drive へのリンク情報

　このほかにも、中の人が遭遇した不具合として、イベントの長さが0時間である場合、インポート時に1時間になってしまうことがありました。例えば、「08:00~08:00 （0時間）」のイベントが「08:00~09:00（1時間）」になってしまうことがまれにあります。
　なお 中の人の場合、google drive へのリンク情報が消えるのは非常に厄介でした。イベントに関連する様々な書類やＦＡＸ（いまだに使っているなんて信じられませんけど、実際ものすごい量のＦＡＸが届きます）をスキャンしたものを大量にアップロードしているため、インポートが終わったら、リンクを含むイベントを一つ一つ default calendar からbackup calendar にコピーを行います。google calendar のコピー機能を使った場合は、エクスポート・インポートと違ってリンクが消えません。とにかく手動でコピーをするしかないようです。

　さて、カレンダーのインポートと添付ファイル(Google drive へのリンク）があるイベントのコピーが終わったら、いよいよ default カレンダーを消去します。

![dragon-quest-lost-save-data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61220/f127d491-947a-8b9c-5670-4897828ade2e.png)

　なお過去のデータをバッサリ切り捨てることができればいいのですが、中の人は諸般の事情により過去の情報を消せない理由がありまして、テストを兼ねてすべてのデータのエクスポート・インポートをしています。それにしても心折れる瞬間です。

　カレンダーの削除が終わったら、GCal Connection を起動して同期設定を行います。このとき、同期先の　google drive の２つのカレンダーには何もイベントがないことを確認し、できれば Cybozu 側のスケジュールもすべて削除しておくのが良いと思います。cybozu のスケジュールはアプリの設定から削除が可能です。

　同期が終わったら、 backup カレンダーもしくはエクスポートしたical からイベントを default カレンダーと社内公開用カレンダーにインポートをしていきます。特に添付ファイルのあるイベントについては、backup からコピーして戻していかなくてはなりません。どの程度復元が必要かは割り切りが必要だと思います。

　書いてみると簡単ですが、手作業が多く、時間も神経も使う作業です。中の人はあやうく徹夜しかけました。まあ、何かのご参考になれば幸いです。
[Rails]credentials.yml.encについてまとめる

某スクールの最終課題であるフリマアプリの作成が始まりました。
私はスクラムマスターの担当になりましたので本番環境へのデプロイ担当になりました。

応用カリキュラムのチャットスペースでは、Railsのバージョンは5.0.7.2です。
なので、カリキュラムの内容もsercret.ymlを使ってAWSのEC2にデプロイする内容でしたが、今回、最終課題で使うバージョンはRails5.2です。
Rails5.2以降は仕様が変更されてsercret.ymlがcredentials.yml.encになっています。
デプロイ環境を構築するのにだいぶ苦労してしまったので、今回はcredentials.yml.encについてまとめていきたいと思います。

##credentials.yml.encとは
Rails5.2ではrails newをするとsercret.ymlの代わりにcredentials.yml.encが生成されるようになっています。
credentials.yml.encの役割は以下の通りです。

- secret.yml、secret.yml.enc、ENV[‘SECRET_KEY_BASE’]の3つのファイルを一元化
- 本番環境のみで使用する想定なので、環境毎に値を設定する必要がない
- 復号にはmaster.keyが必要（credentials.yml.encと一緒に生成されます）

Rails newをするとcredentials.yml.encと一緒にconfig/master.keyが生成されます。
config/master.keyはgitignoreに最初から追加されているので設定する必要はありません。
念を押すのであれば、credentials.yml.encもgitignoreに追加してもいいかもしれません。

##credentials.yml.encを編集する
credentials.yml.encは直接エディタから編集する事はできません。
ターミナルでエディタを指定して編集します。
vimで記述していますが、vim以外でも編集は可能です。

```
<ターミナル>
$ EDITOR=vim bin/rails credentials:edit
```

上記のコマンドを入力すると、ターミナルで下記の画面が表示されます。
※指定したエディタで開きます。今回はvimで指定したのでターミナルです。

```
<credentials.yml.enc>
# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
```

上記の画面にawsのaccess_key_idやsecret_access_key、その他APIキーなどを入力すれば暗号化されて保存されます。
デフォルトで付いているコメントアウトは外しましょう。

言うなれば、master.keyは鍵、credentials.yml.encは秘匿情報を詰め込んだ箱の鍵穴に相当します。
credentials.yml.encで暗号化した秘匿情報をmaster.keyを使って復号します。

##capistranoによる自動デプロイ
手動でデプロイする場合はこれでOKなのですが、capistranoで自動デプロイをする場合は本番環境にshared/config/master.keyを作成して配置する必要があります。
scpコマンドを使って転送するのが良さそうです。
私は今回は本番環境のshared直下にconfigディレクトリを作成して直接master.keyをコピーしました。

##[本番環境]master keyの存在を確認する設定
本番環境ではmaster.keyの指定漏れを防ぐためにconfig/environments/production.rbに
config.require_master_key = trueを有効化することで、本番環境にmaser.keyが存在しない場合エラーになるよう設定できます。

```ruby
<config/environment/production.rb>
config.require_master_key = true
```

##master.keyを紛失した場合
もし紛失してしまった場合はcredentials.ymlの復号ができなくなります。絶対に紛失はしないでください。

ですが、個人開発だったりチーム開発初期段階でcredentials.ymlに重要な記述がされていなかったりして捨てても良いのであれば再作成した方が良いです。
私は2回再作成しました笑

再作成の方法はcredentials.ymlを削除した後に、下記のコマンドを実行します。

```
<ターミナル>
$ sudo EDITOR=vim rails credentials:edit
```
コマンドを実行した時に、master.keyが存在していなければ作成されます。存在している場合は既存のmaster.keyがそのまま使われます。

今回は設定しませんでしたが、master.keyが共有できない環境では環境変数：RAILS_MASTER_KEYで指定できます。

master.keyがgitignoreにあらかじめ入っていたり以前より少し楽になった印象です。
開発環境やテスト環境で設定するような場面もありそう？
今回の実装を通して理解が深まりました。

参考
Rails5.2から追加された credentials.yml.enc のキホン
https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39
Rails5.2から導入されたcredentials.yml.encを極める
https://qiita.com/yuuuking/items/53a37a2e998972be32b8#%E6%9C%AC%E7%95%AA%E7%92%B0%E5%A2%83master-key%E3%81%AE%E5%AD%98%E5%9C%A8%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A
Rails5.2からsecrets.yml*が廃止されcredentials.yml.encに統合されるよ
https://qiita.com/daichirata/items/da40e205d273ae69fcfc
Rails 5.2でActiveSupport::MessageEncryptor::InvalidMessage
https://qiita.com/scivola/items/cc06ddbfd94d3118f693
ESP-WROOM32とRC522でRFIDお遊びしてみた

こんにちは。
今回は、秋月電子で入手したESP-WROOM32を用いて、RC522(rfidリーダ）を動かしてみました。
将来的にはRFIDタグを使って、ドアロックシステム、勤怠管理などへのの活用を想定しています。

#動作環境
+ [ＥＳＰ３２－ＤｅｖＫｉｔＣ　ＥＳＰ－ＷＲＯＯＭ－３２開発ボード](http://akizukidenshi.com/catalog/g/gM-11819/)
+ [RFIDモジュール [RFID-RW522](rc522)](http://www.aitendo.com/product/7415)
+ Arduino IDE 1.8.8
+ 各種ブレットボードなど

開発環境のインストールなどは、他の方の記事がわかりやすいです。
https://qiita.com/Agatsuma854/items/7b8fec42c5e9f0db7002

#RFID-RW522(RC522)について
RFID-RW522は、MFRC522チップが載っているRFIDボードです。500円程度で購入可能。←激安！
ESP-WROOM32とは<b>SPI</b>で接続します。
RFIDの中にも規格が複数あって、rc522は<b>「MIFARE」</b>という規格のICタグに対応しています。

#RFIDってなんぞや
RFIDにもいろいろ種類があります。

* RFID
    * 近接型(13.56MHz)
        * <b>TypeA(MIFARE)(ISO/IEC14443)(学生証、アミューズメントカードなど)
        * TypeB(ISO/IEC14443)
        * TypeC(Felica)(Suicaなど)
    * 近傍型など....

古いのがTypeA(mifare)。世界中で多く使用されています。
TypeC(Felica)は日本で普及している型。有名なのはSuicaなど。

今回使用するRFID-RW522は<b>TypeAのみ対応</b>なので、交通系IC(Felica)(Suicaなど)を読み取ることはできません。
交通系IC(Felica)を読み取りたい方は、[PN532チップ](http://www.aitendo.com/product/16607)を搭載したボードを買いましょう。


#SPI接続について
>シリアル・ペリフェラル・インタフェース(Serial Peripheral Interface, SPI)は、コンピュータ内部で使われるデバイス同士を接続するバスである。パラレルバスに比べて接続端子数が少なくて済むシリアルバスの一種で、比較的低速なデータ転送を行うデバイスに利用される。

なーんか難しそうですが、簡単に言えば

* 4つの信号線
    * SS
    * SCK
    * MOSI
    * MISO
    * RST
* 電源
    * +
    * -

の合計7本の線をつないでやれば、通信できるということ。

んじゃあ、そのSPIとやらの端子はどこにあんの？ってことで
ESP32-devkit Cのピンアサインは以下の通り
![ESP32-Pinout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440839/37c1138e-b00c-ab52-822f-65589338e6b3.png)
(image from https://components101.com/microcontrollers/esp32-devkitc)

まとめてみると

|ESP32-devkitC側|RC522側|
|---|---|---|
|IO5 |SS  |
|IO18|SCK |
|IO23|MOSI|
|IO19|MISO|
|3v3|3.3v(Vcc)|
|GND|GND|
|IO26|RST|

に接続してあげればよい。

#コードを編集する
まずMFRC522のライブラリをインストールしましょう。
<img width="798" alt="スクリーンショット 2019-10-12 1.28.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440839/e1f6f627-0c24-5a62-36e5-e71beec6446e.png">

インストールできたら
Sample Sketch/MFRC522/ReadNUIDを読み込んでみましょう。

そしたら34,35行目に

```
#define SS_PIN 10
#define RST_PIN 9
```
とありますが、これはArduino用?なのでESP32用に書き換えなければなりません。よってピンアサインに従って

```
#define SS_PIN 5
#define RST_PIN 26
```
と書き換えます。

#コンパイル&実行(シリアルモニタ)
コンパイル&実行し、シリアルモニタを起動します。
RFIDタグをかざしてみると、以下のような画面が表示されます。
<img width="524" alt="スクリーンショット 2019-10-13 1.26.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440839/7207abeb-a8d8-2959-743f-385933444478.png">
灰色で隠した部分がNUIDと呼ばれる、<b>カード固有のID</b>です。
(HEXは16進数、DECは10進数表示)
このIDを識別して、キーロックシステムなどの構築が可能、、、<b>なはずでした、、、</b>

#(完全に余談)NUIDとUIDとは
####UID
>UIDは「Unique ID」の略。MIFAREカード製造時にICチップに書き込まれる製造番号。書き換えは不可能。

しかし、
####NUID
>この「UID」は世界に一つしかない番号であったが、2010年で4ByteUIDが枯渇し、
「Non Unique ID」 (NUID) になった。
https://fujifilm.jp/business/security/id_ic/promotion/glossary/

というわけなのです。確率としては非常に低いですが、重複する危険性があるということです。
でもまぁ、アマチュア電子工作レベルでは無視してはいいのでと思います。

#次回予告
お疲れ様でした。今回はNUIDを読み取ってSerialMonitorに表示するところまで進めました。

次回は、NUIDをデータベースと照合するシステムについて書きたいと思います。
(詳しくいえば、読み込んだNUIDを、firebaseに登録しているidと照合し、i2c接続したLCDに照合結果を表示するデバイス)


#(※詳細、躓いたのでメモ)ESP32のSPI接続には実は３種類ある。
* SPI
    * SPI 
    * VSPI
    * HSPI

通常、何もしなければVSPIが使われるとのこと。
わかりやすい記事(https://qiita.com/cattaka/items/48f0853c2ac7552c833e)
SQL Server Express インストールから初期設定まで

##ダウンロードとインストールは下記の記事を参照しました
https://sql55.com/sql-server/install-microsoft-sql-server.php

##インストール後の初期設定は下記を参照しました
SQL Server Express に接続できるようにする3つの設定
https://buzz222.com/mssql-connect

##ハマったところ

###■SQLserver認証でログインできない
インストール時に認証方法を選択できる。
　・Windows認証
　・混合モード(Windows認証とSQLserver認証)
これを確認せずにインストールしてしまい、Windows認証のみとなっていた。

###■認証モードはSSMSでいつでも変更できる
公式ドキュメントを参照してSSMSで認証方法を変更しました.
https://docs.microsoft.com/ja-jp/sql/database-engine/configure-windows/change-server-authentication-mode?view=sql-server-2017#SSMSProcedure

####下記は公式ドキュメントからの抜粋
SQL Server Management Studio オブジェクト エクスプローラーで、サーバーを右クリックし、 [プロパティ] をクリックします。
[セキュリティ] ページの [サーバー認証] で、新しいサーバーの認証モードを選択し、 [OK] をクリックします。
SQL Server Management Studio の再起動が必要であることを示す のダイアログ ボックスで、 [OK] SQL Serverをクリックします。
オブジェクト エクスプローラーでサーバーを右クリックし、 [再起動] をクリックします。 SQL Server エージェントも再起動する必要があります (実行されている場合)。


###■クライアントからSQLserverに接続できない

記事を参照して進めた場合、最後のIPALLのTCPポートの設定は良く考える必要がある。
これはSQLserverのポートを変更している場合の設定なので、通常はTCP1433を設定すればOK。

思ったより苦労しましたので、誰かの参考になれば幸いです。

####後からこんなに良くまとまったページを見つけました。
SQL Server Express にリモート接続
https://creativeweb.jp/fc/remote/
毎年256日目は #プログラマの日 を JavaScript (ES2018) で実装する

毎年256日は #プログラマーの日 という以下のコードを Twitter で見かけました。
もとの開発言語は不明ですが、車載端末でも動くような JavaScript に移植してみます。
async/await と非同期イテレータを使ってみます。

```js
    while (everyYear) {
    if (today().dayNumber == 256) {
        celebrate("Programmers' Day");
        }
    }
```

https://twitter.com/TRIAD_Japan/status/1172412070769258496 より。

もとのコードの処理を頭の中でシミュレーションすると、
256日目に「Programmers' Day」のお祝いがずっと続いてしまう気がしますので、
どこかでウエイトが入っているはずです。

さらに、256日目以外のことも考慮すれば、`while (everyYear)` の部分でウエイトが入り、
１日１回だけ while 文の中が実行されると解釈するのが妥当です。
毎日の処理ぽいのに `everyYear` という変数名？を利用していたもとの命名規則は、
謎ですが、なにか意図があるかと思いますので、そのまま移植することにします。

## 1. async/await で実装した場合

JavaScript 移植では、最初の `while (everyYear)` のところがクセモノです。
`everyYear` を変数でなくて、関数呼び出しに変更してよければ、async/await で実装できます。
もとの `while (everyYear)` が `while (await everyYear())` になります。

```js
const sleep = s => new Promise(r => setTimeout(r, s));
const celebrate = m => console.log(m);
const today = () => ({dayNumber: 256}); // TODO
const everyYear = async () => await sleep(1000) || true;
(async () => {

    // ここから
    while (await everyYear()) {
        if (today().dayNumber == 256) {
            celebrate("Programmers' Day");
        }
    }

})();
```
1年を待つのは辛いので、ここではデモのため、1秒ごとに「Programmers' Day」をお祝いします。
[Top-level await](https://github.com/tc39/proposal-top-level-await) が実装されると、`(async () => {` と `})();` を省けるようになるはずです。

実行結果：（node v10 と Chrome 77 で動作確認済）

```txt
Programmers' Day
Programmers' Day
Programmers' Day
```

ただし、`while (await everyYear()) {` の部分については、
動詞 await の目的語が everyYear に読めてしまうので、英語として読み取りにくいです。
読みにくいコードは、安全の敵なので、イマイチです。

## 2. 非同期イテレータで実装した場合

あるいは、非同期ジェネレータ `async function*` という呪文と `for-await-of` 構文を使えば
`everyYear` を非同期イテレータの変数にできるので、関数呼び出しのカッコ `()` をはずせます。
もとの `while (everyYear)` が `for await (safety of everyYear)` のようになります。

```js
const sleep = s => new Promise(r => setTimeout(r, s));
const celebrate = m => console.log(m);
const today = () => ({dayNumber: 256}); // TODO
const everyYear = (async function* () {
    while (true) yield await sleep(1000) || true;
})();
let safety;
(async () => {

    // ここから
    for await (safety of everyYear) {
        if (today().dayNumber == 256) {
            celebrate("Programmers' Day");
        }
    }

})();
```

`for-of` 構文では、受ける変数が必要そうなので、`safety` としてみました。
`while (true) yield await sleep(1000) || true;` の１行は気持ち良いですが、
非同期ジェネレータ `async function*` はまだ arrow function で書けなないらしく、そこは残念。

仮に `for await safety of everyDay` であれば、日々の安全を求めて活動しながら、
256日目だけは Programmers' Day をお祝いするようなエモいニュアンスが込められそうです。

---

上記の JavaScript 移植版のライセンスは、もとのソースコードのライセンスに従います。

![TRI_AD.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12419/ceb694ff-6059-3c2e-66f0-36a242999036.jpeg)  ![account.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12419/ce7354b8-45e7-b055-8a7c-2de321226293.jpeg)

---

［余談］
そういえば、https://hack4.jp/relatedinfo/t-shirt/1st/ にある
Hack for Japan の T シャツに記載するコードを検討したときは、みんなでコードレビューして、
いくつかの言語でそのまま動きそうな感じに考慮した記憶があります。

```js
    while (Japan.recovering) {
        we.hack();
    }
```

事故を防ぐためには、ソースコードはレビューをしてもらうのが大事ですね。
macのputtygenで秘密鍵から公開鍵を作る

win機でのputtygen操作は引っかかっても、macのコンソールから実行するようなコマンドは
意外とすぐに引っかからなかったので備忘録として書いてみます。需要があれば

## 秘密鍵 -> 公開鍵
```bash
puttygen (秘密鍵ファイル名) -O (変換形式) -o (生成する公開鍵ファイル名)
```

出力形式として指定できるのは次の通り

```bash
public: ssh.com(SECSH)形式の公開鍵として変換
public-openssh: OpenSSH形式の公開鍵として変換
```

## 一例
```bash
puttygen hoge.ppk -O public-openssh -o hoge.pub
```
.bat バッチファイルでファイルのタイムスタンプを更新する touch コマンドの代わり

# これは何

Windows のバッチファイルで、ファイルのタイムスタンプを更新する方法を紹介します。

- できること
    - 空ファイルの作成
    - ファイルのタイムスタンプ更新
- できないこと
    - オプションを使うこと。タイムスタンプを指定時刻に変更したりできません
    - ディレクトリのタイムスタンプを更新すること
- 多分できないこと
    - ネットワークパスのファイルに対する　touch 操作。試せてないのでわかりません。誰か、成功したら教えて

# 想定読者

WSL 、 [cygwin](https://cygwin.com/) 、 [msys2](https://www.msys2.org/) を Windows に install したくない人
外部ツールにできるだけ依存したくない人

# 結論

```bat:touch.bat
@echo off
if "%~1"=="" exit /b 0
if "\\.\"=="%~dp1" exit /b 0
pushd "%~dp1"
if not exist "%~nx1" (
  copy nul "%~nx1">nul
) else if not exist "%~nx1\" (
  copy /B /Y "%~nx1"+>nul
)
if errorlevel 1 (
  popd
  exit /b %errorlevel%
)
popd
exit /b 0
```

# 実行例

## 正しい使い方

通常のファイルに対する touch 操作は、成功すると　0　が返ります。
アクセス権限等で失敗すると非0が返ります。

### 通常のファイルに対する touch

```
C:\a>dir
2019/10/12  00:27    <DIR>          .
2019/10/12  00:27    <DIR>          ..
C:\a>touch.bat foo.txt
C:\a>echo %errorlevel%
0
C:\a>dir
2019/10/12  00:27    <DIR>          .
2019/10/12  00:27    <DIR>          ..
2019/10/12  00:27                 0 foo.txt
C:\a>touch.bat foo.txt
C:\a>echo %errorlevel%
0
C:\a>dir
2019/10/12  00:27    <DIR>          .
2019/10/12  00:27    <DIR>          ..
2019/10/12  00:30                 0 foo.txt
```

### 読み取り専用ファイルに対する touch

読み取り専用属性を付与した foo.txt に対する touch

```
C:\a>touch.bat foo.txt
アクセスが拒否されました。
C:\a>echo %errorlevel%
1
```

## 正しくない使い方

特殊ファイルやディレクトリ等、 touch.bat が対応していないファイルに対する touch は 0 が返ります。

### 特殊ファイルに対する touch

```
C:\a>touch.bat nul
C:\a>echo %errorlevel%
0
```

### ディレクトリに対する touch

```
C:\a>mkdir bar
C:\a>touch.bat bar
C:\a>echo %errorlevel%
0
```



# 雑談

バッチファイルの変数展開は、文を評価するタイミング展開されてしまうので、 if 文や for 文の中で変数を更新しようとすると、色々と面倒臭くて嫌いだった。しかし、`touch.bat`を作成していて、初めて便利だと思った。
それは、`copy` が失敗したときの復帰処理が書きやすかったことです。
復帰処理は、`copy` の戻り値を呼び出し元に転送しつつ、`popd`を実行して元のディレクトリに戻る必要があります。つまり、`copy` の戻り値を `exit /b` の引数に渡しつつ、`popd`の実行をすることになります。if文の中で `popd` と `exit /b %errorlevel%` を実行すると、if文を評価するタイミングで `%errorlevel%` が評価されるので、`exit /b` の引数に指定した `%errorlevel%` は `popd` の英共を受けません。その結果、中間変数に `%errorlevel%` の値を保持する必要はなくなります。素晴らしい。
バッチファイルで一時変数を使う場合、 `setlocal` しないと環境変数が汚れるので、できるだけ使いたくありません。その点でも良いと思いました。

# 参考リンク

[【Windows】空のファイルを作成する（Linuxで言うtouch）](https://www.softel.co.jp/blogs/tech/archives/4596)
[Windows OSでファイルの最終変更時刻を更新する（touchコマンドを実現する）](https://www.atmarkit.co.jp/ait/articles/1809/13/news031.html)
[batファイルでコマンドの実行結果を出力しないようにする方法](https://qiita.com/uhooi/items/b8b25761a5c4efe9025a)
[How to test if a path is a file or directory in Windows batch file?](https://stackoverflow.com/questions/8666225/how-to-test-if-a-path-is-a-file-or-directory-in-windows-batch-file)
基準日から何日後の日付、何日前の日付を生成するクエリ with lateral

# まえがき
おもむろにlateral久しぶりに触ってみた。ハンディに環境ほしいとき、**oracle livesql**とっても便利。sql developerぐらいの機能があったら、もっと便利ですごく嬉しい。😆

# 環境
[Now running on Oracle Database 19c](https://livesql.oracle.com/apex/f?p=590:1000:11844577717828:::::)

# 基準日から何日後の日付を生成

サブクエリで基準日と基準日にある日数を足しこんだ値にリニアに1から連番を足した値を用意。

## コラム
>日次処理等使用するため、**保持期間日数**を各テーブルごとにマスタ等で用意して、**レコード更新日時**からの経過日数がマスタの保持期間日数を超過する際は、テーブルデータを削除するようなロジックとかと考え方は通じるものはあると思う。採番系カラムを保持しているテーブルはこの仕組みの管理下にあるんじゃないかなって思っている。運用開始するまえに**全業務**の紐付きを把握しているレベルでないと、最初の設定はできないと思う。最初に設定する人はすごいと思う。日次処理が終わらない場合は保持期間日数を短くしたり。思ったより早く終了したら、保持期間日数を長くしたり。メンテできるようにテーブル設計しておくものなんであろう。あっ、旅人算みたいな間隔なのかな。2人（マスタとトラン）の距離（日数=日次実行日時-レコード更新日時）が縮まる。縮まり方を早めたり、ゆるくしたり。距離が0になったら、削除。日次なので、業務終了後、毎日動く。これがコケてたりすると、番号被ったりして大変。

そういった状況とか想定してテストデータを作成するときに使えるのではないかと思っている。😆
削除されるべきものが削除されて、削除されてほしくないものは削除されずに残っていることを確認するとか。

```sql
WITH sub AS (
SELECT
    LEVEL AS rn
    ,sysdate + level as self
    ,(sysdate +30 ) + level as other
    ,(sysdate +60 ) + level as another
FROM
    dual
CONNECT BY
    LEVEL <= 4
)SELECT
    dense_rank()over(order by s1.rn,s2.rn,s3.rn) as seq
    ,s1.rn as grp1
    ,s1.SELF
    ,s2.rn as grp2
    ,s2.OTHER
    ,s3.rn as grp3
    ,s3.another
FROM
    sub s1
    ,LATERAL(SELECT s2.* FROM sub s2 WHERE s1.self <= s2.other -30) s2
    ,LATERAL(SELECT s3.* FROM sub s3 WHERE s1.self <= s3.another -60) s3
ORDER BY
    s1.RN,s2.RN,s3.RN
;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286037/f0185719-1531-5aeb-4bfc-70390bdcd376.png)

# 基準日から何日前の日付を生成

サブクエリで基準日と基準日からある日数を引きこんだ値にリニアに1から連番を足した値を用意。

## コラム
>ある卸の会社があったとして、製品や食品等管理する際に、製品・食品ごとにいつまでに物流倉庫に入庫して、いつまでには物流倉庫から出庫するといった日付を算出するため、マスタに**許容日数**を管理していることがある。**入庫許容期間日数**・**出庫許容期間日数**とか呼んだりする。業務ないし用途ごとにこの**許容日**の算出の仕方はいろいろだと思うが、「何日までに何する」といったバリエーションはいくつかあると思う。**出庫許容日**から何日超過してますよーと警告したり、あと何日で許容日に到達しますよーと警告したり、食品だったら、**賞味期間日数**をマスタに保持して、入庫時から起算して賞味期間あとこれだけですよーと警告したりすることがある。

そういった状況とか想定してテストデータを作成するときに使えるのではないかと思っている。😆
警告されるべきものが警告対象として扱われ、警告されてほしくないものは警告対象外として扱われていることを確認するとか。

```sql
WITH sub AS (
SELECT
    LEVEL AS rn
    ,sysdate + level as self
    ,(sysdate -30 ) + level as other
    ,(sysdate -60 ) + level as another
FROM
    dual
CONNECT BY
    LEVEL <= 4
)SELECT
    dense_rank()over(order by s1.rn,s2.rn,s3.rn) as seq
    ,s1.rn as grp1
    ,s1.SELF
    ,s2.rn as grp2
    ,s2.OTHER
    ,s3.rn as grp3
    ,s3.another
FROM
    sub s1
    ,LATERAL(SELECT s2.* FROM sub s2 WHERE s1.self-30 <= s2.other) s2
    ,LATERAL(SELECT s3.* FROM sub s3 WHERE s1.self-60 <= s3.another) s3
ORDER BY
    s1.RN,s2.RN,s3.RN
;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286037/631273a2-0a00-7c4a-d881-b12c5f7e1d11.png)

# あとがき
lateralは組み合わせを生み出すとき、大変便利だと思う。日付関連の処理はいろいろ頭使う。こういう処理を漸化的に表現できたら、面白そう。許容日を算出するファンクションを一つ用意するのかな。

はじめてコラム書いてみた。
>[コラム](https://www.google.com/search?q=%E3%82%B3%E3%83%A9%E3%83%A0%E3%81%A8%E3%81%AF&oq=%E3%82%B3%E3%83%A9%E3%83%A0&aqs=chrome.1.69i57j0l5.1872j0j7&sourceid=chrome&ie=UTF-8)
新聞・雑誌などで、線で囲んだ、ちょっとした記事。囲み欄。

以上、ありがとうございました。
KubernetesでRedisを起動してみる

Windows 10
Docker Desktop 2.1.0.3(38240)
　Engine: 19.03.2
　Compose: 1.24.1
　Kuberneteis: v1.14.6

```redis.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  ports:
    - port: 6379
      targetPort: 6379
  selector:
    app: redis
  clusterIP: None
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis.config
data:
  redis.conf: |
    requirepass password
    bind 0.0.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deploymentの名前。Namespace内ではユニークである必要があります
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  # レプリカ数の指定
  replicas: 1
  # Podのテンプレート(PodTemplate)
  template:
    metadata:
      labels:
        # ラベル指定は必須
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:5.0.5
          command: 
            - "redis-server"
            - "/redis-master/redis.conf"
          ports:
            - name: redis
              containerPort: 6379
          volumeMounts:
            - name: data
              mountPath: /redis-master-data
            - name: config
              mountPath: /redis-master
      volumes:
        - name: data
          emptyDir: {}
        - name: config
          configMap:
            name: redis.config
```

```
$ kubectl apply -f .\redis.yaml
$ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
redis-57f99c6c4c-lrqjs   1/1     Running   0          4m26s

$ kubectl exec -it redis-57f99c6c4c-lrqjs bash
root@redis-57f99c6c4c-lrqjs:/data# redis-cli
127.0.0.1:6379> auth password
OK
127.0.0.1:6379> set mykey "abc"
OK
127.0.0.1:6379> get mykey
"abc"
127.0.0.1:6379> exit
root@redis-57f99c6c4c-lrqjs:/data# exit
exit
```
Docker上で自前OpenSSH(sshd)をビルドして動そうとしてコケた話

# 何がしたかったか？

* 研究関連でOpenSSH(のsshd)を自前でビルドして色々試したい事がある
* Mac上でうまくビルドできないし，どこでもビルドできるようにDockerで動かしたい
    * つまりDocker上でビルド，サービス化，接続テストができるように
    * MacのVSCodeで編集，即座にDocker上でビルド，すぐ接続テスト．したい．
* DockerといえばAlpine Linux!!

# 環境とか
* Docker Engine: 19.03.2
* Docker Compose: 1.24.1

* ディレクトリ構造

```text:tree.txt
.
├── docker-compose.yml
├── src
│   └── OpenSSHのソースコード
└── vm
    ├── Dockerfile
    └── login.sh
```

# 最初に試したこと

## 1. 以下のdocker-composeとDockerfileを書いてみた．

```yaml:docker-compose.yml
version: '3'
services:
  sshd-build: 
    build: ./vm # vm/Dockerfileがあるのでそいつをビルド
    image: sshd-build:latest
    container_name: sshd-container
    restart: always
    volumes:
      - ./:/root/openssh-portable # ローカルで開発してDockerでビルド，検証したいので共有
    tty: true # 立てたコンテナの中で動きたいときに書くやつ
```

```bash:Dockerfile
FROM alpine as sshd-linux

WORKDIR /root # rootとして動くのでここを作っとく

RUN apk update && \ # ビルドに必要なパッケージの追加
    apk add --no-cache openrc openssh \ # この２つはAlpineのデーモン登録のため必要
    gcc g++ make openssl-dev zlib-dev bash # これらはビルドのため

ENTRYPOINT ["/bin/bash"]
```

## 2. コンテナへのログイン

```bash:login.sh
#!/bin/bash
docker exec -it sshd-container /bin/bash
```

## 3. ビルドとインストール

```terminal
# cd openssh-portable/src
# ./configure && make && make install
```

# 問題とその解決

## 1. インストール後， デーモン起動を試みるも...

```text:tty
# rc-service sshd start
/lib/rc/sh/openrc-run.sh: line 100: can't create /sys/fs/cgroup/blkio/tasks: Read-only file system
/lib/rc/sh/openrc-run.sh: line 100: can't create /sys/fs/cgroup/cpu/tasks: Read-
... 同様の表示
 * You are attempting to run an openrc service on a
 * system which openrc did not boot.
 * You may be inside a chroot or you may have used
 * another initialization system to boot this system.
 * In this situation, you will get unpredictable results!
 * If you really want to do this, issue the following command:
 * touch /run/openrc/softlevel
 * ERROR: sshd failed to start
```

起動できていない...ここは[海外ニキ](https://github.com/gliderlabs/docker-alpine/issues/437#issuecomment-494200575)を参考にして修正をした．海外ニキ，全体的にエスパーで解決しに来るのでつよい．
今回環境の場合はdocker-composeを使っているのでそこに追加．

## 2. その後も追加でエラー...

* 後半のエラーコード(`You are attempting...`)は消えず．

エラーコードに従って`touch /run/openrc/softlevel`を叩いたら通った．

# 結論

```yaml:docker-compose.yml
version: '3'
services:
  sshd-build: 
    build: ./vm
    image: sshd-build:latest
    container_name: sshd-container
    restart: always
    volumes:
      - ./:/root/openssh-portable
      - /sys/fs/cgroup
    tty: true
```

```bash:Dockerfile
FROM alpine as sshd-linux

WORKDIR /root

RUN apk update && \
    apk add --no-cache openssh openrc gcc g++ make openssl-dev zlib-dev bash

ENTRYPOINT ["/bin/bash"]
```

コンテナ起動後

```terminal
# cd openssh-portable/src
# ./configure && make && make install
# touch /run/openrc/softlevel
# rc-service sshd start
ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519 
 * Starting sshd ... [ok]
# rc-status
Runlevel: sysinit
Dynamic Runlevel: hotplugged
Dynamic Runlevel: needed/wanted
Dynamic Runlevel: manual
 sshd 
```

あとはソースコード書き換えて， `make && make install && rc-service sshd restart`を繰り返す．

# ちなみに

イメージサイズは197MBであった．もう少し小さくしたいな...
その話はまた今度．

あとビルドが遅い．数秒で終わってほしい(願望)