OmniAICreator/Qiita-1.07M huggingface dataset:
シェルスクリプト type コマンド

type コマンドでは、指定されたコマンドが、外部コマンドなのか、組み込みコマンドなのか、シェル関数なのかを調べることが可能。
普段、自分がよく使うコマンドに対して、type コマンドで調べてみると新しい発見があるかもしれない。

```bash:type-example1.sh
# ls は外部コマンドで、エイリアスが設定されている
$ type ls
ls is aliased to `ls --color=auto'

# ll は ls でエイリアスが設定された外部コマンド
$ type ll
ll is aliased to `ls -alF'

# cd は 組み込みコマンド
$ type cd
cd is a shell builtin

# cp は外部コマンド /bin/cp に存在する
$ type cp
cp is hashed (/bin/cp)

# function はシェルにおけるキーワードの一つ
$ type function
function is a shell keyword

# func というコマンドは存在していない
$ type func
bash: type: func: not found

# func シェル関数を定義
$ func(){ echo "ABC"; }

# 今度は定義したシェル関数が表示される
$ type func
func is a function
func () 
{ 
    echo "ABC"
}
```
Goで音楽を奏でてみた

Advent Calendar5日目に音声分析をGoでやろうとして挫折してしまいましたが、せめて音楽を再生できないか調べてみました。
https://qiita.com/usk81/items/8284ff74e79bdbd7dbae

pydub相当のパッケージは存在しませんが、音楽ファイルを再生できるぐらいのものはありました。

beep
https://github.com/faiface/beep

```golang
// package main plays two audio file
package main

import (
	"log"
	"os"
	"time"

	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"
	"github.com/faiface/beep/speaker"
)

func main() {
	f, err := os.Open("test.mp3")
	if err != nil {
		log.Fatal(err)
	}
	st, format, err := mp3.Decode(f)
	if err != nil {
		log.Fatal(err)
	}
	defer st.Close()

	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))

	done := make(chan bool)
	speaker.Play(beep.Seq(st, beep.Callback(func() {
		done <- true
	})))
	<-done
}
```

ちなみに音楽再生は `oto` というライブラリに依存しているものがほとんどでした。

oto
https://github.com/hajimehoshi/oto

hajimehoshi?
なんか聞いたことがある... (´ε｀；)

golang.tokyoで何度か登壇されてたebiten作った人でした
https://github.com/hajimehoshi/ebiten
golangでslackbotを作る

以前からGAS→Rubyと書き換えてきた鉄道の遅延情報教えてくれるslackbotをgolangで書き換えて運用を始めたので、紹介させてください。

https://github.com/yuina1056/go-TrainInfoBot

## 実動作
<img width="298" alt="スクリーンショット 2019-12-10 21.17.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92194/08426326-f149-1b37-6c83-6580f5a2cf63.png">

## 動作環境
golang 1.12.5
AWS Lambdaで動作
LambdaへのデプロイはGUIから行っています。

## golangコード
仕事でDIして依存をmockできるテストコードを書きやすいコードを書く方法を覚えたので、テストコードを書く練習を兼ねてテストコードを書くようにしています。
ロジックもうちょいなんとかなりそうだけれど、ちょっと面倒だったので一旦はこれで。

今もうまくテストが通ってない部分があるので、ちまちま触ってます。。。

## Lambda
AWS Lambdaにてgolangのサポートがあるため、デプロイ先は最初から決まっていました。
デプロイ方法は以下ブログ参照しました。
https://dev.classmethod.jp/cloud/aws/aws-lambda-supports-go/
イベントに出展してわかったこと 2019年 IoTつくるよ GUGEN Festa2019出展記録 ～POPを作ろう～

2019年11月30日にIoTつくるよ２、12月8日にFESTA 2019 by MAに出展しました。

IoTつくるよ２ではROTSONをFesta2019には、BLEネームタグとROTSONを展示しました。

##IoTつくるよ２
![IMG_0959.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/2fcb2919-b109-a22f-f47d-e901b2cb6bb2.jpeg)

##FESTA 2019 by MA
![IMG_0989.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/58c9476a-11d3-a7fa-227c-f590cb0feec8.jpeg)


##お勧め持ち物
展示にあたり、必要なものとして、以下があります。
・展示品
・POP
・電源
・WiFI

さらに、設営に必須なのは、電源タップ、USBケーブルです。
さらにさらに、セロハンテープや、両面テープ、のり、ボンド、はさみ、カッターなどがあると良いでしょう。
（私は、全部持ち込んでいませんがｗ）
精密ドライバーも持ち込むと良いです。

IoTつくるよの際に短いUSBケーブルしかもっていかず、Festaの際は予備を含めて5本と、USBハブを持ち込みました。
これは大正解でした。

##POPを作ろう
今回はPOPのつくり方を説明したいと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/c27f7d41-07f9-df96-00dd-76f33269b0d8.jpeg" alt="" width="600"height="" border="0" />
LINE Things Mini Award 決勝戦・展示会でMashUpAwardの伴野 智樹さんから頂いたPOPになります
これを真似して展示会用のPOPを作ってみました。

こちらは、いつも使っているPOPです。
百円ショップなどで売っているスタンドと、コルクボードです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3be28231-5b49-460d-49f0-f46079384eb7.jpeg" alt="" width="600"height="" border="0" />

そして、これが今回製作したものです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/8f5249cd-a4d5-d7f4-21b9-9df003ef1722.jpeg" alt="" width="600"height="" border="0" />

使用部材は、アマゾンなどの段ボールです。
アマゾンやヨドバシで買い物をするとダンボールが届きますが、この段ボールを取っておいて再利用します。
スタンドは、以下のサイトなどの段ボール用の型紙を使用しました。
https://www.aak.co.jp/hanbai/paperstand/paperstand_all.html

製作したスタンドです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/72dcef4c-5157-d79e-54d4-524d11649354.jpeg" alt="" width="600"height="" border="0" />

ちなみに、伴野さんが作ってくれたスタンドは右です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ae54f080-dd17-ecf2-113e-22270bb97e2b.jpeg" alt="" width="600"height="" border="0" />

展示条件によって、POPを増やしたい、減らしたいというときに、必要な数のスタンドを用意する必要もなく、嵩張ることもありません。
このスタンドはすごくお勧めです。

ちなみに、今回Festa2019は、GUGENの選出に伴い、3ブース頂けました。
1ブースを返却する予定でしたが、せっかくなので3ブース構成で準備しました。
当日行ってみると、お隣さんは、子供連れ、かつ、ちょっとサイズ的に難しそうだと思ったので、1ブースをお譲りして2ブース（1机）構成としました。
今回、展示用POPを用意していたおかげで増減が容易であり、うまく配置することができました。
これもすべて伴野さんのおかげです。
[rundeck]job1の結果をjob2で使う（値を引き継がせる）

`2.9.0` 以降のRundeckではWorkflow対応しているのですが、それ以前のRundeckでは値を次のjobに引き継がせるのは不可能です。 （ [2.9.0以降のやり方](https://www.rundeck.com/blog/output-processing-data-passing-preview) ）

なので、job1の結果を保持しjob2を実行するjob3というShellを作成する方法をとりました。
rundeck-cliを使っているので、こちらのコマンドはインストールしておいてください。 ( [公式のインストール方法](https://rundeck.github.io/rundeck-cli/install/) ）

```shell
#!/bin/bash
JOB1_RESULT_IDS=`rd run -f -j job1 | tail -n 1`
rd run -f -j job2 -- -IDS $JOB1_RESULT_IDS

exit 0
```

* `rd run` : rundeckのjobを実行する
* `-f` : 実行を出力
* `-j` : jobをnameで指定。 groupがある場合は `group/job名`。環境変数 `RD_PROJECT` も必要です。(同じ名前のjobが別projectに存在する可能性があるので)
* `| tail -n 1` : 最後の行だけ取得
* `-- -IDS` : Rundeck側のoption変数。この値でjob2に渡してあげます

`| tail -n 1` をやっている理由として、rundeck-cliの実行結果はログのような形式で表示されるので、最後の1行に欲しい内容をechoしておけば取得できるためです。

job1の内容が以下だとして

```shell
#!/bin/bash
echo "1,2,3"
```

出力されるログはこんな感じになります

```
# Found matching job: UUID jobName 
# Execution started: [1] UUID /jobName <http://localhost:4440/project/mikeneko-test/execution/show/1>
1,2,3
```

欲しいのはラストの `1,2,3` なので、 `tail -n 1` でここだけ取得しています。

このShellを使って2つのjobの実行管理と値の引き渡しを行います。
なので、Rundeck側でWorkflow機能を使ってスケジュール管理をする必要はありません。

### エラーハンドリング

rd run コマンドは失敗すると 終了ステータス2 を返してくるのでこれでエラーキャッチします

```shell
#!/bin/bash
JOB1_RESULT_IDS=`rd run -f -j job1`

if [ ! $? = 0 ]; then
  echo error: job1
  exit 1
fi

IDS=`echo $JOB1_RESULT_IDS | awk '{print $NF}'`
rd run -f -j job2 -- -IDS $IDS

if [ ! $? = 0 ]; then
  echo error: job2
  exit 1
fi

exit 0
```
* `$?` : 直前のコマンドの終了ステータスをキャッチします。
* `awk '{print $NF}'` : awkで空白区切にして、一番ラストの要素を取得します。

最初の例だと、 `| tail -n 1` で繋げてしまっている関係上、前のrdコマンドが失敗しても必ずここのtailコマンドで成功扱いになってエラーハンドリングができなかったので一旦切るようにしました。

この場合、 $JOB1_RESULT には空白区切で中身が入っているので awkで一番ラストの要素を引っ張り出すことで同じことが再現できます。

様々な理由でバージョン古くて困ってる人は試してもいいかもしれません。
データベースのインデックスに関するメモ

##インデックスとは
- SELECT文の絞り込み条件で使うカラムに貼っておいて、SELECT処理の高速化を図るもの
- 本に目次があると、必要なページにたどり着きやすくなるのと同じようなこと

##注意点
・**貼りすぎ**ると逆に重くなる

・**主キー**には自動でインデックスが貼られるので、手動で追加する必要はない

・`null`かどうかで検索をかける時には機能しない
→削除フラグとして削除日を入れる構成などでは機能しない

・文字列の**中間一致**、**後方一致**では機能しない

・**SELECT文の割合**が少ないシステムの場合は使わない方が良い
→INSERT、UPDATE、DELETEの処理は若干遅くなる

##参考
[【DB初心者向け】SQLアンチパターンから学ぶ、インデックス最適化の基礎](https://qiita.com/Sayatam/items/9c1f125cc97b9e9183a4)

[インデックスが使えない検索条件](https://qiita.com/NagaokaKenichi/items/44cabcafa3d02d9cd896)
Raspberry Pi で HDMIからLPCM8ch  (96kHz24bit)出力する・Pi4対応

# はじめに
Raspberry Pi 楽しいですよね。私は専らオーディオ用に使っています。
普通はピンヘッダのI2S出力をDACに繋いでハイレゾ再生するようですが2chしか出力できません。HDMI出力を使えばAVアンプに接続して8ch出力することができます。ところがネット上を検索してもHDMIからの8ch出力に関しての情報は乏しいようです。
そこで今回はHDMIから8ch出力する簡単な方法を示します。

# 環境
OS:標準のRaspbian（buster、 stretch）
機種:pi0w、pi2B、pi3B、pi4B （pi3B+は持ってない）
もちろんpi4にはbusterが必要です。

# 8ch出力の使い道
8ch出力なんて何に使うの？サラウンド？
もちろんサラウンドやマルチチャンネルの音楽ソフトの再生に使ってもよいのですが私はfirの畳み込みソフトと組み合わせてマルチアンプシステムに使ってます。
マルチアンプシステムって何？サラウンドと違うの？という方はググって下さい。
簡単に言うと適当に作った自作スピーカーから素晴らしい音質で音楽を再生することができます。

# HDMIから8ch出力するサンプルプログラムが最初からあった！
raspbian をインストールすると `/opt/vc/src/hello_pi/`の下にサンプルプログラムのソースコードがあります。音声出力のサンプルプログラム（C言語）は`/opt/vc/src/hello_pi/hello_audio/` にあります。
ちなみにこのプログラムはALSAではなくopenMAXというAPIを使っています。
著作権者はBroadcom Europe Ltd、ライセンスは3条項BSD（で合ってるよね？）なのでありがたく使わせてもらいます。
サンプルプログラムではビット深度が16bitまたは32bitとなってます。
RaspberryPiのHDMI出力は24bitとなっているので下位の8bitは切り捨てられていると思われます。

# サンプルプログラムがバグってる？
サンプルプログラムをmakeして実行ファイルを作って8ch出力を試します。私が試した結果では「マランツ」のAVアンプでは8ch出力できるのに、「SONY」「YAMAHA」のAVアンプでは8ch出力できません（pi0w、pi2、pi3の場合。pi4は8ch出力できる）。いろいろ試した結果、ChマッピングのLEFをCSに変えると8ch出力できるようになりました。他のメーカーのAVアンプは試してないのでわかりません。openMAXに詳しい方がいたら教えて下さい

~~~
// pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
pcm.eChannelMapping[3] = OMX_AUDIO_ChannelCS;
~~~


# サンプルプログラムを修正する
CannelMappingの修正以外にやったこと
出力をHDMI 8ch、bitdepthを32bitに決め打ちしました（私がそれ以外のフォーマットを必要としないので）。
バッファにテスト信号をコピーしている部分をfreadで標準入力からデータを読み込むようにしました。
これだけでサンプルプログラムが実用になるプログラムになります。

# githubに上げてみた
https://github.com/assi-dangomushi/hdmi_play
githubも初めて使うのでqiitaの記事を調べながら登録してみました。
最初にライブラリをコンパイルしておいてください。
makeすれば実行ファイル"hdmi_play.bin"が出来上がるのでパスの通った場所にコピーします。

```
cd /opt/vc/src/hello_pi/libs/ilclient/
make
cd ~
git clone https://github.com/assi-dangomushi/hdmi_play.git
cd hdmi_play
make
sudo cp hdmi_play.bin /usr/bin/
```
 
# 使い方
このプログラムはALSAではないので、余計な出力を避けるために`/boot/config.txt` でaudioを無効にしておいたほうが良いです。


~~~
#dtparam=audio=on
~~~


コマンドライン引数はサンプリングレートのみです。データは標準入力から読み込みます。
データは32bit符号付き整数、リトルエンディアン、８個(8ch分)のデータで1サンプル分です。

linux の音声ソフトは標準入出力に対応したものが結構あります。
sox、aplay、arecord、mpd、bruteFIRなど
入力フォーマットが決め打ちなので出力側でこれに合わせて変換する必要が有ります。

使用例

~~~
sox 8chの音声ファイル -t s32 -r 96000 - | hdmi_play.bin 96000 
~~~

AVアンプの設定はstraightとかDirectとか、HDMIからの入力をサラウンド処理しないでそのまま再生するように設定して下さい。

# 問題点
## 何故かpi4とそれ以外でchが入れ替わる。
原因不明。個人で使う分には気をつけていればよいが、公開するプログラムとしてはいかがなものか。機種を判別してchの順序を統一するべきだろう。

pi0w pi2B pi3B　の順序
Lf, Rf, Lfe, Cf, Ls, Rs, Lb, Rb

pi4B　の順序
Lf, Rf, Lb, Rb, Cf, Lfe, Ls, Rs

pi3B+は持っていないので確認できません。

## AVアンプによってはHDMIから音声信号を受けて再生し始めるのに時間がかかる。
このため、一曲ごとにhdmi_play.binを起動すると曲の頭が欠けてしまう。
これを避けるためにはhdmi_play.binを起動し続けて名前付きパイプからデーターをリダイレクトするようにすれば良い。ただし複数ソフトからデータが送られると正常に再生できない。

## hdmi_play.bin 自身を複数起動すると正常に再生できない。
サービスとしてsystemdから起動したほうが良いのだろう。

# まとめ
1. Raspberry PiからHDMIにLPCM8ch出力（96kHz 24bit）は簡単に実現できるよ。
1. 残念な出来だが実用になるプログラムをgithubに上げてみた（高音質だよ！）。
1. 誰かもっとマシなプログラムを作ってくれ。

# 追記
機種判別してpi4とそれ以外でチャンネルマッピングを統一しました（かなり無理やり）。
2020/03/08

# 追記2
Raspberry Pi OS 2020-08-20 からアップグレードを掛けたら音がでなくなった。 プロプラ部分に依存してるから手の施しようがない。
とりあえずアップグレードから除外するパッケージを指定して乗り切る。
次のバージョンからは最初から音がでなくなりそう。

```
sudo apt-mark hold libraspberrypi-doc raspberrypi-bootloader libraspberrypi0 libraspberrypi-bin libraspberrypi-dev
```
2020/11/29
SwiftでAWS S3に画像をアップロードする時のTips

# はじめに

[GameWith AdventCalendar 2019](https://qiita.com/advent-calendar/2019/gamewith)の11日目の記事になります。

AWSのモバイルSDKの使い方は定期的に更新されるイメージがあるため、最近の書き方が気になって検証してみました。
今回の記事では、**S3の指定バケットに画像を直接アップロードする部分のコードや、気をつけるべきポイント**などを簡単に紹介します！

※ ライブラリの導入や、AWS側の設定などについては今回は省略しています。

# 必要なファイルとプロパティ

```swift
import AWSCore
import AWSS3

// 必須
var uploadCompletionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
// 以下はなくても良い
var uploadProgressBlock: AWSS3TransferUtilityProgressBlock?
var uploadProgress: Float = 0
```

`AWSS3TransferUtilityUploadCompletionHandlerBlock` は名前の通り、アップロードが完了したか否かを取得するために利用します。
`AWSS3TransferUtilityProgressBlock` はアップロードの進捗を取得するために利用します。
アップロードするデータが画像ファイルなど比較的容量の小さいものの場合は、数秒もかからずアップロードが完了するため必要ないかもしれませんが、`uploadProgress` と合わせて利用することで、ナビゲーションバーの下にプログレスバーを置いたり、進捗を示す専用のアラートを用意したりUXを高めることができます。

# アップロード用のメソッドを定義

```swift
func uploadImage(data: Data) {

    // アップロードの進捗を取得(なくても良い)
    uploadProgressBlock = {(task, progress) in
        DispatchQueue.main.async {
            if self.uploadProgress < Float(progress.fractionCompleted) {
                self.uploadProgress = Float(progress.fractionCompleted)
            }
        }
    }
        
    // アップロードの完了可否を取得
    uploadCompletionHandler = { (task, error) -> Void in
        DispatchQueue.main.async {
            if let error = error {
               // エラー処理
            } else {
               // アップロードが完了しているのでその後させたい処理
            }
        }
    }
        
    // AWSのアップロード用の設定(今回はexamplebucket/photoに画像を上げる想定)
    let bucketName = "examplebucket"
    // 時刻を入れたりユーザーIDを入れたりファイル名が被らないようアプリによって定義しましょう
    let uploadKeyName = "photo/\(UUID().uuidString).png"
    let contentType = "image/png"
        
    let expression = AWSS3TransferUtilityUploadExpression()
    expression.progressBlock = uploadProgressBlock
        
    let transferUtility = AWSS3TransferUtility.default()
    transferUtility.uploadData(data, bucket: bucketName, key: uploadKeyName, contentType: contentType, expression: expression, completionHandler: uploadCompletionHandler).continueWith { (task) -> AnyObject? in
        if let error = task.error {
            // エラー処理
        }
        if let _ = task.result {
            // アップロードが開始したのでその後させたい処理（あれば）
        }
        return nil
    }
}
```

## 補足

今回は `Data` 型のオブジェクトをアップロードしていますが、`UIImage` から` Data` への変換は下記の標準コードで簡単に実装できるので以下を使うケースが多いです。

```swift
public func pngData() -> Data? // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format
```

# 気をつけるべき箇所

アップロードが始まったが、**特にプログレスも得られず、エラーも返ってこないといったケース**の際はバケットポリシーの設定漏れのことが多いです。

下記の設定は一旦全ての操作を許可するものなので、本番の際はユーザーに該当バケットに対してどういった操作を許可するのかを考慮して設定しましょう。

```
{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Effect":"Allow",
      "Principal": "*",
      "Action":[
          "s3:*"
      ],
      "Resource":["arn:aws:s3:::examplebucket/*"]
    }
  ]
}
```
GR-Citrusでセンサーで音を出そう

GR-Citrusで音を出そうの続きです。
https://qiita.com/usashirou/items/5e0775653cf54740d092

今回は、以前使った近接センサーを使って音を鳴らしてみましょう
センサーの範囲内に入ると音が鳴るというシステムです。

ただし、困ったことがあります。
アンプをつなげると、ノイズ音が入ってしまうのです。
このために、動作していない時の方が気に障るという最低な仕様となってしまいました・・・
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/69954974-9554-8d90-4238-2c3e385a631c.jpeg" alt="" width="10000"height="" border="0" />

```
#include <Arduino.h>
#include <WavMp3p.h>
#define trigPin 8
#define echoPin 9

WavMp3p wavmp3p(44100);

void setup()
{
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
}

void loop()
{
	 int duration, distance;
	digitalWrite(trigPin, HIGH);
	delayMicroseconds(1000);
	digitalWrite(trigPin, LOW);
	duration = pulseIn(echoPin, HIGH);
 	distance = (duration/2) / 29.1;
 
 if (distance >= 200 || distance <= 0){
	Serial.println("Out of range");
 } else {
	wavmp3p.play("audio2.mp3");
	Serial.print(distance);
	Serial.println(" cm");
 }
 delay(500);
}
```

else以下で動作するようになっており
if (distance >= 200 || distance <= 0)
を変更すれば、反応する範囲を変更可能です。
GR-Citrusで音を出そう

GR-Citrusで近接センサーとServoをつなげたよの続きです。
https://qiita.com/usashirou/items/f8605590b18ee0195eeb

今回は、音を出してみましょう。

内容は、「GR 特設サイト：MP3, WAVファイル再生 内蔵ROM編」です。
https://www.renesas.com/jp/ja/products/gadget-renesas/boards/gr-citrus/project-embedded-rom-music.html

このような形になります。
ピン0とGndを繋ぎます
スピーカーは、100円ショップで売っている単なるスピーカーをばらして使っています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/77ed04a6-8d8e-48a0-526d-f7051fd30369.jpeg" alt="" width="10000"height="" border="0" />
しかし、GR-Citrusは、音声出力機能がありますが、残念ながら、アンプ機能が無く、音が小さいという難点があります。
今回、間にアンプを入れてみましょう
Aliexpress等で60～200円程度で購入できます。
入れてみました。（ジャンパーワイヤーがお邪魔ですね・・・）

アンプへ３Vまたは5Vを接続し、ピン０とアンプのInをつなげれば完成です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d7a64d0d-7abc-fbe0-31eb-14774b085e0e.jpeg" alt="" width="10000"height="" border="0" />

MP3の再生は資料通り以下がループされます。

```
void loop()
{
	wavmp3p.play("jingle01.mp3");
}
```
【Rails】formで情報を登録する時、〇〇_idカラムから親要素の情報を取得して送信する方法

#環境
rails 5.2.4
ruby 2.5.7

#実装したい内容
子要素をformでデータベースに登録する際、selectでデータベースに既に登録されている、親要素を選択したい。

#具体的な状況
子要素→item
親要素→genre
itemsテーブルにgenre_idカラムを持つ。
form_withなどでgenre_idを登録したい。その時、genresテーブルに登録されたgenreのtitleを直接、選択できるようにしたい。

#書き方
[items/new]

```
<%= form_with model:@item, url: admins_items_path, method: :post do |i| %>
<p>name</p>
<%= i.text_field :name %>
<p>genre</p>
<%= i.select :genre_id, Genre.all.map {|p| [p.title, p.id]}, :prompt => "選択してください" %>

<%= i.submit "submit!" %>
```
selectを使うことで選択肢が出現します。
mapはGenre.allで取得したデータを配列として出力してくれます。
 {|p| [p.title, p.id]}このような順で書くことにより、titleデータを選択肢として出力してくれます。
PythonistaでSceneKitを使った3D描画

Pythonista の objc_util で SceneKit を使うと iOS のみで 3D 描画できるスクリプトを見つけたので紹介します。

# 元記事

3d-omz.py 注:load_framework(‘SceneKit’) を足さないとエラーになる
https://github.com/tdamdouni/Pythonista/blob/master/scenes/3d-omz.py

3D in Pythonista
https://forum.omz-software.com/topic/1686/3d-in-pythonista

# 実行イメージ

<img width="300" alt="7BA22298-B587-42D0-8E6D-F17360AF67DC.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36064/47a70e91-2770-87e0-8def-0064bb3ae446.png">

# 解説

```python
from objc_util import *
```

objc_util モジュールが提供する機能を直接呼び出せるようにします。

objc_util モジュールは標準モジュールの ctypes をベースにしているので、この一行で ctypes モジュールが提供する Structure なども使えるようになります。

```python
load_framework('SceneKit')
```

SceneKitフレームワークを読み込んで、プログラム上で操作できるようにします。

3d-omz.py では記載されていなかったので、昔は呼ぶ必要がなかったのかもしれませんが、iPadOS13 ではこれがないと SceneKit が提供する SCNView クラスなどを ObjCClass で Python で使える形式に変換する際に no Objective-C class named ‘xxxx’ found というエラーで怒られてしまいます。

```python
SCNView, SCNScene, SCNBox, SCNText, SCNNode, SCNLight, SCNAction, UIFont = map(ObjCClass, ['SCNView', 'SCNScene', 'SCNBox', 'SCNText', 'SCNNode', 'SCNLight', 'SCNAction', 'UIFont'])
```

SceneKit が提供するクラス群を obj_util.ObjCClass を使って Python で使える形式に変換しています。

標準関数の map を使うと同じ処理をまとめて記述できるので楽ですよね。

```python
class SCNVector3 (Structure):
    _fields_ = [('x', c_float), ('y', c_float), ('z', c_float)]
```

ctypes.Structure を使って、float型の3つの属性(x,y,z)を持つ構造体を定義します。
ここで定義した構造体は後で Text の BoundingBox を取得する際に使います。

```python
    main_view = ui.View()
    main_view_objc = ObjCInstance(main_view)
```

空の ui.View を作成し、その View インスタンスを objc_util.ObjCInstance に渡す事でに Objective-C からアクセスするためのポインタを取得しています。

後で SceneKit の View をこの main_view の子供としてぶら下げる事で、Pythonista の ui.View の中に SceneKit の描画物を表示できるみたいです。
(詳細は勉強不足で理解できていません)

```python
    scene_view = SCNView.alloc().initWithFrame_options_(((0, 0),(400, 400)), None).autorelease()
    scene_view.setAutoresizingMask_(18)
    scene_view.setAllowsCameraControl_(True)
```

SCNView のインスタンスを alloc() メソッドを呼んで作成。
その後 initWithFrame:options: を呼んで、位置(0,0)で大きさ(400,400)に初期化します。
最後にインスタンスに autorelease()を呼ぶ事で、不要になったらメモリを自動で破棄するように設定しています。

SCNView.initWithFrame:options:
https://developer.apple.com/documentation/scenekit/scnview/1524215-initwithframe?language=objc

setAutoresizeMask_ は、親 View のサイズが変わった時にどのような処理をするか設定するメソッドです。
18 という数字は flexibleWidth の 2 と、flexibleHeight の16 の論理和で、これを設定する事で親 View の大きさが変わった時に、幅と高さを追従する形になります。

これは Pythonista の ui モジュールの View クラスの flex 属性と同じだと思うとイメージしやすいと思います。

UIView.AutoresizingMask
https://developer.apple.com/documentation/uikit/uiview/1622559-autoresizingmask

setAllowsCameraControl_を True にすると画面をスワイプしたりしてカメラを回転させたりできるようになります。なんらかのビューアーや、開発の初期の動作確認ではこれを True にしてしまうとが手軽で良いです。

```python
	scene = SCNScene.scene()
	node_root = scene.rootNode()
```

SceneKit で管理するカメラやライト、描画物は全て Node で階層付けされています。
SCNScene の rootNode はその階層構造の一番親にあたるものです。

この後、 rootNode に対して色々な node を追加することで、画面に何をどのように表示するかが決定されていきます。

```python
```
```python
```
```python
```
```python
```
```python
```
bashでシェル変数を環境変数に変換する

# なにがしたい？
別ファイルで定義されているシェル変数を環境変数に変換したい。
初歩的だけど思いつくのに数分かかったのでメモ

# 方法
環境変数は`export`で定義できるので、純粋にexportしてあげればいい。

```var.sh
var="qiita"
```

```run.sh
#!/usr/bin/env bash

source ./var.sh
export var=$var #ここが大事
./print.sh
```

```print.sh
#!/usr/bin/env bash

echo $var
```

`export var=$var`しないと、print.shに`var`の値が引き継がれない
初心者によるプログラミング学習ログ 180日目

# 100日チャレンジの180日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

180日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>180日目<br><br>webサイトコーディング課題<br>フッター作成<br>更新履歴のページ作成<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1204128084766519297?ref_src=twsrc%5Etfw">December 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Swift Network.framework Study 20191210「Bonjour Browse」

# Study

Network.framework
Study：「Bonjour Browse」

## 環境
Client：Java、NetBeans、jmdnsライブラリ
<a href="https://github.com/jmdns/jmdns">https://github.com/jmdns/jmdns</a>
Server：Swift、Xcode

# Client Source Java

```java
package example.java.network;

import java.net.InetAddress;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;

public class ExampleBonjourCreateService {
    public static void main(String[] args) {
        try {
            // Create a JmDNS instance
            JmDNS jmdns = JmDNS.create(InetAddress.getLocalHost());

            // Register a service
            ServiceInfo serviceInfo = ServiceInfo.create("_example._tcp.local.", "example", 7777, "example");
            jmdns.registerService(serviceInfo);

            // Wait a bit
            Thread.sleep(25000);

            // Unregister all services
            jmdns.unregisterAllServices();

        }
        catch(Exception e) {
            System.out.println(e);
        }
    }
}
```

## build.gradle

```text
compile 'org.openhab.jmdns:jmdns:3.4.2'
```

# Server Source Swift
## main.swift

```swift
import Foundation
import Network

if #available(OSX 10.15, *) {
    let exampleNWBrowser = ExampleNWBrowser()
    exampleNWBrowser.startBrowser()

    while exampleNWBrowser.running {
        sleep(1)
    }
} else {
    // Fallback on earlier versions
}
```

## ExampleNWBrowser.swift

```swift
import Foundation
import Network

@available(OSX 10.15, *)
class ExampleNWBrowser {
    public var running = true
    private var browser:NWBrowser?

    func startBrowser() {
        let myQueue = DispatchQueue(label: "ExampleNetwork")
        let nWBrowser = NWBrowser(for: .bonjour(type: "_example._tcp", domain: nil), using: NWParameters())
        self.browser = nWBrowser
        browser!.stateUpdateHandler = {(state) in
            print("State:\(state)")
        }
        browser!.browseResultsChangedHandler = { (results, changes) in
            print("browseResultsChangedHandler")
            for result in results {
                print(result)
            }
            for change in changes {
                print(change)
            }
        }
        browser!.start(queue: myQueue)
        print("start")
    }
}
```

# Output

```text
start
State:ready
browseResultsChangedHandler
Result(nw: example._example._tcp.local.@[en0], endpoint: example._example._tcplocal., interfaces: [en0], metadata: <none>)
added(Network.NWBrowser.Result(nw: example._example._tcp.local.@[en0], endpoint: example._example._tcplocal., interfaces: [en0], metadata: <none>))
browseResultsChangedHandler
removed(Network.NWBrowser.Result(nw: example._example._tcp.local.@[en0], endpoint: example._example._tcplocal., interfaces: [en0], metadata: <none>))
```

ResultにEndPointが入っている
EndPointを使用すれば、送信・受信は可能となる
WindowsPEの構造を説明してみる

DVD/USBメモリなどから起動できるWindowsPE。元々はCDから起動するように作られたはずなので、ISOファイルからたどってみましょう。

##ISOファイルの中
![pe1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/ce548300-2356-1151-9454-687f9f22915d.jpeg)

上図の通りです。例としてAOMEIで作成した(んだっけ？な)isoを使っています。isoファイルは7-zipで中を見ることができますね。
まず中にあるのはsourcesとBootとEFIとファイルが二つ。bootは旧来のBIOSブート時に使うのでUEFIからしか起動しねーよ、という方は削除しても大丈夫です。逆にEFIフォルダはUEFIブートに使用します。重要なのはsources内のboot.wimファイル。ここに、WinPEのシステムファイルが圧縮されています。

###boot.wimファイルの中
次に、そのboot.wimファイルの中身を見てみましょう。
![pe2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/cc5ec9a4-a80a-aa94-5204-a623c5240af3.jpeg)

一番重要なのはWindowsフォルダ、そしてその中のSystem32フォルダ。まぁこの辺りは普通のWindowsと同じです。もちろん、PE特有の部分もあります。
一つ目はwinpeshl.ini。これはシェルとして動くソフトを指定しています。これを編集することにより、独自のシェルを指定したり特定のソフトをいきなり起動されることができます。
二つ目はstartnet.cmd。これはコマンドプロンプトがシェルとして起動するときに自動的に実行されるファイル。AcronisTrueImageのPEなんかはここで指定されていますね。

Program FilesフォルダはいつものWindowsとほぼ同じですね。sourcesフォルダにはWindowsRE(修復環境として起動されるアレ。PE上で動きます。)が入ります。

とりあえず今日はここまで。えっと、リンクの貼り方ってどうするんだろう。徐々に慣れていこうと思いますｗ
paizaでアセンブラ その8


#概要

paizaでアセンブラ、やってみた。
code32でやってみた。

#閃きのイメージ

python2で書いてます。

#サンプルコード


```
import subprocess
import os

def gcc():
    c_file = 'test.s'
    test_c = """
.code32
.text   
.globl  main

main:
    movl    $4, %eax
    movl    $1, %ebx
    movl    $msg, %ecx
    movl    $6, %edx
    int     $0x80
    movl    $1, %eax
    int     $0x80

.data
msg:
    .byte   104
    .byte   101
    .byte   108
    .byte   108
    .byte   111
    .byte   10
"""
    with open(c_file, 'w') as f:
        f.write(test_c)
    os.system("gcc -no-pie %s" % c_file)
    os.system("./a.out")
    os.system("ls")
    
if __name__ == '__main__':
  gcc()


```

#成果物

https://paiza.io/projects/4awc7JXjQZGEizhPs3uA0A


#サンプルコード


```
import subprocess
import os

def gcc():
    c_file = 'test.s'
    test_c = """
.code32
.text
.global main

main:
    mov     $msg, %edi
    call    puts
    ret
    
.data   
msg:
    .asciz "hello world!"
"""
    with open(c_file, 'w') as f:
        f.write(test_c)
    os.system("gcc -no-pie %s" % c_file)
    #os.system("file a.out")
    os.system("./a.out")
    
if __name__ == '__main__':
  gcc()

```

#成果物

https://paiza.io/projects/7_dJGst5y2tIwH9injShpA



以上。
min/maxみたいな関数の呼び出し

これは[C++ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/cpp)11日目の記事です

昨日は@segurさんの[C++版FBX SDK入りのDockerイメージを作ってみる](https://qiita.com/segur/items/9e20a1d29bf397f1f843)でした

## このエラー結構遭遇しますよね?
`std::min`とか`std::max` `std::clamp`のように関数の引数が

```c++
template <class T>
T hoge(T x1, T x2, ...);

template <class T>
T huga(std::initializer_list<T> t);
```

みたいになっている場合の関数でこんな呼び出しをしたいことが結構ある

```c++
double x = ...;
x = std::clamp(x, 0, 1); // xを[0,1]に収めたい
```

しかしこれだとTが推論できなくてコンパイルエラーになる

```
prog.cc:6:9: error: no matching function for call to 'clamp'
    x = std::clamp(x, 0, 1);
        ^~~~~~~~~~
/opt/wandbox/clang-head/include/c++/v1/algorithm:2649:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('double' vs. 'int')
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
^
/opt/wandbox/clang-head/include/c++/v1/algorithm:2638:1: note: candidate function template not viable: requires 4 arguments, but 3 were provided
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
^
```

オーバーロードが多い`std::min`とかだと結構な数のエラーが出る
https://wandbox.org/permlink/xXkJXYMNqMW7PI3d

そして仕方なくこんな感じの対処をすることが多い

```c++
std::clamp(x, 0., 1.); // 小数点をつけて浮動小数点リテラルに変更した
```

## でもさ

リテラルだったらいいけど何か変数だったときがめんどくさい

```c++
int l = ..., h = ...;

std::clamp(x, static_cast<double>(l), static_cast<double>(h));

int y = ...;
float z = ...;
std::min({x, static_cast<double>(y), static_cast<double>(z)});
```

え？C言語スタイルのキャストなら短く書ける？またまたご冗談を

## 推論できないなら

推論させなければいいじゃない

```c++
std::clamp<double>(x, l, h);
```

簡潔だし戻り値の型がハッキリしてるのもよい

`initializer_list`の方も問題なく使える

```c++
std::min<double>({x, y, z});
```

ただし縮小変換に伴う警告はしっかり出るのでそこら辺で結局キャストをそこそこ使うような気もする(でも[この場合](https://wandbox.org/permlink/Q2MdKh9D9pZYQ6jX)だと出ない。c++って難しい)

## 参考までに

`std::gcd` `std::lcm`はテンプレート引数が2つに分かれているので今回の例には当てはまらない(符号の有る無しで結果を分けてるみたい)

## 明日は

@kizulさんの[C/C++間での翻訳フェーズの違い](https://qiita.com/kizul/items/dab3018e51366b301521) です
Gatsby.js + Netlify でつくったサイトに Google Analytics を導入する

## 背景

Gatsby.js + Netlify でつくっているサイトに Google Analytics を入れてみたくなりました。
プラグインでサクッと導入できることは知っていましたが、地味にハマったので共有します。

ちなみに公式リファレンスを隅まで読めばハマりません。
**今すぐこのページを閉じて公式リファレンスを読みましょう。**

## 最初に試したこと

`npm install --save gatsby-plugin-google-analytics`

をしてから、以下のように書きました。

```gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-google-analytics",
      options: {
        trackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID
      }
    },
  ],
}
```

 Google Analytics から発行されたトラッキング ID は Netlify の環境変数に入れておけばよさそうです。
 Netlify の環境変数は process.env.HOGE で参照できます。

これで完璧。
だと思っていたら違いました。

## ハマったポイント

上述した方法では Google Analytics が動きませんでした。
しばらく悩んだ後、以下の対応が必要なことに気がつきました。

### 1. head オプションをつける

[アナリティクスヘルプ](https://support.google.com/analytics/answer/1008080?hl=ja)を読むと、Google Analytics のスクリプトは

>  <head> タグの直後に貼り付けます。

と書かれています。

しかし Gatsby.js では、[head option](https://www.gatsbyjs.org/packages/gatsby-plugin-google-analytics/#head)を指定しない場合、 Google Analytics のスクリプトが body に配置されるそうです。

```gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-google-analytics",
      options: {
        trackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID,
+       head: true,
      }
    },
  ],
}
```

### 2. gatsby-plugin-google-analytics を最初に読み込む

どうやら gatsby-plugin-google-analytics は gatsby-config.js に書かれているプラグインの中でいちばん最初にロードしないといけないようです。

```gatsby-config.js
module.exports = {
  plugins: [
    // ここより前で別のプラグインをロードしないこと
    {
      resolve: "gatsby-plugin-google-analytics",
      options: {
        trackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID,
        head: true,
      }
    },
  ],
}
```

この2つの対応を行った結果、無事に Google Analitics が導入できました。

## おわりに

冒頭でも述べたとおり、当記事の内容は[公式のリファレンス](https://www.gatsbyjs.org/packages/gatsby-plugin-google-analytics/#make-sure-plugin-and-script-are-loaded-first)にも書かれています。

何番煎じか分かりませんが、「公式リファレンスをちゃんと読むべき」ということを改めて学びました。

ちなみに作ったサイトはこちら。
https://machidania.tokyo/
2019年のOSSへのコミット件数は63件でした

2019年は初めてOSSへPRを送ってマージされた年なので、
2019年12月25日時点でのOSSコミット数を計測してみます。

# サマリ

合計63コミットでした。
全てRuby/rails関連でした。
来年も頑張ります。

# 内訳
## rails/rails
27コミット

## yasslab/railsguides.jp
32コミット

## elastic/elasticsearch-ruby
1コミット

cookpad/chanko
1コミット

## cookpad/styleguide
1コミット

## tomiacannondale/era_ja
1コミット
Anaconda 仮想環境

Anacondaでの仮想環境の作り方を、メモしておく

#Condaコマンドで作成
ターミナルを開く

```
conda create -n 任意の仮想環境名 python=3.7
```

#作成した仮想環境をアクティベート（有効化）

```
source activate 任意の仮想環境名
```

#必要なライブラリ等のインストール
※アクティベート状態

```
conda install jupyter
conda install pandas
conda install numpy
conda install matplotlib
```

#作成した仮想環境の一覧

```
conda env list
```

アクティベート状態のものに*（アスタリスク）がついてる
リポジトリパターンの説明とLaravelでのフォルダ構成

####ビジネスロジックとは
アプリケーション固有の処理。
アプリケーション固有の状態遷移を記述した部分。

####リポジトリパターンについて
データの操作に関連するロジックをビジネスロジックから切り離し、抽象化したレイヤに任せることで保守や拡張性を高めるパターン。

ヒラマサでは、Controllerとかの処理の中(ビジネスロジック)で、DB関連の処理を別ファイルに記述し、その処理ファイルを`app/Logic`ディレクトリ中に入れていく。

Modelもディレクトリを作って実装していく。例えば、TaskController内の処理をLogicの方に格納すると下記のような構成になる。

```console
app-・
    |-Console
    |-Exceptions
    |-Http
    |-Logic
     |-Task
      |-TaskLogic.php
      |-TaskLogicInterface.php
    |-Mail
    |-Model
    |-Policies
    |-Providers
```

具体的なリポジトリパターンの実装については下記を参照。
[リポジトリパターンの実装](https://qiita.com/bmf_san/items/c8d7b38b5f1f5747c2fd)
Rails6 Twitterログインでエラー

TwitterログインをRailsで実装したときに苦労したので簡単にメモ

# Invalid Credential

どうやらomniauthを複数の箇所で定義していたのが原因だったようです。
複数の参考サイトを参照するときは注意が必要かもしれません。

```ruby:config/initializers/devise.rb
Devise.setup do |config|
  config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'], callback_url: "http://127.0.0.1:3000/users/auth/twitter/callback"
end
```

```ruby:config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
    provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
```

# 401 Authorization Required
![スクリーンショット 2019-12-10 19.44.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104887/c9de55ec-633b-3a23-29f7-a677501d9e07.png)

TwitterのAPI Keyが違っていました

# 参考サイト
[twtterログインとの死闘（devise+omniauth）](http://www.eggineer.info/entry/2018/02/13/125856)
[RailsでのTwitter認証](https://qiita.com/puremoru0315/items/f1d459b663fd3b715dee)
[Rails5 Twitterログインをdevise+omniauthで実装](https://qiita.com/daigou26/items/d84e64af775a3054e950)
[Swift]アプリの起動シーンにおける画面遷移(SceneDelegateを用いる)


## 概要

　ios13から新たに”SceneDelegate” というクラスができました。このクラスができる前は、起動時におけるStoryBoard間の画面遷移などはAppDelegateクラスでコードを書いていましたが、iosのアップデートに伴い、アプリ起動時にうまく画面遷移しないという問題が生じました。
　本記事は、SceneDelegateにコードを書いて、起動時の画面遷移を制御させるための記事です。
　*(ios13以降を対象にしています)*

参考にした記事は[こちら](https://qiita.com/omochimetaru/items/31df103ef98a9d84ae6b)

## できるようになること
ログインしているときはMain.StoryBoard、会員ではないorログアウトしているときはLogin.StoryBoardに画面遷移することを目標にしています。

## コード内容
UserDefaultsで、ログイン状態の有無を記録します。

## 実際のSceneDelegate内のコード


```swift:SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let _ = (scene as? UIWindowScene) else { return }
        
        
        
        let ud = UserDefaults.standard
        let isLogin = ud.bool(forKey: "isLogin")
        let window = UIWindow(windowScene: scene as! UIWindowScene)
        if isLogin == true {
            // ログイン中だったら
            
            let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
            let rootViewController = storyboard.instantiateViewController(withIdentifier: "RootTabBarController")
            self.window?.rootViewController = rootViewController
            self.window?.backgroundColor = UIColor.white
            self.window?.makeKeyAndVisible()
            
        } else {
            // ログインしていなかったら
            
            let storyboard = UIStoryboard(name: "Login", bundle: Bundle.main)
            let rootViewController = storyboard.instantiateViewController(withIdentifier: "RootNavigationController")
            self.window?.rootViewController = rootViewController
            self.window?.backgroundColor = UIColor.white
            self.window?.makeKeyAndVisible()
        }
    
        
    }
```
GitHub_1端末複数アカウントの設定_https

clone時から設定する用？

###system configを「credential.helper=manager」を削除する。
https://howpon.com/4738#1_credentialhelpermanagerWindows
/etc/gitconfigのcredential部をコメントアウトするだけでも可。
コメントアウト実行時は管理者権限でgitbashを上げること。

###Windows資格情報マネージャを削除する。
http://hajimete-program.com/blog/category/git/

###global gitconfigを「credential.helper=wincred」に設定する。
https://help.github.com/en/github/using-git/caching-your-github-password-in-git

###1端末で複数アカウントを設定する。
「認証まわりを使い分ける…プライベートリポジトリもcloneしたりpushしたい！」から参照
https://tech-1natsu.hatenablog.com/entry/2018/10/27/102621
もう混合しない、CREとカスタマーサクセス

CRE(Customer Reliability Engineering)とCS(Customer Success)混合しがちですが、全く違うので整理しておきます

# Customer Success
## 概要
契約開始から、顧客の満足度、ロイヤリティを高める事で主に以下の成果を期待する為の活動

* チャーン抑止、管理
* 利用者の口コミ、評価の発信拡散などによる二次収益の最大化
* アップセル、クロスセルなどLTVの最大化

## フィールド
サブスクリプションビジネス

## ミッション
顧客の成功

# Customer Reliability Engineering
### 概要
顧客の持つサービスに対する不安を払拭する事を目的とする為の役割
不安とはgoogleのブログより

> 人は、自分の環境を管理したいと進化的に思ってしまうのです。これは、生き抜くための特性として本当に価値のあることです。そのため管理できないと感じると、あまりいい反応を示さなくなります。危険度が高ければ高いほど、管理できないことに対して、より大きく反応してしまいます。

https://cloudplatform-jp.googleblog.com/2016/10/google-cre.html

## フィールド
Saasビジネス

## ミッション
顧客の不安を0にする

# なぜ混合するのか
CRE、CSを混合してしまう理由をざっと考えたところ以下の理由が浮かびました

* 新しい顧客体験の創出が目的
* 顧客体験に主眼をおいている
* サポートから進化した概念
* サブスクリプション事業での概念
* 概念的な発想なので難しい
* 比較的新しい分野
* 理解して実践している人/事例が少ない

CREを名乗る以上

* サブスクリプション事業のCS
* プロダクト運用のCRE

それぞれもっと理解を深めて使い分けていきたいですね
CentOSにKVMインストール

自分用めも。

# 環境

```
$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
```

# CentOSインストール後にやること

## 一般ユーザ作成

```bash
# useradd udon -s /bin/bash -d /home/udon
# passwd udon
# vi /etc/sudoers
----
  ## Allows people in group wheel to run all commands
- %wheel ALL=(ALL)       ALL
+ #%wheel ALL=(ALL)       ALL

  ## Same thing without a password
- # %wheel  ALL=(ALL)       NOPASSWD: ALL
+ %wheel  ALL=(ALL)       NOPASSWD: ALL
----
# usermod -aG wheel udon
```

## 不要サービス停止

いや不要じゃないんだけどさ

```bash
$ sudo systemctl stop NetworkManager
$ sudo systemctl disable NetworkManager
$ sudo systemctl stop firewalld
$ sudo systemctl disable firewalld
```

## if設定

うちは ``L2SW`` に ``vlan`` で接続するんで。

```bash
$ sudo cp -p /etc/sysconfig/network-scripts/ifcfg-eno1 /etc/sysconfig/network-scripts/ifcfg-eno1.10
$ sudo vi /etc/sysconfig/network-scripts/ifcfg-eno1.10
----
- BOOTPROTO=dhcp
+ BOOTPROTO=static
- NAME=eno1
+ NAME=eno1.10
- ONBOOT=no
+ ONBOOT=yes
- UUID=.....
+ IPADDR=192.168.10.120
+ NETMASK=255.255.0.0
----
$ sudo service network restart
```

## 外部接続

```bash
$ sudo vi /etc/sysconfig/network
----
+ GATEWAY=192.168.200.98
----
$ sudo vi /etc/resolv.conf
----
+ nameserver 8.8.8.8
----
$ sudo service network restart
```

## SSH ログイン遅いの嫌です

```bash
$ sudo vi /etc/ssh/sshd_config
----
- #UserDNS yes
+ UserDNS no
----
$ sudo service sshd restart
```

## vim が無いと嫌です

```bash
$ sudo yum -y install vim
```

## SELinux 嫌いです

```bash
$ sudo setenforace 0
$ sudo vim /etc/selinux/config
----
- SELINUX=enforcing
+ SELINUX=disable
----
```

# KVM インストール

参考：[CentOS7上にKVM環境を構築する (CUI環境)](https://qiita.com/jimaoka/items/d528a7f55e832982c193)
参考：[CentOSサーバ構築術 文具堂 - KVM (仮想化環境) のインストール](https://centos.bungu-do.jp/archives/274)

```bash
$ sudo yum -y install libguestfs libvirt libvirt-client python-virtinst qemu-kvm virt-manager virt-top virt-viewer virt-who virt-install bridge-utils
```

# 仕上げ

```bash
$ sudo vi /etc/yum.conf
----
+ exclude=kernel*
----
$ sudo vi /etc/sysconfig/kernel
----
- UPDATEDEFAULT=yes
+ UPDATEDEFAULT=no
----
$ sudo yum -y update

$ sudo cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
```
Treasure Data(Presto/Hive)で月の最終日を取得する方法

### 始めに
SQLで月の最終日かどうかWHERE句で判別したい、なんてことありますよね？
Treasure Data(Presto/Hive)でどうやって月の最終日を取得する方法について紹介します。

### Hiveの場合
Hiveの場合は何も考える必要はありません。 `last_day` という関数があるからです。
扱いが不安だと思う人も多いであろう、うるう年の検証も含めて下記クエリで各年の2月の最終日を取得してみます。

```sql
select last_day('2016-02-10')
union all
select last_day('2017-02-10')
union all
select last_day('2018-02-10')
union all
select last_day('2019-02-10')
union all
select last_day('2020-02-10')
;
```

結果は下記の通りです。無事最終日が取得できましたね。
![Screen Shot 2019-12-10 at 19.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544917/874cff1b-b5a1-382e-377e-cce5d573ce6b.png)

### Prestoの場合
Presto 326だと `last_day_of_month` という素敵な関数があるのですが、Treasure DataがホストしているPrestoのバージョン(0.205と317)ではこの関数がありません。
そのため、下記のように頑張る必要があります。

```sql
select date_format(date_parse(date_format(timestamp '2016-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
union all
select date_format(date_parse(date_format(timestamp '2017-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
union all
select date_format(date_parse(date_format(timestamp '2018-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
union all
select date_format(date_parse(date_format(timestamp '2019-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
union all
select date_format(date_parse(date_format(timestamp '2020-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
;
```

やっていることは、下記のように次の月の初日を計算して1日引き算しているだけです。

```
timestamp '2016-02-10' <--元データ
↓
timestamp '2016-02-10' + INTERVAL '1' month <--1ヶ月足す
↓
date_format(timestamp '2020-02-10' + INTERVAL '1' month, '%Y-%m-01') <--月の初日(01日)にする
↓
date_format(date_parse(date_format(timestamp '2020-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d') <--フォーマットを整えて1日引く
```

下記クエリで各段階を表示するとわかりやすいかもしれません。

```sql
select timestamp '2020-02-10',
       timestamp '2020-02-10' + INTERVAL '1' month,
       date_format(timestamp '2020-02-10' + INTERVAL '1' month, '%Y-%m-01'),
       date_format(date_parse(date_format(timestamp '2020-02-10' + INTERVAL '1' month, '%Y-%m-01'), '%Y-%m-%d') - INTERVAL '1' day, '%Y-%m-%d')
;
```

結果は下記のようになります。

![Screen Shot 2019-12-10 at 20.10.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544917/7defec63-71bb-e8ea-d18d-8db79104b4f7.png)

### 最後に
いかがでしょうか？
Prestoのほうが便利な関数が揃っているイメージがあるかと思いますが、月の最終日を取得する部分に関してはHiveに軍配が上がりますね！
Windows10(非WSL)にpyenv+pipenv環境構築

## 概要
複数のpythonバージョンやAnaconda環境を管理可能なツール **pyenv** と
プロジェクト毎に使用するpythonライブラリを管理可能なpythonライブラリ **pipenv**🐍
2019年末の現在、この2つの組み合わせはベストかどうかは知りませんが[そこそこ使える組み合わせ](https://www.m3tech.blog/entry/python-packaging)と思われます😊

今回はこの便利なpyenvとpipenvをWSLではない素のWindowsに導入していきたいと思います。

pyenvとpipenvをMacやLinuxで導入する場合は
pipenv側がpyenvを自動で検出して連携を取ってくれるので[導入に大きく手間取ることはありません](https://qiita.com/fury00812/items/08036e78a449d1cbeb48)👌
([WSLはちょっと微妙でしたが、、、😒](https://qiita.com/foewhoew32f320/items/bfa90ae1003e45cefe33))
非WSLのWindowsは公式pyenvが対応していない事もあり、やや手間がかかります😡


# 環境
- Windows10 1909
- pyenv-win 1.2.4
- python 3.8.0
  - pipenv 2018.11.26

## [手順1] pyenv(pyenv-win)導入
**公式のpyenvはwindowsに対応していません**😱
そのため、今回は3rdパーティーのツール[pyenv-win](https://github.com/pyenv-win/pyenv-win)を利用します。
このツール、本家pyenvと異なりanacondaの管理はできませんが
pythonだけなら同じ感覚で管理可能です。

基本的には[公式に書かれている手順](https://github.com/pyenv-win/pyenv-win#installation)に
沿って導入していきます。

### [手順1-1]リポジトリクローン
まず、linuxのpyenvと同じようにホームディレクトリ(デフォルトは`C:\User\ユーザー名\`)の配下に.pyenvフォルダにコピーします。

`git clone https://github.com/pyenv-win/pyenv-win.git %USERPROFILE%/.pyenv`

(git未導入場合はリポジトリをダウンロードして配置しましょう)
※ 後で環境変数でこの場所を指定するので、必ずしもこの場所でなくてもいいかも(未確認)

### [手順1-2]環境変数設定
Linuxではこれで終わりですが、Windowsでは追加で環境変数の設定が必要です。
まず、クローン下フォルダパスをユーザー環境変数`PYENV`を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/610e8eda-d38c-1181-d799-38fc3aa651cc.png)

続いて`PAH`に`shims`と`bin`フォルダを追加します。
ここで注意なのが、これらの設定を`～Microsoft\WindowsApps`よりも上位に設定すること。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/6d973756-9fc7-9e45-3211-7c7b0300fc08.png)
もし下位に設定した場合はWindows側がpythonがないとみなしてMicrosoft storeのpythonを進めてくるという邪魔な気遣いをしてきます🤪
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/0f4dd991-6d17-bf3f-8d4e-552ec76c1d87.png)
うまく設定できればコマンドプロンプトやpowershell上でpyenvコマンドが打てるようになります。
pyenvの初期設定は[こちらあたり](https://qiita.com/koooooo/items/b21d87ffe2b56d0c589b)を参考に行ってください

## [手順2] pipenv導入
続いてpipenvの導入ですが、今回公式なpyenvではなく3rdパーティーのツールを使ってしまっているため、
`pip install pipenv`でpipenvをインストールしてもpipenvコマンドが認識されません😱
pyenvのコマンド置き場であるshimsフォルダを見てみるとLinuxでは生成されていたpipenvへリンクするスクリプトが
Windows側では案の定置かれていません😨
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/46bda8f8-f867-d4c5-0e43-f7a23d05d509.png)
とはいえ、Linux側のShimsフォルダのpipスクリプトファイルとpipenvファイルを比較してみると中身が完全に一致します。
ファイル名のコマンドを実環境で探しに行って実行するだけなので中身が一致しているわけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/2645b9e2-4f23-9db7-d8c7-76cfadd601ac.png)

というわけで対策といてはpipenvと中身が同じリンクファイルを確認した上で、
Windows環境側で同ファイルをコピペしてpipenvにリネームするだけです。
`pip → pipenv`
`pip.bat → pipenv.bat`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/e6bf08ee-ed27-1677-c7a8-cc3c214e870a.png)

正しく設定できていればコマンドプロンプトやpowershellからpipenvを認識できます😁

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/2d180771-1152-4b0f-7aba-e112f023b17e.png)


# まとめ
WSLではないWindows環境にpyenv(3rdパーティー製のwindows版)とpipenvを導入しました
CIでNuGetのキャッシュをするときは場所を明示的に指定する

## 2020/3/27追記

[actions/cache](https://github.com/actions/cache)のドキュメントに、記事の内容をマージしてもらいました。
https://github.com/actions/cache/pull/124

----

前回記事の[Github Actionsで.NET CoreのCI/CDを行う](https://qiita.com/nogic1008/items/45b8ccd2dbc3fa4273c2)から、ジョブの高速化を図るため[actions/cache](https://github.com/actions/cache)を使ったらハマったのでメモ。

## TL:DR

- CIの環境によっては、`~/.nuget/packages`に色々入っていることがある
    - 該当フォルダをそのままキャッシュすると、プロジェクトに関係ない余計なものまで含まれる
- `NUGET_PACKAGES`環境変数でNuGetキャッシュの場所を明示的に変更できる

## 現象

NuGetのキャッシュフォルダをキャッシュすることで`dotnet restore`の時間を短縮しようと以下のようなキャッシュ処理を仕込んだ。

```yaml:cache-step
- uses: actions/cache@v1
  with:
    path: ~/.nuget/packages
    key: nuget-${{ runner.os }}-${{ matrix.dotnet-version }}  # ex. nuget-Linux-3.0.101
    restore-keys: |
      nuget-${{ runner.os }}-
```

すると`Post actions/cache@v1`ステップ(キャッシュの保存処理)で、`macos-latest`の場合のみ4分以上かかるようになってしまった。

```console:log
Post job cleanup.
/usr/bin/tar -cz -f /Users/runner/runners/2.161.0/work/_temp/4b80b621-20e0-4bf0-a201-22501682c69b/cache.tgz -C /Users/runner/.nuget/packages .
[warning]Cache size of ~4347 MB (4557940930 B) is over the 400MB limit, not saving cache.
```

[該当部分のログ](https://github.com/nogic1008/dotnet-ci-example/runs/325623635#step:16:3)

「`~/.nuget/packages`がデカすぎるからキャッシュできない」と怒られる。

## 原因

Github Actionsの`macos-latest`ホストランナーには、[標準でXamarinがインストールされている。](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/software-installed-on-github-hosted-runners#macos-1015)
そのため、`~/.nuget/packages`には、Xamarin関係のパッケージが起動時点で入っていることになる。
これらのパッケージまで含めてキャッシュしようとして、キャッシュサイズの上限(400MB)に引っかかっている模様。

[actions/cacheのissue](https://github.com/actions/cache/issues/115)にも報告されている。

## 解決策

NuGetのパッケージをキャッシュするフォルダを明示的に指定する。
環境変数`NUGET_PACKAGES`にパスを指定することで、そのパスにキャッシュしてくれるようになる。

```yaml:dotnetcore.yml
    env:
      NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages  # これを指定
    steps:
    - uses: actions/cache@v1
      with:
        path: ${{ github.workspace }}/.nuget/packages  # NUGET_PACKAGESと同じものを指定
        key: nuget-${{ runner.os }}-${{ matrix.dotnet-version }}
        restore-keys: |
          nuget-${{ runner.os }}-
```

[修正後の実行結果](https://github.com/nogic1008/dotnet-ci-example/runs/339408451#step:16:3)(いろいろワークフローを変えた後ですが……。)

## 参考

- [Pipeline caching](https://docs.microsoft.com/en-us/azure/devops/pipelines/caching/?view=azure-devops#netnuget)
チームで行っているオンボーディングに関する取り組み

# はじめに

先日、オンボーディングに関する記事([エンジニアチームで行っているオンボーディングを紹介するよ](https://tech.smartcamp.co.jp/entry/engineer-onboarding))を拝見し、自分もリーダーの立場からチームで行っているオンボーディングに関する取り組みについて書こうと思いました。

どなたかの参考になれば幸いです。ご指摘などあれば気軽にご連絡いただけますと助かります。


## 関連する記事

- [1on1をするときに意識していること](https://qiita.com/calderarie/items/daa6c82f4cfd687d1c9a)

- [弊チームのマネジメント・ビルディング取り組み](https://qiita.com/calderarie/items/521e6b077abeaaa2e6d5#%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%B0%8E%E5%85%A5)

# オンボーディングの取り組み

## 初日

- オリエンテーション
    - 担当サービスの説明、チームメンバーやステークホルダーの説明、普段の業務の進め方、環境やツールなどを紹介します
    - ボリュームが多すぎるので、全体観を把握してもらうことを目的として、詳細は追って説明していきます

- メンターのアサイン
    - 最初の一ヶ月ほどは、新規メンバーにはメンターのサポートの中もしくはペアリングによって業務を行ってもらいます
    - あまり意識はしてなかったのですが、通例として、新規メンバーの前にチームに加入したメンバーをメンターにアサインしており、その結果、説明の中で更にメンバーの理解が深まるという効用もあります

- 環境のセットアップ
    - 業務を行うための環境を用意します
    - 細かいツールなど、希望があることもありますが、説明の都合上、一旦チームで標準的な設定を利用してもらいます
    - 業務を進めて行く中で、変えていきたい部分に関しては、振り返りや1on1で要望を拾ってチーム全体で変えていきます

- チームメンバーとのウェルカムランチ
    - 初日はチームメンバーとの懇親として、ランチ会をやっています
    - この場で互いに人となりを知ることで、普段の雑談にも繋がっているという印象があります

## 1か月目

- チーム内のイベントの紹介
    - デイリーミーティングや振り返りなど、普段行っているイベントの初回に紹介します
    - 実際に進行する中で、目的や意識してほしいことを理解してもらいます
    - 新規メンバーへの説明が主目的ですが、既存のメンバーにも再認識してもらうことも狙っています

- 業務チュートリアル
    - 基本的なETLと基礎集計を行ってレポート作成を行う課題をやってもらいます
    - 一連の作業内容のレビューは勿論、レポート内容についても細かく試問します
    - これにより、スキル的なところも勿論ですが、サービス周りのドメイン知識についても身に着けてもらいます

- ペアリングによるOJT
    - OJTとして、普段行っている業務をペアリングで進めます
    - 説明を交えつつ業務を進めることで、効率よく作業内容を理解してもらいます
    - ペアリング形式によって、チーム内の細やかな暗黙知が共有され、メンバー間の親交が深まるといったメリットもあります

- 1on1を週1で実施
    - 普段は隔週で1on1を行っていますが、新規メンバーには早期に課題を発見するために毎週行います
    - 業務の中での気付きや困ったことを中心に聞いていきます
    - 最初の内は、関係性を深めていく必要があることと、1on1自体に慣れてもらうために、私が主導となってアジェンダを用意して進めていきます

- スキルマップの記入
    - チーム内で行っている業務に必要なスキルを棚卸したスキルマップに対して、メンバーの評価をディスカッションしながら記入していきます
    - このスキルマップの内容は、1on1の際に内省に活用するほか、注力してもらいたい業務の方向性の決定にも利用します
    - スキルマップについては、この場だけではなく定期的に更新していき、取り組んでいた結果を反映するようにしています

## 2か月目以降

- ペアリングから単独での業務へ
    - 慣れてきた段階でペアリングではなく、単独で業務を進めてもらいます
    - 大まかな方針などはフォローしますが、基本的には性善説に基づいて、手戻りも覚悟の上で、個人の裁量に委ねます
    - ただし、デイリーミーティングなどで日単位での状況確認は必ず行っています

- 1on1を隔週実施へ
    - 一通りOJTが終わったタイミングで、毎週から隔週へと頻度を減らします
        - 毎週のままでもいいんですが、私の時間的な都合で減らしています
    - 話す内容も、業務中心の話題ではなく、本人の興味や強み弱みを掘り下げ、それに対するフィードバックを行った後、タスクのアサインへ反映します
    - 1on1のアジェンダは、メンバー自身に用意してもらうようにし、問題提起の意識を醸成します



## ドキュメント類など

俗人化を避けるために、基本的な業務に関するドキュメントは整備しているので、分からないことも、調べれば比較的対応できるようにしています。

情報整備に関しては、オンボーディングを進める際に、情報が不十分であるところが明確になるので、その時のフィードバックを受けて適宜整備を進めています。

現状、チーム内の行動指針が暗黙的になっているので、言語化して共有する必要性があると感じています。