OmniAICreator/Qiita-1.07M huggingface dataset:
モバイルゲームにおけるユースケーステストを考察

# はじめに
実は私は業務でユースケーステストを使ったことはありません。
なんとなく大きなシステムの大枠部分で適用するイメージを持っており、
なんとなくJSTQBとかを勉強したときに知っている程度です。

そんな私が、ふと家でロールプレイングゲームをやっていたときに、
これってユースケーステストでテストできるのかな？と思ったことをきっかけに
今回の記事を書いてみようと考えました。

## 注意点
・勉強しながら書いてみたため、必ずしも正しい内容ではない可能性があります。
・出てくるサンプルは、妄想の産物です。
# ユースケーステストとは
※詳細はJSTQBのシラバス (http://jstqb.jp/syllabus.html#syllabus_foundation) をご参照ください。
アクター(ユーザーなど)と対象となるシステムの相互作用を記述したユースケースに沿ってテストケースを設計する手法です。
ソフトウェアテスト教科書 JSTQB Foundation<第3版>では、ユースケース記述の例として
以下のフォーマットを紹介しています。
##ユースケース記述のフォーマット
- ユースケース名
- 目的
- アクター
- 事前条件
- 事後条件
- 基本フロー
- 代替フロー
- 例外フロー
- 備考

それぞれの詳細は、上述の教科書をご参照ください。
このフォーマットに沿って、ゲームシナリオを想定したユースケースを作成してみました。
# ゲームシナリオを想定して使ってみた
## 仕様
メインストーリーを盛り上げるために、人気キャラの活躍にフォーカスしたサイドストーリーを実装する。
サイドストーリー内では、新たな村やダンジョンも解放され、それらを攻略するクエストも追加する。
ここでは、そのうちのおつかいクエストの仕様を定義する。
![クエスト仕様.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321152/14ca9c06-b941-1e91-e687-5d7e2fc4cc74.png)
## ユースケースの記述例
なんとなく仕様に明記されていないところも脳内補完しつつ、
以下のようなものを作成してみました。
![ユースケースサンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321152/4311140b-5b04-007f-6bc5-a6abfd9d63b9.png)
## 感想
### 対象を決めるのが難しい
サンプルとして、どういうゲームの仕様ならテストしやすいか考えたのですが、けっこう難しいと感じました。
いくつか参考書を読みながら、初心者でも当てはめやすい事例を考え、
まずは小規模な範囲で「おつかいクエスト」をピックアップしました。
結果としては上記のとおりですが、個人的にはこのレベルがしっくりきました。
### ステップが難しい
不慣れなこともあり、ステップは何回か見直しつつ作成しました。
個人的にはここが一番難しかったです。
(全体を通して作成したあと見直すと、どこか一部だけレベル感が違う、という結果になることも・・・)

対象とするシステムの規模感にあわせてステップを作成できるようになると、
もう少しまともなユースケースを作れるようになりそうなので、
このあたりはもう一段勉強してみたいと思います。
# まとめ
今回試してみて、まだまだ検討の余地ありそうだな、というのが正直な感想です。

個人的にモバイルゲームにおいて、ユースケーステストが有効かも、と思ったのは、

- RPGのように大筋に沿ったゲーム性になっている
- メインとなる流れがありつつ、それに影響するサブ要素があるもの

といったケースで、仕様を整理しつつ、どういったところをテストしていくかを検討する際に使えるかも？というところです。

機会があれば今度は別の範囲などで考察してみようと思います。

すでにユースケーステストをやってる！という方がおられましたらコメント&ご助言いただけますと幸いです。
## 参考書籍
- はじめて学ぶソフトウェアのテスト技法/日経BP社
- ソフトウェアテスト教科書 JSTQB Foundation<第3版>/翔泳社
AzureのBLOBストレージへのファイル転送で、HULFTの動的指定を使ってみた

#はじめに
こんにちは。よろず相談担当　すぎもん:yum:です。
今回は、前回記事のAzure BLOB Storageへのファイル転送についてやってみた。の続きです！
[AzureのBLOBストレージにファイル転送してみた](https://qiita.com/sugimon/items/3a88c11a1b1d736a8659)
#今回やること（アップロードファイルの動的指定）
前記事でもお伝えした通り、HULFT機能の一つである「動的指定」を使ってファイル名を指定し、クラウド転送してみます！

HULFTでは、ファイル転送を行う場合に事前に管理情報の設定が必要です。
その管理情報を動的に変更することができるのです！
※クラウドストレージオプションでは、メッセージ機能のみ有効です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/c5d5065f-7239-967d-e256-bc12d7d0ae43.png)

これを利用して、ファイル名と日付を動的に指定してファイル配信をします。
　**[blobfile_YYYYMMDDhhmmss.txt]というファイルを作成して転送。**
　　⇒［blobfile］を［\$MSG0］に、［YYYYMMDDhhmmss］を［\$MSG1］に設定。 
#集信側HULFTの設定
HULFT管理画面の［システム管理］-[集信管理情報]から、以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/d8d54dec-5129-5f83-2303-7d4474d6ef13.png)

集信管理情報の設定はこれだけでOKです！

#コマンドプロンプトからファイル配信
コマンドプロンプトを起動し、配信側HULFT(ホスト名：HULFT-SEND)のbin配下に移動して実行が必要です。

**```cd C:\HULFT Family\hulft8\bin```**


早速、ファイル配信をしてみます。
集信ファイルの動的指定は、以下のようにします。
　**・［メッセージ0］に［集信ファイル名（blobfile）］を指定**
　**・［メッセージ1］に［現在日時※］を指定**
　　　※ %date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%

これで、集信ファイルは、「blobfile_YYYYMMDDhhmmss.txt」で転送されるはずです。

####配信コマンド
**```utlsend -f BLOB01 -msg0 blobfile -msg1 %date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%
```**![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/0d80ae4d-131d-fc73-7ae2-35ec24320536.png)

####☆時刻の取得の注意点（おまけ）☆
上記の通り、動的指定でファイル名に［現在日時］をセットしましたが、［日時］って一桁数字の場合（例えば9時とか）、先頭が［0］でなく［ブランク］になるときありますよね。（よくそのせいで、コマンド認識が変わったり、javaとかだとnullpointerexceptionで落ちたりした記憶があり……）気になったので、ちょっとやってみたのですが、やはり［時間hh］は、頭の［0］を「スペース」とみなして、「コマンドエラー」になってしまいました。なので、ちょっと気を付けてみてください!!※試してみた結果ブランクになるのは［hh］の時間だけです。私は、``` set TIME=%TIME: =0%  ```　で、TIME変数の先頭空白文字を0に置換してからutlsendコマンドを打つようにして回避しました！

**■配信側HULFT（HULFT-SEND）の配信状況の確認**
「完了コード」は「000000(00000)」になっていればHULFTの配信は正常終了です。
メッセージパラメータで動的指定した値も確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/1ebf8d79-13dc-a1a1-a6ef-7054b139cc92.png)

**■集信側HULFT（HULFT-REVC）の集信状況の確認**
「完了コード」は「000000(00000)」になっていればHULFTの集信は正常終了です。
集信ファイル名に指定した(\$MSG0_\$MSG1.txt)が、メッセージ0, メッセージ1に指定した値に変更されているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/4677071a-0319-6eed-bef8-bd0d27f470aa.png)
**■AzureのBLOB Storageのコンテナーを確認**
［sugimondemo］コンテナー内に、動的指定を使った「ファイル名＋現在日時」のファイルがアップロードされました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458288/b9bef389-8b23-0cf2-7e64-6b25fba2681d.png)
#最後に
今回は、HULFTのクラウドストレージオプションでのAzure BLOB Storage転送に加え、HULFT機能の動的指定でファイル名を指定してみましたが、いかがでしたでしょうか。因みに、今回は集信管理情報にメッセージパラメータを設定しましたが、同様のことを配信管理情報にすることも可能です。是非やってみてください！
設定自体は、前回に引き続き、とてもシンプルで簡単に転送できました！
コマンドプロンプトからの日付取得と編集は少し調べましたが……。


このブログでは、今後も技術の「よろず相談窓口」で相談を受けた内容や、誕生したワザをご紹介していけたらな、と思っています。

これからも是非チェックいただき、宜しければフォローをお願いします。

それでは、また！
【SF標準機能】インテグレーション機能を利用して位置情報を取得する

# はじめに
Salesforce標準機能の中で、リードや取引先責任者に入力した住所情報を元に、緯度経度情報を自動取得してくれる機能があると知り、試しに使用してみました。

# インテグレーション機能の有効化
設定画面の[インテグレーションルール]を表示し、使用する機能を有効化します。
今回は[Geocodes for Lead Address][Geocodes for Contact Mailing Address]を有効化しました。
![WS000144.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311972/d5b5fdc2-669c-aeb2-fb8d-d78960ce1c2d.jpeg)


# 住所を入力
設定が完了したので、実際にリードを作成し、住所を入力して保存します。
![WS000146.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311972/58f7446a-52cc-13bb-85e8-b5ec8dbde535.jpeg)


保存後、緯度経度を取得できていることが確認できます。
![WS000147.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311972/0df0ad69-0d8a-da8e-3b81-46d8c2de5c32.jpeg)


# データ間の距離を算出
緯度経度データを使用して、データ間の住所の距離を測定できます。
![WS000148.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311972/f11da54b-203d-fa40-f961-44d245abc4c4.jpeg)

# さいごに
まだまだ使用していない標準機能がありますので、継続して試用していこうと思います！
AWS の EC2 が ping に応答するように設定

AWS の EC2 はディフォールトでは、ping に応答しません。
セキュリティグループ　の設定をすることで、応答するようになります。

Inbound rules に IPCM　プロトコルを付け加えます。

次のようになります。
![aws_icpm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/bd4470a1-e6f4-3750-42eb-37961f576262.png)
railsでのデータ取得方法　find,where,group by など

#はじめに
railsの基本的なデータ取得方法をまとめます。

#allメソッド
全ての要素を取り出すメソッドです。モデルのすべての要素を配列で取得します。

```
#モデル名.all

#以下が例となります。
User.all
```


#findメソッド
モデルのidをキーとして検索するメソッドです。
idに当たるレコードがない場合はエラー(ActiveRecord::RecordNotFound)を起こします。

```
#モデル名.find(取得したいレコードのid)

#以下が例となります。
User.find(1) 
```

#find_byメソッド
条件にマッチしたレコードを１件だけ返すメソッドです。
条件に一致するものがない場合はnilを返します。

```
#モデル名.find_by(検索するテーブルのカラム名: 検索したいデータ)

#以下が例となります。
User.find_by(name: "たかし")
```

#whereメソッド
条件に対しての結果をすべて返すメソッドです。
条件に一致するものがない場合はActiveRecord_Relationクラスを返します。

```
# モデル.where(検索条件)

#nameがたかしのものを検索
User.where(name: "たかし")

#nameがたかしかつseiがすずきのものを検索
User.find_by("name = ? and sei = ?", "たかし", "すずき")
```

#終わりに
railsで基本的なデータの取得方法について紹介しました。
条件に一致するものがないときはそれぞれ違う結果を返すことは頭に入れておきたいです！
【JavaScript】Objectかどうか判定する方法

# Objectかどうか判定する方法

結論: ```Object.prototype.toString.call()```を使う。

### typeofを使用した場合

以下の出力結果を予想できますか？

```js:console.js
console.log(typeof {});
console.log(typeof []);
console.log(typeof null);
console.log(typeof undefined);
```


```console:result
> "object"
> "object"
> "object"
> "undefined"
```

Javascriptのtypeofでは、{}, [], nullの結果が全て"object"になります。



### Object.prototype.toString.callを使用した場合
```js:console.js
console.log(Object.prototype.toString.call({}));
console.log(Object.prototype.toString.call([]));
console.log(Object.prototype.toString.call(null));
console.log(Object.prototype.toString.call(undefined));
```
```console:result
> "[object Object]"
> "[object Array]"
> "[object Null]"
> "[object Undefined]"
```

それぞれ[object *]のformatで出力されます。
CatapultのMosaicRestriction(モザイク制限)機能

# はじめに

NEMの次世代エンジンCatapultには様々な設定が可能な **Mosaic(モザイク)** と呼ばれるトークン機能があります。これは現行のNEMのプロトコルにも組み込まれているもので、名前は特殊ですが要するにカウンターパーティ[^1] やイーサリアム[^2] のコントラクトによって提供される **トークン** と呼ばれるものと概念は同じものです。具体的にはチケットやメダルなんかがイメージしやすいと思います。

[^1]: https://counterparty.io/
[^2]: https://ethereum.org/


これに加えてCatapultでは新たにこのモザイクの流れに制限をかけることが出来る機能が追加されました。これを、 **MosaicRestriction(モザイク制限)** と呼びます。

https://nemtech.github.io/ja/concepts/mosaic-restriction.html

この機能の説明は上記のURLで飛んだ先に例を交えて書かれていますが、機能が少し複雑なので正直分かりづらいと思います。今回はこの機能の説明です。

# モザイク制限機能

モザイク制限はモザイクの流通に制限をかける機能です。この設定は、**あらかじめモザイクを生成する時にRestrictable(制限可能)であることが宣言されたモザイクにおいて** 、そのモザイクの発行者によって調整を行うことができます。

そのため、例えば手数料支払いに利用される基軸となるようなトークン(CurrencyMosaicなどと呼ばれます)には、この制限をかけるべきではありません。このことは、'はじめに'で紹介したURLの先でも説明がされています。

ここでいう **制限** とは、簡単に言うと送れないということです。発行者と発行者が認めた相手の間では送信が出来るけど、それ以外の人には送れなくすることが出来るようになります。

![iamge1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216882/18feca63-ad4b-e751-167c-471b91cd7505.png)


制限が出来ると何が嬉しいのかというと、例えば何か現実にあるものをパブリックブロックチェーン上でトークン化してみたのは良いものの、誰にでも制限なくやり取りが出来てしまう性質によって国からの規制を受けてしまう（また、規制を受けた後に対策しようにもそれに対する有効な対策が打てない）といった状況を回避出来る場合があります。（勿論、その国の法律によって差は出ると思いますが）

# 例:18禁モザイクを作る

ここから、具体的な例によって機能の説明をしていきます。

例えば「18歳以上の人しか扱えないトークン」を作りたくなったとします。18歳以下の人の手に渡るとあまり良くないよねと社会が認めた何かをトークン化した場合ですね。

## 1.モザイクを作る

まずはモザイクを作ります。この時、前述したとおり **Restrictable** なモザイクを作る必要があります。

モザイクには

1.自由に送信可能
2.供給量変更可能
3.流通制限可能 (これが今回の)

の3つのフラグがあり、これらのYes/Noをモザイク生成時に決めてあげる必要があります。このフラグによって、色々な性格のモザイクを作ることが出来るようになるわけです。

今回は発行者はモザイクに制限をかけたいので、モザイク作成時に3番目のフラグをセットする必要があります。

## 2.グローバル/アドレス制限設定を決める

Restrictableなモザイクを作ったら、次に設定をやっていくことになります。

モザイク制限には **グローバル制限設定とアドレス制限設定** があり、グローバル制限設定でそのモザイクの全体のルールを決め、アドレス制限設定で個々のアドレスに割り当てられた数値を決めます。

今回の場合、

**18歳以上の人が操作していると認められたアドレス間でのみ送受信が可能**

が全体のルール(つまりグローバル制限設定)になり、

**各アドレスを操作している人の年齢**

が個々のアドレスに割り当てられる数値(つまりアドレス制限設定)になります。

発行者はグローバル制限設定により、アドレス制限設定の値が18以上のアドレスしかそのモザイクを扱えないようにする設定を、グローバル制限設定によって行い、発行者が責任をもってKYCを行い、18歳以上であると認めたアドレスのアドレス制限設定の値をその人の年齢にする必要があるということです。ややこしいですね。

## 3.もっと複雑な管理も出来る

### 18歳"以上"だけじゃないよ

上記の例だと、18歳"以上"の人のみが扱うことが出来るトークンを作るということでしたが、この他にも、「等しい」「未満」などの設定をグローバル制限設定として決めることが出来ます。

この設定値は、**MosaicRestrictionType** と呼ばれており、以下のバリエーションがあります。

| 0 (NONE) | 初期化値。設定なし |
|:--|:--|
| 1 (EQ) | 同じ場合に許可 |
| 2 (NE) | 同じでない場合に許可 |
| 3 (LT) | 未満の場合に許可 |
| 4 (LTE) | 以下の場合に許可 |
| 5 (GT) | 超える場合に許可 |
| 6 (GTE) | 以上の場合に許可 |

### 複数設定できるよ

モザイク制限はグローバル/アドレスの設定が一対になることで機能します。この設定のペアは、**RestrictionKey(制限キー)** と呼ばれるIDによって管理されており、複数設定することが出来ます。

制限キーが `0x0000000000000001` のグローバル制限設定と対になるアドレス制限設定は、同じく制限キーが `0x0000000000000001` のものになります。

制限を複数設定できるというのは、例えば「18歳以上、90歳以下、日本人のみが扱えるトークンを作りたい」と思った時に、

1. 18歳以上
2. 90歳以下
3. 国籍

と3つの制限を組み合わせることで、複雑な要求にも答えられるようにもなっているということです。

# 総評

早い話、使ってみよう。
IM-FormaDesignerのグリッドテーブル活用

#はじめに
intra-martの開発に関するメモとして記載しています。
本ページに記載している実現方法は、イントラマート社公式のものではありません。

#やりたいこと
intra-martの画面開発ツール「IM-FormaDesigner」では、jqGridを利用しているらしく、jqGridのAPIが使えるはず。
ということで、jqGridのAPIをFormaDesignerで使ってみようという話。


#実現方法
グリッドテーブルのjqGridオブジェクトは、
・$("#[グリッドテーブルのテーブル識別ID]")
で取得できるようだ。
例えば、テーブル識別IDを「gt1」としたグリッドテーブルを配置する場合は、
$("#gt1")という感じ。
これにより、jqGridのAPIが利用できる。例えば、
・列の表示：$("#gt1").showCol("item1");
・列の非表示：$("#gt1").hideCol("item1");
　※「item1」はグリッドテーブル内の列のフィールド識別ID
という感じ。

#おわりに
jqGridのAPIを利用することにより、グリッドテーブルでいろいろなことが実現できそう。
これで、表示内容に合わせて列の表示・非表示を動的に切り替えたりなど、リッチな表現ができそうです。
Cinema4Dに3rd partyのpythonのライブラリをインストールする

Cinema4D R20よりPythonのインストール周りが変わったようなのでめもです。
pip installできるようにします。

##Cinema4DのPythonのディレクトリはここ
```C:\Program Files\MAXON\Cinema 4D RXX\resource\modules\python\libs\win64\python27.vs2008.framework```

R20以上ではライブラリもこちらにいれていかないといけないようです。
因みにpythonのバージョンは2.7です。

<br>
##pip installできるようにする
[こちら](https://bootstrap.pypa.io/get-pip.py)からget-pip.pyをダウンロード。
上記pythonディレクトリの直下に置きます。

<img width="400" alt="vx1g1-mikvn.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190301/83d44f48-f234-f9ec-b727-d280b39d5aad.gif">
書き方自分で忘れてしまいそうなのでgifにしました><
・管理者としてコマンドを実行
・上記ディレクトリまで行き、get-pip.pyをPythonにインストール
・successfullyと出たらこれで3rd partyのライブラリがpip installできるように
・```.\python.exe -m pip instal ~~```でインストールできる
・C4Dのコンソールを開き ```import ~~```してエラーが出なければインポートできている


**pip installされたものはこちらに格納される**
```C:\Program Files\MAXON\Cinema 4D RXX\resource\modules\python\libs\win64\python27.vs2008.framework\lib\site-packages
```



.
Windowsでよく使うレジストリ~1~

# はじめに
業務でGPOを作成していて思うのは、レジストリでの制御が多い！

その割には、検索では見つかりにくいという初心者には優しくない。

なので、初心者や自分の端末をカスタマイズしたい人のためにWindowsでよく使われるレジストリをまとめました。

# 設定の仕方

GPOで作成するのと直接記入する時は設定方法が変わります。
それぞれの場所は以下の通りになります。

<b>1.GPOの場合</b>
・コンピュータで設定を統一したい場合は
　　<b>コンピュータの構成\基本設定\Windows の設定\レジストリ</b>
・ユーザーで設定を統一したい場合は
　　<b>ユーザの構成\基本設定\Windows の設定\レジストリ</b>

<b>2.直接レジストリに書き込む場合</b>

*<font color="Red">※直接書き込むときはバックアップ(エクスポート)を忘れずに!</font>*

スタートボタン(Windowsボタン)+Rで検索ボックスを起動し、ボックス内にregeditと入力して
レジストリエディタを起動します。

## 1. プロキシの設定
### ・ 自動構成の設定

*レジストリの場所*

```
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : AutoDetect 
  値の種類 : REG_DWORD 
  値のデータ : 0x1
　有効 : 1
　無効 : 2
### ・　プロキシの使用

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : ProxyEnable
  値の種類 : REG_DWORD 
  値のデータ : 0x1
　有効 : 1
　無効 : 2
###・ プロキシアドレスとポート

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : ProxyServer
  値の種類 : REG_SZ 
  値のデータ : プロキシアドレス:ポート　
### ・  プロキシの例外設定/「ローカルアドレスにはプロキシサーバを使用しない

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : ProxyOverride
  値の種類 : REG_SZ
  値のデータ : 例外にするIP等;\<local>

##2. Cortananの設定
*<font color="Red">※Cortanaに関してはコンピュータとユーザー両方で設定が必要！</font>*
### ・ Cortanaを無効にする

*レジストリの場所*

```
 HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Windows Search
```
*設定値*
  値の名前 : AllowCortana
  値の種類 : REG_DWORD
  値のデータ : 0x0

### ・ 検索ボックスからWeb検索を取り除く

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software¥Microsoft¥Windows¥CurrentVersion¥Search
```
*設定値*
  値の名前 : AllowSearchToUseLocation
  値の種類 : REG_DWORD
  値のデータ : 0x0

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : BingSearchEnabled
  値の種類 : REG_DWORD
  値のデータ : 0x0

*レジストリの場所*

```
 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
```
*設定値*
  値の名前 : CortanaConsent
  値の種類 : REG_DWORD
  値のデータ : 0x0
Ruby2.3.1でgemがインストールできない（cannot load such file -- openssl）

# cannot load such file -- openssl

rvmで2.3.1をインストールし、gem install xxx を実行すると以下のエラー。

```
ERROR:  Loading command: install (LoadError)
	cannot load such file -- openssl
ERROR:  While executing gem ... (NoMethodError)
    undefined method `invoke_with_build_args' for nil:NilClass
```

何らかの原因でOpenSSLが読み込めないのが原因らしい。

# 解決法

自分の場合は、rvmのパッケージでopensslをインストールして、それを参照するようにしたら動いた。

```bash
rvm pkg install openssl
rvm reinstall ruby-2.3.1 --with-openssl-dir=$rvm_path/usr
```
パスワードは 90 年代の代物だ（JSConfカンファレンス参加メモ）

この記事は[フューチャー 2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/future2)の 11 日目の記事です。
昨日は[@Tetsu_minorityさんの記事](https://qiita.com/Tetsu_minority/items/23708ffc7f744c0ab285)でした。
**Futureアドベントカレンダーは[その１](https://qiita.com/advent-calendar/2019/future)もあります！！ぜひご覧ください。**

# ごあいさつ
11/30、12/1 に開催された[JSConf JP](https://jsconf.jp/2019/)に参加してきましたが、
たくさんのレクチャーがあり初めて知ることばかりでした。
今回はその中から、個人的に面白かったパスワードについてのレクチャーを
おさらいを兼ねてまとめてみようと思います。

# Password is so 1990s（「パスワードは 90 年代の代物だ」） by Sam Bellen

## 「パスワード」の歴史
* パスワードの歴史ははるか昔、古代ローマ人の時代にさかのぼる。
* 10世紀ごろには「ひらけゴマ」という「パスワード」も誕生した。
* 1961年にはタイムシェアリングシステムが登場。1台のコンピュータを複数人のユーザーでシェアして使うことができるようになった。
* 1970年代には「ハッシュ化」の技術が生まれる。パスワードをよりセキュアに保存することができるように。
* 1990年代には、ハッキングがより深刻な問題として顕在化した。

## パスワードの種類

#### ところでパスワードとは何か
それは **秘密をシェアするすべてのもの** のことである！

#### 色々なパスワード
* 意味のないアルファベットの並んだ文字列など、複雑なものは覚えられにくい。
  * つまり、複雑であれば他人から推定されにくい。
* 一方でPINコードのように簡単なものは覚えやすい。
  * つまり、他人から推定されやすい。
  * よってPINコードなどは生体認証（などの複雑な認証）と合わせて使うとより安全である。
* パターン認証は推定されにくいほどのものではない。
  * 覚えやすくはある。物の認証に使われる。

#### パスワードの問題点
* 忘れたらリセットしなきゃいけない。
* リセットの作業が**とにかく面倒！**
* 手間を省くためにパスワードマネジャーを使うことになるが、パスワードが必要なサイトが増えるほどハックされる可能性も高い。

#### より良いパスワードにするためには
 * 複雑なパスワードにする
 * 個人情報を含めない
 * パスワードを再利用しない
 * 頻繁にパスワードを変更する

これらが有効だが、誰もそんなことしない。Sam Bellen氏だってしない。
そこで、

## パスワードレスな認証
* ワンタイムパスワード
  * 一度だけ使用できる。短時間で有効期限切れる。
  * ユーザーに直接届く。iOSやAndroidならば届いたメッセージから推測して入力できる。
  * 二段階認証が必要ない。
  * ただし：携帯が必要である。
  * メールで送信できれば問題ない？否、メールも解析される恐れがある。
* 認証アプリ
  * 時系列だったり、プッシュ型だったりする。
  * アプリケーションと認証サービス間で秘密の情報を共有する必要がある。
* SMS認証
  * 覚えなくてはならないパスワードが減る。
  * 信頼できるサービスにのみパスワードを教えるだけで良い！
  * ただし；他のサービスに認証を依存することになる。
* 他の認証アプリも、二段階認証の一つとしてよく使われる。

## Web認証API 

#### [webauthn](https://developer.mozilla.org/ja/docs/Web/API/Web_Authentication_API)というクールな認証APIがある
* キーベースの認証である。
* 認証はハードウェアで行う。
* 新しいキーを生成し、保存するようになっている。
* モダンなデバイスだと認証装置がビルトインになっている。（touch IDなど）

#### どのように動作するか？
* クレデンシャル登録・・・一度登録すれば、いつでも認証できるようになる！
  1. 認証のリクエストがサーバーに送信される。
  2. レスポンス（「`Challenge`」と呼ばれていた）がデバイスに返ってくる。
  3. ユーザーがデバイスを操作する。(`Challenge`にSignする)
  4. デバイスからサーバーへ`Signed Challenge`、`Public Key`と`raw ID`が送られる。
  5. サーバーはユーザー名と一緒にそれを保存する。
  6. 登録完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311215/bcb0b988-9593-bf78-8805-de09d7db3e5e.png)

* 認証
  1. ユーザーがユーザー名をクライアントに入力する。
  2. `Challenge`、`Public Key`と`raw ID`がサーバーから返ってくる。
  3. ユーザーがデバイスを操作する。(`Challenge`にSignする)
  4. デバイスからサーバーへ`Signed Challenge`と、登録時と同じ`Public Key`が送られる。
  5. 認証完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311215/f638df24-3c51-ca87-4ebe-e647fd2f7dc5.png)

#### webauthnで嬉しいこと
* ハードウェア認証なのでinternal、externalも分けられる。
* ハードウェアを通しての認証なので、パスワードを入力する必要がない！

#### 課題もある
* ユーザーがクレデンシャルをどう管理するか
* デバイスをまたいでのクレデンシャル発行
  * 紛失したデバイスの認証システムはどう復旧するか、など

#### それでも
* `webauthn`はパスワードに取って代わるシステムとなるだろう。
  * （Auth0などの認証サービスの代わりにはならないだろう）
* W3C勧告にもなっており、様々なブラウザが対応しようとしている。
* GoogleやGithubではすでに`webauthn`を使える！

# 所感
* この発表によって、ログインにはIDとパスワードのセットが当たり前、という思い込みを打ち破られました。
* 時代はクラウド！と言われる中でハードウェア認証なんだ、、と最初は戸惑ったが、物理的な認証であれば自分が持っている限り盗まれることはない＝ハックされにくいという点では納得できる気もしました。

# 参考

- [Sam Bellen 氏の登壇スライド](https://1990.sambego.tech/)
【初心者】phpで動作するプログラムをPythonで書くとどうなりますか？

phpでLINE botを作成しました。チャットに入力された文字がデバッグとして該当txtに入力されるだけの仕組みです。

これをPythonで代替して作る場合のコードが分からず困っています。

以下はphpで実際に動作したコードになります。


<?php

//(1)ログファイルの指定
define('DEBUG','../debug.txt');

//(2)リクエストの取得
$input=file_get_contents('php://input');

//(3)ログファイルの出力
file_put_contents(DEBUG,$input):



これをPythonで代替するとどのようなコードになりますでしょうか？初歩的な事と理解出来ますが恥を承知でご教示頂ければと思います。
requestsを使うんだろうなぁ…というあたりまではつけれるのですが…

何卒よろしくお願いします。
Flaskに関するメモ

備忘録的な要素があるのでそこんとこすみません。

###超絶基本
以下にテンプレ的なプログラムを書きます。
ディレクトリ構成は
>Qiita/
>    ├templates
>    │       ├index.html
>    │       └posted.html
>    └app.py




```python:app.py
from flask import Flask, render_template, request

app = Flask(__name__)
##この上まではテンプレみたいなものなので

@app.route('/home')
def home():
    return render_template('index.html')

@app.route('/post',methods=['POST','GET'])
def post():
    if request.method == 'POST':
        all = request.form
        return render_template('check.html',name=name,val = val)

if __name__ == "__main__":
　　#ここで開くportとかも設定できる。
    app.run(host='0.0.0.0',port=5000,debug=True)
```
ではこのプログラムの解説をしたいと思います。
####解説

```python:
@app.route('/home')
```
これは`http://0.0.0.0:5000/home`にアクセスしたのかを調べている？ものである。
このあとにある

```python:
return render_template('index.html')
```
で、`templates/index.html`を実行する。

```python:
@app.route('/post',methods=['POST','GET'])
def post():
    if request.method == 'POST':
        all = request.form
        return render_template('posted.html',data=all)
```
では**POST**か**GET**のmethodであれば処理をする。
また`request.form`ではPOSTされたデータを`dict`型で受け取ります。例えば`name="tsukkey"`だったら`request.form['name']`と入力すればtsukkeyが参照されます。
`render_template()`の中の`data=all`では、POSTされた値をposted.htmlに送ってる感じです。
htmlファイルに関しては面倒なので上げませんが適当に`{%%}`でくくってif文とか書いとけば基本なんとかなります。
TouchDesinger 簡易ノイズ除去フィルター

[TouchDesigner Advent Calendar 2019](https://qiita.com/advent-calendar/2019/touchdesigner) 8日目の記事にしました。よろしくお願いします。

# はじめに
TouchDesignerがメインのアプリで、RealSenseのデプスストリームから物体検出をしようとしていて、まずはノイズを減らしたかったのでOpenCVかなと思っていたところ、同僚がTOPを駆使してささっとやってみせてくれたので真似することにしました。

# サンプルファイル
githubにアップしましたので必要に応じて参照してください。
https://github.com/chimanaco/touchdesigner-advent-calendar-2019

# サンプルの流れ
![T1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/bd961918-0349-a879-66a8-51eab26b64e1.png)
画像→ノイズを加える→Low pass filter→Spatial filterとなっています。

# Low pass filter
1つめのフィルターです。こんな感じの式を実装しています。

```
y[n] = ß * x[n] + (1-ß) * y[n-1]
```
![T2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/55a7a940-1551-4e40-fde1-0a8e9a020346.png)

サンプルではßに 0.05を設定し、現行のフレームを0.95倍、最新のフレームを0.05倍してaddしています。ßの値を大きくするほどノイズの影響を受けやすくなります。

#Spatial filter

2つめのフィルターです。こちらは単純にblurをかけています。
![T3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58558/4dfff4cf-9d4b-0ab7-03f3-5236c48a6a53.png)

ノイズにもよりそうですが、俺の目的にはこの2つだけで物体検出に使えそうなイメージが得られました。ここで対象画像と比較しています。

# 最後に
個人的にMathやAnalyzeなどのCHOPはよく使っていたのですが、TOPのは使ったことが無かったので、今更ですがこれはオペレータごとに変化がビジュアルとしてよく分かる、TouchDesignerの素晴らしい例だと思いました。

残りのアドベントカレンダーの投稿も楽しみにしています。
ありがとうございました。
ITパス　補助記憶装置

#目次：補助記憶装置
1. [補助記憶装置とは](#1補助記憶装置とは)
2. [仮想メモリ](#2仮想メモリ)
3. [リムーバブルディスク](#3リムーバブルディスク)

#1.補助記憶装置とは
補助記憶装置は電源の供給がなくなっても記憶を保ち続ける。試補助記憶装置の１つであるHDDはメモリより安価なので、何百倍もの容量を搭載することができる。
その代わり、読み書きの速度が主記憶装置に比べて比較にならないほど低速。人間が手書きでメモを書き、膨大な量のメモの中から該当するメモを探し当てなければいけないと考えるとわかりやすい？
#2.仮想メモリ
メモリに入りきれない容量のプログラムが起動した時に、ハードディスクに**仮想メモリ**を作り、一時的に今現時点では動作に関係のないプログラムを避難させることができる。これを**スワップアウト**と言う。
逆にメモリに空きができ、動作に必要なプログラムをメモリに戻すことを、**スワップイン**という。
このメモリと仮想メモリの読み書きのことを総称して**スワッピング**という。
ハードディスクは低速なため、スワッピングが発生するとコンピュータの処理速度は低下する。
#3.リムーバブルディスク
補助記憶装置はハードディスク以外にも、駆動装置から取り外して持ち歩ける**リムーバブルメディア**がある。

| リムーバブルメディア  | 例 | 概要 |
|:-----------------|:------------------:|:-------------------|
| 光ディスク　        | CD-ROM、DVD-ROM等    | **レーザー光**使ってデータの読み書きを行うディスクメディア。非常に安価なので配布媒体としても広く使われる。ディスクの種類には、読み出し専用、一度だけ書き込み可能、何度でも書き換え可能タイプがある。 |
| 光磁気ディスク      |  フロッピーディスク | **レーザー光と磁気**の両方を使って書き込みする。読み出しには**レーザー光のみ**を使う。 |
| 磁気テープ         |     カセットテープ | **磁気体を塗ったテープ**を使い、磁気によってデータの読み書きを行う。**非常に低速**だが、**かなり大容量なのでバックアップ用**によく使われる。 |
| フラッシュメモリ      |       SDカード | **EEPROMの一種**を補助記憶装置に転用したもの。**コンパクトかつ低価格**なので**デジタルカメラや携帯電話**などの記録メディアとして使われる。 |
強化学習３３　Colaboratory+Breakout+chainerRL　画面を出してみる

中学生から大学生までのAI初学者を対象にしています。
強化学習２８が終了していることが前提です。

さて、このシリーズもいよいよ、Atariをすることにしました。
ブロック崩しに挑戦です。
まずは、こちらから動いているゲームを確認します。
https://gym.openai.com/envs/#atari

breakout-ram-v0を使います。

以下のような、画面確認用のnotebookを作ります。
chokozainerRL/ipynbsに入れておきました。

#program install
必要なプログラムをインストールします。数十秒で終了します。

```
!apt-get install -y xvfb python-opengl ffmpeg > /dev/null 2>&1
!pip install pyvirtualdisplay
```
#パラメータの作成

```python

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--env', type=str, default='Breakout-ram-v0')
parser.add_argument('--outdir', type=str, default='result')
parser.add_argument('--save_mp4', type=str, default='test.mp4')
args = parser.parse_args([])
```
#パラメータ設定
パラメータを設定します。

```python

#@title Configuration
args.outdir="result" #@param{type:"string"}
args.env = "Breakout-ram-v0" #@param ["Breakout-ram-v0","Acrobot-v1","Pendulum-v0","CartPole-v0","MountainCar-v0"]{allow-input: true}
args.save_mp4=args.outdir+'/pretrain.mp4'#@param{type:"string"}

import os
if not os.path.exists(args.outdir):
    os.makedirs(args.outdir)
```

##Evaluation
1回試行した結果が表示されます。動画は、outdir+'/pretrain.mp4'に出力されます。

```python

from pyvirtualdisplay import Display
display = Display(visible=0, size=(1024, 768))
display.start()
%matplotlib inline

from IPython.display import HTML
from matplotlib import animation
import matplotlib.pyplot as plt
import gym
env = gym.make(args.env)

frames = []
obs = env.reset()
done = False
R = 0
t = 0
while not done and t < 2000:
  frames.append(env.render(mode = 'rgb_array'))
  action = env.action_space.sample()
  obs, r, done, _ = env.step(action)
  R += r
  t += 1
print('test episode:1',  'R:', R)
env.close()

plt.figure(figsize=(frames[0].shape[1]/72.0, frames[0].shape[0]/72.0),dpi=72)
patch = plt.imshow(frames[0])
plt.axis('off') 
def animate(i):
  patch.set_data(frames[i])
anim = animation.FuncAnimation(plt.gcf(), animate, frames=len(frames),interval=50)
anim.save(args.save_mp4)
HTML(anim.to_jshtml())
```

これをやってみて気づくのですが、今までやってきたclassicとatariは、ほぼ同じようにできるんですね。
VSCode拡張機能Intelephenseの更新によるUndefined type 'Route'(他クラス)のエラー

####VSCodeを開いたら、急にRouteやAuthなどのクラスに対してエラーを吐いていてびっくりヽ(ﾟ∀。)ﾉ

<img width="609" alt="スクリーンショット 2019-12-11 13.49.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406662/401658c1-38e8-679a-e97f-dd654d33cbd1.png">

####ググったら、下記リンクを発見。12月初旬のIntelephense更新に依るものとの説明がありました。
https://stackoverflow.com/questions/59149877/visual-studio-code-php-intelephense-keep-showing-not-necessary-error

####早速習って、VSCodeのSettings->Extensions->intelephenseから、設定の下記の５項目のチェックを「外す」。

intelephense.diagnostics.undefinedClassConstants 
intelephense.diagnostics.undefinedConstants 
intelephense.diagnostics.undefinedFunctions 
intelephense.diagnostics.undefinedMethods 
intelephense.diagnostics.undefinedProperties 
intelephense.diagnostics.undefinedTypes 

####VSCodeを再起動したら直りやした〜！！
SSH接続時、初回確認メッセージを出さないようにするAnsibleロール

このエントリは Ansible 3 Advent Calendar 2019の11日目の投稿です。
ちょうど空いていたので、書いてみました。


# この記事の内容

- SSH初回接続時の確認メッセージを、出さないようにAnsibleで設定する

# 前提

- 特定のホストへのSSH接続時のみ、確認メッセージを出さないようにしたい
- ホストA、ホストBがあると仮定し、A -> BへSSH接続する
- Ansibleを実行するクライアントは、A、BどちらへもSSH接続できる前提
- **StrictHostKeyCheckingの設定はいじらない**

# 実装方法

- Aのknown_hostsにBの公開鍵情報を直接記載する
- Ansibleの[known_hosts](https://docs.ansible.com/ansible/latest/modules/known_hosts_module.html)モジュールを使う


# コード

```main.yml

# vars:
#     - ssh_host_and_user:
#         - from:
#             user: vagrant
#             host: A
#           to:
#             user: root
#             host: B

# ホストBのrootユーザの公開鍵を、変数に格納する
- name: Copy public key to variable
  slurp:
    src: "{{ ROOT_PUBLIC_KEY_HOST_B }}"
  with_items: "{{ ssh_host_and_user }}"
  register: to_host_public_key
  when: item.to.host == inventory_hostname

# ホストAの,任意ユーザのホームディレクトリを取得する
- name: Get home direcotry of from.user
  shell: |
    set -o pipefail
    egrep "^{{ item.from.user }}:" /etc/passwd | awk -F: '{ print $6 }'
  register: from_user_home_directory
  with_items: "{{ ssh_host_and_user }}"
  changed_when: false
  failed_when: from_user_home_directory.rc != 0
  when: item.from.host == inventory_hostname

# ホストBのrootユーザの公開鍵を、ホストAのknown_hostsへ書き込む
- name: Add Host B infomation to known_hosts in Host A
  become: item.from.user
  known_hosts:
    key: "{{ item.to.host }}
          {{ hostvars[item.to.host].to_host_public_key.results[0].content | b64decode }}"
    name: "{{ item.to.host }}"
    path: "{{ hostvars[item.from.host].from_user_home_directory.results[my_idx].stdout }}/.ssh/known_hosts"
    state: present
  with_items: "{{ ssh_host_and_user }}"
  loop_control:
    index_var: my_idx
  when: item.from.host == inventory_hostname


```

# 終わりに

known_hostsモジュールを使って、SSH初回確認メッセージを出さないように処理を書いてみました。
- 特定のホストへSSH接続するときのみ、確認メッセージを出さないようにできた
- 場合によっては、StrictHostKeyCheckingの設定をいじったほうが便利かもしれない
High Availability (HA) と仮想化について

今日は簡単に。
最近は少なくなってきていると思います（信じたい）が、昔物理から仮想化するときによく聞いた話、
「vSphere は HA の機能を持っているから、今まで物理で構成していた HA クラスタ構成は無くて大丈夫ですよ。」
でも、シングルにしてしまうと vSphere の機能でしか HA できず、アプリのクラッシュとかでの復旧が出来なくなってしまうのに後から気づくとかありました。今はそんな設計や構築しているところはないと思いますが。
釈迦に説法なのですが、最近「vSphere HA あるから大丈夫！！」というようなことをよく耳にするようになったので、ちょっと仮想化環境での High Availability を構成する場合の考慮点を書いてみました。

## 仮想化環境で HA クラスタを構成する際の考慮点
![High Availability.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/0530ffbf-be36-7de2-7511-f9ba4fcad8d0.jpeg)
ハイパーバイザー部分での HA 機能に加えて上位の部分は、今までの物理と同じ考慮が必要です。そして、仮想化環境の場合は共有ディスクの構成をどのようにしていくかが重要になってきていて、Fiber Channel と RDM を使って構成、またはネットワークストレージを使う、非共有ディスクのストレージのレプリケーションのソフトウエアやハードウエアの仕組みを使うなどでやっていたかと思います。前者の場合は同じディスクをHA 構成した仮想マシン同士がアクセスするので問題はありません（厳密にはということではなく）が、後者の場合別々のディスクに書き込みを行うのでそのデータの同期をどのようにするかが問題になってきます。ここ重要ですね。

## 異なるストレージ間でのデータ同期（レプリケーション）
データ同期の仕組みによっては同期または非同期の選択が出来ますが、その同期のためのネットワークの負荷などを考えた場合は非同期を使うことも多いかと思います。同期の場合はほとんど完全に同じデータが相手側にも書かれますが、非同期の場合は同期の間隔の間は Active 側でキャッシュしているのでフェイルオーバーした後のデータの整合性の確認が必要になります。ここ、データの同期（レプリケーション）するソフトウエアなどによって微妙に処理が違うので確認が必要。場合によってはデーターベースなどでは書き込み情報を他にも持っておいて同じようにレプリカ側に送っておくなども必要になるかもしれません。
このように仮想化環境で HA を構成する場合は、vSphere なら vSphere HA で全て大丈夫と思うことなく、今までの物理の時代と同じように OS やアプリケーションのクラッシュなどをチェックして切り替わる HA クラスタソフトウエアと、その上で動くアプリケーションのデータを保全するための仕組みの 3つは必要になるということがわかるかと思います。
ちなみに、データー部分は別として vSphere 環境上の仮想マシンで Windows Server + WSFC を組む場合は、以下の KB が参考になります。
[VMware vSphere 6.x での Microsoft Windows Server フェイルオーバ クラスタ：サポートされる構成のためのガイドライン (2147661)](https://kb.vmware.com/s/article/2147661?lang=ja)

## vSAN を使った場合の構成
上の KB2147661 の中ほどに「vSAN 6.1 以降での MSCS/WSFC に対するサポートのスタンス」とうものがあり、共有ディスクを備えた MSCS/WSFC（つまり SQL FCI）および非共有ディスク（つまり SQL AAG、Exchange DAG）はサポート対象外となっているようです。この辺り、この KB 以降に何か変わったかは VMware 社の担当に確認するしかないと思います。
なお、vSAN をストレージとして使う場合は vSphere HA クラスタ = vSAN クラスタなので、この辺りの情報を抑えておいて将来的にサポートされるのを待っているのも良いかもしれません。
[VMware Virtual SAN 利用時の vSphere HA 設定に関するベストプラクティス](https://blogs.vmware.com/jp-cim/2014/12/vsan-ha.html)

文責：imaisato
Blazor WebAssembly を Azure Blob Storage でホストする

本記事は以下サイトにて記載しています。
恐れ入りますがリンクから移動してご参照ください。

**Blazor WebAssembly を Azure Blob Storage でホストする**
https://cloudsteady.jp/blog/2019/12/11/10344/

現在パーソルプロセス＆テクノロジーではAdvent Calendar 2019を開催中です。
https://qiita.com/advent-calendar/2019/ppt

こちらも興味ある記事あれば是非ご参照ください。
GitHub Actionsのgradle buildをキャッシュを使って速くしてみる

#GitHub Actionsのgradle buildをキャッシュを使って速くしてみる

GitHubを利用しているとActionsの無料枠（ビルド時間）があります。

https://help.github.com/ja/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions

出来るだけビルド時間を短くして回数を使えるように依存関係のキャッシュの機能を利用してみることにしました。

https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows

## ymlファイルにgradleのキャッシュを記述する

以下を参考にしてトライ！！
https://github.com/actions/cache

### こんな感じ
```ruby:balnk.yml
name: CI_Cache

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    # Checking out
    - uses: actions/checkout@v1

    # Using caches　←このセクションがキャッシュ
    - uses: actions/cache@v1
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
    
    # Setting up JDK
    - name: set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8

    # The following generates a debug APK
    - name: Build with Gradle
      run: ./gradlew assembleDebug
```

## 実際に速くなったのか検証してみる

#### キャッシュなしの場合
ビルド時間は 1m 46s
![スクリーンショット 2019-12-11 14.06.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/6c2986c7-02d1-8655-98c3-6b94fa90dfc3.png)

#### キャッシュありの場合
ビルド時間は 1m 6s
キャッシュがリストアされているのが分かりますね
![スクリーンショット 2019-12-11 15.00.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/6dc70336-71a5-8d6f-f8a5-371750631ef3.png)


## まとめ
### キャッシュありの方が40秒速い。
この後、何度かキャッシュありとなしで試行してみましたが、キャッシュありの方が早いのでおそらく正しく使えているんだろうという結論。
ジェイソンはLambdaを実行できるのか

#はじめに
この記事は[AWS初心者 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/aws_beginner)に参加しています。
AWS初学者のため間違い等ありましたらコメントで指摘していただけると大変助かります:man_with_turban_tone4:
#ジェイソンって?
ジェイソンとは映画13日の金曜日に登場する殺人鬼の名前です。
~~JSONではない。~~
1作目での殺人鬼はジェイソンの母親なので少しタイトルは的外れな感じがありますが気にしないでください。
#何がしたいのか
13日の金曜日の時だけLambda関数を実行するルールを作りたい。
#ジェイソンはLambdaを実行できる？
結論から言うとできません。
この記事ではその理由とCloudWatchEvents(長いので以後CWE)でのCron式の使い方について解説していこうと思います。

#Cron式って？
スケジューリングを行うための式です。
CWEでは6つの項目を設定するCron式を利用します。

```
cron(分 時間 日 月 曜日 年) 
```
このように記述します。

#実際の例
実際の例をもとにその時使うべきCron式を記述して行きます
##その１
例えば毎日正午にお昼ご飯を食べるように通知してくれる関数を作りたいとします。
Lambda側に通知をしてくれるプログラムを記述し、CWEで毎日12時に関数を実行してくれるように設定するとします。
その際のCron式は

```
Cron(0 3 * * ? *)
```
のように書きます。
12時なのに3を指定しているのはUTC(協定世界時)で管理されてるからです。

UTC = JST - 9時間 です。

\*や?はワイルドカードで特に指定しない場所に記述します。
ここでなぜ\*と?を併用しているのかは後ほど説明します。
##その2
目覚ましのスヌーズ機能のようにある時間から一定間隔の時間ごとに関数を実行したい場合を考えます。
Cron式では分を指定するところを(開始/間隔)とすることで開始分から間隔分ごとに関数を実行することができます。

24時間5分おきに何かを確認しなければいけない仕事についている人がいるとします。~~AIに仕事を奪われそうな人No.1ですね。~~
その人に対して5分間隔で通知を送ってくれるCron式を書くとすると

```
Cron(0/5 * * * ? *)
```
と記述します。
すると毎時0分から5分おきにLambda関数を叩いてくれるようになります。

#なぜジェイソンはLambdaを実行できないのか
やっと本題に入っていきます。
例の1と2でどちらも曜日の欄にワイルドカード「?」を利用しています。
その理由は**日付か曜日のどちらかに「?」を利用しなければならない**からです。

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)には次のように書かれています。
>You can't specify the Day-of-month and Day-of-week fields in the same cron expression. If you specify a value (or a *) in one of the fields, you must use a ? (question mark) in the other.

片方に値か\*を使ったならもう片方には?を使えよ的なことが書いてあります。

つまりこれがジェイソンをLambdaを実行することができないかわいそうな子にしている原因なのです。

```
Cron(0 0 13 * 6 *) //13日の金曜日になった瞬間に実行されそうな見た目

保存↓

ルール ～ の保存中にエラーが発生しました
詳細: Parameter ScheduleExpression is not valid.。
```
と出てしまいます。(曜日は日曜日始まりの1-7の数字で指定)

#まとめ
もう1つ、Cron式には制限があります。
それは秒までの時間を調整することができないという点です。
なので秒調整の機能はLambda関数側に実装する必要があります。

CWEではこのようにCron式に制限がかかっています。
なかなか日時+曜日で指定することもないとは思いますが、通常設定時にも片方のワイルドカードを?にする必要があるので覚えておくとスムーズに設定を終えることができます。
#おわりに
今回は運よく13日の金曜日の欄が開いていたためAdvent Calendar ~~童貞を卒業~~ に参加させていただきました、一人でもこの記事が役に立つと感じてくれる方がいてくだされば幸いです:upside_down:
OP_CHECKMULTISIGのバグで躓いた話(Dummy CHECKMULTISIG argument must be zero)

#環境
Bitcoin Core v0.18.0
P2WSHの2-of-2マルチシグスクリプトを実装していた．

#OP_CHECKMULTISIGのバグ
マルチシグのunlocking scriptには，先頭にOP_0を追加しなければいない．
[mastering bitcoin](https://bitcoinbook.info/wp-content/translations/ja/book.pdf)より，
>最初に置かれている OP_0 は CHECKMULTISIGのオリジナルの実装にバグがありそれを補完するために必要となっています。このバグというのは、 CHECKMULTISIGを実行した時に処理に関係のないスタック上のアイテムを余分に1つpopしてしまうというバグです。 CHECKMULTISIG 処理は事実 OP_0 を無視して実行され、 OP_0は単なる空箱のようなものになっています。マルチシグを使用する際，unlocking scriptにOP_0を追加する必要があります．

#OP_0を付け加えてみる
トランザクション作成後，sendrawtransactionで以下のエラーが出た．
non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)

知らないエラーなのでコードを見てみる．
https://github.com/bitcoin/bitcoin/blob/master/src/script/script_error.cpp#L64
> case SCRIPT_ERR_SIG_NULLDUMMY:
  return "Dummy CHECKMULTISIG argument must be zero";

NULLDUMMYって何？
→以下のBIPがヒット
https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki

> To fix the dummy element malleability, a new consensus rule ("NULLDUMMY") is deployed to require that the dummy element MUST be the empty byte array.

とのこと．OP_0(0x00)ってempty byte arrayで正しいはずなのになぜエラー？

#解決
エラーが出た以下のwitnessに関して，
`01 OP_0
 Sig1のサイズ　Sig1
 Sig1のサイズ　Sig2
 redeem scriptのサイズ　redeem script`

OP_0のサイズは指定しなくていいみたい．
`01 OP_0` を `OP_0`に変更．

decoderawtransactionで以下のようになればOK.
##before
"txinwitness":[
"00"
"Sig1"
"Sig2"
"redeem script"
]

##after
"txinwitness":[
""
"Sig1"
"Sig2"
"redeem script"
]
Rubyで文字コードや区切りを指定して、CSVを読み込む

# TL;DR

## 一括読み取る
```rb
CSV.table('path/to/tsv', encoding: 'utf-16', col_sep: "\t")
```
注意:
1. [BOM](https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%83%9E%E3%83%BC%E3%82%AF)付きUTF-8など扱う時、 `encoding: 'bom|utf-8'` を使うと便利です。
2. システム内でUTF-8以外のエンコードで処理したい場合は`encoding: 'utf-16:Shift_JIS'`のような書き方が可能です。
3. `col_sep: "\t"` のダブルクォーテーションをシングルにするとエラーになります。 

## 行ごと読み取る
```rb
CSV.foreach('path/to/tsv', encoding: 'utf-16', col_sep: "\t", headers: true) do |data|
  p data
end
```

ちなみに `CSV.foreach(headers: true)` では、デフォルトのキーはStringですが、`header_converters: :symbol` を設定すると、キーがSymbolになります。詳しくは[こちら](https://docs.ruby-lang.org/ja/latest/class/CSV.html#S_TABLE)


## NKFを使って、文字コードを推定
```rb
require 'nkf'
enc = NKF.guess(File.read('path/to/tsv', 10))
p enc.name
# => "UTF-16"

CSV.foreach('path/to/tsv', encoding: enc, col_sep: "\t", headers: true) do |data|
  p data
end
```

# おまけ
## `file`コマンドで文字コードの検知
```sh
$ file -b utf16.tsv
Little-endian UTF-16 Unicode text, with very long lines, with CRLF, LF line terminators
$ file -b utf8bom.tsv
UTF-8 Unicode (with BOM) text, with very long lines, with CRLF, LF line terminators
$ file -b  shift_jis.tsv 
Non-ISO extended-ASCII text, with very long lines, with CRLF, LF, NEL line terminators
```

## `iconv`で文字コード変換
```sh
# 変換結果を見る
$ iconv -f utf-16 -t utf-8 utf16.tsv | less

# utf8.tsvに書き込む
$ iconv -f utf-16 -t utf-8 utf16.tsv -o utf8.tsv
```

注意: 
Rubyで使う場合、[ruby/iconv](https://github.com/ruby/iconv)というライブラリがありますが、どうやら`v1.9`から[非推奨になりました](https://blog.sarabande.jp/post/35525999667)。


# 参考
- [Ruby文字エンコードに悩まされ、直接指定やnkfによる推測などを試した](https://qiita.com/m-shin/items/9d40cb294eb08f2204ac)
- [【 iconv 】コマンド――文字コードを変換する](https://www.atmarkit.co.jp/ait/articles/1609/12/news019.html)
- [ファイルから読み込む時に自動的にBOMを削除する](https://qiita.com/KitaitiMakoto/items/2e2d425e439d4b16a279)
- [[小ネタ]RubyでTSVを読み込む](https://qiita.com/toshihirock/items/38bb8da3c10220b8b65c)
- [【 file 】コマンド――ファイル形式を確認する](https://www.atmarkit.co.jp/ait/articles/1605/10/news018.html)
- [RubyでBOM付きUTF-8、BOM無しUTF-8、Shift JISなCSVファイルをそれぞれいい感じに読み込む](https://qiita.com/mktakuya/items/cfebd94c4cdc12aeb691)
- [異なるエンコーディングでのファイル書き出しと読み込み](https://qiita.com/Linda_pp/items/3da11f9a6584b8592867)
DGBrokerで楽々運用管理

こんにちは、kurouuuronです。
このエントリは Oracle Database or GoldenGate Advent Calendar 2019 の Day 9 の記事です。(日をまたぎました、すみません...)

>JPOUG Advent Calendar 2019
>https://adventar.org/calendars/4154

今回はOracle Data Guard(以降DG)構成において、ワンコマンドでS/O(Switch Over)やF/O(Fail Over)できる、DGの付随管理ツールである、Data Guard Broker(以降Broker)についてご紹介しようと思います。(全然新しい機能ではないけど)

# Data Guard Brokerとは？
ひとことで言えば、
> DGのプライマリDBとスタンバイDBをまとめて1つの論理ユニットとし、管理を簡素化する DG の補助機能。

本来なら物理的に離れているプライマリDBとスタンバイDBを各々操作するには、各サーバにアクセスする必要があります。しかし、本機能を用いればこれらを1つのかたまりとしてみなし、任意の片サーバから両サーバのDG状況を管理・確認できます。

イメージはこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323323/01ef4623-bc82-c5c9-2577-30131a05bc14.png)

新たにDMONというバックグラウンドプロセスを起動し、本プロセスで両DBの状況(インスタンスの状態やREDO転送状況 ..etc)をやり取りします。DGB管理者はsqlplusではなく、DGMGRLというユーティリティでDMONにアクセスして操作をします。

# Data Guard Brokerのメリットは？
 - DG構成のメンテナンスや監視を自動化・集中化
    - 両ノードにアクセスする必要なし！
 - S/O, F/O の手順簡素化
    - ほぼone commandで実行可能！定期的にS/Oするようなシステムはだいぶ楽になります。
 - DG構成の作成やスタンバイDBの追加の簡素化

おまけですが、EM(Enterprise Manager)を利用している場合、EMからもDGB情報が参照できるようになります。さらにS/OやF/Oも画面から操作できるようになります。
なので、EMからDG間のタイムラグや適当パフォーマンスなどが確認および監視できるんですね。
※DGBを構成するとEMのページが自動で追加されます。

# どうやったらData Guard Brokerを構築できる？
DG環境構築済を前提として進めます。全体でたったの**４STEP**！
1. [プライマリ、ターゲット] listener.oraへ静的リスナーの追加
2. [プライマリ、ターゲット] DB初期化パラメータの変更(3つ)
3. [片方] Broker構成ファイル作成
4. [片方] Broker構成ファイル有効化

早速ですが、コマンドベースで見ていきましょう。

1. [プライマリ、ターゲット] listener.oraへ静的リスナーの追加
以下を追記。S/O,F/Oでshutdown中にDBに接続するための静的サービス登録をします。

```shell

# -- add for DGBroker
SID_LIST_LISTENER =
    (SID_DESC =
      (GLOBAL_DBNAME = ●DB_UNIQUE_NAME●_DGMGRL)
      (ORACLE_HOME = /opt/oracle/app/oracle/product/11.2.0)
      (SID_NAME = ●ORACLE_SID●)
    )
)
# -- add end for DGBroker
```

2.　[プライマリ、ターゲット] DB初期化パラメータの変更(3つ)
DGB構成に必要なBroker構成ファイルのパスとファイル名を指定します。
「dg_broker_config_file1」と「dg_broker_config_file2」には、同じ内容のものが作成されます。バックアップ的な立ち位置。
続いて「DG_BROKER_START」を**TRUE**にすると、DGB用プロセスであるDMONが起動します。

```sql

alter system set dg_broker_config_file1='【出力パス】/dr1●DB_UNIQUE_NAME●.dat' scope=both sid='*';
alter system set dg_broker_config_file2='【出力パス】/dr2●DB_UNIQUE_NAME● .dat' scope=both sid='*';
ALTER SYSTEM SET DG_BROKER_START=TRUE SCOPE=BOTH SID= '*';
```

3.　[片方] Broker構成ファイル作成
ここからはDMONが起動しているので、DGMGRLユーティリティを使用し、DGBに設定を施します。DGBに設定するので、作業するのはどちらのノードからでも構いません。
下記はプライマリDBがporcl、スタンバイDBがsorclという構成のもと、DGConfigという構成ファイルを作成している例です。

```ruby
create configuration 'DGConfig' as primary database is porcl connect identifier is porcl_dg;
add database sorcl as connect identifier is sorcl_dg;
```

4.　[片方] Broker構成ファイル有効化
作成した構成ファイルを有効化します。

```ruby
enable configuration
```
下記コマンドで状態の確認ができます。

```shell

DGMGRL> enable configuration

Configuration - DGConfig

  Protection Mode: MaxPerformance
  Databases:
     porcl - Primary Database 
     sorcl - Physical Standby Database

Fast-Start Failover: ENABLED

Configuration Status:
SUCCESS
```

以上です。
この状態で下記コマンドを実行すると、switchoverが出来ます。

```rb
DGMGRL> switchver to sorcl
```

# まとめ
DGのS/OやF/Oは手動では結構めんどくさいですよね。
DGBを取り入れて運用管理の簡素化を！

あと、心を入れ替えてAdvent Calendar以外でも投稿していこうと思います。
Robloxでスタート時の場所を指定する

# 概要
- ゲーム開始時に何も指定しないと、座標（0, 0, 0）からスタートしてしまう
- 特定の場所（たとえば家とか牢屋の中とか）からスタートしたい場合に使いましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/5dbce649-079e-3ce7-9110-0e664fe0cd16.png)


# 準備するもの
- ServerScriptServiceの中に１つのスクリプト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/759eae28-3cf9-23da-6b41-41284ce558c3.png)

- workspaceの中に１つのSpawnLocation（Workspaceのとなりの「＋」マークから追加できます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/ec9929ad-df10-1ad3-7180-27ec11eec39e.png)

# プログラミング

```script.lua
-- Playersフォルダの中にいる全プレイヤーをとってくる
local Players = game:GetService("Players")

-- プレイヤーの生まれる場所（スポーンポイント）を、WorkspaceにあるSpawnPointというブロックの場所にする
local function onPlayerAdd(player)
	player.RespawnLocation = workspace.SpawnPoint
end

-- 各プレイヤーがゲームに入った瞬間に、onPlayerAdd関数が実行される
Players.PlayerAdded:Connect(onPlayerAdd)

```


# チャレンジ課題
- 以下のページを参考にして、複数のスタートポイントの中から、ランダムにえらんでスタートするように作ってみよう

> https://blog.mitsuruog.info/2019/05/roblox-build-save-point
【BigQuery】日ごとのリストをつくる【SQL】

```
WITH
# 2018-04-01 ~ 2018-06-30 の日ごとのリスト
date_list AS (
  SELECT 
    date
  FROM 
    (
      SELECT DATE_ADD(DATE('2018-04-01'), INTERVAL n DAY) AS date
      FROM UNNEST(GENERATE_ARRAY(0, 100, 1)) AS n
    )
  WHERE 
    date < '2018-07-01'
)

SELECT 
  *
FROM 
  date_list 
```

# 出力結果

```
date
2018-04-01
2018-04-02
2018-04-03
2018-04-04
2018-04-05
2018-04-06
2018-04-07
2018-04-08
2018-04-09
2018-04-10
2018-04-11
2018-04-12
2018-04-13
2018-04-14
2018-04-15
2018-04-16
2018-04-17
2018-04-18
2018-04-19
2018-04-20
2018-04-21
2018-04-22
2018-04-23
2018-04-24
2018-04-25
2018-04-26
2018-04-27
2018-04-28
2018-04-29
2018-04-30
2018-05-01
2018-05-02
2018-05-03
2018-05-04
2018-05-05
2018-05-06
2018-05-07
2018-05-08
2018-05-09
2018-05-10
2018-05-11
2018-05-12
2018-05-13
2018-05-14
2018-05-15
2018-05-16
2018-05-17
2018-05-18
2018-05-19
2018-05-20
2018-05-21
2018-05-22
2018-05-23
2018-05-24
2018-05-25
2018-05-26
2018-05-27
2018-05-28
2018-05-29
2018-05-30
2018-05-31
2018-06-01
2018-06-02
2018-06-03
2018-06-04
2018-06-05
2018-06-06
2018-06-07
2018-06-08
2018-06-09
2018-06-10
2018-06-11
2018-06-12
2018-06-13
2018-06-14
2018-06-15
2018-06-16
2018-06-17
2018-06-18
2018-06-19
2018-06-20
2018-06-21
2018-06-22
2018-06-23
2018-06-24
2018-06-25
2018-06-26
2018-06-27
2018-06-28
2018-06-29
2018-06-30
```
React/Redux + Firebase で結婚式二次会で使う余興用のクイズアプリを改造して使った時の話

Ubiregi Advent Calendar 2019 の 11日目です

React/Redux + Firebase で結婚式二次会で使う余興用のアプリを使った時の話を書きます

# 2019年９月20日に結婚式をやった

大宮で挙式しました。

# オールスター大感謝祭風のクイズを２次会でやりたい

２次会の余興でオールスター大感謝祭風のクイズゲームをやりたいと思いまして、

- 会場のディスプレイを映して、回答者は手元のスマホでリアルタイムに回答
- 選択肢の画像と文字が表示される
- ランキングが表示される
- なるべく楽な方法で

既存のサービスでそういうのがあればそれを使おうと思ったのですが、検索してみたのですが良さそうなのがなく、
一つだけ、GitHubで自分がやりたいことにちかいものをみつけました。
[MITライセンス](https://qiita.com/yyama2/items/20bdf5e914c20025498a)で公開されていたので、React-Reduxの学習がてらそれを改造しようと思いました。

元のソースコード
https://github.com/kenichirosuzuki/react-firebase-quiz-game

・・・今改めて検索して探してみると、会社の納会用、結婚式の余興用にクイズアプリ作っている記事が出てくるので、そちらを使ってみても良かったかも知れません。

- [オール◯ター感謝祭もどきアプリで社内イベントを乗り切る](https://sota1235.hatenablog.com/entry/2015/12/24/130906)
- [会社の納会用にクイズアプリを作りました（React / TypeScript）](https://tech-magazine.opt.ne.jp/entry/2016/11/02/153941)

# 改造したところ

元のソースコードをforkして改造したのがこちらです
https://github.com/kitaindia/react-firebase-quiz-game

### packageを最新にアップデート

元のソースコードが2017年のもので、`npm audit` すると `critical` なpackageがいくつか有りました。
実際にこのクイズアプリ使うのって一日だけだし、このまま進めてもいいんですが少し気持ち悪いので直しました。影響範囲が少ないpackageから一つずつ最新に上げていきました。

### 画像がでるようにした。

元のソースコードは４択は文字のみだったので、画像を表示できるようにしました。
これもバックエンド的には大したことはやってなく、むしろCSSでデザイン調整するのが大変でした。

# 実際の様子

2次会の幹事の人には受付時にこのようなコピー用紙を参加者に渡してもらいました。

![70422940_2571039389646274_3264623389221847040_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/806/87b93b8a-dbfe-a393-cc6a-274de7438397.jpeg)

クイズ中の様子です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/806/f2a87f98-62f9-325e-5ff3-c48e5c60c020.png)

![70614698_2571039376312942_1160533195972673536_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/806/283fa25e-a959-0641-7134-5d9309d2cf0d.jpeg)

# 反省点

###   文字が小さすぎて、問題が読めなかった

ディスプレイに映すのが本番一発勝負だったのと、実際にクイズをやるときにどのようにやるかのイメージがついてなかったです。
思ったよりプロジェクターが小さく、参加者の席もディスプレイから５ｍ以上離れていたので、画像ぐらいしか認識できなかったのではと思います。



### 問題数が多くて意外と時間がかかった

10問出題したけど、問題の解説したりしてたら30分以上掛かってしまいました。成績優秀者にプレゼント渡したりしていると小一時間掛かっていました。
会場借りられる時間が決まっていて、2時間しか借りられなかったので、ちょっと時間使いすぎでした。

# やってみてわかったこと

ゼロからアプリ作ると時間も掛かっちゃってなかなか大変なのですが、そういう時は既存のアプリを改造するのも勉強になってよいと思いました。
Google広告　キーワードごとにランディングページ変更

#キーワードごとにランディングページを変更する

・左のタブのキーワードをクリック

最終ページURLにカーソルを合わせると、鉛筆マークが出る。
そこに、最終ページURLにを入力すると
キーワードごとのランディングページの変更が可能となる。
pandas groupbyで特徴量生成

# pandasのgroupbyで特徴量を作りたい
カラムの属性ごとの統計量を特徴に追加したいときに，collectionsやgroupbyでdictみたいなの作ってマージしなくても良い場合が結構あります．
単に統計量出すだけであれば簡単なものの，特徴量としてレコードに追加したい局面にpandas.DataFrame.groupbyの使い方に苦戦したのでメモとして残します．

何が言いたいかというとgroupby.transformは便利．

## サンプルデータ

```py
import pandas as pd
df = pd.DataFrame({
     "site":["A","A","A","B","B","C"],
     "dat":[15,30,30,30,10,50]
})
```

|| site | dat |
|:--:|:--:|:--:|
|0| A | 15 |
|1| A | 30 |
|2| A | 30 |
|3| B | 30 |
|4| B | 10 |
|5| C | 50 |

## 属性ごとの平均，最大，最小など基本統計量

transformの引数をnp.maxやnp.minに変えれば直接特徴量が生成できる．
median, varなども同様．
siteごとの平均値を算出するコードを下に示す．

```py
import numpy as np
df["site_mean"] = df.groupby("site").transform(np.mean)
```

|| site | dat |site_mean|
|:--:|:--:|:--:|:--:|
|0| A | 15 |25|
|1| A | 30 |25|
|2| A | 30 |25|
|3| B | 30 |20|
|4| B | 10 |20|
|5| C | 50 |50|

## Count Encoding
あるカラムの（カテゴリ）特徴の出現回数を新たな特徴にする手法がカウントエンコーディングと呼ばれている．groupbyと組み合わせることで，ある属性の中での希少性のようなものを特徴にできる．
collections.Counter使えばできますが，これも同じくtransformで終わらせます．

siteとdatのペアの出現回数に変換するコードを示す．
（site Aにおける30の出現回数は2回）

```py
df["count_site_dat"] = df.groupby(["site","dat"]).transform(np.size)
```

|| site | dat |site_mean|count_size_dat|
|:--:|:--:|:--:|:--:|:--:|
|0| A | 15 |25|1|
|1| A | 30 |25|2|
|2| A | 30 |25|2|
|3| B | 30 |20|1|
|4| B | 10 |20|1|
|5| C | 50 |50|1|

## 順位
ある特徴を持っているデータの中で，ある特徴が何番目に大きいデータかを算出する．

```py
df["site_rank"] = df.groupby("site")["dat"].rank(method="dense")
```

|| site | dat |site_mean|count_size_dat|site_rank|
|:--:|:--:|:--:|:--:|:--:|:--:|
|0| A | 15 |25|1|1|
|1| A | 30 |25|2|2|
|2| A | 30 |25|2|2|
|3| B | 30 |20|1|2|
|4| B | 10 |20|1|1|
|5| C | 50 |50|1|1|

rankの引数を変えると，主に同じ値（同じ順位）の表現方法が変わる．
詳細は[pandas.DataFrame, Seriesを順位付けするrank](https://note.nkmk.me/python-pandas-rank/)のmethodを参照．
Google広告 検索キーワード、予測　表示性別、年齢

【最適化案】特に意味はない。

全サイトにグローバルサイトタグを貼って、サンクスページにイベントスニペットタグを貼ると、コンバージョンが取れる。

#新しい検索キーワードを見つける


・右上のツールと設定→キーワードプランナー
・新しいキーワードを見つける→結果を表示


これで、関連するキーワードを見つけることができるので、
除外キーワード、新しく追加するキーワードを見つけやすい。

#どのくらい費用がかかるか？効果があるか？予測する

・右上のツールと設定→キーワードプランナー
・検索のボリュームと予測のデータを確認する


どのキーワードで出すとどのくらいの費用がかかるのか、
クリック率、順位などの目安が出せる。
一番効果的というわけではない。あくまでも目安。


#Google広告 表示させる性別を選択

・概要　ユーザー属性
ここで、表示させる年齢と性別を絞れる。

#Google広告審査落ち

もしも、審査に落ちたら電話することで審査部に掛け合ってもらえる。
tmux上のVimで、Vim側のバッファをスクロールしたい

すごく簡単ですが情報が少なかったので記載

tmux上でVimを実行している時にスクロールをすると
tmux側のスクロールバッファの方が動いてしまう問題。

対策は、vimrcに以下を記載でOK

```vim:.vimrc
set mouse=a
```
暗号化・復号を Laravel で行う

## 基本

Laravel の暗号化は、 `.env` で設定された `APP_KEY=base64:XXXXXX` をシークレットとして使用します。暗号化時のこの値を忘れると復号できなくなるので注意してください。

### シリアライズして任意の型を暗号化

```php
use Illuminate\Support\Facades\Crypt;

$encrypted= Crypt::encrypt(['foo' => 'bar']);
dump($encrypted );
/*
Base64エンコードされた暗号化結果が出力される
*/

$decrypted = Crypt::decrypt($encrypted);
dump($decrypted);
/*
array:1 [
  "foo" => "bar"
]
*/
```

- メリット: 任意の値を暗号化できる
- デメリット: 他のアプリケーションとの相互運用性が低い（PHPにべっとり依存している）

### シリアライズせずに文字列だけを暗号化

```php
use Illuminate\Support\Facades\Crypt;

$encrypted= Crypt::encryptString('foo');
dump($encrypted);
/*
Base64エンコードされた暗号化結果が出力される
*/

$decrypted = Crypt::decryptString($encrypted);
dump($decrypted);
/*
"foo"
*/
```

- メリット: 他のアプリケーションとの相互運用性が高い
- デメリット: 型が文字列に限定される

## 応用

### 特定のモデルのフィールドを自動で暗号化・複合する

````php:ユーザモデルの&#32last_name&#32;フィールドを暗号化する例
public function getLastNameAttribute(): string
{
    return Crypt::decrypt($this->attributes['last_name']);
}

public function setLastNameAttribute(string $value): void
{
    $this->attributes['last_name'] = Crypt::encypt($value);
}
```

````php:ユーザモデルの&#32last_name&#32;フィールドを暗号化する例<br><strong>（<code>null</code>を認める場合）</strong>
public function getLastNameAttribute(): ?string
{
    return isset($this->attributes['last_name'])
        ? Crypt::decrypt($this->attributes['last_name'])
        : null;
}

public function setLastNameAttribute(?string $value): void
{
    $this->attributes['last_name'] = $value !== null
        ? Crypt::encrypt($value)
        : null;
}
```

**またメモすることがあれば追記します。**
APNs証明書の更新時にアプリの更新は必要か否か

#はじめに
先日、アプリのAPNs証明書の更新を行ったとき、
アプリの更新予定がないタイミングだったので
**『APNs証明書の更新時にアプリの更新は必要か否か』**
が気になり調べてみた。

#開発環境
使用サービス：[GrowthPush](https://growthpush.com/)

#調査開始
**ネットで検索をしてみる**
下記で同じようなことをstack overflowに質問している人が見つかった。

- https://stackoverflow.com/questions/13321528/apple-push-notifications-certificate-expiry
- https://stackoverflow.com/questions/46769355/will-push-notification-work-on-my-old-app-if-i-update-push-notification-certific

質問への回答によればAPNs証明書を更新するだけで既存アプリにもプッシュ通知が届くとのこと。

**念のため証明書周りに詳しい先輩にも話を聞いてみた**
ちょうど他のアプリで更新の予定があったのでAPNs証明書を更新してみてProvisioning Profileが変更されないか見てもらえることに！
その結果、Provisioning Profileが変更されないことも確認できた。

#実際に更新して通知を確認
APNs証明書を更新して、設定してある証明書を最新のものに変更し、
プッシュ通知が届くのかを確認する。
無事に公開中のアプリに通知が届きました。

#まとめ
APNs証明書の更新時にアプリの更新は必要ありません。
APNs証明書を更新するだけで公開済みの既存アプリにもプッシュ通知が届きます。