OmniAICreator/Qiita-1.07M huggingface dataset:
【挑戦】Rubocopを使って仮想Railsアプリをリファクタリングする

### 概要
リファクタリングとかしなければいけないのは分かるけど、具体的にどうしたらいいのか分からなかったり、そうした題材みたいなものって少ないかと思います。

この記事では仮想のアプリケーションを元にRuby on RailsのコードをRubocopを使ってキレイにしていく題材を紹介します。

開発環境
- Mac
- Ruby：2.5.1
- Rails：5.2.6.2

### 準備
- [こちらのファイル](https://github.com/Tsuchiya2/experience_rubocop_app/archive/refs/heads/main.zip)をダウンロードします。
- ターミナルを開いて以下の操作を行ってください
   ```
    $ cd
    $ mkdir try_code
    $ cd try_code
    $ mv ~/Downloads/experience_rubocop_app-main ~/try_code/experience_rubocop_app
    $ cd experience_rubocop_app
    $ rbenv local 2.5.1
    $ gem install bundler -v 2.1.4
    $ bundle install
    $ bin/rails db:migrate
    $ bin/rails db:seed
    ```
- 上記まで完了したら、`bin/rails s`でサーバーを立ち上げます。
- 以下のような画面が表示されたら準備完了です。

![root_page.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587204/e8979168-7fee-af67-3811-dc8291ba3a73.jpeg)

### 体験手順

まずは仮想アプリケーションを触って見てください。どんなアプリケーションか体験してもらったら、以下にあげるファイルを確認しましょう。

- config/routes.rb
- app/controllers/posts_controller.rb
- app/controllers/change_posts_controller.rb

コードを見ていろいろ思うところはあるかと思いますが、一旦ターミナルで`bundle exec rubocop`を実行してみましょう。


すると、以下の画像のようにRubocopからの指摘事項が確認できるかと思います。
[![Image from Gyazo](https://t.gyazo.com/teams/startup-technology/ed98e29af18b63cf88f990e04f4d46c5.png)](https://startup-technology.gyazo.com/ed98e29af18b63cf88f990e04f4d46c5)

この指摘事項、もっと言えば`bundle exec rubocop`コマンドを実行して何も指摘されない状態にできれば、一定基準のコードになります。

＊Rubocopの対象から外したりすることもできますが、今回は用意されている仮想アプリケーションの設定に沿ってコードをキレイにしてみましょう。

一度に全ての指摘項目を修正するのは大変なので、config/routes.rbに絞って修正を試してみましょう。

config/routes.rbで指摘されているのは、以下の4つですね。
[![Image from Gyazo](https://t.gyazo.com/teams/startup-technology/10eafd63fbc473d91dee448bf536e1f9.png)](https://startup-technology.gyazo.com/10eafd63fbc473d91dee448bf536e1f9)

指摘箇所は表示されているとおりですが、その指摘内容を見てみると以下の2つが指摘されているのが分かりますね。

- Layout/SpaceInsidePercentLiteralDelimiters: Do not use spaces inside percent literal delimiters.
- Layout/SpaceInsideArrayPercentLiteral: Use only a single space inside array percent literal.

これらを翻訳したり、検索した先の公式の記載からどんなことが指摘されているのかを確認してみましょう。その上で、該当箇所・config/routes.rbファイルを修正して`bundle exec rubocop`を実行し、指摘項目数が42個から38個になるようにトライしてみましょう。

config/routes.rbを修正した際のターミナルは以下のような表記になるかと思います。

[![Image from Gyazo](https://t.gyazo.com/teams/startup-technology/43f9b7d5d6c8ca301062105dbdd7eb72.png)](https://startup-technology.gyazo.com/43f9b7d5d6c8ca301062105dbdd7eb72)

今回の指摘事項の修正は割りかし軽微なもので物足りなかったかもしれません。

物足りなく感じた方、より良いコードを書くためにもう少し取り組みたい方、Fat controllerを解消したいけど具体的にどうしたらいいのかがよく分からない方などなど、残りの指摘事項をどうしたら解消できるか挑戦してみていただけると嬉しいです。

＊修正のイメージが難しい方でも、どうしたらそれができるかを以下のファイルのコメントに書いているので、コメントを読みながら取り組んでもらえると嬉しいです！

```
① posts_controller.rbの修正：config/routes.rbのときと同様に指摘項目を翻訳したり、検索したりして修正してみましょう！

② change_posts_controller.rbの修正：同ファイル内に書かれているコメントも参考に修正してみましょう。

③ change_posts_copntroller.rbの"Fat Controller"解消：app/models/post.rb内のコメントを参考にロジックをモデルに移行させてみましょう。
```
Neovimに雪を降らせてみた

12月も中旬になってきて寒くなってきましたね
そろそろ雪が降ってくるころでしょうか。

![snow_vim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1438460/1db7db04-120e-ef3f-552d-dd203ae3e529.gif)

floating windowを使って何かをやってみたかったので、
Neovimに雪を降らせてみました。 
やったことは、 以下です。
1. 背景が透明で●をランダムに入力したfloating windowを作成 
1. timerを使ってwindowの高さを下げる 
1. 画面最下部に到達した時点でwindowを削除 


この時使ったfloating window関連や便利だったものをご紹介します。

## 作り方と動かし方
基本的に`:h api-floatwin`で細かな内容を確認できます。
### 作り方
基本的に以下２つで新しくFloating Windowを作成します。
#### nvim_open_win
`nvim_open_win(buffer, focus, config)`
これでウィンドウを開くことができます。
ここにはバッファとウィンドウの場所や大きさなどの設定を渡すことができます。

ここで渡すバッファは次の方法で作成できます。
#### nvim_create_buf
これで新しいバッファを作ります。
戻り地でバッファIDを得られるのでこちらを`nvim_open_win`に渡すと任意のバッファをFloating Windowで開くことができます。

### 動かし方
#### nvim_win_set_config
こちらに動かしたいバッファと設定を渡せば動かすことができます。
今回、雪が降ってくる動作のとき、`redraw`が必要です。
使わない場合、関数実行したあとに描画がされないようです。
スムーズで任意のタイミングで描画させたい場合はいれる必要があります。
```
let config = {'relative': 1,'row': 2,'col': 2} 
call nvim_win_set_config(win_id, config)
```

#### nvim_win_set_option
アクティブなウィンドウでは`set`コマンドを使えると思いますが、
非アクティブなウィンドウにもコマンド実行したいことがあると思います。
そんなときに便利な関数です。
ウィンドウIDとコマンドを引き数に実行すると任意のコマンドを適用できます。
```例 init.lua
call nvim_win_set_option(win_id, 'winblend', 40)
```
#### winblend
`set windblend=100`の形でFloating Windowの背景を透明っぽく見せることができます。
「っぽく」というのは、重なった部分の色を混ぜて透明に見えるように
していて、実際に透けていないためです。
そのため、文字は透けず、一番上の文字が優先されています。

## timer関数
雪を断続的に降らせるために使いました。

### timer_start
以下のように間隔、関数、オプションを引き数に実行できます。
```
call timer_start(200, function("s:snow", [win_id]), { 'repeat': -1 })
```
自分で止めるまで関数実行し続けてほしかったため、`repeat: -1`を使っています。
指定回数を設定することで任意の回数分実行できます。
### timer_stop
上記の`timer_start`の戻り値を渡すことで実行を辞めることができます。
今回は以下のように配列に入れたtimer idを`timer_stop`にいれることで止めています。
```
let s:timers_list = []
call add(s:timer_list, timer_start(200, function("s:snow", [win_id]), { 'repeat': -1 }))
```


# 終わりに
いかがでしたでしょうか。
今回は遊んでみたのですが、これらを使ってファイルを見ながら開発をしたり、
付箋のようなメモスペースを作ったりと色々できるのかなと思いました。 
読んでいただきありがとうございました。
ReactNativeことはじめ(With Expo)

### 動作環境
PC:MacbookPro(2018)
OS: Big Sur(11.6.2)
エディタ:Visual Studio Code
XAMPP(PHP7.4)を使用
ターミナルはzshを使用

## open App

```bash
expo start
```

## 再読み込み

キーボードの`R`(⌘+Rは録画になるので注意)

## トラブルシューティング

### ■エミュレーターで起動できない

**→ expoを一度落として再起動する**

`expo start` したターミナルにて `ctrl + c`で終了

※キャッシュクリアして再起動
再起動する際 `expo start -c` と-cオプションを追加

**→ node_modulesをクリアしてみる**

フォルダを削除して `yarn install` にて再インストールしてみると解消する場合あり

**→ エミュレータ内のExpo Clientを最新にする**

iOS
`expo client:install:ios`
Android
`expo client:install:android`

エミュレータ内でExpo Clientアプリを削除して、再度 `expo start` してもOK

※`”requires a newer version of Expo Client app"`のようなエラーメッセージが表示されている場合は、おそらくこれで解消

**→ XCodeを最新にする**

### ■ スマホ実機で起動できない

**→ macとスマホが同じLAN環境にある確認する**

**→ Expo Clientアプリを最新にする**

**→ LANのセキュリティに阻まれている可能性**

### ■ Can't resolve 'expo-constants'のようなエラーが出る

**→ node_modulesをクリアしてみる**

フォルダを削除して `yarn install` にて再インストール

### ■ (React Navigation導入の際に)Tried to register two views with the same name RNCSafeAreaProvider のようなエラーが出る

→以下手順を実行

1. node_modulesフォルダとlockfile (yarn.lockもしくはpackage-lock.json)を削除する
2. package.jsonのexpoのバージョンを 38.0.8 にする
3. `react-native-safe-area-context` をpackage.jsonから削除する
4. yarn install (もしくはnpm install)を実行する
    
    `expo install react-native-safe-area-context`
    を実行
    

### ■ Unable to resolve "react-native-gesture-handler”

デフォルトでreact-native-gesture-handlerが実装されていないので追加

```jsx
expo install react-native-gesture-handler
```
地理情報用ANNを自作する。

本notebookは[情報検索・検索技術 Advent Calendar 2022](https://adventar.org/calendars/7389)の17日目の記事です。

はじめまして、nadareと申します。普段はMLエンジニアとしてレコメンドエンジン等を作っています。
今回は緯度経度の距離計算に用いられるhaversine関数を用いた近傍探索を、近似近傍探索(ANN)により高速化したのでその実装とコードを公開します。

記事本体となるNotebookはこちらになります。
https://www.kaggle.com/code/nadare/ivfxl2rrflat-for-haversine

# おまけ(ポエム)
近似近傍探索、個人的に好きな分野ですが割と使いどころが難しいです。

近似近傍探索が有効なのは大量の画像のembeddingに対してコサイン類似度で探したいみたいなケースだと思います。ユークリッド距離のような条件ではK-D TreeやBall Treeといったアルゴリズムが使えますが、コサイン類似度は全探索で探す必要があります。([scikit learnのNearest Neighborの項](https://scikit-learn.org/stable/modules/neighbors.html#nearest-neighbor-algorithms)に詳しいです。)

ANNはこのようなケースで有効ですが、faissやnmslib等の実装はprefilterによる部分検索ができないので検索対象のメタ情報との組み合わせが難しいです。具体的にはxxのタグがついた類似画像の検索みたいなことをしたい場合は、ANNを使うのであれば多めに近傍を取得したうえでフィルターをかける、ただし件数の保証はされない、みたいなことが起こります。タグがない場合でもレコメンドシステム等でembeddingによる検索を行う場合、全アイテムを探索するのではなくランキング上位N件に絞ったほうが精度良くてANNの効果が薄い(KNNの方が精度よく速度も十分)みたいなことも起こります。

ElasticsearchやOpensearchにANNの機能が追加されてきています。(前者はnmslibのHNSW、後者はさらにfaissに対応)
とはいえそのままでは全体集合に対する近似近傍探索しかできないので、自前でANNを実装できると活用の幅は広がるとおもいます。
例えばKMeans + 転置インデックスによる粗量子化は比較的簡単に実装できますし、最近だと[BigQueryによる最大内積検索の実装](https://blog.recruit.co.jp/data/articles/bigquery_vector_search/)の記事の「ベクトルの離散化による候補削減」では4次元のLSHによる候補削減を行っていて感動しました。

近似近傍探索はGCPで[Vertex Matching Engine](https://cloud.google.com/vertex-ai/docs/matching-engine/overview?hl=ja)が使えるようになったり、windowsでも使えるfaissにFastScanが実装されたりと近年ホットな分野です。ぜひ活用していきましょう。
ジーズで作った課題をドヤ顔で紹介したい

# 本記事について
[ジーズアカデミー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/gsacademy)の17日目（カレンダー2）の投稿です。  
僕がジーズアカデミーでプログラミングを学んでいたときに作った課題をただ誇らしげに紹介する記事です。  
3作品紹介しますが、どれもGitHub Pagesでデプロイ済みなので皆さんご自由に遊んでみてください！

# 自己紹介
G's ACADEMY FUKUOKA LAB6期生。それまでプログラミングはほぼ未経験。現在はエンジニアとして勤務。

# 作った課題たち
## チーズアカデミー（HTML/CSS）
https://ykiyoshima.github.io/cheese-academy/

ソースコード：https://github.com/ykiyoshima/cheese-academy
![スクリーンショット 2022-12-12 23.47.18.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517152/acb0d594-7b6e-ee56-d470-dece3ce2aa7e.jpeg)
ジーズアカデミーの初回課題としておなじみ「チーズアカデミー」。このときは基本に忠実に作りました笑  
申し訳程度の魔改造要素として、右上の「Into the dark...」ボタンを押すとすべてのコンテンツの色が反転したり、右端で動いているチーズアイコンをクリックしたらチーズの亡霊がクイズを出したり（？）する機能を実装しています。

## 勇者ジーズの冒険（JavaScript じゃんけんアプリ）
https://ykiyoshima.github.io/janken-app/

ソースコード：https://github.com/ykiyoshima/janken-app
![スクリーンショット 2022-12-12 23.56.57.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517152/94c684e4-9734-e905-678f-15140642ff0b.jpeg)
コマンドバトル制のゲーム。JavaScriptの乱数と条件分岐だけで作っています。  
フィールド画面で操作キャラを1マス動かしたときに敵キャラがランダムな方向に1マス動くのも乱数と条件分岐ですし、バトル画面でコマンドを選択したとき、敵にダメージを与えるか、自分がダメージを食らうか、何も起きないかも乱数と条件分岐です。たまに攻撃が相手の急所に当たることもありますが、これも乱数と条件分岐です。
ちなみにフィールド画面からバトル画面への場面転換はz-indexを使ってフィールド画面の上にバトル画面のコンテンツを重ねることで実装しています。なかなかゴリ押しの効いたパワーコードですね笑  
当時「最強のじゃんけんアプリを作る」と決意して本気で作った課題なので、よかったら皆さんに遊んでもらえると嬉しいです！
![スクリーンショット 2022-12-13 0.05.31.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517152/c1853181-9c20-91fe-7419-af8fb998d53e.jpeg)

## Web Drums（JavaScript メモパッドアプリ）
https://ykiyoshima.github.io/memopad-app/

ソースコード：https://github.com/ykiyoshima/memopad-app
![スクリーンショット 2022-12-13 0.08.36.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517152/d0fea051-93df-e9c7-1800-5157a6044a51.jpeg)
あなたのキーボードがドラムになるアプリ。録音、再生、リズム修正、テンポ変更、ローカルストレージへ録音データの保存ができます。  
ここだけの話ですが、**実は録音自体はしていません**。録っているのは特定のキーを押したときのタイムスタンプです。  
「Start Rec.」ボタンを押してメトロノームが8回鳴った後（9回目の音）を始点（0秒）として、そこから何秒経過したときにそのキーが押されたか、の情報を配列に格納しています。「Play Music」ボタンを押すと、その瞬間を始点（0秒）として配列に格納したタイムスタンプに達したとき、そのキーに対応するドラムの音を鳴らす、というカラクリです。  

さらなる推しポイントは「リズム修正」機能です！  
Web Drumsでは各ドラムパーツの音を重ねて録音することができるのですが、重ねると同じタイミングで鳴ってほしいところが少しズレてしまっていることが往々にしてあります笑  
そこで「Fix Music」ボタンを押してください。プログラムでキーを押したタイミングのズレをいい感じに補正してくれます！  
この機能を紐解くと、以下のような処理の合わせ技であると言えます。
1. 設定したテンポから拍の基準リズムを計算し、配列に保存する
例えばBPM = 60（1秒に1回メトロノームが鳴るテンポ）の場合、テンポを設定した時点で`rhythm = [0, 0.25, 0.5, 0.75, 1, ...]`のように1秒間当たり4拍分の基準リズムを事前に作成しておきます。
1. 録ったタイムスタンプと1.で作った基準リズムを比較し、タイムスタンプを最も数値が近い基準リズムに補正する
例えばBPM = 60で録ったタイムスタンプが`rec = [0.04, 0.22, 0.53, 0.74, 0.99, ...]`だった場合、それぞれの数値が基準リズムのどの値と最も近いかを繰り返し処理で判定します。  
その結果、0.04 ≒ 0、0.22 ≒ 0.25、0.53 ≒ 0.5、...となるため、`rec = [0, 0.25, 0.5, 0.75, 1, ...]`のような感じで、録ったタイムスタンプの配列を基準リズムの数値で構成される配列に置き換えるわけです。  

こうすることで、録音時の微妙な音のズレを解消する機能が実装できた、というお話でした。  
難しい話はとにかく、まずは触ってみてください！操作方法は画面右上の？マークをクリックすると表示されます！

## まとめ
とにかく楽しんでコード書きまくりましょう！好きこそものの上手なれです！
【リファクタリング記事】for文【for(これ;これ;これ)】の内容を正しく説明できますか？よくある勘違いを解説します。

## 【後記】新人研修で教えられないforのお話
これ結構良かったので、勝手にパクリます（なお、パクもラレも本人です）
なんで下書きに残っとるんや…！

元々は過去日に公開していたテーマだったんですが、結構ブラッシュアップしたので別記事になりました。
とはいえ、同じ事を言っているのでそのまま更新して2022アドカレに登録する運びにします。

## 今日いいたいこと
タイトルの通り、for文の

``` php
for(
  1. これ;
  2. これ;
  3. これ
) {
  // 処理
}
```

を正しく説明できるか？というのが本旨です。

## 研修中の説明例
``` php
for(
  変数の初期値;
  繰り返しの条件;
  カッコが終わった後にすること・繰り返しの条件が終わるようにする
) {
  // 処理
}
```

です。
研修など時間が限られている中で解説するため、forを使うだけならこの説明でも良いです。
が、今回取り上げたいのは、この説明は**間違っている**ということです。

### for文をwhile文で書き直してみる
下記にコード例を示します。
いずれも出力は以下のような結果になります。

1. `1 / 0`
1. `1 / 1`
1. `1 / 2`
1. `1 / 3`
1. `1 / 4`

``` for.php
<?php
$i = 1;
$before = 0;
$after = 0;

for(
  $before++;
  $i <= 5;
  $after++
) {
  $i++;
  echo $before . " / " . $after . "<br />";
}
?>
```

これをfor->whileにリファクタリングします。

``` while.php
<?php
$i = 1;
$before = 0;
$after = 0;

$before++;  // for文の１行目
while($i <= 5) {  // for文の2行目
  $i++;
  echo $before . " / " . $after . "<br />";

  $after++;// for文の3行目
}
?>
```

### JavaScript
（※）PHP側の書き方に寄せています。

``` for.js
let i = 1;
let before = 0;
let after = 0;

for (
  before++;
  i < 5;
  after++
)
{
  i++;
  console.log( before + " / " + after );
}
```

これをfor->whileにリファクタリングします。

``` while.js
let i = 1;
let before = 0;
let after = 0;

before++;  // for文の１行目
while ( i < 5 )  // for文の２行目
{
  i++;
  console.log( before + " / " + after );

  after++;  // for文の3行目
}
```

## 勘違いしていても使えます
プログラミングの世界では、「厳密に意味を正しく理解していなくても使えてしまう」ものがいっぱいあります。
これは言語仕様であったりフレームワーク仕様などで「何となくいい感じにしてくれる」ものがある事を認識して使うのと、認識せず使うのでは意味が大きく異なります。

本来であれば、しっかりと指導するべきなのですが実際問題として指導できていないという問題があるので、せめてこういった時間を意識しなくても良い場では、ガチャガチャいじって予測と実験をする練習する機会を作っていくと、言語やフレームワークだけでなく、特にインフラ周りは理解が大幅に進みやすくなります。

## 次の記事
- [(17日目) 【俺のエディタ年表】現役エンジニア講師のエディタ変遷〜なぜそのエディタを選んだのか〜](https://qiita.com/nomurasan/items/db69d80af8c90bbeaafe)
- [カレンダーページ](https://qiita.com/advent-calendar/2022/oreno_nomurasan2022)
Azure Durable Functions Monitor の紹介

この記事は [bitFlyer Advent Calendar 2022](https://qiita.com/advent-calendar/2022/bitflyer) の 17 日目の記事です。
 
## 前提知識
 
[Azure Functions](https://learn.microsoft.com/en-us/azure/azure-functions/) と [Azure Durable Functions](https://learn.microsoft.com/en-us/azure/azure-functions/durable/) については説明しません。
 
## Durable Functions Monitor とは
 
<https://github.com/microsoft/DurableFunctionsMonitor>
 
Durable Functions によって、時間的な状態を持つ処理をサーバーレスな形で動かすことが比較的簡単にできますが、ある程度複雑な状態をもつ function を開発していると、デバッグや状況の監視が難しいと感じることがあります。
 
- アプリケーション内でログをとっていても、直線的なログだけでは、処理の依存関係と対応付けるのが難しい（例えば、activity の一部だけが失敗してリトライが絡んでいる場合とか……）
- Azure Storage（デフォルトの場合）に history としてログが保存されているが、これも同じ問題があってしんどい
- 失敗した処理や、時間のかかっている処理を見つけたい
 
[**Durable Functions Monitor**](https://github.com/microsoft/DurableFunctionsMonitor)（以下、**DfMon**）を利用すると、Azure Storage に保存されたログを、各 orchestration / activity function の処理と対応させて視覚化することができ、上記のような問題に対処できます。
また、Durable Functions をあまり使ったことのない方が、動作を把握するのにも役立つと思います。
 
意外と知名度が低く、Azure Functions を利用していても Durable Functions は使っていない、あるいは
Durable Functions を利用していても DfMon は使っていなかった、ということがあり、ここで紹介しています。
 
## 導入方法
 
大きく分けて 3 つの導入方法があります
 
- [Visual Studio Code の拡張機能](https://marketplace.visualstudio.com/items?itemName=DurableFunctionsMonitor.durablefunctionsmonitor)としてインストールする
- 既存の Function に [NuGet パッケージ](https://www.nuget.org/packages/DurableFunctionsMonitor.DotNetBackend)としてインストールして UI を追加する
- 独立したサービスとして動かす
 
開発する際には VSCode 拡張として導入するのが簡単です。
インストールすると Azure タブに "Durable Functions" ペインが追加され、ここから起動できるようになります。
 
導入方法や機能について詳細はリポジトリの [wiki](https://github.com/microsoft/DurableFunctionsMonitor/wiki) に記載されています。
 
## 機能
 
### Orchestration インスタンスの検索と状態の閲覧
 
![s1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/9c571f33-de35-057c-a6e2-459b8fb6fe03.png)

 
### 各インスタンスごとの状態の閲覧、操作
 
インスタンス ID を選択すると各インスタンスの状態が見えます:
 
![s2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/3b5679d7-d303-d00d-b504-138de5ce2ec5.png)
 
- ここからリスタートや実行中の instance の停止などの操作も可能です
- 各 activity functions の結果や例外の内容がすぐ見られて、デバッグが捗ります
- 時間のかかる処理について Gantt chart タブもよく見ることがあると思います
  - 例: exponential backoff が効いているのがよくわかる様子

![s3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952758/5d519b24-a644-51b0-99be-8d09a66b988f.png)
 

## 開発上の注意
 
DfMon を使うかどうかにかかわらないものの、Durable Functions の開発の上で注意しておくとよい点があります。
 
### Instance ID と外部の ID を結びつける
 
orchestration instance ID はデフォルトでは GUID が割り振られますが、外部の ID がある場合はその値と同じにしておくと特定が楽になります。
 
### Custom status を有効に使う
 
`IDurableOrchestrationContext.SetCustomStatus()` で custom status を設定しておくと、DfMon 上でも一覧・フィルタできて便利です。
see: <https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-custom-orchestration-status?tabs=csharp>
 
### Activity function を分割する
 
オーバーヘッドとの兼ね合いではあるものの、それぞれの activity functions はなるべく小さい処理にして分割しておくと、DfMon 上でも処理が追いやすく、また時間のかかっている処理や並列化できる処理を探すこともしやすくなります。
 
並列化したり sub orchestration を使ったりすると、ログが貧弱だと処理の流れがわかりづらくなり、問題が起きたときの対処が難しくなりがちですが、DfMon のような方法で視覚化することでそれに恐れず設計できるのではないかと思います。
アウトプットのすすめ〜転職活動しながら思うこと〜

# はじめに
この記事は
[Qiita史上最多記録をつくろう！アウトプットはいいぞカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/output)
16日目の記事です。
アドベントカレンダー初参加！わくわく！！

Qiitaに投稿はじめてもうすぐ3年。
転職活動をしている今、アウトプットに対して思うことをまとめたいと思います。

# わたしについて
+ ギリギリ20代（院卒5年目）
+ 現職：新卒で入ったメーカー勤務、研究開発職
+ 主な業務：深層学習のモデル開発、WEBやモバイルアプリのプロトタイプ作成と評価
+ アウトプット実績：対外的にはたまに書くQiita、全然草生えてないGithub。会社では勉強会実施など
+ Qiitaに記事書くこと：好き
+ 転職：したい
+ 活動状況：先週から面接祭り

# アウトプットのモチベーション
### ● 自分が困ったことはきっと誰かも困るだろう
困ったことをすんなり解決する手助けになれればいいな、
という思いが強いのが記事を書く１番のモチベーションです。
困ったとき、ググれば大体偉大な先人たちの知見が助けてくれます。
記事を書いて誰かが見てくれたら、自分自身も偉大な先人の仲間入りです。
人知れず誰かの役に立てていたら嬉しいですよね。

### ● 努力をカタチに残したい
私は理系の大学院卒ですが、専攻や研究内容がちょっと特殊だったために
学生時代はほぼテキストコーディングをしたことがありませんでした。
そのため会社に入ってからコードゴリゴリ書ける同期に囲まれ、
それはもう大変なコンプレックスを感じていました。
部署にコードレビューなどの文化も全くなかったために
書籍と動画講座と学習サイトをフル活用して独学で
なんとかいっちょまえにコードが書けるようになりました。
(　クソザコなので1年半くらいかかりました。その頃にQiita始めました。)
今は部署でほぼ誰もやっていない技術や言語に触れる機会が多く
自分で学んで実装していくことが常のため、毎日モリモリインプットしています。
そんな努力の結果をどっかに残しておきたいなという気持ちもアウトプットのモチベーションの1つです。

# アウトプットにおいて気をつけていること
### ● 1文の長さ
Qiitaに記事書くにあたっては、1文の長さに結構気をつかっています。
私自身が横にながーーく書いている文字列を目で追うのが苦手なので
なるべく１行の文字数は少なくなるように
また1文が長ったらしくならないように推敲しながら記事を書いています。

### ● 検索に引っかかるようなタイトルにする
自分が困ったことを記事にしている訳なのですが
そのとき検索していたワードをできるだけタイトルに盛り込むようにしています。
せっかく書いても見つけてもらえなかったら力になれないですもんね。

### ● 自分が参照したサイトはとりあえず全部リンク貼っとく
何がどこで役に立つかわかりません。
私自身の書いた記事が読んでくれた方の問題をクリティカルに解決するものでなかったとしても
リンク先の記事がそうである可能性は大いにあります。
いろいろ調べ物して参考になったなと思うものは記事の最後に引用するようにしています。
そのリンクに後々自分が助けられたりすることもあります。


# アウトプットやっててよかったと思う瞬間
### ● 人に聞かれたときにすでにまとめているものを知見として提供することができる
「これどうすればいいんだったっけ？」と聞かれたときに慌てません。
汎用的なお外に出せる知見の場合はQiitaの記事のURLを
(会社でやってる諸々の場合はやったこと全部パワポにまとめてるのでパワポを)
お渡しすればOK。
口頭で説明した結果抜け漏れあった！みたいなことにもならないし
しばらくして再び同じことが訳わかんなくなってしまったときにも参照できるものがあれば安心です。
その上でわからない部分があれば相談にのれるので、話もスムーズで説明がしやすくて良いなと思っています。

### ● 反応がもらえると嬉しい
Qiitaはじめて良かったなーーと思う１番の瞬間は記事に反応がもらえたときです。
いいねだったりストックしてもらえたりはもちろんですが
記事に書いたことに対してもっと良いやり方だったり更なる知見だったりを
コメントで書いてくださる方もいらっしゃって、本当にありがたいことだなと思っています。
(自分の書いたコードを他人様に見ていただく機会が本当にないのでそういうのに飢えています)
もちろんいいねも楽しみにしてます
私もいろんな記事に押してまわってます。

### ● 今！ナウ！転職活動中！！
今まさにひしひしと感じているのですが、
しょぼしょぼとでも記事書くこと続けてきてよかったなあと思っています。
自分がどういうことを勉強してきたか、
どういうところに躓いて、どういうふうに解決してきたか、
どういうモチベーションで記事を書いてきたか、
実際にアウトプットしてきたものがあるからこそ実感として語れるし、見ていただけます。
ここ最近休日にものづくりしたり仕事がらみ以外の勉強したりすることがなかった故に
全然草生えてないGithubにしか書いたコードがないので
Qiitaの記事がちょっとでも足しになっていればなと思っています。

# さいごに
締め方わからなくなってきたんですけど
とりあえずアウトプット、ちょっとでもやってきてよかったーー！と思っています。
これからも自分のペースで続けていきたいです。
現に今も下書き止まりのものがいくつかあるのでちゃんと世に送り出したいですね。


現在、現職の昇格断った結果、部署内外の偉い人に転職します宣言してしまった状態での
かなりパンクな転職活動しています。
成功を祈っていてください。

→無事転職活動終了しました！4月から新しい会社の予定です！やったね！！
ラズパイにgitlab-eeをインストールした話

## ラズパイ4にgitlabをインストールしたので、その時の記録を記載します。

### CI/CDが出来る環境を自分で構築したいと思ったことが、これをやろうとしたきっかけです。<br>gitlabを選択した理由は、ローカル環境にインストール可能なものが、これしかなかったためです。

## 開発環境
　　|バージョン
---|---
筐体|rasberry Pi4 8GB
OS | Ubuntu Server 22.10
gitlab|gitlab-ee 15.6.2-ee


## 今回のお題！
1．事前準備
2．gitlabのインストール
3．アクセス確認

までを行っていきます。

## 実行！
### 1．事前準備
#### ①先ずは、パッケージを最新バージョンにします。
```
$sudo apt update && sudo apt upgrade
```

#### ②curlのインストールを行います。
```
$sudo apt install -y curl
```

### 2.gitlabのインストール
先ずは、以下のコマンドを実行し、インストールするパッケージをダウンロードします。
```
$curl -s "https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh" | sudo os=ubuntu dist=jammy bash
```
以下の内容が表示されたら、インストール可能となります。
```
$The repository is setup! You can now install packages.
```
次に実際に、gitlabをインストールしていきます。
```
$sudo apt-get install gitlab-ee
```
以下の内容が表示されたら正常にインストールが完了したことになります。
```
...
User sessions running outdated binaries:
 pi @ session #1: sshd[1812]
 pi @ user manager service: systemd[1844]

No VM guests are running outdated hypervisor (qemu) binaries on this host.
```


### 3．アクセス確認
インストールが正常に終了したので、アクセスできるか確認していきます。
gitlabのURLは、デフォルトで以下の内容が設定されています。
http://gitlab.example.com

インストールした状態で、URLを実行してた場合、以下の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196226/f6016411-2800-c3a3-f0eb-086d94855ab3.png)
※インストールしただけの状態では、設定が反映されていないようです。

そこで、以下のコマンドを実行し、設定を反映させます。
```
$sudo gitlab-ctl reconfigure
```
※このコマンドを実行したら、終了するまで、十数分かかります。
以下が表示されたら、正常に設定が反映されたことになります。
```
gitlab Reconfigured!
```

この状態で、再度ブラウザからgitlabにアクセスしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196226/f9f03f2d-7f06-730f-074e-b8c4aae6d6df.png)
正常にログイン画面が表示されました。
ログインするための初期PWは、以下に記載されています。
```
/etc/gitlab/initial_root_password
```
usernameをrootとし、上記で確認したPWを入力して、Sign inボタンをクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196226/f83fc31d-14c8-7a50-aca6-15b9b7c446c2.png)

正常にログイン出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196226/6c238512-6c8c-0bd4-e7e7-b7b266ca946a.png)
※このパスワードは、24時間しか利用できないので、ログイン後ｍ、すぐに管理者用のユーザ登録を行ってください。

今回はこれで、以上となります。
多少、躓くところはありましたが、正常にインストールできました。



## 参考にしたサイト
https://qiita.com/wataru775/items/a7fb5f5342600ba6b062

https://masavlog.com/programming/gitlab-install/

https://yudachi-shinko.blogspot.com/2019/03/gitlab.html
discord botをdaemonにしたい準備編

# 前提

:::note info

この記事は，discord botでminecraft serverを操作したいアドベントカレンダーの記事です．

:::


そもそもdaemonというものの私の認識は，PCが起動している間はずっと裏で動いてて，PCを再起動しても勝手に起動してくれるよ，程度です．この認識が間違っていた李，齟齬があるかもしれませんので，この記事では
- 裏でずっと動いてる
- 起動時に自動的にプログラムが実行される

という意味合いでdaemonを使います．

また，タイトルにdiscord botをdaemonにしたい書きましたが，どこかのサーバーにおいて起動させるわけではなく，ローカルの環境でdaemonにします．つまり，本当の意味でdiscord botを常駐させるわけではありません．PCを起動したらdiscord botも勝手に起動する，という感じになります．

また，環境は
- WSL, Ubuntu22.04.1

です．

# daemonのための準備

まず，プログラムをコンピュータが実行できるようにする必要があります．そのために，ファイルに実行権限を`chmod`を使って追加します．権限の変更については，[Linuxの権限確認と変更(chmod)（超初心者向け）](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)，という記事を見つけたのでこちらを見るといいと思います．


## 実行権限を付与しての実行

まずは実験ということで適当なファイルを作り，実行させたいシェルスクリプトを仕込んでおきます．

```bash: bash
$ touch somefile
$ echo "echo \"this is runnable?\"" > somefile
$ cat somefile
echo "this is runnable?"
```

この`somefile`に実行権限を与えます．
```bash: bash
$ ls -l
-rw-r--r-- 1 user user 18 Dec 16 21:13 somefile
$ chmod +x somefile
$ ls -l
total 4
-rwxr-xr-x 1 user user 18 Dec 16 21:13 somefile
```

付与されました．

実行してみましょう．実行にはそのファイルまでの相対パスを指定するのだと理解しています．自分のディレクトリの`somefile`というファイルを指定すればいいです．

```bash: bash
$ ./somefile
this is runnable?
```

文字列が返ってきました．つまりは`echo`コマンドが実行されたということですね．
ここで，この状態でpythonのファイルを実行しようとしても，シェルスクリプトとして解釈されるのでエラーが発生します．

```bash: bash
$ cat pyfile.py
import os

print(os.getenv("EXAMPLE"))
$ ./pyfile.py
./pyfile.py: line 1: import: command not found
./pyfile.py: line 3: syntax error near unexpected token `os.getenv'
./pyfile.py: line 3: `print(os.getenv("EXAMPLE"))'
```

そのため，どのコマンドでこのファイルを実行するかを指定する必要があります．これに必要なのが**Shebang**です

## Shebang

Shebangについては，[手を動かして理解するshebang](https://qiita.com/takey/items/ae2124531fb57a197b22)という記事を見てください．私は，そのファイルを実行するコマンドを記述できる，程度の認識です．

とりあえず，pythonのファイルを動かせるようにしましょう．

```python: pyfile.py
#! /usr/bin/env python3
import os

print(os.getenv("EXAMPLE"))
```

```bash: bash
$ ./pyfile.py
None
```

実行できました．`EXAMPLE`という環境変数は存在しないので`None`が表示されています．

### `/usr/bin/env`

この`/usr/bin/env`は何者かは実行すればわかります．

```bash: bash
$ /usr/bin/env
SHELL=/bin/bash
WSL2_GUI_APPS_ENABLED=1
WSL_DISTRO_NAME=Ubuntu-22.04
......
```

とこんな感じで，単体で利用すれば環境変数を表示してくれるものです．ちなみに，この`env`については[私が書いた環境変数の設定を説明した記事](https://qiita.com/halglobe0108/items/735433531e7b17a20b54)でちょっと触れていますので読んでいただけると嬉しいです．


この`env`では，環境変数を設定しつつコマンドを実行することができます．
一旦，shebangを使わないpythonファイルを用意しました．
```python: pyfile_nosb.py
import os

print(os.getenv("EXAMPLE"))
```

これに対して，`env`で`EXAMPLE`の値を設定して実行します．

```bash: bash
$ env EXAMPLE=example python3 pyfile_nosb.py
example
```

このように，`EXAMPLE`に値を入れて実行することができました．

これをShebangを使ってすることもできます．ただし，Shebang内で複数引数を渡すときは最初に`-S`オプションを付ける必要があります．

```python: pyfile.py
#! /usr/bin/env -S EXAMPLE=example python3
import os

print(os.getenv("EXAMPLE"))
```

```bash: bash
$ ./pyfile.py
example
```

環境変数が設定されて実行されましたね．

本題に戻ると，`env`をShebangで利用すると，環境に依存した`python3`を探して実行してくれます．他のコマンドでも同様です．

これでdaemonにする準備ができました．
【Killed】dnf使うと殺される【Google Compute Engine】

# メモリ増やす
e2-microだときびい
```bash
dmesg
[  452.618590] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-1000.slice/session-1.scope,task=dnf,pid=3111,uid=0
[  452.853581] Out of memory: Killed process 3111 (dnf) total-vm:1095928kB, anon-rss:516240kB, file-rss:4kB, shmem-rss:0kB, UID:0 pgtables:1744kB oom_score_adj:0
[  453.132285] oom_reaper: reaped process 3111 (dnf), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/b86f1c2e-e802-f457-5fa9-b72ca6fab13d.png)


https://stevescargall.com/2021/12/20/resolving-commands-killed-on-gcp-f1-micro-compute-engine-instances/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/64777c28-1d9b-4695-fc63-4b6b87487514.png)

# `sudo dnf config-manager --disable google-cloud-sdk` でも回避できます

```bash
sudo dnf config-manager --disable google-cloud-sdk
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/c4cb677a-6e79-d70e-dfc5-0cc5e898328a.png)

https://higherhope.net/?p=4979
qiitaの文字数制限は2000000文字

qiitaのタイトルは255文字までです。
https://qiita.com/narita1980/items/545e2dc92bd9385cbcb7

中身が探してもなかったので調べてみると、
# 2000000文字
(200万文字)まででした。

ひたすらloremで回すと、こんなんになりました。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230043/b4968eb3-eec0-fcca-e520-506d3943bb17.png)
【雑記】人間が生みだした技術は人間の手の内に収めるべし

こんにちは、arcadia13です。

今回も思うところがあって雑記をします。

※雑記を書く目的は基本的に、自分に対する教訓・戒めとして残すことです。


# 人間が生みだした技術は人間の手の内に収めるべし

人間は文明を築く過程で様々な技術を生み出しました。

科学技術はもちろん、IT技術、手作業でしか行えない細かな技術、芸術、口伝や秘伝の技術、匠の業等、膨大な種類が存在します。

たくさんの人がこれらの恩恵を大なり小なり受けているはずです。

私もその一人です。

その生み出した技術の恩恵を受け続けるために、人間が常に意識しないといけないこと。

それは「人間の手の内に収めておく」ことだと私は思います。

技術は人間の手の内にある限りどうとでも扱えます。

日常生活を豊かにすることはもちろん、悪意ある使い方だって出来ます。

しかし、技術が一度人間の手を離れたらどうにもなりません。最悪、それが人類全体の敵になります。

人間の知恵や価値観、論理が通用するのも**技術が人間の手の内にあるから**です。

ゆえに、まずは**人間の制御下に置く**ことが重要だと私は考えています。

では、制御下に置いた後はどうするのか。

ただ制御下に置いただけでは無法地帯です。

残念ながらこの世には素晴らしい技術を悪用する人がたくさんいます。

また、新しい技術、革新的な技術が生まれたら、その度に法整備やガイドラインをきっちりしないと、社会が大変なことになりかねません。

世の中に新技術が出回るというのは、それだけで凄まじいパワーがあるわけですよ。

良くも悪くも、世の中を変えるような、そんなパワーが。

例えばこの情報社会において人工知能がその際たる例だと思いませんか？

未来のエンジニアとしては、IT技術とAIが人類に牙をむけるような未来を創りたくないですね。

以上、雑記でした。
【Git】git pullした際に自動でpruneする方法

## `git pull --prune`

`git pull --prune`を実行することで削除済みのリモートブランチをローカルに反映できます。  

```terminal
git pull --prune
```

https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---prune

また`git fetch`でも同様のことが可能です。  

https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---prune

## 常に`--prune`する

`git pull`や`git fetch`の際に常に`prune`するには以下のコマンドを実行してGitの設定を追加します。  

```terminal
git config --global fetch.prune true
```

現在のリポジトリのみに設定するには以下のコマンドを実行します。  

```terminal
git config --local fetch.prune true
```
【Playdate】文字入力用のキーボードを表示する

Playdateには文字入力機構も備わっていて以下キャプチャのようなiOSのデートピッカーのように上下で文字切り替え・入力できる機構が利用できます。
非常に簡単に実装できるので簡単に紹介します。

<img width="590" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/b3a0ed90-bf78-3fac-bf37-3bb4579fac74.png">

```main.lua
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

import "CoreLibs/keyboard"

local gfx <const> = playdate.graphics

local inputText = "Edit PressA" -- 編集テキスト

function myGameSetUp()
	-- キーボード: 文字変更時実行
	playdate.keyboard.textChangedCallback = function()
		inputText = playdate.keyboard.text
		gfx.sprite.redrawBackground()
	end
	
	-- キーボード: 変更終了時実行
	playdate.keyboard.keyboardDidHideCallback = function()
		print(playdate.keyboard.text)
	end
	
	gfx.sprite.setBackgroundDrawingCallback(
		function( x, y, width, height )
			gfx.drawText(inputText, 20, 20)
		end
	)
end

myGameSetUp()

function playdate.update()
	
	-- Aボタン: 文字入力
	if playdate.buttonIsPressed(playdate.kButtonA) then
		playdate.keyboard.show(inputText)
	end
	
	gfx.sprite.update()
	playdate.timer.updateTimers()
end
```

キーボードAPIを使うには`"CoreLibs/keyboard"`をimportします。
キーボードの表示は`playdate.keyboard.show([初期値])`を実行します。
今回はAボタンを押すとキーボードを表示するようにしました。

キー入力中の値を取得するには`playdate.keyboard.textChangedCallback`で実行したいコールバック関数を記述します。
キー入力している値は`playdate.keyboard.text`で取得できます。

キーボードを非表示した時には`playdate.keyboard.keyboardDidHideCallback`でコールバック関数を記述します。
他にも以下のコールバック関数が存在します。

`playdate.keyboard.keyboardDidShowCallback`：キーボードが表示された時
`playdate.keyboard.keyboardWillHideCallback([bool])`：キーボードを非表示する直前に呼び出す。引数はtrueがOKを押した時、falseがそれ以外の時
`playdate.keyboard.keyboardAnimatingCallback`：キーボードが表示/非表示アニメーションする際に呼び出す
IchigoJam でガッテンR？

[IchigoJam](https://ichigojam.net/) で「ガッテンR」的なものを作ってみた。

# ガッテンR

「ガッテンR」とは、プロジェクト59 タケ様がかつて頒布していたキットである。

[『ガッテンR』 ⑥　キット頒布について - プロジェクト59　：　キット頒布、電子工作　『ユルハム派』](http://project59.blog.fc2.com/blog-entry-619.html)

以下の仕様となっているようである。

* ボタンを押して離すと、モールス信号の「R」の音が鳴り、LEDが光る。
* 光るLEDの色は、ボタンを押すたびに緑と赤で交互に切り替わる。
* スイッチを切り替えると、「R」のかわりに「FB」の音を鳴らすモードにできる。

# 今回の仕様

ボタン (BTN) を押して離すとLEDが光り、モールス信号の「R」の音が鳴る。

# プログラム

20行目で設定を行う。`S` は音の高さ、`T` は音の速さに対応する。

```
10 ' ｶﾞｯﾃﾝ R ﾓﾄﾞｷ
20 S=10:T=4
30 IF BTN()=0 GOTO 30
40 IF BTN()<>0 GOTO 40
50 LED 1
60 BEEP S,T:WAIT T
70 WAIT T
80 BEEP S,T*3:WAIT T*3
90 WAIT T
100 BEEP S,T:WAIT T
110 LED 0
120 GOTO 30
```

# ポイント

`BEEP` で音を鳴らした時、実行が止まるわけではなく、音を鳴らしながら次の処理を行うようだったので、
音の長さ分の `WAIT` を入れた。

# 実行結果

IchigoJam S (1.3.1) で実行した。

<iframe width="560" height="315" src="https://www.youtube.com/embed/XjCuPbPAMPA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# おわりに

以下は読者への宿題とする。

* 「FB」を鳴らす機能
  * 「FB」を表すモールス信号は「・・－・　－・・・」である
  * ある文字を表す最後の音の終わりから次の文字を表す最初の音の始まりまでは、短点3個分の時間を開ける
* 光らせるLEDの色を変える機能
  * 緑色のLEDを適当なOUT端子に接続するか、WS2812B系のLEDを用いる

※IchigoJamはjig.jpの登録商標です。
現場で遭遇したテスト設計のアンチパターン

# はじめに

こちらは [ゆるWeb勉強会@札幌 Advent Calendar 2022](https://adventar.org/calendars/7513) 16日目の記事です。
最近悩む機会が多い「テスト設計」について書いてみます。

# 記事を書くきっかけ
2022年の仕事を振り返ると、テストに苦労した一年でした。

私のプロジェクトは新規開発よりも既存機能を改修することの方が圧倒的に多いのですが、改修で過去のテスト設計を活用しようとすると、よくこんなケースに遭遇します。

- テスト仕様書とテストコードが一致しない
- 具体的な実施条件や手順が明記されていない
- 期待結果に具体値が記載されていない
- テストデータが残っていない

今回はこういった内容を、実際に現場でも困っていることなので、テスト設計アンチパターンの事例紹介としてまとめます。

# 実録：テスト設計のアンチパターン
※主に単体テストをイメージして書いています（それ以外のテスト工程でも共通する部分があると思います）
## テスト仕様書とテストコードが一致しない
私のプロジェクトでは、テストコードの有無に関わらず、最初にマトリクス形式のテスト仕様書を作成します。
※歴史的背景から、テストコードは一部にしか導入できていません

本来であれば仕様書とテストコードは同期が取れているべきなのですが、いつのまにか内容にズレが発生していることが多々ありました。

そうすると改修部分のテスト設計に集中したいのに、まず「現行仕様を担保できるテスト設計&テストコードに修正する」という余計な作業が発生してしまいます。

これが非常にしんどい作業。何が正解か調べないと分からない。
そもそも見積にそんな作業工数は見込んでいないので、時間を理由に諦めてしまうことも多く、傷口がどんどん広がっていく状況でした。

まずは仕様書とテストコードを少しずつでも合わせていきながら、改修したときは必ず同じタイミングで本流へマージすることを徹底することから始めてみようと思います。
※ごく当たり前の話ですが、できていないのが事実！


## 具体的な実施条件や手順が明記されていない
手作業で実施するテストの場合、実施条件や操作手順が具体的に書かれていないと、前回と同じテストの再現が難しくなります。

プロジェクトには人の入れ替えが付き物であること、運用していくなかで何度も同じ機能をテストする可能性があることを踏まえると、再現性を意識したテスト設計はとても大事です。例えばAPIのURL、ジョブの実行コマンドなどはコピペしてそのまま使えるぐらい明確に書いておくのがベターです。

テスト設計するときは「何も知らない自分がこの仕様書を渡されて、迷いなくテストが実施できるか？」ということを一つ基準にして考えてみると良いのかもしれません。

## 期待結果に具体値が記載されていない
先ほどと近い話ですが、どういうインプット（データや操作）に対して、どういうアウトプットが期待されるのかも具体的に記述する必要があります。

例えば「XXマスタの項目値」「入力データのうち設計書の条件に合うもの」のような表現では、テストの状況や実施担当者によって正しいかどうかの判断が変わってきてしまいます。

テストは、誰が見ても客観的に同じ判断ができる状態が理想です。

## テストデータが残っていない
テストに使うデータは、テスト用のデータだけで完結させるのが望ましいです。条件に合うデータがたまたまあったからという理由で、既存データを流用してしまうと、次にテストをしたタイミングで状態が変わっている可能性があるためです。

これが私のプロジェクトでは徹底できておらず、毎回テストのためのデータ作成や修正に時間がかかっています。

理想を言えば、リリース環境（DEVやSTG）のデータを汚染しないように、テスト用の環境が別にあると良いのですが、共存せざるを得ないケースも少なくありません。その場合は通常のマスタとテスト用マスタでコード体系を分けるなど、データがぶつからないように工夫して登録するのが良さそうです。

# 学んだこと
いくつかのテスト設計アンチパターンを記載してきましたが、すべてに共通するのは「**再現性**」や「**客観性**」といったキーワードです。

誰でも同じようにテストを実施できて、同じように結果が判断できて、テストの再実施も簡単！という状態にしておかないと、システムやプロジェクトの継続的な運用は厳しいものになってきます。（厳しさを実感しています...）

こうしたアンチパターンから得た知見は体系立てて整理するとともに、プロジェクト全体で共有して、みんなでテスト設計のあるべき姿について理解を深めていきたいなぁと思いました。

しかし、テストって本当に難しい。
Ubuntu 22.04 で はまったこと

# Install編

## BIOS

* BIOSの入り方は機種によって変わるが、最近のmouseのは、ESC or DELなので、両方連打して入れる
* Bootで、UEFI HDDが1st priorityになっているので、UEFI DVD/CDやUEFI USB Diskなどを優先するように設定の変更が必要になる
* しかし、.isoを、DVDに焼いて、起動させようとすると、"Out of memory"と表示される
* Windowsに戻って、再度、installerのBootを試みると、BIOSのboot orderがリセットされる
→ BIOSのバグか、WindowsがBoot orderを変更したか
* Ubuntu 20.04/18.04/16.04と遡っていくと、20.04だと、Load kernel firstという意味不明なerror, 18.04/16.04は起動するものの途中でエラー
    * 途中でUEFIのSecure Boot: disableに変更しないと、古めのinstallerは起動もしない
* 一か八かで、BIOS modeをUEFIからCSM (Compatibility Support Module?)に変更し、legacy BIOS modeに変更すると、PMM function errorと出るが、見事、Ubuntu 22.04のinstaller diskから起動ができた
→ 2022年でも、未だにUEFIとOSの相性があるようだ・・・

## Installerが立ち上がっても

途中でエラーが出ることがあるが、気にせず無視すると、setupを完了させることができる


# repo

source.android.comによると、最近は、```$ sudo apt-get install repo``` でいけるとあったが、read onlyだとエラーになるので、昔ながらのcurlでdownloadして、chmod +xして、、、の方が良い

```
#!/usr/bin/env python3
```

# ssh

特定のhostの ```repo init``` や ```ssh``` で、 ```no mutual signature supported``` の エラーが出る。

どうも、OpenSSHの新しいバージョンで、利用できるalgorithmをdefaultでは制限しているようだ.

```~/.ssh/config
Host hoge
  PubkeyAcceptedKeyTypes +ssh-rsa
```

のようにして、明示的に指定すればOkのようだ.

```
$ ssh -o `PubkeyAcceptedKeyTypes +ssh-rsa` hostname
```

でsshが成功すれば、そのkey typeを上に書けばOk.


# python 2.7

```
$ sudo apt-get install python2
```

## pip for python2.7 env

```
$ wget https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.py
$ wget https://files.pythonhosted.org/packages/27/79/8a850fe3496446ff0d584327ae44e7500daf6764ca1a382d2d02789accf7/pip-20.3.4-py2.py3-none-any.whl
$ python2 pip-20.3.4-py2.py3-none-any.whl/pip install --no-index pip-20.3.4-py2.py3-none-any.whl
```

## pip with python2.7 (example)

After the above installation,

```
$ pip install markdown
$ pip install py-gfm
```

## error case study : proxy with pip

```
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', NewConnectionError('<pip._vendor.urllib3.connection.HTTPSConnection object at 0x7f749375a890>: Failed to establish a new connectio
```

が出た場合は、

```~/.bashrc
export http_proxy=http://userId:password@proxy.xxx.com:8080
export https_proxy=$http_proxy
export HTTP_PROXY=$http_proxy
export HTTPS_PROXY=$https_proxy
```

どうも、pythonのurllib3は、proxyの時に、http://　のみを受け付けるproxy serverの場合には、```https://proxy.xxx.com:8080``` のように書いてはいけなく、 ```http://``` と書けとのことです。

```~/.pip/pip.conf
[global]
trusted-host = pypi.python.org
               pypi.org
               files.pythonhosted.org
```

も必要になるかもしれません。
TypeScript/JavaScript: performance.mark を使うときは初回 mark は捨てる？

# 背景

ある Library 関数において無駄な処理だなぁと思った際に、感覚ではなく、客観的に見せる為に速度比較をしようとした。

TypeScript 初心者が辿り着いたのが 
1. performance.now による計測
1. performance.mark/measure による計測

どちらも同じ performance なんで、何が変わるんだろうとなんも考えず計測関数を用意して測ってみたところ・・

何故か、想定通りに計測出来なかった。その原因推測と対処法の共有

そう
**Solve「本質を追求し問題を解決する」**
の実現・・の筈 :hamburger: 

# 結論

- performance.mark を使う際は、一個目は cache が効いてなさそうなので、使い捨てしよう。（たぶん

ほんとかどうかは、下層まで追ってない（追い方知らない）ので不明ですので、詳しい人の教えがあると嬉しい

# 調査内容
## コード
### 計測関数
```typescript: performance.now を使った計測関数
function measureExeFunc(executeFunction: { (timestamp: Date): number; (arg0: Date): void; }, date: Date) {
    var startTime = performance.now();
    executeFunction(date);
    var endTime = performance.now();
    console.log(`${executeFunction.name}: `, endTime - startTime);
}
```

```typescript: performance.mark/measure を使った計測関数
function measureExeFunc2(executeFunction: { (timestamp: Date): number; (arg0: Date): void; }, date: Date) {
    performance.mark('ini'); // ここがcache 効かせるための捨て mark
    performance.mark('start');
    executeFunction(date);
    performance.mark('end');
    performance.measure(executeFunction.name, 'start', 'end');
    console.log(performance.getEntriesByType('measure'));
    performance.clearMarks();
    performance.clearMeasures();
}
```

### 被計測関数
単純にループ処理にしてみた

```typescript: 100 count
const functionMeasured100 = (timestamp: Date) => {
    let sum = 0;
    for (let count = 0; count < 100; count++) {
        sum += count;
    }
    return sum;
};
```
```typescript: 1000 count 
const functionMeasured1000 = (timestamp: Date) => {
    let sum = 0;
    for (let count = 0; count < 1000; count++) {
        sum += count;
    }
    return sum;
}
```
### 実際の計測処理
参照キャッシュが影響しないように２つの Date() を用意して計測
```typescript 
const currentDate2 = new Date();
currentDate2.setMilliseconds(currentDate2.getMilliseconds() - 5);
const currentDate3 = new Date();
currentDate3.setMilliseconds(currentDate3.getMilliseconds() + 5);
measureExeFunc(functionMeasured100, currentDate2);
measureExeFunc(functionMeasured1000, currentDate3);

measureExeFunc2(functionMeasured100, currentDate2);
measureExeFunc2(functionMeasured1000, currentDate3);
```

## 計測結果
### 読み捨て無し
mark('ini') の部分をコメントアウトした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/05b70d8a-460b-a593-2d93-40875a25f5ba.png)

### 読み捨て追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f34242d5-2515-b1aa-20a6-fe9125ba5543.png)

## 所感
mark() の初回に now を記録しつつ、初期化処理で時間がかかってそう


# Documents

https://developer.mozilla.org/ja/docs/Web/API/Performance/now

https://developer.mozilla.org/ja/docs/Web/API/Performance/mark

https://developer.mozilla.org/ja/docs/Web/API/Performance/measure


# あとがき
VS Code でのインテリセンスもほんと便利ですね。
便利過ぎて、無いとコードかけそうにない気がします :laughing:
[php]クラスって何?結局わからない!関数との違いは?

## はじめに
クラスって何?結局わからない!
私は今まで何度もクラスについて理解しようとしましたが、挫折を繰り返していました。
今回は、腹を括ってクラスについて学びます。


## まずは関数
以下のような関数を作りました。

```php
function animals($one,$two,$three){
	echo 'あなたの好きな動物は'.$one.'と'.$two.'と'.$three.'ですね!';
}
```
はい。
好きな動物3つを引数（ひきすう）に渡して表示するだけのなくても良いような関数です。
これをクラス化してみます。
```php
class Like_animals{
	public $one;
	public $two;
	public $three;
	
	public __construct($one,$two,$three){//コンストラクタ。クラスが呼び出された時に最初に実行されるもの
		$this->one = $one;
		$this->two = $two;
		$this->three = $three;
	}

	public Echo(){
		echo 'あなたの好きな動物は'.$this->one.'と'.$this->two.'と'.$this->three.'ですね!';
	}
}
```
いかにも長ったらしくなりました。
これを起動するには、
```php
$animals = new Like_animals('ブドウ','りんご','ゴリラ');
$animals->Echo();
```
ってやったげます。
そーすると、
```あなたの好きな動物はブドウとりんごとゴリラですね!```
っていうしょーもない内容が出力されます。

## え,何?
え?ここまで読んで「結局何が関数とちゃうん?長ったらしいだけちゃうんか?おぉ?」というツッコミをされた方、いますよね。
ここからが本題です。
最近のゲームでは描写も美しく、レーシングゲームなんかを作る時も計算の量は膨大になります。
例えば、さっきのクラスで
・あなたの好きな動物はブドウとりんごとゴリラですね!
・あなたの好きな動物はブドウとりんごとゴリラかい?
・あなたの好きな動物はブドウとりんごとゴリラですからね?
・あなたの好きな動物はブドウとりんごとゴリラです!
・あなたの好きな動物はブドウとりんごとゴリラですよ
の5種類の文章を出力する必要があるとします。

これが関数だと、
```php
function animals($one,$two,$three){
	echo 'あなたの好きな動物は'.$one.'と'.$two.'と'.$three.'ですね!';
}
function animals2($one,$two,$three){
	echo 'あなたの好きな動物は'.$one.'と'.$two.'と'.$three.'かい?';
}
//以下省略
```
というふうにいっぱい書かなくてはなりません。
そして、いちいち引数を宣言して処理するため時間がかかります。
ただ、これがクラスになると
```php
class Like_animals{
	public $one;
	public $two;
	public $three;
	
	public __construct($one,$two,$three){//コンストラクタ
		$this->one = $one;
		$this->two = $two;
		$this->three = $three;
	}

	public Echo(){
		echo 'あなたの好きな動物は'.$this->one.'と'.$this->two.'と'.$this->three.'ですね!';
	}
	public Echo2(){
		echo 'あなたの好きな動物は'.$this->one.'と'.$this->two.'と'.$this->three.'かい?';
	}
	public Echo3(){
		echo 'あなたの好きな動物は'.$this->one.'と'.$this->two.'と'.$this->three.'ですからね?';
	}
}

$animals = new Like_animals('ブドウ','りんご','ゴリラ');
$animals->Echo();
$animals->Echo2();
$animals->Echo3();
```
あーら楽チン。
書く量が少ないし、コンストラクタで引数を保存しているため、引数を宣言し直す必要もありません。

## まとめると
クラスを使うことで処理を速く、可視性の高いコードとなるのです。

## でも、関数の方が良い時もある?
ここからは私の持論ですが、クラスを使うときは限られるんじゃないかな?なんて思います。
例えば、引数に1を足すプログラムを作るとき、関数なら
```php
function plus_one($number){
	return $number+1;
}
```
ですみますが、クラスにすると
```php
class Plus_one{
	public $number;

	public __construct($number){
		$this->number = $number;
	}

	public echos(){
		return $this->number+1;
	}
}
$one = new Plus_one(10);
echo $one->echos();
```
なんて長ったらしくなっちゃいます。
一つの値を使ってたくさんの処理をする必要があるときに、クラスは役に立つものなんじゃないでしょうか。

## 最後に
今回、初めてクラスについて学びました。
間違えているところ、多々あると思うので、指摘をよろしくお願いいたします。
Kageki (TD4互換機) でなんちゃって電子オルガン

[TD4の命令を実行できる自作CPU「Kageki」](https://elchika.com/article/9ac9fd67-86c5-4b1b-a355-4f662e8af794/)で電子オルガンっぽい何かを作ってみた。

# 仕様

入力ポートの各ビットにHIGHを入力すると、HIGHを入力したビットによって異なる周波数の信号を出力ポートのビット1 (0-origin) に出力する。
音階は保証しない。

# プログラム

```
場所 機械語   アセンブリ言語
-------------------------------
0    00100000       IN  A
1    00001000       ADD A, 1000
2    11100100       JNC NO3
3    11111100       JMP BEEP
4    00000100 NO3:  ADD A, 0100
5    11100111       JNC NO2
6    11111100       JMP BEEP
7    00000010 NO2:  ADD A, 0010
8    11101010       JNC NO1
9    11111100       JMP BEEP
A    00000001 NO1:  ADD A, 0001
B    11100000       JNC START
C    10110010 BEEP: OUT 0010
D    01011000 WAIT: ADD B, 1000
E    11101101       JNC WAIT
F    10110000       OUT 0000
```

# 解説

0番地で、入力ポートを読み込む。
1番地～B番地で、HIGHのビットの判定をする。立っているビットによってここの判定に費やすクロック数が変わるため、出力がLOWとなる時間が変わり、出力信号の周波数が変わる。
C番地～F番地で、出力ポートにHIGHを出力する。

# 実行結果

入力ポートに [Pmod BTN](https://digilent.com/shop/pmod-btn-4-user-pushbuttons/) を、出力ポートに [2-way Buzzer Board](https://elchika.com/article/c55891ed-5a5f-4355-bf36-8a9f5ca6cd37/#h_2-way%20Buzzer%20Board) を接続し、10kHzのクロックで実行した。
出力ポートのビット1は 2-way Buzzer Board の manual 端子(音声信号入力)に接続される。

<iframe width="560" height="315" src="https://www.youtube.com/embed/8lUSnupvw5w" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
Raspberry Pi Pico Wのちょいネタ

Raspberry Piは、基本Debian GNU/Linuxベースの専用ＯＳであるRaspberry Pi OSで動作する小型の組み込みPCですが、そのマイコン版であるRaspberry Pi Picoは、PythonやC/C++または、Arduino IDEでプログラミングができます。種類でいうとESP32やそのESP32を搭載しているM5 Stackシリーズに近いものになっています。
Raspberry Pi Picoは、純粋なマイコンボードとして発売されているので、BluetoothやWi-Fiなどは搭載されておらず、マイコンRP2040のI/Oが扱いやすいピンとして用意された基板となっています。
特徴的なのは、基本的なマイコンとしてのペリフェラルに加え、低消費電力駆動可能なスペック且つ、その割には豊富なFlashやメモリの容量だと思います。USB機能も扱いやすいので、Raspberry Pi Picoを使ったオリジナルキーボードなどもRaspberry Pi Picoを使った作例や商品が数多く見られます。
私もRaspberry Pi PicoをArduino IDEで開発するための入門本は、いくつか出版しています。

https://amzn.to/3YsnQHa

今回は、そんなRaspberry Pi PicoにWi-Fi機能が搭載されたRaspberry Pi Pico Wについてちょっと紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/b5094230-666c-59f5-cde0-e5ce9b7e6c0c.png)


Raspberry Pi Pico Wは、まだ日本では発売されておらず、海外の通販サイトで購入できる形となっています。
ただ、2022年10月には、[技適も通っている](https://www.tele.soumu.go.jp/giteki/SearchServlet?pageID=jg01_01&PC=008&TC=N&PK=1&FN=221101N008&SN=%94%46%8F%D8&LN=1&R1=*****&R2=*****)ので、日本国内の販売ももうすぐなのではないでしょうか。

Raspberry Pi Pico Wに搭載されている通信モジュールは、Infineonというメーカーの[CYW43439](https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/wi-fi-4-802.11n/cyw43439/?redirId=216343)というもので、モジュール自体は、Wi-FiもBluetoothも対応しているものですが、配線的にRaspberry Pi Pico Wとしては、Wi-Fiのみ使用可能だと思います。

Raspberry Pi Pico Wとしても低消費電力が魅力だと思うので、以前M5ATOMと[Raspberry Pi Pico Wの消費電力を比較した記事](https://qiita.com/jksoft/items/86d61e85320733da70cc)を書きました。電池駆動でも長時間動作可能で、基板サイズは、Raspberry Pi Zeroよりも小型で、ちょっとしたところにも組み込めると思います。

Arduino IDEのボード定義では、Raspberry Pi Picoも対応しているので、M5Stackシリーズで動作しているスケッチはすぐに移植できると思うので、国内で販売されたらまた、記事や本にしたいと思います。
EC2にSSH接続するためのセキュリティグループの設定

毎回どーーーーーーしても忘れてしまうので、自分のメモ＆アウトプット用に書き出します。

## 覚えたいこと
EC2にSSH接続するとき、セキュリティグループのインバウンド設定をしなければいけません。
そのインバウンド設定で特定のIPアドレスを設定することでSSH接続できる範囲を狭めることができます。
↓の設定のことですね。
![Screenshot 2022-12-16 21.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704144/952b6b88-06e3-27af-23bf-22ee35ebf16c.png)

このようにIPアドレスを0.0.0.0/0にすると言わば誰でも入れるようになってしまいます。
とはいえキーがないとSSH接続できないのですが、やっぱ怖いですね。

ただ、このインバウンド設定するIPアドレスは何にすればいいのか？
覚えてはしばらく経って忘れ、覚えてはしばらく経って忘れを繰り返してしまい、同じことを調べる自分が嫌になります。。笑

##  結論
一般家庭のWIFIを使用している場合はプロバイダーから割り当てられたIPアドレスを設定すればおK。
簡単に言うと、自分が使ってる通信のIPアドレスを使いなさいということ。

__ではどこでIPアドレスを知ることができるのか？__

それは↓のサイトを使えば一発でわかる。
https://www.cman.jp/network/support/go_access.cgi
※変なサイトではありません。

↑のサイトはグーグル先生で「グローバルIPアドレス　確認方法」で調べて一番上の検索結果に出てきたサイトです。

サイトで出てきたIPアドレスをセキュリティグループのインバウンドに設定すればSSH接続できます。

## 仕組み
ぶっちゃけここは勉強不足もあり、あんまりよくわかっていません笑
簡単に調べた感じだと通信をするには契約しているプロバイダーを使ってネットを見ていると思いますが、そのプロバイダーから教えてもらったIPアドレスから通信をするわけで、パソコンから直接通信するわけではありません。

__イメージ__
PC ←→　プロバイダー　←→　サイト

パソコンもIPアドレスを持っていますが、パソコンだけではネットに繋がりません。
Wi-FiやLANケーブルを使わないと通信できないですよね。

更にいうとそのWi-Fiなどは契約しているプロバイダーが提供しているので、プロバイダーがIPアドレスを教えてくれてみなさんが使っているケータイやPCが接続することでネットの海に飛び込むことができます。

このように通信しているのはプロバイダーなわけなので、プロバイダーからいただいたIPアドレスをセキュリティグループに登録することでSSH接続が可能になります。

僕はこのように理解しているのですが、違っていたらぜひぜひ教えて下さいmm

ここまで言葉にすれば次回から忘れないだろう。。。笑
【GMC-4】ガッテンR的なもの

学研の4ビットマイコン GMC-4 で「ガッテンR」的なものを作ってみた。

# ガッテンR

「ガッテンR」とは、プロジェクト59 タケ様がかつて頒布していたキットである。

[『ガッテンR』 ⑥　キット頒布について - プロジェクト59　：　キット頒布、電子工作　『ユルハム派』](http://project59.blog.fc2.com/blog-entry-619.html)

以下の仕様となっているようである。

* ボタンを押して離すと、モールス信号の「R」の音が鳴り、LEDが光る。
* 光るLEDの色は、緑と赤がボタンを押すたびに交互になる。
* スイッチを切り替えると、「R」のかわりに「FB」の音を鳴らすモードにできる。

# 今回の仕様

* F以外のキーを押して離すと、2進LEDのビット3を点灯させ、モールス信号の「R」を鳴らす。
* Fキーを押すと、「R」のかわりに「FB」を鳴らすモードの有効/無効を切り替える。
* 「FB」を鳴らすモードのときは、2進LEDのビット0を点灯させる。

# プログラム

以下のプログラムは、[MikeAssembler](https://mikecat.github.io/mike_assembler/) でアセンブルできる。

```
target gmc4

	TIY 3
	TIA 0
	AM
main_loop:
	CAL RSTR
key_wait:
	KA
	JUMP key_wait
key_release_wait_loop:
	KA
	JUMP key_released
	JUMP key_release_wait_loop
key_released:
	TIY 3
	CIA 0xF
	JUMP make_sound
	; R / FB 切り替え
	MA
	AIA 8
	AM
	TIY 0
	CIA 0
	JUMP switched_to_fb
	JUMP main_loop
switched_to_fb:
	CAL SETR
	JUMP key_wait

make_sound:
	CAL SETR
	CAL SHTS
	MA
	CIA 0
	JUMP play_fb
	CAL LONS
	CAL SHTS
	JUMP main_loop

play_fb:
	CAL SHTS
	CAL LONS
	CAL SHTS
	TIA 2
	CAL TIMR
	CAL LONS
	CAL SHTS
	CAL SHTS
	CAL SHTS
	JUMP main_loop
```

以下は、このプログラムの機械語表現である。

```
  | 0 1 2 3  4 5 6 7  8 9 A B  C D E F
--+-----------------------------------
0 | A 3 8 0  4 E 2 0  F 0 7 0  F 1 2 F
1 | 0 B A 3  C F F 2  C 5 9 8  4 A 0 C
2 | 0 F 2 7  F 0 5 E  1 F 0 7  E 1 E 9
3 | 5 C 0 F  3 D E A  E 9 F 0  5 E 9 E
4 | A E 9 8  2 E C E  A E 9 E  9 E 9 F
5 | 0 5
```

# 解説

GMC-4 の「短い音」`CAL SHTS` および「長い音」`CAL LONS` は、以下のようなモールス信号に都合がいい仕様になっているようなので、そのまま用いた。

* 音を鳴らした後、「短い音」1個分の動作停止が入る
* 「長い音」は「短い音」3個分の長さになっている

また、「短い音」1個分の長さは約0.15秒のようである。

「R」と「FB」の切り替えは、8を足すことで同じ処理で互いに切り替えられるようにした。
さらに、「R」と「FB」で共通する最初の部分を使いまわしたり、モールス信号の終了時の `CAL RSTR` と「R」モードに切り替える時の `CAL RSTR` を重ねたりすることで、容量を節約した。

# 実行結果

<iframe width="560" height="315" src="https://www.youtube.com/embed/vSisxQgneUg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

モールス信号が遅い印象がある。
Fluentdを使ってデータ分析に必要なログを収集してみた

### はじめに

データに基き適切な意思決定を行うため、データ分析が重要視されています。
そこで欠かせない要素が、分析に必要なデータを集めるためのログ収集処理。

ログ収集ツールFluentdを使って、Nginxアクセスログを収集しMySQLに保存してみました。

### 構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/7f70c205-2a8f-836e-3b10-99cf938ef452.png)

### ログ収集に求められる機能

- さまざまな構造・非構造データを収集可能
    - アプリ依存のログフォーマットを、分析に使えるように整形し一元化可能か
- (ニア)リアルタイムにログ収集可能
    - ストリーミングや非同期処理によりログ収集の高速化可能か
- システム性能へ影響しない
    - ログ収集のリソース消費による業務システムが性能劣化を抑制可能か
- スケーラビリティ
    - データ量が急増しても、スケールアップ・スケールアウトにより対応可能か
- ログ欠損の対策
    - バッファ機能やリトライ機構が備わっているか

### Fluented(フルエントディー)とは

https://www.fluentd.org/

- ログ収集ミドルウェア
- ストリーミングデータ処理
- バッファ機能が備わっている
- プラグインによる機能拡張

### Nginx(エンジンエックス)とは

https://ja.wikipedia.org/wiki/Nginx

- フリーかつオープンソースなWebサーバである
- 処理性能・高い並行性・メモリ使用量の軽減に焦点を当てて開発されている
- HTTP, HTTPS, SMTP, POP3, IMAPのリバースプロキシの機能を持つ
- ロードバランサ、HTTPキャッシュなどの機能も持つ

### ログ収集を行うための設定

#### Nginxの設定

- クライアントからのHTTPリクエストボディを収集するため、アクセスログに記録しました

Nginxの`HTTP Echo`モジュールを使用し、HTTPリクエストボディをエコーバックします。

設定例:
```
load_module modules/ngx_http_echo_module.so;

location /xxx {
    echo_read_request_body;
    echo $request_body;
}
```

`echo_read_request_body`ディレクティブを使って、リクエストボディを読み込み、
`echo`ディレクティブを使って、リクエストボディをクライアントに返却します(これでアクセスログに記録されます)。

- アクセスログのフォーマットは、`ltsv`形式を使用しました

`ltsv`は、`Labeled Tab-separated Values`の略で、`key:value`形式のタブ区切り形式です。

設定例:
```
http {
    log_format ltsv escape=none 'timestamp:$time_iso8601\t'
                            'request_method:$request_method\t'
                            'uri:$request_uri\t'
                            'status:$status\t'
                            'size:$bytes_sent\t'
                            'request_body:$request_body';
}
```

#### Fluentdの設定

- `in_tail`入力プラグインを用いて、Nginxアクセスログファイルの末尾からログを読み取ります

`in_tail`の動作は、`tail -F`コマンドに似ています。

設定例:
```
<source>
  @type tail
  format ltsv
  path /var/log/nginx/access.log
  pos_file /var/log/td-agent/nginx.access.log.pos
  tag nginx.access
</source>
```

- `filter_grep`フィルタープラグインを使って、ログ収集対象を絞り込みます

収集負荷の軽減とログ量の削減のため、収集対象データを絞り込みます。

`request_methodがPOST`かつ`statusが500`のアクセスログに絞り込むための設定例です:
```
<filter nginx.access>
 @type grep
  <regexp>
    key request_method
    pattern /^POST$/
  </regexp>
  <regexp>
    key status
    pattern /^500$/
  </regexp>
</filter>
```

- `mysql_bulk`出力プラグインを使って、収集したログをMySQLに保存します

設定例:
```
<match nginx.access>
  @type mysql_bulk
  host <MySQLサーバーのホスト名>
  port <MySQLサーバーのポート番号>
  database <MySQLデータベース>
  username <MySQLユーザ>
  password <MySQLパスワード>

  column_names <MySQLに格納する列名>
  key_names <収集ログのキー(column_namesの列名と1対1の関係)>
  table <保存先のMySQLテーブル>

  flush_interval <バッファーのフラッシュ間隔>
  buffer_chunk_limit <バッファーチャンク上限値>
  buffer_queue_limit <バッファーに貯めるキュー上限値>
</match>
```

### ログ収集の流れ

冒頭構成図の再掲です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/7f70c205-2a8f-836e-3b10-99cf938ef452.png)

- クライアントからNginxにHTTPリクエストを発行します
- リクエストのボディなどのデータがNginxアクセスログに書き込まれます
- FluentedがNginxアクセスログを監視し、ログ増分を収集します
- 収集したログを、MySQLの指定テーブルに格納します
- MySQLの保存データを使って、データ分析を行います

### おわりに

Fluentdを使ってNginxアクセスログを収集してみました。
Fluentdの特徴として、ログ収集の方法と記録先を柔軟にカスタマイズできることを確認できました。