OmniAICreator/Qiita-1.07M huggingface dataset:
Having句でグループを抽出

駆け出しエンジニアのNishです
今回はHaving句を利用して、特定条件を満たすグループの抽出についての記事です

# 事前準備
今回は、以下のデータを使用します
毎度のことながらダミーデータがテキトーですが、ご容赦。。
ec_saleテーブルには、各ユーザの購入履歴が保存されています

- 会員id(user_id)
- 任意で連携できる別サービスのid(member_id)
- 性別
- 購入した商品のカテゴリ
- 金額

上記の情報がこのテーブルに保存されているとします
member_idについては、別サービスの連携が任意なのでNullが入るのを許容しています


```text:ec_saleテーブル
+---------+-----------+-----+---------------+------+
| user_id | member_id | sex | item_category | sale |
+---------+-----------+-----+---------------+------+
|   10001 |      NULL | M   | A             | 3200 |
|   10002 |    779265 | M   | B             | 1200 |
|   10003 |    235340 | M   | C             | 5600 |
|   10004 |     34008 | W   | B             | 4200 |
|   10005 |      NULL | W   | B             |  900 |
|   10006 |    193197 | M   | A             | 2000 |
|   10007 |    724526 | W   | C             | 1500 |
|   10008 |     85284 | M   | A             | 1000 |
|   10009 |     83226 | W   | B             | 2900 |
|   10010 |     30057 | W   | C             | 3000 |
+---------+-----------+-----+---------------+------+
10 rows in set (0.04 sec)

```

# データ欠損を調べる
Having句を用いて、データ欠損があるかを調べます
ここで利用するのは、COUNT関数です
COUNT(*)はNULLも含めるのに対し、COUNT(<カラム名>)はNULLを除外することを利用します
別サービスを連携していないユーザが存在するかは次のクエリで確認できます

```sql
SELECT
  '未登録ユーザ有' AS gap
FROM
  ec_sale
HAVING
 COUNT(*) <> COUNT(member_id)
```
Having句単体で利用して、テーブル全体を集約しています

# 要素数で条件を指定
特定条件を満たすレコード数を調べて、さらに絞り込みをかけたい場合の解説です

指定条件にマッチするレコード数を算出するには、以下のように書けばokなので、

```sql
SUM(CASE WHEN <指定条件> THEN 1 ELSE 0 END)
```
これをHaving句で使用します

例として、「女性より男性の方が購入している商品カテゴリー」を抽出するには、以下のクエリを実行します

```sql
SELECT
  item_category
FROM
  ec_sale
GROUP BY
  item_category
HAVING
 SUM(CASE WHEN sex = 'M' THEN 1 ELSE 0 END) > SUM(CASE WHEN sex = 'W' THEN 1 ELSE 0 END)
```
# 統計量で条件を指定
先ほどと同じように、Having句で集約関数を使用すればok
例として、「男性の平均購入価格が3000円以上の商品カテゴリー」を抽出するには、
以下のクエリを実行します

```sql
SELECT
  item_category
FROM
  ec_sale
GROUP BY
  item_category
HAVING
 AVG(CASE WHEN sex = 'M' THEN sale ELSE NULL END) > 3000
```
キャリブレーション　ubuntu ROS

#環境
ubuntu18.04
ROS melodic

#インストール

```
sudo apt-get install ros-melodic-camera-calibration
```

#使い方

- キャリブレーションボードを用意し（ディスプレイに写すのでも可）
- 下記コマンドを各ターミナルで実行

```
roscore
rosrun uvc_camera uvc_camera_node
rosrun camera_calibration cameracalibrator.py --size 7x11 --square 0.02 image:=/image_raw
```

**オプションの意味**
--size 横×縦（白黒の交点の数）
--square 0.02 (20mm）１マスのサイズ

- GUIの画面で、xyzの軸が緑色に変わるまで、キャリブレーションボードを写して色々な角度で撮影
- 撮影できたら[calibration]をクリック(結構時間かかる）
- [save]で　/tmp/にファイルが保存される
- [commit]は、キャリブレーション情報をカメラに送るコマンド（多分使わなくて良い）


#保存されたキャリブレーションファイルのコピー

```
cd /tmp
tar -zxvf calibrationdata.tar.gz
mv ost.txt ost.ini
rosrun camera_calibration_parsers convert ost.ini camera.yaml
mv camera.yaml ~/.ros/camera_info（フォルダが無ければ作る）
```
libuvcのインストールと使用方法

#環境
ubuntu18.04 
ROS melodic

#使い方

webカメラを接続した上で、下記コマンドを各ターミナルで実行

```
roscore
rosrun libuvc_camera camera_node
rosrun image_view image_view image:=/image_raw
```


#liuvcのインストール

apt-getでインストール

```
sudo apt-get install ros-melodic-libuvc-camera
```
もしくは、githubからインストール

```
mkdir libuvc
git clone https://github.com/ktossell/libuvc
cd libuvc
mkdir build
cd build
cmake ..
make && sudo make install
```

実行

```
rosrun libuvc_camera camera_node
```




#エラーが出た場合

上のコマンドで下記のエラーが出た場合

```
/opt/ros/melodic/lib/libuvc_camera/camera_node: error while loading shared libraries: libuvc.so: cannot open shared object file: No such file or directory
```


https://stackoverflow.com/questions/480764/linux-error-while-loading-shared-libraries-cannot-open-shared-object-file-no-s

上記サイトより

>
Your library is a dynamic library. 
You need to tell the operating system where it can locate it at runtime.
To do so, we will need to do those easy steps:


>[1]  Find where the library is placed if you don't know it.
```sudo find / -name libuvc.so```

/usr/local/lib/x86_64-linux-gnu/libuvc.so
find: ‘/proc/1429/task/1429/net’: 無効な引数です
find: ‘/proc/1429/net’: 無効な引数です
/home/okubo18/workspace/libuvc/libuvc/build/libuvc.so
/opt/ros/melodic/lib/x86_64-linux-gnu/libuvc.so
find: ‘/run/user/1000/gvfs’: 許可がありません

>[2]  Check for the existence of the dynamic library path environment　variable(LD_LIBRARY_PATH)
```echo $LD_LIBRARY_PATH```

/home/okubo18/workspace/vins-fusion_ws/devel/lib:/home/okubo18/workspace/catkin_ws/devel/lib:/opt/ros/melodic/lib

>[3] We add the desire path, export it and try the application.
>
`LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/x86_64-linux-gnu/`
`echo $LD_LIBRARY_PATH`

/home/okubo18/workspace/vins-fusion_ws/devel/lib:/home/okubo18/workspace/catkin_ws/devel/lib:/opt/ros/melodic/lib:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu/
※usr/local/lib も加えた

>
`export LD_LIBRARY_PATH`
`rosrun libuvc_camera camera_node`
【Go】バイナリファイルからContent-Typeを取得する

# ファイルからContent-Typeを検出

バイナリの先頭ヘッダ`512byte`を読んで取得後、ポインタをもとに戻す

```.go
func DetectFileContentType(file *os.File) string {
	// 最初の512bytesを読む
	buffer := make([]byte, 512)
	file.Read(buffer)

	// 有効なMIMEタイプでない場合は「application/octet-stream」が返る
	contentType := http.DetectContentType(buffer)

	// 読み取りポインターをリセットする
	file.Seek(0, 0)

	return contentType
}
```

ファイルタイプを調べるライブラリ([h2non/filetype](https://github.com/h2non/filetype))によっては[先頭`261byte`だけ読んでる](https://github.com/h2non/filetype#file-header)のとかあったんですけど、このヘッダってどこまでとか定義されてたりするんですかね？
（ちなみに上記のライブラリで検出できなかったMP4の動画ファイルがあったのでライブラリ使わず処理を書きました）

# 参考URL

- [h2non/filetype](https://github.com/h2non/filetype)
- [How Detect Content Type of a File · GolangCode](https://golangcode.com/get-the-content-type-of-file/)  
- [Detect content type of a file | golang blog](https://ispycode.com/Blog/golang/2017-01/Detect-content-type-of-a-file)  
- [go - Mime type checking of files uploaded Golang - Stack Overflow](https://stackoverflow.com/questions/51209439/mime-type-checking-of-files-uploaded-golang)
windows10にubuntu18.04 (virtualbox) のインストール

#環境
windows10
ubuntuバージョン　18.04


#virtual box をインストールする

参考にさせていただきました:bow:
https://www.rem-system.com/virtualbox-install/

下記サイトからインストーラーをダウンロードし、起動
https://www.virtualbox.org/
- Download virtual box
- ver ... windows hosts

#ubuntu用マシン作成
- Virtual box manager起動
- 新規ボタン
- 名前適当,Linux, ubuntu(64bit)選択
- メモリーサイズ　8G (本体が16なので半分くらい。適当）
- 仮想ハードディスク作成 
- タイプは　VDI　（適当）
- 可変サイズ
- ハードディスクサイズ　100GB (サイズは後でも変えられる）

# ubuntu18.04OSのインストール
- マシン選択（さっき作成したもの）
- 「設定」
- 「ディスプレイ」
- ビデオメモリーのバーを90MBくらいに（60MBとかでもいいかも。こうしないと高解像度が利用できない）
- 「ストレージ」
- 「コントローラーIDE」
- 「空」
- 「光学ドライブ」右端のディスクイメージのアイコン
- 仮想光学ディスクファイルを選択
- ubuntuのisoファイルを選択
- マシンを起動
- 後はいつものubuntu インストールに従う
- サードパーティーも含めてインストール

※再起動に時間がかかります


#画面サイズを変更する（必要なら）
- 上部メニューのデバイスを選択
- Guest Additions CD イメージの挿入
- 実行

※ここでエラーが出る場合
多分，・gcc・make・perlが無いとか言われているはずなので、無いものをインストール
（その前にVBoxGuestAdditionsはアンインストールしておく）

**手順**
- sudo /opt/VBoxGuestAdditions-(バージョン文字列)/uninstall.sh
- デスクトップにあるディスクイメージもアンマウント
- sudo apt install gcc make perl -y
- Guest Additions CD イメージの挿入
- 実行する　
- 無事に終わったようだったら再起動
Ubuntu と Node.js と npm

> この記事はメモとして残して置いた限定公開記事を全体公開にしたものです。記事の内容は古い可能性があります。

Ubuntu で Node.js を管理する方法はいくつかある。

1. 普通に apt する
2. [nvm](https://github.com/nvm-sh/nvm) を利用する
3. [n package](https://github.com/tj/n) を利用する

代表的なところではこんなところ。それぞれメリット、デメリットがあると思うが、今回は、一番シンプルだと感じた n package を使う方法をおススメします。

## 導入

まず、nodejs と npm を普通にインストール

```
sudo apt install -y nodejs npm
```

n package を npm で global にインストール

```
sudo npm install n -g
```

n package を使って node をインストール

```
sudo n lts
```

最初に入れた nodejs、npm を削除 ＆ 再ログイン

```
sudo apt purge -y nodejs npm
exec $SHELL -l
```

バージョン確認

```
node -v
```

## バージョン管理

別バージョンのインストール、切り替えもとてもシンプルです。list で確認できたバージョン番号を指定するだけ

### インストール済みバージョン確認

```
n ls
n list
```

### 推奨、最新バージョンの確認

```
n --lts     # 推奨
n --stable  # 推奨（alias）
n --latest  # 最新
```

### インストール可能なバージョンを確認（最新から20件）
```
$ n lsr 
```

### インストール可能なバージョンを表示（すべて）
```
$ n --all lsr
```

### バージョンの切り替え
```
sudo n
```

### LTS（Long Term Support）バージョン/推奨バージョン/最新バージョンのインストール＆切り替え

```
sudo n lts      # LTS
sudo n stable   # 推奨
sudo n latest   # 最新
```

### バージョン指定のインストール＆切り替え

```
sudo n 16.18.0
sudo n 16      # 16内での最新版
```

### npm 自体の更新


#### 最新バージョンを確認

```
npm info npm version
```

#### 最新バージョンに更新

```
sudo npm install -g npm
sudo npm update -g npm
```

### npm パッケージのバージョン確認

#### バージョン一覧

```
npm info (パッケージ名) versions
```

```
npm info expo versions
[
  '0.1.0-pre',           '0.1.0-pre2',          '0.1.1',
～中略
  '35.0.0-rc.0',         '35.0.0'
]
```

### バージョンの絞り込み

```
npm info expo@33 version
expo@33.0.0 '33.0.0'
expo@33.0.1 '33.0.1'
expo@33.0.2 '33.0.2'
expo@33.0.3 '33.0.3'
expo@33.0.4 '33.0.4'
expo@33.0.5 '33.0.5'
expo@33.0.6 '33.0.6'
expo@33.0.7 '33.0.7'
```

### 最新バージョン

```
npm info expo version
35.0.0
```

### インストール済みのバージョン確認（グローバル）

```
npm list --depth=0 -g
```

### インストール済みのバージョン確認（ローカル）

```
npm list --depth=0
```

### バージョン指定のインストール（@以降に指定するだけ）

```
npm install -g expo@33.0.7
```
【備忘】VscodeやWindows Terminal で Git Bash を使うとなんか表示がちがって困った

たぶん当たり前のことだと思いますが、備忘として書きます

# TL;TD 


* 今までGit Bash はbash.exeを実行してつかっていた
* VscodeやWindows Terminal で Git Bash を使うときは`C:\\Program Files\\Git\\bin\\bash.exe`を呼び出すようにする
* けど、そうするとディレクトリに色がつかないなど、なんか表示違う
* bash.exeは`C:\\Program Files\\Git\\bin\\bash.exe --login -i`を実行して起動しているようので、同じようにすればOK


# どう違うの

* `C:\\Program Files\\Git\\bin\\bash.exe`の場合
    * ディレクトリに色がつかない
    * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372042/608e1efd-126f-dc8a-5887-26699234469d.png)

* `C:\\Program Files\\Git\\bin\\bash.exe --login -i`の場合
    * bash.exeと同じ
    * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372042/d85e0877-8e43-9c82-6af8-f6437035f4a1.png)




# Windowns Terminalの場合

* Git Bash を使えるようにする、基本的な設定はこちらを参考にしました。(分かりやすい。。感謝ですm(__)m)
    * [Windows Terminal で Git Bash を表示する](https://qiita.com/yokra9/items/bdd0882268b308cf22ca)
* configで設定するcommandlineに引数追加
    * `"commandline" : "C:\\Program Files\\Git\\bin\\bash.exe"` を
    * `"commandline" : "C:\\Program Files\\Git\\bin\\bash.exe --login -i"`にすれば良し

# VScodeの場合

* `terminal.integrated.shellArgs.windows` でwindows OSでのtemrinal実行時引数が設定できる
* 設定ファイルのJSONにterminal.integrated.shellArgs.windowsを追加。valueを↓みたいにする
    * `"terminal.integrated.shellArgs.windows": ["--login", "-i"]`
* windows OSでのtemrinal実行をWSLにしていると無効な引数に扱われて実行失敗するので、使い分ける人とかは注意

# なぜなのか

* ログインシェルとインタラクティブシェルの違いに原因がある様子。
* bash.exeはログインシェルで起動している
* ログインシェルじゃないと、~/.bash_profileなどが読みこまれない。


# 参考

* [ログインシェルとインタラクティブシェルと~/.bashrc達の関係](https://qiita.com/incep/items/7e5760de0c2c748296aa)
* [ログインシェルとインタラクティブモードの話](https://qiita.com/akata/items/4eaf93e8f63a55d0536f)
カーネルのダウングレード

#環境
ubuntu18.04

# kernelをダウングレードした理由

5.0.0-27-generic --> 4.18.0-25-generic

自動でカーネルが5.0.0-27にアップデートされたせいでmakeが通らなくなったので、カーネルのダウングレードを試行

※さらに下記の問題も。。。
・wifiが繋げなくなる
・有線もログイン度に切れる



#作業手順

参考にさせていただきました！:bow:
https://ry0.github.io/blog/2015/07/11/remove-newest-kernel/
https://kishiyama.hatenablog.com/entry/2019/05/02/025350?utm_source=feed
http://kumquat512.blogspot.com/2018/09/ubuntu1804.html

- grub-custmizerをインストール
- grub-custmizerを起動、"一般"の advanced option for ubuntu の中にある4.18をデフォルトに指定
- /etc/apt/preferenc.d/以下に　linux-kernelのファイルを作成しアップデート阻止

linux-kernelの中身

```
Package: linux-generic
Pin: version 4.18.0-25*
Pin-Priority: 1001

Package: linux-headers-generic
Pin: version 4.18.0-25*
Pin-Priority: 1001

Package: linux-image-generic
Pin: version 4.18.0-25*
Pin-Priority: 1001
```
scalacacheでCodecを実装してcase classを格納できるようにする

scalacache-redisで自前のcase classを保存する際には、そのcase classがSerializableをミクスインしていないとダメっぽい。
Serializableを使わないで格納できるようにするには、以下のCodecトレイトを実装すればよい。

```scala:Codecトレイト
trait Codec[A] {
  def encode(value: A): Array[Byte]
  def decode(bytes: Array[Byte]): Codec.DecodingResult[A]
}
```

以下のような感じで実装する。

```scala:User用のCodecを実装した例
import scalacache.Cache
import scalacache.redis.RedisCache
import scalacache.serialization.Codec
import scalacache.serialization.Codec.{ DecodingResult, tryDecode }

case class User(name: String)

private implicit val codec = new Codec[User] {
  def encode(code: User): Array[Byte] = code.value.getBytes("UTF-8")
  def decode(data: Array[Byte]): DecodingResult[User] = tryDecode(User(new String(data, "UTF-8")))
}

private implicit val cache: Cache[User] = RedisCache("localhost", 6379)

scalacache.put("key")(user, ttl = Nothing)
```
https://cb372.github.io/scalacache/docs/serialization.html#custom-codec

## JSONとして格納する

しかし上のやり方だと複数の値を持つタイプのcase classのCodecを実装するのが難しい。
この場合にはcirceを用いてJSONとしてまるごと格納するのがよいとのこと。

```scala
import io.circe._
import io.circe.generic.semiauto._

case class User(name: String, age: Int)

implicit val catEncoder: Encoder[User] = deriveEncoder[User]
implicit val catDecoder: Decoder[User] = deriveDecoder[User]
```
https://cb372.github.io/scalacache/docs/serialization.html#json-codec
ffmpegの使い方

#自分用メモとして

動画から画像を切り取るために使ったので、そのときのメモ。


ubuntu18.04
ubuntu16.04
確認済み



#ffmpegのインストール

参考サイト（ありがとうございます。:bow:
https://www.komee.org/entry/2018/02/01/163958

```
sudo apt update
sudo apt upgrade
sudo apt install ffmpeg
ffmpeg -version
```
最後verの確認ができたら完了です。

#ffmpegの使い方

動画MOVかMP4を作業ディレクトリに入れ、そこでコマンド実行

```
・画質半分?
ffmpeg -i ac_trainingdata.mp4 -vcodec mjpeg -r 2 ac_%03d.jpg
・まぁまぁ画質
ffmpeg -i movie.MOV -r 1 -q:v 1 movie_%03d.jpg
・最高画質
ffmpeg -i input.mp4 -f image2 -vcodec mjpeg -qscale 1 -qmin 1 -qmax 1 -r 2 Tic_kendo4_%03d.jpg

```

###オプション

-i ... インプットファイル
-f ... フォーマット
-vcodec ... コーデック
-r ... 1秒あたりのコマ数 (数字を小さくすると間引く回数が減る)
%03d ... ファイル名につける3桁の数字
pngで保存する場合 ... mjpegをpngにして、ac_%03d.png
react-native-unimodules と Expo の Bare workflow

> この記事はメモとして残して置いた限定公開記事を全体公開にしたものです。記事の内容は古い可能性があります。

# プロローグ

私がそれに気づいたのは、ReactNative で、センサー系の値を取得したいと考えていたときでした。いくつかのライブラリを調査しましたが、私の求めている機能を持っているものはありませんでした。ただ、欲しい機能がすべてあるとは言えないまでも、それに近いものを実現しているライブラリがひとつだけありました。

https://docs.expo.io/versions/latest/sdk/sensors/
そう、expo-sensors です。  

私は、正直思いました。「…またExpoか」と。Expo は素晴らしいツールです。ただいくつか欠点がありました（正しくはあると思っていました）。Eject しなければ使えないプラグインが多すぎること。Eject がなんとなく怖いこと。Eject 以外の方法で Expo API 群を使うのは難しいことです。

私は、いつも通り「これは使えないな。。」と、あきらめようとしました。が、ふと上のドキュメントにある文言が目に入りました。

> To use this in a bare React Native app, follow the installation instructions.

「素の ReactNative で使いたければ、ここを参考に」といった感じでしょうか。私は素晴らしいプロジェクトの入り口を見つけたのです。

# Installation in bare React Native projects

https://github.com/expo/expo/tree/master/packages/expo-sensors
さっそく上記のページの飛んでみると、以下のような項目が見つかりました。

> Installation in bare React Native projects 

そこにはこう書いてありました。  

> For bare React Native projects, you must ensure that you have installed and configured the react-native-unimodules package before continuing.

「素の ReactNative で使うためには、react-native-unimodules パッケージのインストールと設定が必要です。」

そこではじめて知ったのです。「react-native-unimodules」を。

# react-native-unimodules とは？

端的に言ってしまえば、Expo API 群を、素の ReactNative で使えるようにするライブラリです。ただ、すべての API を使えるわけではないです。が、ほとんど使えます。サポートしている API は以下をご確認ください。

https://docs.expo.io/versions/latest/bare/unimodules-full-list/

# react-native-unimodules を使うと、なにがいいのか？

素の ReactNative で開発している人にはよくあることだと思いますが、導入したライブラリがメンテナンスされていないことが多々あります。とくに ReactNative が 0.60 以降になってからは顕著です。使えそうなライブラリを見つけても、まず、使えるかの検証が必要で、正直手間です。一方 react-native-unimodules を導入して使う Expo API 群は、Expo が管理しています。メンテがされていないこともほぼないので安心して使うことができます。

また、Expo の機能を段階的に導入したい人にもオススメです。他のライブラリで実装していたが、メンテされてないから今後が不安。。といった機能を書き換えるのもいいのではないでしょうか。

react-native-unimodules の説明はこんなところです。私と似たような状況の方はぜひ使ってみてください。基本的には react-native-unimodules と、使いたい API のパッケージをインストールするだけで使えるはずです。

おまけとして、react-native-unimodules に関することを調べようと Expo のドキュメントを読んでいると「Bare workflow」という言葉が頻繁に出てくるので、簡単に説明します。

# Expo の Bare workflow

「Bare workflow」は、Expoツールを使ってアプリを構築する方法のひとつです。

expo-cli を使って react-native-unimodules が導入済みの ReactNative プロジェクトを作成するイメージです。expo init 時に以下のような選択肢が出るので、どちらかを選択すると作成できます。

```
 ----- Bare workflow -----
 minimal               bare and minimal, just the essentials to get you started
 minimal (TypeScript)  same as minimal but with TypeScript
```

これで作成したプロジェクトは、構造的には素の ReactNative ですが、Expo の API 群を使えることはもとより、Expo Client での動作確認ができます（制限はありますが）。Expo が ReactNative より使いやすいところは、API 群が充実していることもそうですが、動作確認を Expo Client でできることも魅力です。選択肢のひとつとして覚えておいて損はないかと。

また、Eject した Expo プロジェクトも、結果的に「Bare workflow」で構築していることになります。

「Bare workflow」は、言葉の意味合いとしては結構広そうです。「react-native-unimodules」を導入して、構築している ReactNative プロジェクトは、「Bare workflow」で構築している。。ぐらいで考えてしまってもいいかもしれません。

Workflow による違いは、以下でも説明されているので一読してみてください。
https://docs.expo.io/versions/latest/introduction/managed-vs-bare/

読んでいただき、ありがとうございました。
AWS MFA認証のためのハードウェア購入方法

# この記事でお話することは何？
AWSのIAMユーザ認証等でMFAを利用する際に必要となるハードウェアデバイスの
購入方法について解説してみます。
※意外と情報まとまっているところがないですね

# どこで買えるの？
早速結論ですが、最新情報は以下のページが参考になります。

- [Multi-factor Authentication](https://aws.amazon.com/jp/iam/features/mfa/)

ページ中の「***Purchase.***」リンクをたどると海外のAmazonページで購入可能です。

# 他のデバイスは利用できないの？
2016年の記事ですが、以下でサポートに関する記載がありました。
結論としては、Gemalto以外は利用できないぽいです。

- [AWSセキュリティのベストプラクティス](https://d1.awsstatic.com/International/ja_JP/Whitepapers/AWS_Security_Best_Practices.pdf)　26/110ページ

>現在のところ、AWSでは、GemaltoのハードウェアMFAデバイスおよび仮想MFAデバイスをスマートフォンアプリケーションの形でサポートしています。
Wordpressプラグイン、Smart Custom Fieldの使い方

Wordpressプラグイン「Smart Custom Field」の使い方について、いつも参照している内容とリンクをまとめる。

# なぜSmart Custom Field なのか
- 無料で繰り返し機能が使える。
- ソースベースでカスタムフィールドの内容を設定できる

# Smart Custom Fieldの内容を表示させる

## 繰り返しの場合
```php
<?php
  $info_array = SCF::get('group-post-info');

  // 該当ページ以外
  // SCF::get('group-shop-info', get_page_by_path('shop'));

  foreach($info_array as $info):
?>
  <?php if(isset($info['name']): ?>
    <p><?=$info['name'] ?></p>
  <?php endif; ?>
<?php endforeach; ?>
```

## 繰り返ししない場合

```php
<?= $cf_sample = post_custom('cf_sample'); ?>

```

### 参考
[ Smart Custom Fields(SCF)でカスタムフィールドを出力する ]( https://www.akecre.com/wordpress/display_scf/ )
[Smart Custom Fieldを使ってカスタムフィールドを追加する](https://hyme.site/blog/posts/smart-custom-field/)

# 一覧表示
```php

$args = Array(
            'post_type' => 'test',
            'posts_per_page' => -1,
            'meta_query' => array(array(
                                'key' => 'address',
                                'value' => '神戸市',
                                'compare' => 'LIKE'
                            ))
        );
$the_query = new WP_Query($args);
if($the_query -> have_posts()):
    while($the_query -> have_posts()): $the_query -> the_post();
        //ここに処理を記述
    endwhile;
endif;
wp_reset_postdata();
```

### 参考
[[WordPress] カスタムフィールドで絞り込んで一覧表示する](https://sachips.byeto.jp/wordpress/wp-customfield-wpquery.html)

# functions.phpでカスタムフィールドの定義をする

```php:functions.php
function add_post_info_fields($settings, $post_type, $post_id, $meta_type)
{
    // post以外の投稿タイプなら特に何もしない
    if ($post_type != 'post') {
        return $settings;
    }

    // 特定IDの投稿タイプなら特に何もしない
    /*
    if($post_id != '57'){
        return $settings;
    }
    */

    // 引数: (設定名スラッグ, ラベル名)
    $Setting = SCF::add_setting('post-setting', 'カスタム投稿設定');

    $items = post_array();

    // 引数: (グループ名, ループの可否, 項目の配列)
    $Setting->add_group('group-post-info', false, $items);

    // 今あるカスタムフィールドの設定に$Settingを追加
    array_push($settings, $Setting);
    return $settings;
}

// smart-cf-register-fieldsにフック
add_filter('smart-cf-register-fields', 'add_post_info_fields', 10, 4);

// カスタムフィールドの定義を設定
function post_array()
{
    $items = array(
        array(
          'name'  => 'form_name',
          'label' => 'テキスト入力枠1',
          'type'  => 'text',
        ),
        /*
        array(
          'name' => 'select',
          'label' => '選択肢',
          'type'    => 'select',
          'choices' => array( 'a', 'b', 'c' ),
          'default' => 'aa@bb.com',
          'instruction' => 'テキスト',
          'notes' => '注釈',
          'date_format' => '日付のフォーマット　y/m/d i:s',
          'max_date' => '最大日付　+1m +1w',
          'min_date' => '日付のフォーマット　+1m +1w'
        ),
        */
  );
    return $items;
}
```

### 参考
[SmartCustomFieldsのコードでの定義についてのまとめ](https://qiita.com/yousan/items/7cbd56308ecc0e2bb263)

# カテゴリーに画像を追加する

### 参考
[Smart Custom Fieldsでカテゴリー・カスタムタクソノミーに設定を追加する]
( https://yosiakatsuki.net/blog/scf-category-option/ )
Railsで作ったアプリをAWSでデプロイ⑦　〜Nginx導入〜


前回までにひとまずデプロイが完了しました

今回はWebサーバのNginxをEC2インスタンスに導入しようと思います

```terminal:EC2インスタンス
$ sudo yum -y install nginx
```
続いてNginxの設定ファイルを変更します

```terminal:
$ sudo vim /etc/nginx/conf.d/rails.conf
```
vimコマンドで設定ファイルを開いて以下をコピペし自身のアプリに合わせて書き換えます

```terminal:/etc/nginx/conf.d/rails.conf
upstream app_server {
  # Unicornと連携させるための設定。アプリケーション名を自身のアプリ名に書き換えることに注意。
  server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name <Elastic IP>;

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際のrootディレクトリ
  root /var/www/<アプリケーション名>/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

```

Nginxの権限を変更してPOSTメソッドでリクエストされてもエラーがでないようにします

```terminal
$ cd /var/lib
$ sudo chmod -R 775 nginx  
```
ここまでできたらNginxをスタートさせます

```terminal
$ cd ~
$ sudo service nginx start
```

Nginxの設定は完了しましたが、Nginx導入に伴ってディレクトリ構造が変化したため、
前回までに導入したUnicornの設定ファイルを変更する必要があります

```rails:アプリ/config/unicorn.rb
listen 3000

↓以下のように修正

listen "#{app_path}/tmp/sockets/unicorn.sock"

```
Githubにプッシュしたら本番のアプリにも反映させ、Unicornを最スタートさせます
Nginx導入したら今までhttp://IPアドレス:3000/だったのが
http://IPアドレスになり、3000が必要なくなるので注意してください
JavaScript(ES6)でアルファベットの連番を作成する

## アルファベット連番

A-Zの連番。
単純な話。需要が無いのか意外と情報が無い。

```javascript
[...Array(26)].map((v, i) => String.fromCodePoint(i + 65));
// Array(26) [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", … ]
```

コードが少し長くなるが、中間配列を生成しない場合は以下。

```javascript
Array.from({length: 26}, (v, i) => String.fromCodePoint(i + 65));
// Array(26) [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", … ]
```
Java 日付の厳密なチェックとサマータイムの関係

## 日付の厳密なチェック

`DateFormat#setLenient(boolean)` は、**緩やかな日付チェック**に関する設定です。`SimpleDateFormat`などで使います。デフォルトは`true`で厳密なチェックをしない。
厳密なチェックをしたい場合は、`false`をセットする。[^1]
[^1]: 厳密でないの反対なのだ(捉え方によってbooleanの値が逆向きになってしまう設計はやめましょう)。緩やかでない。ゆるくない。ガチで。ちなみにJava 8からは`DateTimeFormatter`で[列挙型ResolverStyle](https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/ResolverStyle.html)が使えるようになっています。

参考：[Open JDK DateFormat#setLenient(boolean)](https://cr.openjdk.java.net/~iris/se/11/latestSpec/api/java.base/java/text/DateFormat.html#setLenient(boolean)), [Oracle Java DateFormat#setLenient(boolean)](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/text/DateFormat.html#setLenient(boolean))

厳密なチェックをしない場合は、うるう年でないときに2/29としても3/1で解釈してくれます。

## サマータイム (daylight saving time)

日本ではあまり馴染みはありませんが、夏の時期だけ1時間早めるという[アレ](https://ja.wikipedia.org/wiki/%E5%A4%8F%E6%99%82%E9%96%93)[^2]です。
ニューヨークのある東部時間(EST/EDT)ですと、3月の第2日曜日午前2時から11月の第1日曜日午前2時まで[^3]を夏時間とし、この間を1時間進めます。
[^2]: サマータイムだったり、夏時間だったり、デイライト・セービング・タイムだったり、サンマータイムだったり。日本でも昔あったみたいです。地域によっては1時間ではなく30分などの場合もあります。
[^3]: 2006年までは4月の第1日曜日午前2時から10月の最終日曜日午前2時でした。法律により変わります。

## 2020/03/08 02:00:00がエラーになる

```java
private static void datechange(String date) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    sdf.setLenient(false); // ゆるくない
    sdf.setTimeZone(TimeZone.getTimeZone("US/Eastern")); // EDT
    try {
        Date pdate = sdf.parse(date);
        System.out.println(sdf.format(pdate));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
```
```java
// 夏時間の開始(1時間進める)
datechange("2020/03/08 01:59:59"); // OK
datechange("2020/03/08 02:00:00"); // NG: ParseException
datechange("2020/03/08 02:00:01"); // NG: ParseException
datechange("2020/03/08 02:59:59"); // NG: ParseException
datechange("2020/03/08 03:00:00"); // OK

// 夏時間の終わり(1時間戻す)
datechange("2020/11/01 01:59:59"); // OK
datechange("2020/11/01 02:00:00"); // OK
datechange("2020/11/01 02:00:01"); // OK
datechange("2020/11/01 02:59:59"); // OK
datechange("2020/11/01 03:00:00"); // OK
```

```java
java.text.ParseException: Unparseable date: "2020/03/08 02:00:00"
	at java.text.DateFormat.parse(DateFormat.java:357)
```

厳密なチェックをしている`setLenient(false)` かつ、タイムゾーンが`EDT`の場合、`2020/03/08 02:00:00`をparseすると`java.text.ParseException`が発生します。

`EDT`でなくても、**夏時間を考慮するタイムゾーンで「夏時間になる際にスキップされる1時間」**を指定した場合はエラーになります。

つまり、**`EDT`には`2020/03/08 02:00:00`は存在しない**ということ。

1時間戻る際の場合はエラーになりません。
今回の話から少しそれますが、1時間戻る場合に日付をユニークキーにしていたら一意制約違反になります。ソートも期待通りになりません。[^4]
[^4]: 現地時間を文字列でDBに登録しているシステムなどないことを祈ろう。(普通はタイムゾーンの影響がない日付型か、文字列だとしてもUTC、あるいは数値でエポック秒ですね)

## 根本原因

存在しない時間を指定しているので、問題があるのは上記の仕様ではなく元データと取込処理の方です。
今回の例ですと、元データが`EDT`ではなく`JST`だったというのが原因でした。(元データ[JST]と取込処理[EDT]のタイムゾーン不整合)
nerves_pack（vintage_net含む）を使ってNervesのネットワーク設定をした〜SSHのポート番号変更〜

先日「[nerves_pack（vintage_net含む）を使ってNervesのネットワーク設定をした〜SSHログインまで〜](https://qiita.com/nishiuchikazuma/items/01f5df5472ec0feceb5f)」を公開したので調子にのって`nerves_pack`の特徴にもあるSSHのログインポート番号を変更してみました。


# 環境
ハードウェアとネットワークはこのような構成です。
今回もホスト名flamboise03を置き換えることにします。
`nerves_pack`のインストールと設定は「[nerves_pack（vintage_net含む）を使ってNervesのネットワーク設定をした〜SSHログインまで〜](https://qiita.com/nishiuchikazuma/items/01f5df5472ec0feceb5f)」をみてください。

## ハードウェア
- Mac OSX
- NervesをRaspberryPi 3で稼働

## ネットワーク
- Mac OSX
  - 有線LAN→メンテナンス用、固定IPアドレス（192.168.5.100/24）

- RaspberryPi 3(flamboise03)
  - 有線LAN（eth0）→メンテナンス用、固定IPアドレス（192.168.5.57/24）
  - 無線LAN（wlan0）→インターネット接続用、DHCP（192.168.46/24から自動割当）
![ネットワーク構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51020/95e29daf-01e9-ac3b-3e5e-3d4448db4f19.png)


# SSHポート番号変更

`config/target.exs`に設定を追記します。
今回は公式ドキュメントどおりポート番号を2222に変更してみます。

``` elixir:config/target.exs
config :nerves_pack, ssh_port: 2222
```

## コンパイル＆アップロード

`config/target.exs`に設定を追記したらコンパイルしてファームウェアをアップロードします。

``` shell:fish
~> mix firmware
~> ./upload.sh 192.168.5.57
```


# 確認

まずポート番号を指定せずにSSHして失敗するかどうか確認します。

``` shell:fish
~> ssh 192.168.5.57
ssh: connect to host 192.168.5.57 port 22: Connection refused
```

無事に失敗したので次にポート番号を指定してSSHしてみます。

``` shell:fish
~> ssh -p 2222 192.168.5.57
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:

  RingLogger.attach

or print the next messages in the log:

  RingLogger.next

iex(1)>
```
うまくログインすることができました！


# まとめ
SSHでログインする場合のポート番号を変更することができました。
sshd.confを設定するような感じでサクッと変更できるのは嬉しいですね :smile: 


# 参考URL
- [nerves-project / nerves_pack](https://github.com/nerves-project/nerves_pack)
Kinesis Video Streams のサンプルアプリを Mac で動かす

# これは何？

Kinesis Video Streams のサンプルアプリを Mac で動かしたメモ

# 前提としてインストールが必要なものを準備

amazon-kinesis-video-streams-producer-sdk-cpp/install-instructions-macos.md at master · awslabs/amazon-kinesis-video-streams-producer-sdk-cpp
https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/install-instructions-macos.md#installation

> Install the build tools
>
>    - cmake 3.7/3.8 https://cmake.org/
>    - xCode (Mac OS) / clang / gcc (xcode-select version 2347)
>    - autoconf 2.69 (License GPLv3+/Autoconf: GNU GPL version 3 or later) http://www.gnu.org/software/autoconf/autoconf.html
>        - one option is to use brew to install e.g. brew install autoconf
>    - bison 2.4 (GNU License)
>    - pkgconfig
>    - Java JDK (optional) - if Java JNI compilation is required

homebrew 使うなら下記のような感じでインストールできる

```bash
brew install cmake autoconf bison
```

あとは Xcode や Java をよしなにインストールしておく

# サンプルアプリ動かすために必要なものをインストールし、動かす

awslabs/amazon-kinesis-video-streams-producer-sdk-cpp: Amazon Kinesis Video Streams Producer SDK for C++ is for developers to install and customize for their connected camera and other devices to securely stream video, audio, and time-encoded data to Kinesis Video Streams.
https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/install-instructions-macos.md#alternate-option-to-build-the-sdk-and-sample-applications-using-libraries-installed-by-homebrew

```bash
# 必要となるパッケージをインストール
brew install pkg-config openssl cmake gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly log4cplus gst-libav

# sample app を clone
git@github.com:awslabs/amazon-kinesis-video-streams-producer-sdk-cpp.git

# build を行うディレクトリに移動
cd ./amazon-kinesis-video-streams-producer-sdk-cpp/kinesis-video-native-build

# build
sudo ./min-install-script

# サンプルアプリを動かす
AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=zzz ./kinesis_video_gstreamer_sample_app my-stream
```

us-west-2 region の kinesis video streams で動作する。
おそらくソースコードは下記。

amazon-kinesis-video-streams-producer-sdk-cpp/kinesis_video_gstreamer_sample_app.cpp at master · awslabs/amazon-kinesis-video-streams-producer-sdk-cpp
https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/kinesis-video-gst-demo/kinesis_video_gstreamer_sample_app.cpp

# 試した環境

```bash
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.6
BuildVersion:	18G3020
```
ifconfigコマンドが使えない問題

#エラー文
IPアドレスを確認しようとすると

```common-lisp:command

ifconfig 

-bash: ifconfig: command not found
```

と表示されます

色々調べていると

バージョンによって使えるコマンドが異なるという事がわかり、、、

##解決方法


```common-lisp:command
ip address show
```

のコマンドで、表示される模様
FactoryBotで忘れがちなことfor Ruby on Rails

# よくやります

Aに関連するユーザーを生成する。
関連付けで`association :user`で設定していると、ついついあることを忘れてしまい、そのユーザー所有のAを作成できない。

# 駄目なところの説明

`FactoryBot.create`でテストデータを作成するとき、FactoryBotのdefaultで作成させている。
これを実行すると、campaignが先に作成されてcampaignで関連付けしたuserのIDは1になる。
その後に、userが作成されるので、userのIDは２になる。
campaignをcreateしたときに、userを作っているので正しい動きですね。

```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user, aliases: [:owner] do
    name 'MyString'
    sequence(:email) { |n| "tester#{n}@example.com" }
    password 'MyString'
    remember_digest 'MyString'
    admin true
  end
end
```

```ruby:spec/factories/campaigns.rb
FactoryBot.define do
  factory :campaign do
    name "MyString"
    association :owner
    status 0
    start_date Date.today
  end
end
```


```ruby:spec/features/campaigns_spec.rb
require 'rails_helper'

RSpec.feature "Campaigns", type: :feature do
  let(:user) { FactoryBot.create(:user) }
  let!(:campaign) { FactoryBot.create(:campaign) }

  scenario "Campaign list" do

    puts "This note's user is #{user.inspect}"
    puts "This note's campaign is #{campaign.inspect}"
  end
end
```

# 駄目なところのログ
campaignの`user_id: 1`でuserの`User id: 2`というのが確認できる。

```
This note's user is #<User id: 2, name: "MyString", email: "tester2@example.com", password_digest: "$2a$04$WonV91JKr29eOLQZAVnHm.7Dh3hkpvkbWEBe.uyxN4a...", admin: true, created_at: "2020-03-12 03:50:45", updated_at: "2020-03-12 03:50:45", remember_digest: "MyString">
This note's campaign is #<Campaign id: 1, name: "MyString", user_id: 1, status: 0, start_date: "2020-03-12", created_at: "2020-03-12 03:50:45", updated_at: "2020-03-12 03:50:45">
```

# どちらもID１にするように直す

これを、以下のように変更する。
これを実行すると、userを先に作成してuserのIDは1になる。
そのuserのIDを使ってcampaignを作成してくれる。

```ruby
  let!(:campaign) { FactoryBot.create(:campaign, user_id: user.id) }
```


# 直したあとのログ
campaignの`user_id: 1`でuserの`User id: 1`というのが確認できる。



```
This note's user is #<User id: 1, name: "MyString", email: "tester1@example.com", password_digest: "$2a$04$gP.QxECesAUpD41z9KLqw.ZnYBbXppVDv2FgurFEd2o...", admin: true, created_at: "2020-03-12 04:01:37", updated_at: "2020-03-12 04:01:37", remember_digest: "MyString">
This note's campaign is #<Campaign id: 1, name: "MyString", user_id: 1, status: 0, start_date: "2020-03-12", created_at: "2020-03-12 04:01:37", updated_at: "2020-03-12 04:01:37">
```

# P.S.
他に良い方法があればご指南ください。
チームジャーニー（グループからチームへ

## やりたいこと
2017年3月に今の会社に入ってから、3年近く経とうとしている。この3年間エンジニアのメンバーの入れ替わりはあったが、組織体制としては変化がない。エンジニア以外の部署は、結構頻繁に組織図が変更になっていることを考えると、エンジニア組織もそろそろ変わってもいいのではないかと考えて久しいこの頃です。

ただし他が変わってるから変わりたいのではないです。「俺たちもっと良くなれるはず！」という思いが出発点です。具体的には、これからQ ~半年単位で以下2つのステップをクリアできれば生産性爆上げできるんじゃないかと思っています。（もっと早くできるならより望ましい
1. チーム内のつながりをもっと強くする
2. チーム間の連携を強める

そこで、当座の問題となるチーム内のつながりの強化のためにこんなことができるかなと思っています。
1. チーム内でのコミュニケーションを増やす
2. チームメンバーの自主性を高める


## 1. チーム内でのコミュニケーションを増やす

今のエンジニア組織は以下の3つのデバイスごとに分かれています。
1. ウェブ
2. iOS
3. Androidタスクの内容は、マネージャーが各自にアサインする方式になっています。

各デバイスごとにチームが分かれているのは、組織運営上の便宜的な部分が大きそうな気がします。チームごとに共通認識となるミッションがあるわけではないです。そのためチームMTGの内容は、経営陣からの情報の伝達か、月ごとに行う振り返りでの個人の仕事の成果の確認になっています。せっかくチームで集まっても、横でのコミュニケーションが生まれることはあまりありません。

また、状況によってはウェブのタスクをAndroidの人やiOSの人がやったりもしています。そのためある時は、AndroidのタスクをやっているのがAndroidチームの中の一人だけということもあり得ます。

この個人が集まったグループという状況を超えるためには、チームごとの目標が必要です。目標があれば、目標に向けた進捗などを話し合うきっかけになります。そして目標達成に向けてプロセスを改善していくことがここの成長につながり、メンバー間のより深い信頼関係を築くきっかけにもなります。チーム力が上がって、個々の生産性が上がると他の領域に染み出していく可能性が増えます。そうするとチームの組織貢献度が上がり、組織的にもメンバー個人の貢献が認められるようになるので、個人の仕事から得る満足度も上がります。

## 2. チームメンバーの自主性を高める

現在、タスクはマネージャーからメンバーにアサインする方式を取っています。そのため、メンバーはこの点に関しては受け身な姿勢でいます。そのタスクへのアサインは、何を期待されているのかがわかりません。

個人の業務遂行能力をあげるという点では、自主的に動けるようになるべきなので、タスクへはサインアップする（やりたいものに手をあげる）方式が良さそうです。タスクの割り振りを密室で決めて、メンバーに受け渡すのではなく、公開の場で誰がやるのかを話し合うようにすることが重要です。

これをすることで、個人の自主性を促すだけではなく、他のメンバーへの仕事に対する思いも気にかけるようになるかもしれません。というのは、この仕事は、oooが学べそうだからxxxさんにやってもらうとより成長できそう。などという会話が出てくるようになると思うからです。

## まとめ

最後の方はざっと書いてしまったけど、まずはチーム内の個人の連携を強めるのが大切。
そのためには、以下ができると良いなと思っています。
・業務レベルでのつながりを強め（チームの目標に向けた活動）
・個人の思いなどに触れつつ個人の将来をみんなで考えた話し合いができるようになる
Pythonを使ったBasic認証の設定@Lambda

# はじめに
LambdaでBasic認証って検索すると、Node.jsのものしか見つからなかったので書いてみた。
自身の備忘録も兼ねて。
Node.js版は、ぐぐるとすぐに出てくるので、ここでは触れないです。

# コード
と言っても大したものではなく、Node.js版の焼き直しな感じです。
ただ、マルチアカウントに対応できるようになっている点はちょっと違う。

``` Python
import json
import base64

accounts = [
    {
        "user": "user1",
        "pass": "pass1"
    },
    {
        "user": "user2",
        "pass": "pass2"
    }
    ]

def lambda_handler(event, context):
    request = event.get("Records")[0].get("cf").get("request")
    headers = request.get("headers")
    
    authorization_header = headers.get("authorization")
    
    if not check_authorization_header(authorization_header):
        return {
            'headers': {
                'www-authenticate': [
                    {
                        'key': 'WWW-Authenticate',
                        'value':'Basic'
                    }
                ]
            },
            'status': 401,
            'body': 'Unauthorized'
        }
            
        
    return request

def check_authorization_header(authorization_header: list) -> bool:
    if not authorization_header:
        return False
    
    for account in accounts:
        encoded_value = base64.b64encode("{}:{}".format(account.get("user"), account.get("pass")).encode('utf-8'))
        check_value = "Basic {}".format(encoded_value.decode(encoding='utf-8'))
        
        if authorization_header[0].get("value") == check_value:
            return True

    return False

```

# 設定たち

基本的に、[簡単だった！CloudFront + S3 に BASIC認証を入れる方法](https://kahoo.blog/howto-basic-auth-on-cloudfront-s3/) を見たら問題ないはず。
他のサイトでは抜けている `Authorization` ヘッダの記述がここにはあるので。
S3(Static website hosting) + ACM + CloudFront + Route53で静的コンテンツ公開

静的コンテンツをサブドメインで公開したいとの要望を受けてセットアップした際の手順メモです。

# 前提条件／要件

* Route53で設定済みドメインのサブドメインとして公開する（レジストラのネームサーバーは設定済み）
* S3のStatic website hostingを利用する
* 証明書はACMで新規に発行する

# S3のバケット作成／設定

## 名前とリージョン

* バケット名：今回利用するサブドメインと同じ名前にします。
* リージョン：東京リージョンを選択

## オプションの設定

バージョニングなどの必要性はなかったので、デフォルトのままにしました。

## パブリックブロックアクセス

[パブリックアクセスをすべてブロック]のチェックを外します。
この後の手順でバケットポリシーで公開設定をします。
ACLによるアクセス制御は行わないので、ACL設定のブロックはチェックしてても良いはずですが、すべてチェック外れる設定にしました。

## バケットポリシー

以下を参考に作成したバケットの`s3:GetObject`を許可するように設定します。

[ウェブサイトアクセスに必要なアクセス許可](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/WebsiteAccessPermissionsReqd.html)

## Static website hosting

以下を参考に設定します。
[エンドポイント]のドメインは、CloudFrontの設定時に使います。

[ウェブサイトのホスティングの有効化](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/EnableWebsiteHosting.html)

## コンテンツのアップロード

作成したバケットにコンテンツをアップロードします。
ここまでで、[Static website hosting]のエンドポイントでサイトを参照できるようになります。


# ACMで証明書を発行

CloudFrontに設定するSSL証明書をACMで発行します。
米国東部 (バージニア北部) リージョンで作成する必要があります。

[CloudFront ディストリビューションにカスタム SSL 証明書を使用できないのはなぜですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/custom-ssl-certificate-cloudfront/)

なお、CloudFrontの設定画面に、ACMに遷移するボタンがあって、そちら遷移するとバージニア北部のリージョンが選択されました。

## 検証方法の選択

Route53と連携して検証できるので、[DNS の検証]を選択しました。

## 検証

展開すると、[Route 53 でのレコードの作成]というボタンが現れるので、これを押してセットアップを済ますことができます。
（検証用のCNAMEレコードセットが自動作成されます）


# CloudFront ディストリビューション作成

* Origin Domain Name：[Static website hosting]で割り当てられたドメインを設定します。
* Alternate Domain Names：サブドメインを設定します。
* SSL Certificate：ACMで作成した証明書を選択します。

その他は要件に合わせて。
以下、大変参考になりました。

[CloudFrontのデフォルトルートオブジェクトとS3の静的ウェブサイトホスティングのインデックスドキュメントの動作の違い](https://dev.classmethod.jp/cloud/aws/cloudfront_s3_difference/)

ディストリビューションが作成されるまで根気強く待ちます。


# Route53でサブドメインのAレコード作成

最後にRoute53でサブドメインのAレコード作成します。
[レコードセットの作成]で[エイリアス]を[はい]し、[エイリアス先]に作成したCloudFrontディストリビューションを選択します。

設定後、反映までにそこそこ時間かかりますので、やはり根気強く待ちます。


以上でコンテンツを公開できました。
linuxコマンド　エラー集　１




###サーバーを起動する


```

Service apache2 start
```

で起動できなかった時の対策方法

下記は、その時に表示されるエラー文です


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/4e9560c6-bb55-0e53-8384-c1f93df76fa8.png)


#解決方法

/sbin/パスをとうしていなかった事が要因でした

```
cd /sbin/

Service apache2 start
```

上記の手順を踏むとエラーが解決しました



#終わりに

参考記事

http://piyopiyocs.blog115.fc2.com/blog-entry-1130.html
https://www.linuxmaster.jp/linux_skill/2010/02/06linux.html
Surgeにデプロイしようとしたら「Aborted - you do not have permission to publish to some-name.surge.sh」で失敗する

# 事象

* Gatsbyのチュートリアル「[Get to Know Gatsby Building Blocks](https://www.gatsbyjs.org/tutorial/part-one/)」に取り組む
* コマンド `gatsby build` で静的なファイルを生成する
* コマンド `surge public/` で生成したファイルをデプロイしようとすると、以下のメッセージが出力されて失敗する:thinking:

```
[UserName: hello-world]$ surge public/

   Running as username@example.com (Student)

        project: public/
         domain: some-name.surge.sh

   Aborted - you do not have permission to publish to some-name.surge.sh

[UserName: hello-world]$
```

* チュートリアルの手順に従ってnpmでパッケージ `surge` を導入済み
* コマンド `surge login` から会員登録も済ませている


# 原因

会員登録したメールアドレスの確認が済んでなかったんですよ…:weary:


# 対応

コマンド `surge login` から会員登録すると、指定したメールアドレスに「Welcome to Surge!」というタイトルのメールが届く。
メール本文の「Verify your email」ボタンを押下すると、メールアドレスの確認が行われて以下の画面が表示される。

<img width="949" alt="20200312_surge_verify_email.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371702/9eac6fb2-2350-f5f9-5686-c3ba6cde886a.png">

メールアドレスの確認後は、コマンド `surge public/` で正常にデプロイできる。
Ruby技術者認定試験Silverに2週間で合格したので、学習方法をまとめてみた

先日、Ruby Silver試験に合格しました。

学習期間は2週間、点数は86点とまずまずの結果でしたが、同じくSilverの合格を目指されている方の参考になればいいなと思い、学習方法をまとめさせていただきました。

#前提
- 未経験からRubyで開発している会社に入社。学習開始時点で、2週間ほどRubyでの開発経験あり。
- Rubyを全く知らない方は、まずは[Progate](https://prog-8.com/)や[たのしいRuby](https://www.amazon.co.jp/%E3%81%9F%E3%81%AE%E3%81%97%E3%81%84Ruby-%E7%AC%AC6%E7%89%88-Informatics-IDEA-%E9%AB%98%E6%A9%8B/dp/4797399848)などをざっと読んでみるとよいかなと思います。

#学習時間
約2週間、1日1~2時間学習。
全体で20~30時間程度の学習時間でした。

#学習方法
教材は、以下のテキストとオンライン模擬試験を使用しました。

- テキスト
 - [Ruby技術者認定試験合格教本(Silver/Gold対応)](https://www.amazon.co.jp/%E6%94%B9%E8%A8%822%E7%89%88-Ruby%E6%8A%80%E8%A1%93%E8%80%85%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC-Silver-Gold%E5%AF%BE%E5%BF%9C-Ruby%E5%85%AC%E5%BC%8F%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8/dp/4774191949)  
試験に必要な知識としては、この本を読めば十分かなと思います。コツとしては、ただ読むだけではなく自分のPC上でirbを起動し、コードを書いて実行しながら学ぶことで理解しやすくなると思います。

- オンライン模擬試験
以下の模擬試験を9割以上取れるまで繰り返しました。本試験では、模擬試験と似たような問題がほとんどだったので、この学習法はかなり有効でした。
 - [Ruby技術者認定試験合格教本(Silver/Gold対応)](https://www.amazon.co.jp/%E6%94%B9%E8%A8%822%E7%89%88-Ruby%E6%8A%80%E8%A1%93%E8%80%85%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC-Silver-Gold%E5%AF%BE%E5%BF%9C-Ruby%E5%85%AC%E5%BC%8F%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8/dp/4774191949)
 - [模擬問題(Silver試験用)](https://gist.github.com/sean2121/945035ef2341f0c39bf40762cd8531e0)
 - [RubyExamination](https://rex.libertyfish.co.jp/)
 - [Rubyがミニツク Ruby技術者認定試験（Silver）対策問題集](http://www.minituku.net/courses/1049510743/contents/775230600.html)

#試験のポイント
- String/Array/Hashクラスのメソッドの動作を理解する。
- 破壊的メソッドと非破壊的メソッドを区別する。  
以下のように、!が付いていない破壊的メソッドを覚える。
 - shift
 - unshift
 - pop
 - push
 - concat
 - insert
 - replace
 - clear
 - update
 - delete_at
 - delete_if
 - delete　※deleteはArrayやHashクラスでは破壊的だが、Stringクラスでは非破壊的
- 同じ機能を持つメソッドを覚える。
 - map/collect
 - find/detect
 - find_all/select
 - reject!/delete_if
 - inject/reduce
 - delete_at/slice!
 - has_key?/include?/key?/member?
- 分からない問題は切り捨てる。  
毎回2〜3問ほどRubyのコミッターさんでも分からない問題が出るらしいので、分からない問題は潔く切り捨てましょう。

#まとめ
Silverの学習方法について、まとめてみました。
今後Goldも受験予定なので、合格したらGoldの学習方法についてもまとめていきたいと思います。
特定のバージョンのcocoapodsをインストールする

開発中のプロジェクトに途中からジョインした場合など、Podfile.lockに記載されているcocoapodsのバージョンと最新のcocoapodsのバージョンが違ってビルドするたびにdiffが出て困る場合がある。
そういうときはそのバージョンのcocoapodsをインストールするのが問題も起きにくいし便利。

**バージョン1.9.0** のcocoapodsをインストールしたい時は、こんな感じのコマンドを打つと良い。

```
sudo gem install cocoapods -v 1.9.0
```
WooCommerce For JapanのUndefined Indexを修正してみた

Wordpressはとかくプラグイン同士のコンフリクトが多くて嫌になる。正常に動いているようでも、サーバエラーがたくさん出ていたと思ったら、バージョンが勝手に上がって解決していたりと、動作が安定しない。しょうがないので細かいエラーはこちらで対応することしている。

今回起きたエラーは、「```Notice: Undefined index: section in /var/www/html/wp-content/plugins/woocommerce-for-japan/includes/gateways/paidy/class-wc-gateway-paidy.php on line 506```」というもの。これはPAIDYという決済モジュールでのAdmin画面での表示に、GETパラメータで`section`を呼び出す際の判定処理がなされていないことによるもの。つまり`$_GET['section']`がセットされていないときに、参照するものがないというエラー。NULLですらないのでエラーとなる、よくあるやつですね。

というわけで、このパラメータ判定の前にIF文を一つ噛ませてやりました。閉じ括弧を忘れないように。

```class-wc-gateway-paidy.phpのline506の前
if( isset($_GET['section']) ){

....

}
```

これでAdmin画面のエラー表示がなくなります。まぁ表示が出るだけで特に支障なく動いているみたいでしたが。しかしこれはPaidy側が配っているモジュールなんでしょうか？ authorのartisan workshopというのが誰なのかわからず。
【まじで注意】NestJSをAPIサーバとして使ってユーザの認証管理をする時の注意事項

昨日公開したサーバの挙動がどうもおかしかったのです。ガチガチにValidationかけてたので不具合とはならなかったのですが、想定してるよりバリデーションにひっかかる可能性が高い。具体的には、Controllerの上のほうの処理と下のほうの処理で、ユーザが異なるような挙動が確認される。

具体的なコードで紹介すると

```ts
@Injectable()
export class AuthService {
  public authId: number;

  get userId() {
    return authId;
  }

  // ...認証やらいろいろして、認証できたらauthIdにユーザIDを入れる処理とか
}
```

といったサービスをDIした以下のようなControllerがあったとします。

```ts
export class StatusController {
  constructor(
    private auth: AuthService,
  ) {}

  @Get()
  async userStatus(): Promise<IResponseGetUserStatus> {
    console.log(this.auth.userId);  // 【1】
    // ...時間のかかる非同期処理
    console.log(this.auth.userId);  // 【2】
  }
}
```

みたいな処理をしていると、【1】と【2】でそのリクエスト内では再ログインや上書きをしていないのに、なぜか値が異なる！！

ちょっと各位に相談したりドキュメントみたりしてたのですが、どうもNestJSではデフォルトではDIはHTTP Request単位ではなく、サーバ全体で行われるようです。簡単にいうと、ControllerもServiceもユーザ間で共有します。なので、プロパティでユーザIDをいれようものなら、取り合いがはじまって容赦なく書き換わります。

Issuesはこちらですね。

Http Request based DI #1376
https://github.com/nestjs/nest/issues/1376

いやー、焦った。テストでまったくでてこないし、当然ローカルテストで発見できるようなものではないので。確認したところ、ちょうど1年前にこれを解決するための機能が実装されていました。

Injection scopes
https://docs.nestjs.com/fundamentals/injection-scopes

この機能を使うことによって、DIをHTTP単位で生成するようにすることができます（代わりにコストが高くなることを注意する旨書かれていたりしますので、何でもすればいいわけじゃないです。認証といったクリティカルなものはそうしないとだめなだけです）。

先程の例だと、以下のようにすれば治ります。

```ts
@Injectable(
  { scope: Scope.REQUEST }  // 追記
)
export class AuthService {
  public authId: number;

  get userId() {
    return authId;
  }
}
```

実環境で動かすまで気づけない的にはかなりハマりポイントだと思いますので、ぜひ設計段階でNodeのDIをどの範囲で行うかは考えるようにすることをおすすめします。ブラウザと違って、DIは他のユーザと共有するリスクがあることにご注意ください。

それではまた。
LT用: 20200312

![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/416e6091-cedc-1e23-2044-f53b753e6b78.png)
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/b50fcfac-2db9-9166-353b-77a6c14d8e47.png)
![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/c9d3b0e5-c339-81e7-1a65-31fe3b0ad570.png)
![スライド4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/c6313b5e-c903-a9bd-4ad9-c14f72d8c63e.png)
![スライド5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/e9ec3b38-994a-0989-77f7-8123cacd08f9.png)
![スライド6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/4ab4a082-af9d-5a36-0b54-3f1c6f7dad53.png)
![スライド7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/655af0b9-0f8a-9337-1be5-8f44ea063a83.png)
![スライド8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/b514aba0-bcfa-2c69-80fc-7f3da75780a1.png)
![スライド9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/436a67d6-5c82-e22f-55c9-ede480836688.png)
![スライド10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/3e97a228-700d-bee4-2268-75dc0a48fcf7.png)
![スライド11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/ec63f874-b17d-23da-70f9-296b3396394a.png)
![スライド12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/7f538304-ec65-abfc-e493-d108a7ad6a91.png)
![スライド13.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/77476434-d1bc-53a8-2f7c-b23cb4bdc55b.png)
![スライド14.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/3df4e989-ffa9-de56-47a3-344d543cd038.png)
![スライド15.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/e64f4f7e-6ada-126b-43e0-d7912bb82078.png)
![スライド16.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/f86f0201-47cd-7227-5e5c-5830ac4221f7.png)
![スライド17.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/64f8055c-309c-eaeb-d2f9-bbd1826251ed.png)
![スライド18.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/acc15ec5-c118-360a-4714-6cfd3a06c551.png)
![スライド19.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/a783e6cc-b968-2380-42ce-5378586ed600.png)
![スライド20.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/6faa25ea-f26b-4429-eb59-e1cb03ae3408.png)
![スライド21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420547/c81d4a4e-ca7f-48bd-7f8d-6005c8d3d558.png)
AngularのngClassで条件に応じてスタイルを切り替える(三項演算子)

例えば、bootstrapのutilを用いてボタンの色を条件に応じて切り替えたい場合、

```html:hoge.html
<button class="btn" [ngClass]="hoge.isFuga ? 'btn-success' : 'btn-primary'">
  あああ
</button>
```

このように書く。
`{}`ではなく、`""`で囲わないと動かない。
よくやるけど`ngClass`を入力した時デフォルトで`""`ではなく`"{}"`が出てきてしまうので一応メモ。
Kaggleのワークフロー

U++氏の「[Kaggleにおける「特徴量エンジニアリング」の位置づけ　〜『機械学習のための特徴量エンジニアリング』に寄せて〜](https://upura.hatenablog.com/entry/2019/02/22/221125)」より。

1. （探索的データ分析）人のEDA系カーネルを読んで2に進むことが多い。
2. ベースラインモデルの構築
3. Validationの構築
4. 特徴量エンジニアリング
5. ハイパーパラメータ調整
6. アンサンブル
Active Storageでデフォルト画像を設定する

CarrierWaveでデフォルト画像を設定する記事はよく見かけるが、Active Storageの日本語の記事は見かけなかったのでメモ。
オブジェクト作成時に、デフォルトの画像を紐付ける。

### 方法
- assets/images　に適当な画像を保存。
-  デフォルト画像を設定したいクラスのファイルに以下を追加。

```ruby
before_create :default_image

def default_image
  if !self.image.attached?
    self.image.attach(io: File.open(Rails.root.join('app', 'assets', 'images', 'event_default.png')), filename: 'default-image.png', content_type: 'image/png')
  end
end
```

これでオブジェクト作成時にデフォルト画像を設定することができた。

今まではビューファイルにif文で表示を変えるコードを書いていたが、このようにスマートにかけるようになった。

```ruby
#変更前
<% if event.image.attaced? %>
 <%= image_tag event.image %>
<% else %>
 <%= image_tag 'dehault.img' %>
<% end %>

#変更後
<%= image_tag event.image %>
```
iOS アプリのB2B配布




Apple Store Connect がB2B向けの配布手段
・プライベートかつセキュアに配信できます。
・配信先は、特定のパートナー企業やユーザー、フランチャイズ先、従業員などを指定できます。


Apple Store Connectを使用するのに以下が必要。
- Apple Developer Programnの申請
- 有料アプリやアプリ内課金を行う場合、税金＆口座情報の入力。




参考
https://developer.apple.com/business/custom-apps/
https://help.apple.com/app-store-connect/#/dev300c2c5bf