OmniAICreator/Qiita-1.07M huggingface dataset:
未来のnlコマンド


[nlコマンド Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nl)最後の記事です。今後のnlコマンドの方向性についてまとめます。

# GNU coreutils

coreutilsには今後の方針がある程度示されている機能があります。

## 今後もやらないこと

[Coreutils - rejected feature requests](https://www.gnu.org/software/coreutils/rejected_requests.html)
このページにはリジェクトされた機能一覧がまとめられています。実施しないことが決まったにもかかわらず、何度も同じ機能リクエストが投稿されることを防ぐためです。`nl`には過去にリジェクトが決定された機能はありません。

### cat -n

[RE: cat -n with different format?](https://lists.gnu.org/archive/html/coreutils/2012-01/msg00002.html)
`cat -n`については、セパレータのフォーマットを変更したいと要望がありリジェクトされた経緯があるようです。セパレータを`:`に変えたいという要望に対し、「`sed`や`nl`を使えばできるよ」と答えながらも`awk`と`grep -n`の例を示しています。~~そこは`nl -s`の例も示してあげて…~~

## 予定されていること

[TODO](https://github.com/coreutils/coreutils/blob/master/TODO)
coreutilsのリポジトリにはTODOというファイルがあり、今後対応すべきことがまとめられています。しかしながら`nl`に関する項目はありません。


## メーリングリストでの議論

### PBRE

[nl: add way to exclude matching lines from getting numbered!](https://www.mail-archive.com/bug-coreutils%40gnu.org/msg31376.html)
比較的最近の機能提案で、正規表現を用いた付番方式`pBRE`に対して、「正規表現がマッチしなかった行に付番する`PBRE`」という拡張機能が提案されたことがあります。しかし、（bug-coreutilsのメーリングリストに投げてしまったためか？）今のところレスがついていません。

私個人の意見としては、一部の行だけ付番するよりも一部の行だけ**付番から除外する**機会の方が圧倒的に多いと思いますので、拡張する価値はあるんじゃないかなと思います。とはいえ「一部の行だけ」というニーズそのものがどれだけあるのか、というと自信はありません。

## その他

自分なりに案を捻り出してみると、機能改良案は3つあります。

### 処理速度の改良

[この記事](https://qiita.com/Carol_815/items/ae8c1d9adda66d7bd740)に関連して、行番号を付加する専門とする`nl`として`cat -n`より遅いのはちょっと存在価値が危ぶまれると思います。です。もちろんコマンド名が短くタイプ数の少なさでは勝るのですが、選ばれる理由としては少し魅力が乏しいような気がします。

### 最大値の拡張

[この記事](https://qiita.com/Carol_815/items/88153744df5133b0db54)に関連して、行番号として大きな値をカウントすることはなさそうですが、大きな値をサポートしておくことは、coreutilsの他のコマンドとの一貫性を持たせるために意味のあることだと思っています。最近のアップデートでは、`bc`と`factor`がすべての環境でGNU MPを利用するようになりました。MPは任意精度計算ライブラリであり、メモリが尽きない限り整数の最大値制約がなくなります。`seq`や`nl`など整数の供給源となりうるコマンドでも、MPを利用した実装にしてみても良いかもしれません。

### 論理ページ無効化オプション

[この記事](https://qiita.com/Carol_815/items/2066deddbac59a3f83a5)に関連して、結果的に-dオプションのGNU拡張という落とし所の対応になってしまいましたが、本当は独立した新しいオプションとしたほうがわかりやすかったかなと、今更ながらに思っています。

# *BSD

NetBSDをはじめBSDではほとんどコマンドの改良はされていない印象です。

## POSIX

とはいえ、`nl`には[POSIXとの非互換がまだ残っています](https://qiita.com/Carol_815/items/c81a278788978b5901d0)から、機能拡張よりもそちらの対処が先になるでしょう。


# BusyBox

BusyBoxの`nl`においては、当面の実装項目は「論理ページ」のサポートでしょう。しかしながら、「ほとんど使われていない機能との互換」と「フットプリントの増加」のトレードオフは悩みの種となりそうです。

## ソース内のコメント

実際にソースを見ると、論理ページの実装予定はあるようです。「not implemented yet」だそうです。

https://github.com/mirror/busybox/blob/master/coreutils/nl.c

```c
	static const char nl_longopts[] ALIGN1 =
		"body-numbering\0"	Required_argument "b"
	//	"footer-numbering\0"	Required_argument "f" - not implemented yet
	//	"header-numbering\0"	Required_argument "h" - not implemented yet
	//	"section-delimiter\0"	Required_argument "d" - not implemented yet
		"line-increment\0"	Required_argument "i"
	//	"join-blank-lines\0"	Required_argument "l" - not implemented yet
	//	"number-format\0"	Required_argument "n" - not implemented yet
		"no-renumber\0"		No_argument       "p" // no-op so far
		"number-separator\0"	Required_argument "s"
		"starting-line-number\0"Required_argument "v"
		"number-width\0"	Required_argument "w"
	;
```



----
Rails + Docker環境でBetterErrorsを表示する


```
$ docker-compose up
```

コマンドを打っても通常のエラー画面が表示される。

<h1>解決策</h1>

```ruby:config/enviroments/development.rb
if Rails.env.development?
  BetterErrors::Middleware.allow_ip! "0.0.0.0/0"
end
```

このコードを追記する。
BetterErrorsはdevelopmentでしか使っていないらしいです！
なのでenvで条件をつけます！

以上です。。。
自作キーボード6 Elecrowから基盤到着

注文していたElecrowから基盤が、昨日届いた。注文してから2週間弱ぐらいか。

綺麗に梱包されていてずっしりと重い。5枚が最低発注ロットなので、左右合わせて10枚の基板が入っていた。
初めて設計した基盤が形になり感無量だ。
早速開けてみた。

# 開封
![IMG_20201224_225411.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135714/ae747375-9bee-fabe-de7c-3f3e04d46b2c.jpeg)

ちょうどクリスマスだったので、サンタクロースのキーホルダーみたいなものも入っていた。

かなり厳重に梱包されていて好印象

# 左側を取り出してみて寸法とか大丈夫かチェック

![IMG_20201224_230544.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135714/1a5a896f-2c5c-890e-f6b1-0a4ab4b8e3c0.jpeg)

## 寸法チェック
Kicadで設計したときに、自分で作ったフットプリントの寸法精度が心配だったので、
キースイッチがはまるのかやElite-Cのマイコンがきっちり、穴にはまるのか寸法が心配だったが問題なさそうだ。

## 回路のチェック
[テスター](https://amzn.to/3pq43G4)で導通、ショートないかチェックして、
左側しか未だ見てないが、問題なさそう。

## 穴漏れの失敗
失敗はTRRSのスルーホールを開けてなかったことと、
スタビライザー用の穴をあけてなかったこと。
基盤に直接ドリルで穴をあけても良いのかな？

# 支払い料金がおかしい
めっちゃいい買い物したよ。とお得感に浸っていたのだが、支払いがおかしいことに気づいた。

発注の時にクレジットカード支払いをしようとしたらエラーになって完了処理ができなかったため、
Elecrowサポートに確認したところ、Paypalで払うよう指示されたためPaypalで送金した経緯があるのだが、
今日クレジットカード明細を見たところ、2重支払いが発生している。

12/14 Paypal $ 78.84
12/17 Credit Card $ 79.63

あれ？12/17のElecrowへの支払いはおかしい。
最初にクレジットカード支払いでエラーになっていたと思っていた処理が続行されている。

メールでやり取りして、Paypal送金した内容がきちんとオーダに引き継がれてないのだろうと予想。

早速サポートに連絡。
google翻訳で英語化で不安だが、サポートからの返事を待つ。
こんなメールで意味通じるかな、、

```
Dear xxxxxx.  ← Paypal支払いのやり取りを行ったElecrowの担当者

The item arrived yesterday.
Thank you

However, after Paypal payment, payment is also made from credit card and it is doubled.

12/14 Paypal $ 78.84
12/17 Credit Card $ 79.63

What do you mean?
```
<br><br>
<td><font size="6">
Amazon商品へのリンクは「Amazon.co.jpアソシエイト」を使用しています。
「Amazon.co.jpアソシエイト」とは、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイトプログラムである、Amazonアソシエイト・プログラムの参加者です。
</font>
</td>
Linux【コマンド一覧表】

#はじめに
学習用のメモになります。

## Linuxは簡単にいうと、

* Mac OS
* Windows XP
* Windows 10

などと同じOSの種類の一つです。OSとは、`コンピューターのすべてのハードウェアを管理しているソフトウェア`のことです。

Linuxは、主に`サーバー用として使うOS`です。

##カーネルとディストリビューション(Linux）
`カーネル`はOSの中核となるソフトウェア。`ディストリビューション`はカーネルに色々なソフトウェアを組み合わせて使いやすくしたもの

##シェルとは？
シェルはLinuxのCLIを提供するソフトウェア。ユーザーとLinuxカーネルの仲介役（カーネルのインターフェース）をしている。

＊`CLI`とは、キーボードからコマンドを入力し、文字列として結果を出力するインターフェース

## 基本コマンド
|コマンド| 説明　|使用例　|オプション|
|:------:|:------:|:------|:----|
|cd | ディレクトリ（フォルダ）移動| cd 移動フォルダ名|
|ls | フォルダの内容をリスト形式で表示する| 対象フォルダに移動して、ls|-a システムファイル表示   -l ロングフォーマット  -d 指定のディレクトリ情報のみ表示|
|mv| ファイルを移動| mv 移動元　移動先|
|cp | ファイルやフォルダのコピー|cd 移動元　移動先|-i インタラクティブモード　-p ファイルの属性を維持　-R 丸ごとコピー　-v コピーされたファイル名の表示
|clear | 消さずに画面を綺麗にする | |
|mkdir| フォルダを作成する|mkdir 名|-p入れ子のフォルダを一気に作成|
|touch| ファイルを作成する|touch 名|
|rmdir|空のファイルを削除する |rmdir 名|
|rm|ファイルやフォルダを削除する|rm 名|-r ディレクトリとディレクトリ内の全てのファイルを削除。確認は無し
|pwd|現在いる位置を表示する ||
|find|ファイルの検索をする|find / -name 名 |
|cat|ファイルの内容を表示する  |cat ファイル名 |-n 行数表示
|diff|ファイルとファイルの内容の違いを表示する |diff 旧名 新名  |
|grep|指定した文字列がテキスト内に存在した場合その行を抽出する|grep "検索したい文字" * ファイル名|
|chmod|ファイルやフォルダのアクセス権限を変更する|chmod 権限ファイル名|
|chown|ファイルやフォルダのオーナーやグループを変更する|chown 変更したいユーザー名 変更したいファイル名|
|history|コマンドの履歴を表示する||
|ln|ファイルやフォルダにリンクを設定する|ln リンク元　リンク先|
|man|コマンドのマニュアルを表示する|man コマンド|
|apropos|manページの内容を検索する|apropos キーワード|
|less|テキストファイルを閲覧する|less ファイル名|
|more|ファイルをページ単位で閲覧する|more ファイル名|
[ServiceNow]DateTimeのgetValueとgetDisplayValueの違い

日付・時刻をスクリプト内で使用する際はちょっと気を付けないといけない話

##getValueとgetDisplayValue

getValueで取得できるのは、システムのTimezoneを変更していてもUTCのタイムゾーンで値を取得する。
getDisplayValueでは、ユーザのタイムゾーンで値を取得する。

『プロパティ』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/060f9f31-9f23-44ba-4567-faf618cb7c1b.png)

『ユーザ言語』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/7efee2db-1561-760d-9c7e-8d69c549a5c1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/a9be7921-a39d-a764-dc78-66774f979023.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/f1573d61-3589-126d-4998-3f50d51f5fc9.png)

時差によって、日付が変わったりするので気を付けないといけないですね。

ちなみに・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/913d1091-4dd8-2775-3d35-4287207d0256.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922262/d8be6cb0-7d5e-c081-3d13-67d32c42d799.png)

GlideDateの場合だと、getValue、getDisplayValueどちらもUTCでとれるので、0時に動くバッチとかでGlideDateを使用するときは注意が必要。
Could not load NIB in bundle の対処法

ほにゃららという NIB ファイルはあるんだけど、ロードされていないみたい、という現象があった。
なにかの拍子に、Build/PhasesのCopy Bundle Resourcesから該当ファイルが消えていたのが原因だった。
Build/PhasesのCopy Bundle Resourcesの＋ボタンをクリックして該当ファイルを追加したら治りました。

![スクリーンショット 2020-12-25 9.44.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4cda2d7f-255a-9ce0-758f-e3407754926a.png)
🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Ruby 3.0.0の型チェック（rbs）を簡単に試す

[Ruby 3.0.0](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/)がリリースされたので、型チェックを試してみました。

型チェックをするためには、少し準備が必要だったりするので簡単にできる方法を紹介します。

**1.Ruby 3.0.0をインストールする**

```sh
$ rbenv install 3.0.0
$ rbenv local 3.0.0
```

ここでエラーが出る場合は、ruby-buildをアップグレードしないといけないかもしれません。

参考：
rbenv/ruby-buildのアップデート
https://qiita.com/jhanyu/items/38671f7e9f03b77670c0

**2.目的のコードを書く**

このコードを対象に型チェックをしてみます。
`test.rb`というファイル名で保存します。

```ruby:test.rb
class Test
  def myfunc str
    puts str
  end
end

t = Test.new
t.myfunc("test")
```

**3.型情報を書き出す**

typeprofを使うと、型推論をして型情報を書き出してくれます。

```shell
typeprof test.rb > test.rbs
```

`test.rbs`の中身はこんな感じです。

```ruby:test.rbs
$ cat test.rbs
# Classes
class Test
  def myfunc: (String str) -> nil
end
```

今回はtypeprofで生成しましたが、このファイルは自分で定義を指定することもできます。

詳しくはこちらをご覧ください。
ruby/rbs
https://github.com/ruby/rbs

**4.型チェッカー(steep)を準備する**

型チェッカーをインストールします。

なぜsteepをインストールする必要があるのかについてはこちらをご覧ください。

Ruby 3の静的解析機能のRBS、TypeProf、Steep、Sorbetの関係についてのノート
https://techlife.cookpad.com/entry/2020/12/09/120454

```
$ gem install steep
```

steepの初期化をします。

```shell
$ steep init
```

`Steepfile`が出来るのでこれを次のように書き換えます。

```ruby:Steepfile
target :lib do
  check "."
  signature "."
end
```

**5.型チェックをする**

```shell
$ steep check
```

何も表示されません。これは問題がないということです。

**6.わざとおかしい型を使ってチェックしてみる**

元のコードを次のように書き換えます。

```ruby:test.rb
class Test
  def myfunc str
    puts str
  end
end

t = Test.new
t.myfunc(1) # わざStringではない型を使う
```

あらためてチェックします。

```shell
$ steep check
test.rb:8:9: ArgumentTypeMismatch: receiver=::Test, expected=::String, actual=::Integer (1)
```

エラーが出ました。
いい感じですね⭐

**終わりに**

NoteではiOS開発、とくにCoreML、ARKit、Metalなどについて定期的に発信しています。
https://note.com/tokyoyoshida

Twitterでも発信しています。
https://twitter.com/jugemjugemjugem


**参考資料**
Ruby 3.0.0 リリース
https://www.ruby-lang.org/ja/news/2020/12/25/ruby-3-0-0-released/

Rubyで型チェック！動かして理解するRBS入門 〜サンプルコードでわかる！Ruby 3.0の主な新機能と変更点 Part 1〜
https://qiita.com/jnchito/items/bf8c6c2e1dd6cff05f4e
bitbake のログファイル名確認方法

# bitbake のログファイル名確認方法

## 方法

```
bitbake -e <recipename> | grep ^T=
```

### 具体例　(linux kernel)

```
bitbake -e virtual/kernel | grep ^T=
```

### 具体例　(bootloader)

```
bitbake -e virtual/bootloader| grep ^T=
```


## リンク

https://wiki.yoctoproject.org/wiki/Technical_FAQ#Where_do_I_find_build_logs.3F
border(-top,-bottom)の長さを設定したい時 #教えて工藤さん

例えば一つのdivタグで括った項目にそれぞれ下線などを引きたい時、一般的な長さでもいいのですが差別化を図るため長さを設定したい時は
・widthを設定する。(要素の長さにborderが比例するため。）
・marginを０にする。(widthの設定をすると謎のmarginが割り込んできた為。）

以上
第十一回



# class


## 概要

今回はクラスについて取り扱っていく．基本rubyでは，クラス名はアルファベットの大文字で始めなければならない．クラス定義は，識別子で指定した定数へのクラスの代入になる．クラスがすでに定義されているとき，同じクラス名でクラス定義をかくとクラスの定義の追加になる．ただし，元のクラスと異なるスーパークラスを指定するとTypeErrorを起こすので注意．


## プログラム

以下，サンプルプログラムとなる．

```ruby:hello_class.rb
class Greeter
  def initialize
    @name = gets_name
    puts_hello
  end
  def puts_hello
    puts "Hello #{@name}."
  end

  def gets_name
    name = ARGV[0] || 'world'
    return name
  end
end

Greeter.new
```

これを実行すると

    C:\Users\nobua\M1>ruby hello_class.rb
    Hello World.
    #->何も入力しない場合
    
    C:\Users\nobua\M1>ruby hello_class.rb Ruby
    Hello Ruby.　　　
    #->Rubyと入力した場合

と出力された．


## 解説

本プログラムのGreeterクラスは・initialize・puts\_hello・get\_nameの三つのメソッドで構成されている．初めにgets\_nameでターミナルで受け取ったワードかあらかじめ用意しておいたworldをローカル変数nameに代入し，頭文字を大文字に変換する．次にメソッドinitializeにおいて，インスタンス変数@nameにgets\_nameで定義したnameを代入し，puts\_helloを呼び出す．puts\_helloではinitializeで定義された@nameを受け取り，"Hello #{@name}"の形で出力する．これが本プログラムの流れとなる．


# classの継承


## 概要

classの欄で言及したように，クラスは既に作成されているとき，そのクラスを拡張して新しいクラスを作成することができる．これをクラスの継承という．


## プログラム

クラスを継承する方法を以下のプログラムで確認していく．

```ruby

class Greeter < String
  def hello
    "Hello #{self}."
  end
end

class String
  def hello
    "Hello #{self}."
  end
end

greeter = Greeter.new(ARGV[0])
puts greeter.hello

```

プログラムではGreeterクラスがStringクラスを継承しており，StringクラスはGreeterクラスの親クラスといい，GreeterクラスはStringクラスの子クラスという．


# 参考文献

<https://www.javadrive.jp/ruby/inherit/index1.html>

<https://qiita.com/daddygongon/items/969ad5112878f6dab844>



------
 - **source** ~/grad_members_20f/members/NobuakiMori/L11_class.org
[Elixir/Nerves] 温度センサや環境センサを選ぶ

## はじめに

世の中には、当然色んな温度センサや環境センサが存在しますが、どう選べばいいのかわからないので、ちょっと調べてみました。

![](https://res.cloudinary.com/practicaldev/image/fetch/s--VwudcUW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/7563926/103111408-b550d680-461a-11eb-8140-48adefe99eb2.gif)

## [DHT11](https://www.google.com/search?q=DHT11)、[DHT22](https://www.google.com/search?q=DHT22)、[AM2302](https://www.google.com/search?q=AM2302)

- 電子工作やラズパイの初心者向け文脈では[DHT11](https://www.google.com/search?q=DHT11)が頻繁に登場。
- DHT11もDHT22もAM2302も若干の仕様が異なるだけでほとんど似たようなもののようです。
- [1wire](https://ja.wikipedia.org/wiki/1-Wire)に似ているがことなる謎のプロトコルをつかっているらしい。
- Elixirライブラリの[jjcarstens/dht](https://github.com/jjcarstens/dht)
  - [Adafruit Python DHT](https://github.com/adafruit/Adafruit_Python_DHT)のCコード（サポート終了）をポートしたもの。
  - Nervesとrpi0で動作確認OK。
  - ホストマシンで`mix test`したら、コンパイルエラーがでた。原因不明。
  - 今後メンテされることもなさそうなので、大事なプロジェクトには向いていないと思われる。

## [AHT20](https://www.google.com/search?q=AHT20)

- DHT11の新しい版？
- I2Cでシリアル通信。
- [データシート](https://cdn-learn.adafruit.com/assets/assets/000/091/676/original/AHT20-datasheet-2020-4-16.pdf?1591047915)にある換算方法を使い、取得したデータを簡単に温度と湿度に変換できる。
- @myasuさんの「[Elixir Circuits I2Cで温度・湿度測定 (AHT20)](https://qiita.com/myasu/items/97f208d14ccfab01d1d7)」がデータ取得方法の説明がわかりやすい。　
- [Nerves JP](https://nerves-jp.connpass.com/)の@takasehidekiさんも[オススメ](https://qiita.com/torifukukaiou/items/dc54108e4a1f1cb3a650#comment-c84820a6d331ae918904)なので間違いなし。

## [BME280](https://www.google.com/search?q=bme280)、[BME680](https://www.google.com/search?q=bme680)

- Bosch製
- I2CとSPIの両方使える。
- BME680は値段が高いが複数のセンサが一つの基盤にコンパクトに収まっているので、考えようによってはお買い得かも。
- メーカーがドライバーを提供してくれる。[BoschSensortec/BME280_driver](https://github.com/BoschSensortec/BME280_driver)
- それをElixirにポートした[lucaong/elixir_bme680](https://github.com/lucaong/elixir_bme680)でBME280とBME680の両方を使える。

## さいごに

またあたらしいことが分かったら追記していこうと思います。

## Links

- [Nervesならできるもん！ |> 本当にできんのか！ (Elixir)](https://qiita.com/torifukukaiou/items/dc54108e4a1f1cb3a650#comment-b7c9da8306e623e125a3) by @torifukukaiou
- [DHT11, DHT22 and AM2302 Sensors | Adafruit](https://learn.adafruit.com/dht)
- [Help connecting a Temperature/Humidity sensor | Elixir Forum](https://elixirforum.com/t/help-connecting-a-temperature-humidity-sensor/28174/10)
- [AHT20 データシート](https://cdn-learn.adafruit.com/assets/assets/000/091/676/original/AHT20-datasheet-2020-4-16.pdf?1591047915)

[![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F131808%2Fe310d56e-c416-ad39-d05d-23a375862eda.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&w=1400&fit=max&s=cf23bced73068a2d05463d5da816cef4)](https://nerves-jp.connpass.com/)
【Laravel】キューを使う上で知っておきたいこと

# 参考
キュー 6.x Laravel
https://readouble.com/laravel/6.x/ja/queues.html

# ワーカの起動方法
workとlistenの2種類がある。

## queue:work
> キューワーカは長時間起動するプロセスで、メモリ上にアプリケーション起動時の状態を保存していることを記憶にとどめてください。そのため、開発段階ではキューワーカの再起動を確実に実行してください。付け加えて、アプリケーションにより生成、もしくは変更された静的な状態は、ジョブ間で自動的にリセットされないことも覚えておきましょう。

> デーモンキューワーカは各ジョブを処理する前に、フレームワークを「再起動」しません。そのため、各ジョブが終了したら、大きなリソースを開放してください。たとえば、GDライブラリでイメージ処理を行ったら、終了前にimagedestroyにより、メモリを開放してください。

> キューワーカは長時間起動プロセスであるため、リスタートしない限りコードの変更を反映しません。ですから、キューワーカを使用しているアプリケーションをデプロイする一番シンプルな方法は、デプロイ処理の間、ワーカをリスタートすることです。queue:restartコマンドを実行することで、全ワーカを穏やかに再起動できます。

通常のワーカを立ち上げる。
`queue:listen`と違いフレームワークを再起動しないため、デプロイ後はワーカを再起動しない限り、古いコードが動き続けてしまう。
また、完全にメモリを開放しないため、コードの内容によってはメモリリークが発生する可能性がある。
ワーカ再起動には`queue:restart`を使う。
これはgraceful restartであり、ワーカは既存のジョブが完了したタイミングで再起動される。

## queue:listen
> queue:listenコマンドを使えば更新したコードをリロード、もしくはアプリケーションの状態をリセットしたい場合に、手動でワーカをリスタートする必要がなくなります。しかし、このコマンドはqueue:workほど効率はよくありません。

1ジョブごとにフレームワークを再起動するワーカを立ち上げる。
ジョブごとにメモリが開放され、コードが再読み込みされるため安心。
ただし、オーバーヘッドが大きい。

# ワーカの終了方法
## デフォルト
> queue:work Artisanコマンドを使いワーカを実行できます。queue:workコマンドが起動したら、皆さんが停止するか、ターミナルを閉じるまで実行し続けることに注意してください。

ジョブが無くてもワーカは動き続ける。
例) `php artisan queue:work`

## once
> --onceオプションは、ワーカにキュー中のジョブをひとつだけ処理するように指示します。

1つのジョブを実行した後にワーカを終了する。
例) `php artisan queue:work --once`

## stop-when-empty
> --stop-when-emptyオプションは、すべてのジョブを処理してから終了するように、ワーカへ指示するために使用します。

全てのジョブを実行した後にワーカを終了する。
例) `php artisan queue:work --stop-when-empty`

# ジョブの排他制御方法
[Cron タスクスケジューラの onOneServer() と withoutOverlapping() の違い](https://qiita.com/mpyw/items/15d14d920250a3b9eb5a "Cron タスクスケジューラの onOneServer() と withoutOverlapping() の違い") を読む

# MaxAttemptsExceededExceptionとの接し方
[MaxAttemptsExceededExceptionと戦って気付いたこと](https://qiita.com/_hiro_dev/items/e8e608a53bb29c13ce04 "MaxAttemptsExceededExceptionと戦って気付いたこと") を読む
Wio TerminalでBluetooth（その１）

# Wio TerminalでBluetoothを使う
[Wio Terminal](https://wiki.seeedstudio.com/jp/Wio-Terminal-Getting-Started/)でBluetoothを扱う日本語の記事をあまり見かけないなので、備忘録としてここに残す。

## 本家本元サイト
とは言っても、本家本元との[こちら（英語）](https://wiki.seeedstudio.com/Wio-Terminal-Bluetooth-Overview/)に従って進める。ただし、つまづいた点もある。

## 基本環境
Windows10上でのArduino IDE利用。[Wiki](https://wiki.seeedstudio.com/jp/Wio-Terminal-Getting-Started/)に従って準備する。

## Bluetoothを使うまでの設定
### SAMD51からRTL8720へのシリアル通信を有効化
[こちら](https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/#update-the-wireless-core-firmware)にそって、WiFi&Bluetooth用のFirmwareをUpdateする。まずは、SAMD51からRTL8720へのシリアル通信を行うための「rtl8720_update_v2.uf2」をDownloadする。Chromeでは警告が出るが無視して進める。電源ボタンをクイックに２度スライドすると、Wio TerminalがMass Storageデバイスとして認識される。
![MassStorage1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/5274df21-c6ca-99f5-9db7-893f4c7c4513.png)
![MassStorage2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/54bef1d9-c68b-0516-3d77-cb364151ce37.png)
Downloadした「rtl8720_update_v2.uf2」をここにコピーする。すると、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/1b3b4fcd-a398-ff28-1aa6-e3303e5f175a.jpeg", width=50%>
というメッセージがLCDに表示される。

### Firmware Update
次に最新のFirmwareを[ここ](https://github.com/Seeed-Studio/seeed-ambd-firmware/releases)からDownloadする。今回は"JP"がついているものを使った。CLIによるUpdateを行う。Firmwareを焼くツールをDownloadする。（gitは別途インストールしておく。）

```
F:\Workspace\Arduino\WioTerminal\> git clone https://github.com/LynnL4/ambd_flash_tool
```

amid_flash_toolフォルダができる。
![FlashTool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/1a9ff321-c4ed-ae9e-89f9-37c62cd7eb5c.png)
この中のfirmwareフォルダにDownloadしたFirmwareを格納する。
![Firmware.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/9fbfa5c0-f817-f795-6582-ede85963bf30.png)
Firmwareの更新（erase&flash）を行う。

```
F:\Workspace\Arduino\WioTerminal\ambd_flash_tool> ambd_flash_tool.exe erase
Erasing...
All images are sent successfully!
Image tool closed!

Success!

F:\Workspace\Arduino\WioTerminal\ambd_flash_tool> ambd_flash_tool.exe flash
copy img to workspace...
Flashing...
All images are sent successfully!
Image tool closed!

Success!
```

## ライブラリのインストール＆サンプルプログラムのビルド
Arduino IDEからZIP形式のBluetooth関連ライブラリをインクルードする。
- [Seeed_Arduino_rpcBLE](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE)
- [Seeed_Arduino_rpcUnified](https://github.com/Seeed-Studio/Seeed_Arduino_rpcUnified)
するとサンプルプログラムも同時にインストールされる。
![BTsample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/d33a949d-c93c-8e42-cffc-e2d98326f606.png)
しかし、このままでは、Seeed Arduino rpcBLEおよびSeeed Arduino rpcUnifiedのサンプルプログラムをビルドすることができなかった。調べると、
- [Seeed_Arduino_FreeRTOS](https://github.com/Seeed-Studio/Seeed_Arduino_FreeRTOS)
が必要であった。このライブラリをDownloadし、同じようにArduino IDEに組み込みことにより、サンプルプログラムをビルドすることができる。

## 補足
上記サンプルプログラムは、Wio TerminalのメインプロセッサであるSAMD51用のようだ。どうも、Aruduino IDEを用いて、WiFi＆Bluetooth用のプロセッサRTL8720を直接ハンドリングできる方法がある。

なので、続き（その２）を考えてみる。
PostgreSQL バージョン不整合によるエラーの修正方法

AWS の RDS を使っていて、PostgreSQL のバージョンが 12 だが、EC2のバージョンが 10 なので、psql のバージョンが古いために、\d <テーブル名> で、以下のエラーが出力される。

```
ERROR:  column c.relhasoids does not exist
LINE 1: ...riggers, c.relrowsecurity, c.relforcerowsecurity, c.relhasoi...
```

postgresql12のレポジトリを追加して、現在の postgresql10パッケージを削除、レポジトリを直接指定してpostgresqlのバージョン12をインストールしたら、直った。

（参考）
https://techviewleo.com/install-postgresql-12-on-amazon-linux/
Z2JH8(Zero to Jupyter Hub)のhubポッドに対するsqlitedbストレージ設定

JupyterNotebookを使う環境を構築したく、Z2JH(Zero to JupyterHub)をhelmを使って導入していたらsqlitedbを格納するディレクトリ設定に悩んだのでメモを残しておきます。

#### 対象バージョン

```
 jupyterhub : 0.10.2
 (https://jupyterhub.github.io/helm-chart/jupyterhub-0.10.2.tgz)
```

#### 公式ガイドを見ても設定ファイルが見当たらない
ガイド<a href="https://zero-to-jupyterhub.readthedocs.io/en/0.10.2/resources/reference.html">(https://zero-to-jupyterhub.readthedocs.io/en/0.10.2/resources/reference.html)</a>を見ても、annotationなどの間接的な指定方法は記載あるものの、直接的に設定できる方法が見当たらなかった。

```
hub.db.pvc
　Customize the Persistent Volume Claim used when hub.db.type is sqlite-pvc.

hub.db.pvc.annotations
　Annotations to apply to the PVC containing the sqlite database.
　See the Kubernetes documentation for more details about annotations.

hub.db.pvc.selector
　Label selectors to set for the PVC containing the sqlite database.
　Useful when you are using a specific PV, and want to bind to that and only that.
　See the Kubernetes documentation for more details about using a label selector for what PV to bind to.

hub.db.pvc.storage
　Size of disk to request for the database disk.
```

#### 設定ファイルを探ってみる
helmでは設定内容をリストアップすることができるので、やってみます。

```
# helm inspect values jupyterhub/jupyterhub
```

コマンド実行結果。`storageClass:`が設定できる事が見つかりました。

```
hub:
 <途中略>
  db:
    type: sqlite-pvc
    upgrade:
    pvc:
      annotations: {}
      selector: {}
      accessModes:
        - ReadWriteOnce
      storage: 1Gi
      subPath:
      storageClassName:　←ココ！
```

helmの設定ファイルに記載します。

```yaml:config.yaml
hub:
  db:
    pvc:
      storageClassName: local-jupyter-hub-storage
      accessModes:
        - ReadWriteOnce
```
【Laravel】MaxAttemptsExceededExceptionと戦って気付いたこと

MaxAttemptsExceededExceptionと10時間くらい戦って気付いたことを書きます。

# 環境
- PHP 7.4.3
- Laravel Framework 6.14.0

# この例外 is 何
> has been attempted too many times or run too long. The job may have previously timed out.

ジョブのタイムアウト時、もしくはジョブの試行回数が設定値を超えた場合に発生する。

# この例外が発生する条件
この例外に関連する登場人物（設定値）は以下の3つ。

- timeout
- retry_after
- tries

このいずれかの設定値が間違っていると、意図せずこの例外が吐かれる可能性がある。

# 設定値について
ジョブ自体に設定することもできるし、ジョブ実行時にオプションで設定することもできる。
どちらも設定した場合は、ジョブ自体に設定したほうが優先される。
retry_afterに関してはconfig/queue.phpでしか設定できないっぽい。

## ジョブ自体に設定する場合
```php
...

class ExampleJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Notifiable;

    public $timeout = 1; // タイムアウト秒数
    public $tries = 1; // 試行回数

    ...
}
```

## ジョブ実行時に設定する場合
```bash
$ php artisan queue:work --timeout=1 --tries=1
```

## retry_afterの設定
バックエンドサービスにdatabaseを使う場合の例です。

```php:config/queue.php
    'connections' => [
        ...
        'database' => [
            'driver' => 'database',
            'table' => 'jobs',
            'queue' => 'default',
            'retry_after' => 1,
        ],
        ...
    ],
```

# 気付いたこと
## timeoutを設定する場合、retry_afterも設定する必要がある
> キュー 6.x Laravel
https://readouble.com/laravel/6.x/ja/queues.html
>> --timeout値は、最低でも数秒retry_after設定値よりも短くしてください。これにより、与えられたジョブを処理するワーカが、ジョブのリトライ前に確実にkillされます。--timeoutオプションをretry_after設定値よりも長くすると、ジョブが２度実行されるでしょう。

timeoutだけを設定して安心してはいけません。それは罠です。
retry_afterをtimeoutより長く設定しないと、ジョブが意図せず再試行され、MaxAttemptsExceededExceptionに繋がる可能性があります。

## tries=0にするとfailedメソッドが動かなくなる
tries=0でジョブを実行すると、例外発生時にfailedメソッドが動作しません。
triesの設定値は1以上を推奨します。

# 余談
[キューを使う上で知っておきたいこと](https://qiita.com/_hiro_dev/items/eef6778179e692507c84 "キューを使う上で知っておきたいこと") も書いてみました。
こちらも参考になるかもしれません。
RaspberryPi 4 上の FreeBSD で USB接続のWebカメラ + OpenCV ネコの顔抽出を試す

# RaspberryPi4 で Webカメラが動くようになった

RaspberryPi3/4 の aarch64環境では純正のカメラモジュールが動きませんが USB 接続のWebカメラはどうでしょうか？
実はRaspberryPi3/4 上のFreeBSDで USB接続のWebカメラが動かない(デバイスとして認識されるが、画像が取得できない）状態がしばらく続いていました。同じ aarch64の Pine64ではWebCamが動いていたのですが...。
ですが最近の RaspberryPi4 環境でやっとこさ Webカメラが動くようになったので、ついでにお約束の OpenCV の顔認識ができるかどうかやってみました。

RaspberryPi4 は 8G を[こちらの記事](https://qiita.com/s_mitu/items/8ac2983230a293e3d212)で設定したやり方で設定したものです。

ためした Webカメラは大昔に買った https://www2.elecom.co.jp/multimedia/pc-camera/ucam-c0220fb/ ですが、UVC（USB Video Class）形式ならば動く可能性が高いと思います。

#Webカメラ設定

Webカメラの設定は、RaspberryPi でもPC(amd64) も同じです。

* cuse.ko のロード
* webcamd の pkg インストール
* Webカメラを使いたいユーザーを webcamd グループに追加
* webcamd を起動

以上のことを、スクリプトにまとめました。pkg install webcamd した後、こちらにあるスクリプト

https://github.com/s-mitu/FreeBSD-raspberrypi-make/blob/master/setup-webcamd.sh

を実行して再起動すれば、Webカメラが使えるようになっていると思います。

# OpenCV インストール

現時点(2020/12/25)ではaarch64 の pkg に opencv (graphics/opencv)と python3.7用 python パッケージ py37-opencv(graphics/py-opencv) が無いので、ports でビルドしてインストールします。graphics/py-opencvをmake install すれば、依存関係で graphics/opencv も入ります。
<pre>
# cd /usr/ports/graphics/py-opencv
# make install
</pre>

これでpython からカメラ画像が取得できるようになっているはずです。

```camera.py
#!/usr/local/bin/python3.7

import cv2

cap = cv2.VideoCapture(0)

result, frame = cap.read()

cv2.imwrite('camera.jpg', frame)
```
上記スクリプトを実行して、camera.jpg カメラ画像が取得できていれば設定成功です。

#ネコの顔抽出

OpenCV をインストールと、人間の顔やら目やら全身などいろんなものを抽出するためのカスケード分類機がインストールされます。
その中にネコの真正面顔抽出なんてのもあるので(/usr/local/share/OpenCV/haarcascades/haarcascade_frontalcatface.xml)ネコ好きとしてはちょっとこれを試してみようかということで、やってみました。

[こちらの記事](https://qiita.com/yuta_0709/items/1e3295796b66d3dae1b5)を参考にし、

カメラ撮影
↓
ネコの顔を矩形で抽出
↓
矩形描画
↓
画像保存

のループを行うスクリプトを作成しました。
実行すると、猫画像を検出した場合に /tmp/cat.png が更新され続けます。

```cat.py
#!/usr/local/bin/python3.7

import cv2
import time

cap = cv2.VideoCapture(0)

cascade_path = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalcatface.xml"
cascade = cv2.CascadeClassifier(cascade_path)
color = (255, 255, 255)

while True:
	ret, frame = cap.read()
	if ret != True:
		continue
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	rect = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30))
	if len(rect) > 0:
		for x, y, w, h in rect:
			cv2.rectangle(frame, (x, y), (x + w, y + h), color)
		cv2.imwrite('/tmp/cat.png', frame)
	time.sleep(1)
```

我が家のクロ氏の協力が得られなかったので、動物園で撮影したマヌルネコのアズさんの画像で試しています。PC画面をWebカメラで撮影して、RaspberryPi4 で撮影した画像をまた PC で表示させています。
動かしてみると、壁の変な模様などを認識してしまいがちで、下のようにきれいに認識はなかなかしてくれませｎ。

![スクリーンショット_2020-12-26_00-49-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103137/14482267-6509-69e9-3d0d-83c54b34a0d2.png)

カメラ画像が使えるようになるとできることが広がるので、GPIOなどと組み合わせて変なものが作れないかなぁ。
NetlifyのDNSレコードで“This is a system record that cannot be managed directly.”の対処法

## 問題

下の画像のように、`api`サブドメインと同じように`assets`サブドメインを追加しようとしたところ、`assets`サブドメインが`A`レコードになっていないので、削除したいけど、なぜか削除できません。

> This is a system record that cannot be managed directly.

と表示されています。
このレコードが削除できないと`A`レコードも追加できないので、少し焦ります。

![スクリーンショット 2020-12-25 0.05.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/7000c917-ce5c-be1b-ee2b-17ccb64f7479.png)

## 原因

ドメイン追加のときに、`Add new record`ではなく、`Add domain alias`してしまっていて、`A`レコードではなく、Netlifyエイリアスのレコードを追加しているのが原因です。

また、Netlifyでは、おそらく事故防止のために、Netlifyエイリアスはユーザによって削除できないようになっています。

## 解決方法

コンソールからの操作では削除できないようになっているので、Netlifyのサポートに問い合わせて、レコードを削除できるようにしてもらう必要があります。

Netlifyのサポート([https://www.netlify.com/support/](https://www.netlify.com/support/))にアクセスし、以下のように問い合わせします。

![スクリーンショット 2020-12-25 0.27.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/0dfee341-d813-7f79-7901-721e40cb4233.png)

問題が発生しているDNSレコードを特定してもらうために、以下の情報は全て伝えましょう。
* 削除できなくて困っているDNSレコードのドメインのホスト名
* 削除できなくて困っているDNSレコードのドメイン名
* NetlifyにログインしているGithubのユーザ名
* Netlifyに使用している（もしくはGithubで使用している）メールアドレス
* 削除できなくて困っているDNSレコードそのままのコピペ

私が実際に使用した文章のテンプレートは以下の通りです。適宜書き換えてご利用ください。

```
Unable to delete DNS records of type NETLIFY. Please change it so that it can be deleted.

The DNS information is as follows.

* The record that cannot be deleted : assets.example.com
* Site URL : example.com
* Github user name : Michin0suke
* registered mail address : info@example.com
* target record detail : assets.example.com, 3600, IN, NETLIFY, example.netlify.app
```

> Netlifyのサポートでは無料ユーザでも対応してもらえますが、有料ユーザが優先されるので、無料ユーザの場合は返答まで時間がかかるかもしれません。私はProユーザでしたが、返答までちょうど24時間でした。

しばらくすると、Netlifyのおじさんからメールが来ます。
![スクリーンショット 2020-12-26 5.07.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/e2b84cfe-9702-4bb0-15fc-0c302b49aafb.png)

NetlifyでDNSレコードを確認すると、Netlifyエイリアスのレコードが削除できるようになっているので、削除しましょう。問題が発生しているNetlifyエイリアス以外のエイリアスも削除できてしまうので、削除を行う場合は慎重に行ってください。

![スクリーンショット 2020-12-26 4.42.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/9f9f3ac7-c8eb-e439-ccae-d423413100d9.png)
[Docker] could not find an available,  non-overlapping IPv4 address pool among the defaults to assign to the network エラー

##はじめに
dockerが立ち上がらなくなり、下記のエラーを対処したので備忘録として記事を作成しました。

##エラー
```
ERROR: could not find an available, 
non-overlapping IPv4 address pool among the defaults to assign to the network
```

#原因
使用可能なIPv4アドレスプールが見つからないとの事
デフォルトだとネットワークは最大30個までしか作れないとの事

下記コマンドでネットワーク一覧を見ることができる

```
docker network ls
```

##対処方法
```
docker network prune
or
docker network rm ネットワークID
```


##参考
https://qiita.com/tksugimoto/items/e42b0d6931898671734f
右クリック押しながら左クリックでブラウザのタブを閉じたい（AutoHotKey）

左クリックが効かなくなる問題が起きた

[RButton + LButton = Keystroke - Ask for Help - AutoHotkey Community](https://autohotkey.com/board/topic/95410-rbutton-lbutton-keystroke/)

```
#InstallMouseHook
$RButton::
Send {RButton down}   ;hold it down
KeyWait, RButton          ;wait for user to release it
Send {RButton Up}        ;release it
return
```

これ追記すればいいよって書いてあったので

```
#InstallMouseHook
$RButton::
Send {RButton down}   ;hold it down
KeyWait, RButton          ;wait for user to release it
Send {RButton Up}        ;release it
return

#IfWinActive ahk_exe chrome.exe
RButton & LButton::^w
#IfWinActive
```

こんな感じでchromeだけ反応するようにした。
めっちゃ快適！！！
TypeScriptのenum型のキー名を取得する

TypeScriptにはJavaScriptにない機能がたくさんあり、その一つとしてenum型がある。

例えば果物の種別をenum型で定義すると、`Fruits.Apple`は0、`Fruits.Orange`は1のように連続した値が割り当てられる。

```ts
enum Fruits {
    Apple,
    Orange,
    Banana,
}
```

逆に0から`Apple`という文字列を求めたい時は以下のようなコードを書いていた。

```ts
function getkeyName(value: Fruits) {
    if (value === Fruits.Apple) {
        return 'Apple';
    } else if (value === Fruits.Orange) {
        return 'Orange';
    } else if (value === Fruits.Banana) {
        return 'Banana';
    }
}
```

ところがTypeScriptでは*enum型[enum型のvalue]*と書くことにより、キー名が取得できる。

```ts
function getKeyName(value: Fruits) {
    return Fruits[value];
}
```

前のコードより短く書けた。

これに限らずTypeScriptにはいろいろな書き方があるので、公式ドキュメントを読み漁ったりするとよりスマートな記述が可能になることが多いと思った。
getter setterについて

#はじめに
現在Javaを学習しており、継承についての記事を書こうと思っていたが、書いている途中でgetter setterの説明ができないことに気づき急遽題材を変えてこの記事を書くことにした。

#存在意義やその定義
カプセル化する際、フィールドを全てprivate にすると外部からの読み書きが一切できなくなる。そこで登場するのがgetter setterである。言い換えると本来アクセスできないはずのprivateフィールドに、getter setterを経由してアクセスすることができるようになる、と言うことである。
また、『外部から自由に読めるようにしたいが、内容を書き換えられると困る』際に使われたり、将来的に何らかの理由でフィールド名を変更したい時( 例えばname から names )に、変更がしやすいといったメリットもある。

**●getterメソッドの定石**
public　フィールドの型　getフィールド名( ) {
　　return this.フィールド名;
}

**●setterメソッドの定石**
public　void　setフィールド名　(フィールドの型　任意の変数名) {
　　this.フィールド名 = 任意の変数名;
}

それぞれについて具体的なコードを書きながら見ていこう

#"getter" を使ってみよう
```Java
//Humanクラス
public class Human {
  void eat (Noodles r) {
    System.out.println (r.name + "を食べた");
  }
}

//Noodlesクラス
public class Noodles {
  private String name = "ラーメン"; 
  //nameフィールドが private によって他(ここではHuman)クラスからは見えない
}
```

上記の例だと、次のようなコンパイルエラーが発生。

######結果
```Java
name は Noodles で private アクセスされます
```
エラー文の意味... name は private によって外部からアクセスできない

そこで、Noodles クラスに getName メソッドを追加して、Human (人間) がNoodles (麺) の名前、言い換えると name フィールドの値、を知ることができるようにする。

```Java
//Humanクラス
public class Human {
  void eat (Noodles r) {
    System.out.println (r.getName() + "を食べた");  //修正箇所  --①
  }
}

//Noodlesクラス
public class Noodles {
  private String name = "ラーメン"; 
  
  public String getName() {                      //修正箇所
    return this.name;                            //--②
  }
}
```

上記の getter メソッドでは何をしているかというと、外(ここでいうHuman)のメソッドから getter を呼び出し(--①)、その戻り値として Noodles クラスの name フィールドの値を戻し(--②)ている。

#"setter"を使ってみよう
```Java
//Humanクラス
public class Human {
  void eat (Noodles r) {
    r.setName("うどん");                          //--③
  }
}

//Noodlesクラス
public class Noodles {
  private String name = "ラーメン"; 
  
  //setterメソッドを追加
  public void setName(String name) {            
    this.name = name;
  }
}
```

上記の setter メソッドでは何をしているかというと、Noodles クラス内に setter メソッドを定義し、外部から呼び出す(--③)ことによって、引数にした値を代入(ラーメン から うどんに値を書き換え)している。

#まとめ
ここまで getter setterの記事を書いてきたが、実はこの2つは無いのが理想的である。特にsetterに関してはメソッドを呼び出す手間を加えることによって値を変更できるので、使わない方が良い。getter に関しても、ほぼ参照しているだけだが使わない方が良い。らしい。
ではここで、 private の中の値を知りたい時どうすればいいのか？と言う疑問が生まれるが、それについては追々記事にできたらな、と。
現在勉強中の身ということもあり、間違ってる箇所もあるかと思いますがその時は教えていただけますと幸いです。
【Vue.js】Vue Selectでリストに候補がない時の「Sorry, no matching options.」を変更する

vue-selectで入力した時に、リストに候補がない場合に表示される「Sorry, no matching options.」を設定する方法です。
![スクリーンショット 2020-12-26 2.05.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410392/e188f5cf-dfe7-c23e-e103-740eac1973eb.png)

## slotを使う
```vue

      <v-select :options="prefectures" v-model="selected" label="name" :reduce="options => options.id">
        <span slot="no-options">検索候補がありません</span>
      </v-select>
```

v-selectの間に`slot="no-options"` を追記し、任意の文を設定することができます。
![スクリーンショット 2020-12-26 2.12.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410392/04fd2c9a-9ec4-8326-95c3-5fc3bdb1be2a.png)

## 参考
- [Vue Select - Improving the default no-options text](https://vue-select.org/guide/slots.html)

入力前と入力後で違う内容を表示したり、入力した文字をメッセージに反映させることもできます。
MSIのマザーボードで構築したマシンでExcel導入にはまった件

個人メモですが、同様の現象が発生している方はご参考ください。

私は自宅PCを5年ごとに自作しており、2020年はまさにそのタイミングだった。
今年の夏はずっと在宅勤務で、長期休暇もコロナ禍で遠出できず、私は家で鬱々とした日々を過ごしていた。
そんな中だからこそ、来るべきPC新設というイベントは本当に楽しみであり、私は毎日仕事終わりにCPU, メモリ, FANなど、各PCパーツの性能や値段をネット上で比較するのが癒しの時間だった。

8月下旬にその日はやってきた。
この日までにネットやドスパラ、ツクモなどでパーツを買い集め、部屋の片隅に積んでおいた。
旧PCの解体も済ませ、まだ価値のあるパーツは清掃後、ヤフオクへ出品した。
あとは組み立てるのみである。
組み立てはスムーズに進んだ。
初めて大型FAN(忍者５)を採用したこともあり、取り付けに戸惑う工程もあったが、手戻りもなく、
組み立てた後の起動チェックもすんなりと通った。
ハードの後はソフトということで、各種のアプリの設定やCPUの制御をこなす必要があったが、
操作していて、以前より遥かに優れたスペックを実感出来たので、感動しながらアッという間に進めることが出来た。
ーーそう、Officeをインストールするまでは。

Officeのインストール後、PowerPointが一瞬で開くことに感動しながら、流れるように次のExcelを
起動した瞬間、それは起こった。
Ryzen 3900X, memory32GBのPC上でExcelが立ち上がってこないのである。
慌ててタスクマネージャを覗くと、いくつかのプロセスは重たいように見えるが、全体としては15%程度しか占有しておらず、問題があるように見えなかった。(いくつか見覚えのないプロセス名はある)

Excelは永遠とも思える5分前後の経過の後、ノロノロと立ち上がった。とりあえず一旦閉じようと、閉じるボタンを押そうとしたが、ボタンを全く反応しない状況であった。
まるでmemory2GBのマシンで数100MBのイラスト満載の謎資料を開かされているような気分である。
だめだこれ、なんとかしないと。

その後、私はネットの関連情報を探し回った。
memoryブランドとExcelの相性・・・は問題なさそう。CPUは関係ない。
Officeは再インストールしても遅い。Excelのオプションをアレコレいじくっても治らない。。。
表面的な対応を一通り終えた私は、取り合えず良くわからないが疑わしいプロセスの調査することにした。
ん、このNahimicSVN32.exeってなんだっけ？
ネットで該当プロセス名で引っ掛けると、MSI(マザーボードブランド)のサウンドユーティリティだということが分かった。
入れた覚えはないが、マザーボード導入時に知らない内に紛れ込んだのだろう。
ネットで次のように検索すると。。。
　msi nahimic excel

出てきた。同様の障害事例報告が3件ほど。
それぞれ閲覧すると、いずれもこのサウンドユーティリティをOFFにすると治った、というもの。
私も早速、サービスマネージャからNahimic Serviceの自動起動を無効にし、PCを再起動した。
すると、Excelが音速で開くようになった。
やはり新マシンは素晴らしい。10kbの.txtファイルを開くかのようなレスポンスである。

なぜ、サウンドユーティリティがExcelの起動を邪魔するのかは、私には理解できないが、
何か深い理由を感じざるを得ない。

MSIはお手頃に拡張し易い良質のマザーボードを提供してくれるメーカであるので、購入する方も多いと思う。
そんな諸兄がニューマシン導入後のワクワクしたタイミングで私のように焦らないように、ここに書す。
(テスト自動化) Textで要素を見つけてクリックする

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

#課題
TestablishはSelenium準拠のブラウザ操作向けアプリで、ブラウザ外操作のファイルアップロードやダウンロードは標準で対応できない。
一方、SikuliはOSSのRPAツールであり、人が画面を目で見てマウスを動かして実現できる操作は概ね再現できる。
そこで私の環境では、基本的にはTestablishでテストを作成し、不足するテスト操作についてはSikuliで補完する形で運用している。
全体を通してテスト自動化の工数はやはり重たいが、その中でもSikuliによるテスト自動化工数がネックと感じる。

*ネックとなる要因*
　対象操作を１つずつ画像取得しながら記述する必要がある
　実行環境が異なる場合はエラーとなりがちで、その場合は以下対応が必要となる
　　　マッチング率を下げる(60%くらいがいいかも)
　　　ExcelやEdgeなどのツールでバージョン違いによるデザイン差がある場合は実行環境で作り直す

#対応
画像認識は便利だが、やはり環境差異による影響が大きく、なるべくならテストで使ってもらいたくない。
そこで１つの解決手段として、Sikuliのもう一つの認識機能である文字認識による操作を利用して、画像認識以外の経路を見出せないか、検証する。

#目的
Testablish上で文字列を指定すれば、その文字列で対象要素を特定して操作(クリック)できるコマンドをSikuliで作成する。

#内容
以下のような記述で目的を達成できた。
>\-----------------------
import sys
reload(sys)
\#日本語を扱うため、utf_8指定
sys.setdefaultencoding("utf_8")
\#日本語モードへ切り替え
tr = TextOCR.start()
tr.setLanguage("jpn")
\#画面上から対象文字列のワードを探す
\#strにはMatch型(座標データ)が返る
str = findText(u"対象文字列")
click(str)
\-----------------------

あとは対象文字列をTestablishから引き渡せるようCommnad登録すればよい。

#気付いた点
ものすごくレスポンスが遅い(Ryzen 9 3900X & 32GB memory)
複数ワード存在する場合は具合が悪い
文字列以外(リンクがアイコンになっているなど)だと画像認識になる

#結論
一部のテスト操作では活用できるかも
Spring BootでSQLite3をインメモリモードで利用する際のデータソース設定

# SQLiteのインメモリモード
[公式](https://sqlite.org/inmemorydb.html)を参照。メモリ上なので当然プロセスの消滅と共に揮発しちゃいますが、テスト実行時などは都度の揮発による冪等性の維持といった利点もあるため便利ではないでしょうか？

# Spring Bootにおけるデータソース設定
Spring BootでSQLiteをインメモリモードで利用する場合のDB設定は以下の通り。
（ビミョーに書き方が分からなくて正解にたどり着くまで時間がかかったのでメモ…）

```application.yml
spring:
  datasource:
    url: jdbc:sqlite:file::memory:?cache=shared
```

**file::memory** のところがなんか直感的じゃないんですよね…個人的には。ファイルなのか、メモリなのか。うーん。

ちなみに、インメモリモードではなくファイルモードで利用する場合のデータソース設定は以下の通り。こちらの方がメジャーですよね。

```application.yml
spring:
  datasource:
    url: jdbc:sqlite:./DBファイル名
```
postgresqlのtrigger によるユニークチェック

postgesqlでは、unique indexによってユニーク制約できますが、
値の一部（例：timestampの日付部分)でユニーク制約したい場合、
unique index　では対応できません。
この場合は、trigger　を利用する必要があります。

以下のtest テーブルを例とします。

<pre>
CREATE TABLE public.test
(
    id integer NOT NULL,
    name text COLLATE pg_catalog."default" NOT NULL,
    age integer NOT NULL,
    created_at timestamp with time zone NOT NULL
)
</pre>

同じ日付でname,ageも同じレコードを insert するとエラーにしたい場合、以下のトリガーを定義します。

まず、トリガー用の function を定義します。
対象レコードがすでに存在する場合、unique_violation　を発生するようにします。
<pre>
CREATE OR REPLACE FUNCTION trigger_unique_check_func()
 RETURNS TRIGGER
 LANGUAGE PLPGSQL
 AS
 $$
BEGIN
	IF EXISTS (SELECT name from test WHERE name = NEW.name
			    and age = NEW.age
				and created_at::date = NEW.created_at::date ) THEN
		RAISE EXCEPTION unique_violation;
	END IF;
	RETURN NEW;
END $$;
</pre>

次は、トリガーを定義します。
<pre>
CREATE  TRIGGER trigger_unique_check
BEFORE INSERT
ON test
FOR EACH ROW
EXECUTE PROCEDURE trigger_unique_check_func();
</pre>

試験：
まず、以下のＳＱＬを実行します。
<pre>
INSERT INTO test VALUES(1, 'a', 1, '2020-12-02 13:14:15');
</pre>
結果：
<pre>
INSERT 0 1
</pre>
最初は、対象レコードがまだテーブルに存在しないので、
無地にinsert できました。

次に、以下のSQLを実行します
<pre>
INSERT INTO test VALUES(2, 'a', 1, '2020-12-02 13:14:15');
</pre>
結果
<pre>
ERROR:  unique_violation
CONTEXT:  PL/pgSQL 関数 trigger_unique_check_func() の6行目 - RAISE
SQL state: 23505
</pre>
オー、ちゃんっとエラーでました！
以上です。
Hyper-V の有効化の途中で「機能を構成できませんでした」になる問題

手元の Windows 10 で WSL2 を使いたくて Hyper-V を有効にしようと思ったら意外にも苦戦した。

## 環境

環境は以下。

* Windows 10 Pro バージョン 2004 (OS ビルド 19041.630) 

`systeminfo` コマンドでは以下が表示されているので Hyper-V の使用条件は満たしている。

```shell-session
>systeminfo
・
・
・
Hyper-V の要件:         VM モニター モード拡張機能: はい
                        ファームウェアで仮想化が有効になっています: はい
                        第 2 レベルのアドレス変換: はい
                        データ実行防止が使用できます: はい
```

## エラー発生時の手順

1. Hyper-V を有効にすると他の仮想環境が動かなくなるとのことなので、使用している VMware や VirtualBox を Hyper-V と共存可能なバージョンに更新
2. [コントロールパネル] - [プログラムと機能] - [Windows の機能の有効化または無効化] で以下をチェック
    - Hyper-V 
    - Linux 用 Windows サブシステム 
    - Windows ハイパーバイザー プラットフォーム 
    - 仮想マシン プラットフォーム 
3. OK をクリックするとインストールされ、完了したら再起動 

これで通常なら入るはずだが、再起動後プログレスバーが 90 % 辺りで「機能を構成できませんでした」となり、その後「元に戻しています」となって有効化できない。

## 原因を調べる

このメッセージからは原因が全く推定できないので、「Hyper-V 機能を構成できませんでした」などのワードで検索した結果を試してみる。

* `bcdedit` コマンドから一旦 off にしてから有効化する
    * 変わらず
* Kaspersky をアンインストールしてから有効化する
    * Kaspersky 使っていない
* ディスク容量が十分空いていないと有効化できないことがある
    * 空いてる 

再起動待ちに飽きたので、何か手がかりにならないかとイベントビューアを見ると Setup に以下が記録されていた。

* Update Microsoft-Hyper-V-Management-Clients of package Microsoft-Hyper-V-ClientEdition? failed to be turned on. Status: 0x800f0922. 
* Update Microsoft-Hyper-V-Services of package Microsoft-Hyper-V-ClientEdition? failed to be turned on. Status: 0x800f0922. 
* Update Microsoft-Hyper-V-Hypervisor of package Microsoft-Hyper-V-ClientEdition? failed to be turned on. Status: 0x800f0922. 
* Update Microsoft-Hyper-V-Management-PowerShell? of package Microsoft-Hyper-V-ClientEdition? failed to be turned on. Status: 0x800f0922. 
* Update Microsoft-Hyper-V-All of package Microsoft-Hyper-V-ClientEdition? failed to be turned on. Status: 0x800f0922. 

今度はこのメッセージでググってみると、以下の記事に辿り着いた。

Unable to install hyperv on Windows 10 
https://social.technet.microsoft.com/Forums/ie/en-US/4d373cc1-faec-41e5-84cd-f56bc464b3a9/unable-to-install-hyperv-on-windows-10?forum=win10itprovirt

この記事ではパフォーマンスカウンタの再構築をすることで解消した、と言っている人がいる。
イベントログに出ていた Status の値も同じなので、ダメモトで試してみる。

## 解決した時の手順

パフォーマンスカウンタの再構築の手順については上記記事内にもあったが、一応公式ドキュメントを参照した。

https://docs.microsoft.com/ja-jp/troubleshoot/windows-server/performance/manually-rebuild-performance-counters#rebuild-all-performance-counters-including-extensible-and-third-party-counters

実行。

```shell-session
>cd c:\windows\system32
>lodctr /R

エラー: パフォーマンス カウンターの設定をシステムのバックアップ ストアから再構築できませんでした。エラー コードは 2 です
```

いきなりのエラーで一瞬焦るが、ググってみると正常終了するまで実行してみろ、という情報があったので何もせずに再度実行。


```shell-session
>lodctr /R

情報: パフォーマンス カウンターの設定をシステムのバックアップ ストアから正常に再構築しました
```

今度は上手く行った模様。
続けて以下も実行した。

```shell-session
>cd c:\windows\sysWOW64
>lodctr /R

>cd C:\Windows\System32\Wbem\
>winmgmt.exe /RESYNCPERF
```

これでパフォーマンスカウンタの再構築は完了したはずなので、今度は Hyper-V だけにチェックを付けて再起動。
今度は無事に有効化された！

その後その他の機能も有効化して再起動。  
問題なく入ったので以下を実行して WSL2 を有効化した。

```shell-session
>wsl --set-default-version 2
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください
```

できれば有効化できなかった理由はもう少し分かりやすく出力して欲しいと心から思った。
EC2でpythonプログラムをJavascriptから呼び出す簡易コード

# ボタンを押してpythonプログラムを起動

以下のようなhtmlを作成する。入力すると、入力した値を返すpythonプログラムを用意する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/c0ebd87d-a0c6-230f-b83e-68aedafb3216.png)

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
  <h1>テスト</h1>
  <p>文字を入力してください</p>
  <input id="plane" type="text" value="">
  <input id="btn" type="button" value="入力">
  <p id="string"></p>
  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
  <script>
    $(function(){
      $("#btn").click(
        function() {
          var plane = document.getElementById("plane").value;
          $.ajax({
            url: "./test.py",
            type: "post",
            data: {data: plane},
            success: function(data){
              document.getElementById("string").innerText = data;
            },
            error: function(data){
              console.log("failed");
            }
          });
        }
      );
    });
  </script>
</body>
</html>
```

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

import cgi

storage = cgi.FieldStorage()
data = storage.getvalue('data')
print('Status: 200 OK')
print('Content-type: text/html\n')

print('入力された文字は、' + data + 'です。')
```

# httpdの設定

```
[ec2-user@ip-xxx-xxx-xxx-xxx ~]$ sudo -i
[root@ip-xxx-xxx-xxx-xxx ~]# yum install python3
[root@ip-xxx-xxx-xxx-xxx ~]# yum install httpd
[root@ip-xxx-xxx-xxx-xxx ~]# systemctl start httpd
[root@ip-xxx-xxx-xxx-xxx ~]# cd /var/www/html/
[root@ip-xxx-xxx-xxx-xxx html]# vi index.html
[root@ip-xxx-xxx-xxx-xxx html]# vi test.py
[root@ip-xxx-xxx-xxx-xxx html]# chmod 775 test.py
[root@ip-xxx-xxx-xxx-xxx html]# vi /etc/httpd/conf/httpd.conf
   144行目あたり行末にExecCGIを追加         Options Indexes FollowSymLinks ExecCGI
   157行目あたり行を追加                    AddHandler cgi-script .cgi .py
   306行目あたり行末に.html .htmを追加      AddType text/html .shtml .html .htm
   307行目あたり行末に.html .htmを追加      AddOutputFilter INCLUDES .shtml .html .htm
[root@ip-xxx-xxx-xxx-xxx html]# systemctl restart httpd
```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/eb6088e4-e828-d9fb-b8ac-99d28c8fe474.png)
javascript requireとimportの違い


## require
・commonJSのモジュールシステム
・nodejs環境で使用可能
・module.export = function () {} でエクスポート
・require('')で読み込み
・chrome等のブラウザでは使えない

## import
・ES6(ES2015)から導入されたモジュールシステム
・IEを除いた主要ブラウザで使用可能
・export default function () {} でエクスポート
・importで読み込み
Hyper-vを最適化してディスク容量の逼迫を解消するの巻　(Dockerを使っているエンジニア)

#目次
[1.ストーリー](#1-ストーリー)
[2.解決編](#2-解決編)
[3.結果](#3-結果)

#1. ストーリー

開発マシンのディスク容量が逼迫してきている。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364471/a3794e78-b2b9-a1eb-e85b-5894f80374da.png)

なにが原因がわからないが、昔はよくWindows updateの失敗で容量が逼迫することがあったがそのせいか？
まずは不具合等を疑ってみたが・・・不明！

一旦状況を確認しようと下記のディスク容量調査ツールを入れてみた　(使用は自己責任にてお願いしやす)

https://forest.watch.impress.co.jp/library/software/diskinfo/

※”管理者として実行”しないと全部は分析できない

分析したところ、特になにか不具合等が理由ではなく、単に色々使い過ぎと判断に至った
疑ってm(__)m　マイクロソフトー

その中でもHyper-vの約57GB容量に目をつけ削減する方法を探した
SSDも256GBで十分でしょって思ってたけど足りないんだなー
特にDockerが全体の5分の1超も使っているなんて・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364471/b5794a5d-188d-68a4-73b4-2f0c2eb29265.png)


#2. 解決編

※注意、下記をするとコンテナは一度消されてしまうのようなので 再度コンテナは再作成してください　(docker-compose up するなりなんなりで)
[Troubleshoot]を起動しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364471/68bbbb66-9042-97f8-48e8-d56f23ab9223.png)

[Clean / Puge Data ] をクリックしましよう。　あとはよしなに。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364471/71e25b4b-8bff-b87d-5ca8-94cdc137aba2.png)

#3. 結果

あー50GBも空いたよ～

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364471/6906cd3e-6fe2-4408-8dff-fc4ba6572839.png)
【Python】Excelの複数シートを1つにまとめる

Excel for Macでは、ピボットテーブルを作成する際に複数テーブルを一括指定できないため結構不便です。（古いバージョンではできていたはず…）
まずは、pythonで複数シートのデータを1つシートにまとめてデータを扱いやすくしていきます。

#使用ライブラリ
openpyxlを使用します。
Excelの読み書きなどの操作を行うためのライブラリです。
https://openpyxl.readthedocs.io/en/stable/

#事前準備
openpyxlのインストール

```
pip install openpyxl
```

#ファイルの読み込み
```python
#ファイルの読み込み
read_path = "./input.xlsx"
output_path = "./output.xlsx"
wb = load_workbook(read_path)

```

#全シートのデータを取得する
```python
#全シートのデータを取得する
sheet_names = wb.get_sheet_names()
first_row = 1
l_2d_output = []
for sheet_name in sheet_names:
    sheet = wb.get_sheet_by_name(sheet_name)
    
    for row in sheet.iter_rows(min_row=first_row):
        l = []
        for cell in row:
            l.append(str(cell.value))
        l_2d_output.append(l)
        
    #次シートからヘッダーの読み込みを飛ばす
    first_row = 2
```

#書き込み
```python
#ファイルに書き込み
def write_list_2d(sheet, l_2d, start_row, start_col):
    for y, row in enumerate(l_2d):
        for x, cell in enumerate(row):
            sheet.cell(row=start_row + y,
                       column=start_col + x,
                       value=l_2d[y][x])

#書き込み
output_wb = openpyxl.Workbook()
output_ws = output_wb.active
write_list_2d(output_ws, l_2d_output, 1, 1)
output_wb.save(output_path)
```
#最後に
改善の余地がありすぎるコードですが、
自分が使う分には使えたので、いったん良しとします。
JUCEで個人的に良くオーバーライドするLookAndFeel

備忘録的に随時更新していけたらな…と。

##TabbedComponentのタブのサイズを均等割にする。
V4でテキストの長さに合わせたサイズになったのが好きじゃないので。

```MyLookAndFeel.h
    int getTabButtonBestWidth(juce::TabBarButton& button, int tabDepth) override
    {
        return button.getTabbedButtonBar().getWidth() / button.getTabbedButtonBar().getNumTabs();
    }
```

##スクロールバーのサイズを変更
主にタッチ操作をメインでスクロールバーを操作したい時に。

```MyLookAndFeel.h
    int getDefaultScrollbarWidth() override { return 32; }
```
学年を計算・表示する

生まれた年と生まれた月から学年を計算・表示するコードです。
イレギュラーはあるので人によって違うこともあると思いますが、多くの人はこれに当てはまるはずです。

学年は、4月を区切りとして計算しています。
`birth_year`, `birth_month` には生まれた年月を、 `judge_year`, `judge_month` には計算するときの年月を渡します。

### 引数の例

* 2018年1月生まれで 2021年4月での学年を計算する場合
    * `birth_year` : 2018
    * `birth_month` : 1
    * `judge_year` : 2021
    * `judge_month` : 4

## コード

```ruby
 def grade(birth_year, birth_month, judge_year, judge_month)
    judge_year -= 1 if judge_month < 4
    birth_year -= 1 if birth_month < 4
    year = judge_year - birth_year

    return "未就学" if year <= 3
    return case year
           when 4 then
             "年少"
           when 5 then
             "年中"
           when 6 then
             "年長"
           when 7 then
             "小学1年"
           when 8 then
             "小学2年"
           when 9 then
             "小学3年"
           when 10 then
             "小学4年"
           when 11 then
             "小学5年"
           when 12 then
             "小学6年"
           when 13 then
             "中学1年"
           when 14 then
             "中学2年"
           when 15 then
             "中学3年"
           when 16 then
             "高校1年"
           when 17 then
             "高校2年"
           when 18 then
             "高校3年"
           else
             "卒業"
           end
  end
```

### 計算の流れ

4月からの1年間を年度として考えます。 年度の始まり(4月1日)においての年齢から学年が決まります。
早生まれ(1-3月生まれ)の人は `birth_year` がひとつ前になりますから、 `birth_year` から1を引きます。
計算年月が1-3月の場合は、 `judge_year` で指定された数値より1つ前の年度の計算になりますから、 `judge_year` から1を引きます。
年度の差が就学前に年少なら3年、小1進級前なら6年あります。つまり年少の場合は年度の差が4年、小1の場合は7年です。
この数値に合わせて文字列を返します。

## その他

同じことをやろうとしている人は他にもいました

* [誕生日から現在の学年(小学校)を求める](https://qiita.com/wataruru35@github/items/f05b41b3e97d2de16f6c)
* [SQLで誕生日から現在の学年を取得する](https://qiita.com/ShibuyaKosuke/items/c8e7da395c78cc0bbca4)