OmniAICreator/Qiita-1.07M huggingface dataset:
Shift_jis(CP932) -> UTF-8変換の例外処理

# Shift_jis(CP932) -> UTF-8へのcsvの変換機能
今回はrubyで開発をしたので、rubyの書き方で説明致します。
Shift_jisで書かれたcsvをUTF-8に変換する機能を実装した際、エラーが起きてしまい変換出来ない件について。

## 課題
エラー文
`"\xFB\xFC" from Shift_JIS to UTF-8`

コード

```
CSV.foreach({ファイル名}, encoding: "Shift_JIS:UTF-8", headers: true) do |row|
```
Shift_JIS→UTF-8に変換してcsv出力したいのに、、エラーが。。
何を言っているんだ？
どーいうエラー？
どう対処すれば、、。

## 何が起きている？？
このエラー文は、`変換出来ない文字が含まれているよー！だから変換出来ません！`と教えてくれています。

変換出来ない文字とは、`Shift_JISの範囲外の文字(旧字体)`の事！
→Shift_JISで書かれたcsvに、Shift_JISが認識出来ない文字が含まれてる。

**Shift_JISが認識出来ない文字(Shift_JISにはない文字)：**
「髙(はしご高), ①, ㈱, 﨑, ✖︎」などの旧字体！

csvにこの旧字体が含まれている事によって、エラーが起きてしまいます。

例)
sample.csv :
山田花子,前田敦子,髙田啓介   　　　←　「髙」が紛れ込んでいる

## 解決策
解決策は何通りかありますが、(1)一番確実に変換出来るものと、(2)簡単に変換出来るものをご紹介します！
#### (1) 強制変換
初めから、UTF-8としてcsvを読み込ませる！

```
CSV.parse(NKF::nkf('-w',File.read({ファイル名})), headers: true) do |row|
```
~~Shift_JIS　→　UTF-8 ( Shift_JISで書かれたcsv を UTF-8に変換する！)~~
のではなく、

`Shift_JISで書かれたcsvを初めからUTF-8として変換する`
初めからUTF-8として変換する事によって、文字化けも起こる事なく、エラーも回避する事が出来ます！

#### (2) CP932を使う

単純です

```
CSV.foreach({ファイル名}, encoding: "CP932:UTF-8", headers: true) do |row|
```
~~Shift_JIS　→　UTF-8~~　
`CP932　→　UTF-8`　(ただ、Shift_JISをCP932に変えただけ)

こちらでも、文字化け、エラーを防ぐ事が出来ます！

お試しください^^
Debian で vmware horizon client を動かす

Debian Linux (AMD64) に VMware horizon client をインストールして、firefox から起動するための手順。当てはまるのは、うちの会社だけかも。
Linux から、Windows のリモートデスクトップにつなぐための手段。

# VMware horizon のインストール

1. Web browser で https://my.vmware.com/jp/web/vmware/info/slug/desktop_end_user_computing/vmware_horizon_clients/4_0 (version は変わっていくと思われる) に行く。
2. 表示されたページの 64 bit linux のところの[ダウンロードする]ボタンから、ダウンロードページへ飛ぶ。
3. ダウンロードする。
4. /bin/su - で root になる。
5. echo $PATH で /sbin や /usr/sbin が PATH に含まれることを確認。これがないと、インストール途中でエラーに。
6. ダウンロードしたディレクトリに移動し、 VMware-Horizon-Client-5.3.0-15208949.x64.bundle というような名前のファイルを sh で実行。
7. 質問には、 yes と答えておく。
8. /tmp/vmware-root 中の vmware-installer-*.log のファイルのうち、一番新しいものを less で見る。
9. 深刻なエラーが起こっていないことを確認。
10. /usr/bin/vmware-view が存在し、 /usr/lib/vmware 中に library files やディレクトリが生成されていることを確認する。
11. 環境にもよるが、一度ログアウトして、入り直したほうがいいかも。

# firefox から起動

1. 社内の　Workspace One のページを firefox で開く。
2. 認証を済まして、デスクトップを開くためのアイコンを出す。
3. アイコンをクリックする。
4. 多分、立ち上がらないので、firefox の設定画面を出す。
5. プログラムのところに、「ファイルの種類」が vmware-view となっていて、「取り扱い方法」が「毎回確認する」になっていたら、「毎回確認する」をクリック。
6. ファイルを選べるはずなので、/usr/bin/vmware-view を指定する。
7. 一度、firefox を立ち上げ直したほうがいいかも。
8. 再度 Workspace One を開いて、アイコンをクリックすると、きっと立ち上がる。

# スマートカードを使う

1. apt install pcscd で debian にソフトウェアを入れたら動いたようす。他にも、
gnome-keyring-pkcs11
libpkcs11-helper1
opensc-pkcs11
を入れたが、関係ないかも。
各RPAツールの「部品化」まとめ

# 各RPAツールの「部品化」まとめ

## 部品化って？

RPAツールに限った話じゃないですが、よく使う操作は１つにまとめて、部品として扱ってあげましょうという考えです。この名称もまったく一般的なものではないのですが、いったんこの定義とさせていただきます。ちなみに、部品の対となるものを「フロー」とします。

「フロー」から「部品」を呼び出す。そんな関係性が基本です。

## 部品化のメリット

部品化をまったく意識しない開発でありがちなのが、複数のロボットで同じ処理を組み込んでしまっている例。例えば、システムのログイン処理とかがいい例ですね。

こうなってしまうと、ログイン処理の画面変更が起こったとき、ログイン処理を組み込んでいるロボット全部を変更しなくてはいけません。

変更するのも手間、洗い出すのはもっと手間、いいことありませんね。

## よろしい、ならば部品化だ

今回は、UiPath, blueprism,automation anywhereの3ツールにおけるフロー定義と部品定義のすみわけについてまとめてみます。


| ツール | フローとして使用 | 部品として使用 |
|-------|-------|-------|
| UiPath | プロジェクト | xaml(ワークフロー) |
| blueprism | プロセス | オブジェクト |
| Automation Anywhere | Taskbot | Metabot |

## さいごに
部品化意識すると開発捗る！
この記事はiPhone onlyで作成した！記事作成捗る！
Flutter開発に便利なWEBサイト＆サービス一覧

現在Flutter開発の勉強をしているのですが、オンライン学習コースの中や知り合いから便利なWEBサイトやサービスをたくさん教えてもらいました。
ただメモ書きにするのももったいないので記事にまとめます。

# 素材系

## materialpalette.com
色の組み合わせを確認できるカラーパレットサイトです。
マテリアルデザインアイコンも一覧&コードコピーできるのでめっちゃ便利です。
https://www.materialpalette.com/
<img width="1438" alt="スクリーンショット 2020-02-05 13.46.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/b8b458d4-ea2b-7203-81cd-3124cfd51645.png">


## icons8
無料アイコン画像素材を探して取得することができます。
https://icons8.jp/icons
本のアイコンを調べてみるとこんな感じ。
<img width="1438" alt="スクリーンショット 2020-02-05 13.36.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/26b00c02-f35a-2185-4c0f-55f21f4d8861.png">

## canva
デザインツールで、ロゴを作ったりすることができます。
色々なサンプルがあるので参考になります。
https://www.canva.com/
<img width="1438" alt="スクリーンショット 2020-02-05 13.39.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/2f327b50-60ad-6360-3427-0f3448177de7.png">

## fonts.google.com
フォントを探すことができます。
https://fonts.google.com/
<img width="1438" alt="スクリーンショット 2020-02-05 13.42.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/46ff541b-3525-6df6-aebd-d61804c5fc80.png">

## freesound.org
音系の素材を探すことができます。音素材は自分で作成するには骨が折れるので助かります。
https://freesound.org/
<img width="1438" alt="スクリーンショット 2020-02-05 13.44.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/183c87f2-708d-c654-0db5-c297d6d196b3.png">

# サービス系

## Dartpad

Dart記述をWeb上で実行できるサービスです。
記述をシェアする機能もあるのでエンジニア同士でコミュニケーションを取るのにも便利です。
https://dartpad.dartlang.org/
<img width="1438" alt="スクリーンショット 2020-02-05 13.57.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/8688e71e-dd0c-83b9-789d-5b8b3e1e8bf7.png">

## pub.dev
Dart公式パッケージリポジトリです。
使いたい機能がある場合はこちらで探します。
パッケージごとにスコアリングされているので選ぶ際にも参考になります。
https://pub.dev/dart/packages
<img width="1438" alt="スクリーンショット 2020-02-05 14.01.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/05fc4592-7063-d6dd-c2dd-ee2224a89cdb.png">

## flutter studio
Widgetのシミュレーションが可能です。
どのようなレイアウトにするのか、確認するのに便利です。
コードやpubspecも取得できるのすごい。
https://flutterstudio.app/
<img width="1438" alt="スクリーンショット 2020-02-05 14.03.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/4df6fac2-1439-5d73-d46e-a6f28205ec45.png">


# ドキュメント系

## 公式ドキュメント
言わずもがなの公式ドキュメント。まずはこれを読まねば。
https://flutter.dev/
<img width="1438" alt="スクリーンショット 2020-02-05 13.55.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/22c89f9a-9d95-e1d4-ad38-9114a0d1b3cf.png">

## Flutter Layout Cheet Sheet
Mediumの記事なのですが、Flutterのレイアウトに関してとても詳しく書いてあります。
https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e
<img width="1438" alt="スクリーンショット 2020-02-05 13.54.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401312/c1f40d8b-e171-3590-370c-9fe19cf0bad0.png">


# おわりに
普段サーバサイドプログラムを書いているときは公式マニュアルくらいしか読んでなかったので、特にUI系やデザイン系のサービスが揃っていてクライアントアプリは面白いな―って思いました。
適宜追加していきます！
RxSwiftでVoidをonNextした時、subscribeが処理されなかった


## とある処理
RxSwiftを正しく使ってないとかそういうことは置いておいて、下記のような記述があった。

```swift
class HogeView: UIView {
    private subject: PublishSubject<Void> = PublishSubject()
    var observer: Observable<Void> { return subject }

    @IBOutlet func onTap(_ sender: UIButton) {
        subject.onNext(())
    }
}

class HogeViewController: UIViewController {
    @IBOutlet weak var hogeView: HogeView!

    override func viewDidLoad() {
        super.viewDidLoad()
        hogeView.observer.subscribe {
            // 処理
        }
    }
}
```

この`hogeView.observer.subscribe`の処理部分がボタンをタップしても動かず、なんでだろうと悩んだ。

## 結論
subscribeのevent引数を省略していたことで、今回の問題が起きていた。
`event.element`はどうせVoidだしボタンのタップだけ検知できればいいから、eventいらないと記述を忘れていた結果、

```swift
public func subscribe(onCompleted: (() -> Void)? = nil, onError: ((Error) -> Void)? = nil) -> RxSwift.Disposable
```

が推論として呼ばれるようになっていた。


下記記述にしたことで、意図通り動いた。

```swift
class HogeView: UIView {
    private subject: PublishSubject<Void> = PublishSubject()
    var observer: Observable<Void> { return subject }

    @IBOutlet func onTap(_ sender: UIButton) {
        subject.onNext(())
    }
}

class HogeViewController: UIViewController {
    @IBOutlet weak var hogeView: HogeView!

    override func viewDidLoad() {
        super.viewDidLoad()
        hogeView.observer.subscribe { (_) in // event引数を省略しない
            // 処理
        }
    }
}
```

## 備考
debug オペレータを使ってデバッグしろとアドバイス貰って、onNextが正常に飛んできているのを確認できたので、subscribeに問題あることがわかり解決できた。

初歩的なミスだった。
備忘録がてら記述しておく。
VirtualBoxを使用したlaravelでweb.phpのルーティング設定が何やっても404になる人

今回、mac使用で環境構築していたが突然故障したのでwindows10に環境を持って行ったらサイト表示が404エラーとなってとても焦ったのでまとめました。

#【環境/前提】

・laravel5.8
・php7.3
・virtual boxを使用
・サーバーはphp artisan serveを使ってるのでwebサーバーは使用しておらず
・windows10(MacOSから環境を移動)
・他のルートは表示されるが、いくつか又は特定のルートだけ404表示


#解決
web.phpの順序がおかしかった。


```
Route::get('/posts/{post}', 'PostsController@show')->where('post', '[0-9]+');
Route::get('/posts/{ico}', 'PostsController@show')->where('post', '[0-9]+');

 
 //ログイン
Route::post('/posts/login_output', 'PostsController@login_out');
Route::post('/posts/login', 'PostsController@login');

//ログアウト
Route::get('/posts/logout', 'PostsController@logout');
 
 
Route::get('/posts/test', 'PostsController@test');
 

//CSVダウンロード
Route::get('/posts/csv', 'PostsController@csv');


```

上部の上2つのコードのせいで/posts/○○とルート設定してあるものはすべて404エラーでした。
【python3】いずれかの文字列が含まれるかの判定

またまたメモ書きの駄ブログ。

# 概要

以下のプログラムで期待する処理が動いたことは確認できた。

```python
if 'soccer' in hogehoge or 'baseball' in hogehoge:
```

しかし数が多いとプログラムが横に長くなるので、
まとめて判定できないかとふと思った。

# テストその1

```python
if {'soccer', 'baseball'} in hogehoge:
```

これはTypeError。
なんか色々と間違ってる。

# テストその2

```python
import re

try:
    re.search('(soccer|baseball)', hogehoge).group(1)
except AttributeError:
    pass
```

これは出来そうだけど例外処理が入るので1行で書けない。


# テストその3

```python
import re

if re.search('(soccer|baseball)', hogehoge) is not None:
```

これはいいかも！
けどまだ短くできるのでは・・・？

---

その他いいものがあれば募集します！
【heroku】ActiveRecord::IrreversibleMigration が出たときの対処法

nemlog検索サイト　https://searchnemlog.herokuapp.com/
作成の時herokuデプロイで詰まってしまったので解決方法をメモしときます。

 
#ActiveRecord::IrreversibleMigration
おそらくスクレイピングを通してデータベースに保存していたので起きてしまったエラーと思われます。
 

以下からはこのエラーの解決手順を記したいと思います。

 

#ロールバック
```
heroku run rake db:migrate:reset
```

恐らくエラー文が表示されると思います。

そこに

```
DISABLE_DATABASE_ENVIRONMENT_CHECK=1
```

と書かれていたらそれを利用してDB生成が可能になります。

 

#ドロップ

```
heroku run RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop
```

先ほどのエラー文を利用してドロップするとなんとかドロップしてくれます。

 

#DB生成
あとはdb:createを実行。

```
heroku run rails db:create
```
 

#マイグレーション
最後はいつも通り heroku run をしましょう。

```
heroku run rake db:migrate
``` 

 

この手順でいけばなんとかアプリが立ち上がると思います。

 

 

#まとめ
データベース系のエラーにハマるとデリケートなイメージなのでめちゃくちゃビビり倒してしまいます。

herokuエラーは前回大概ハマったと思っていましたがまだまだ見知らぬエラーがたくさんである意味奥が深いですね。

 

とりあえず誰かの参考になればと思います。
iOS Safariでselect optionにdisplay:noneが効かない対策



表題のとおり、iOSの場合はselect optionにdisplay:noneは効かない。
ググってるとwrapするといいとのことで、たしかにwrapすると何故か消える。
(wrapするタグにはstyleを一切設定していないのに・・！？)
ただ、個々にちまちまwrapさせるのもめんどくさいので
optionにdisplay:noneをしたら勝手にoptionタグをwrapしてくれれば
今まで通りだしいいやんって思った次第。

attrchange.js
https://github.com/meetselva/attrchange/
このjQueryプラグインを利用すると
styleに変化があるとEventが上がってくるので利用させてもらったのが以下のコード。

もう少しやり方あるだろ？って思われそうだけど、ひとまずそこは・・



```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="./Scripts/attrchange.js"></script>

<script>
$(document).ready(function(){

	//iOSのときselect optionをdisplay=noneにしても消えないので、
	//attrchange.jsを利用してcssがdisplay=noneとかにいじられたらoptionタグをwrapする
	$("option").attrchange({
	    trackValues: true,
	    callback: function(evnt) {
	    	//console.log(evnt);
	    	if(evnt.type == "attributes" && evnt.attributeName=="style"){
	    		if($(this).css("display")=="none"){
					if($(this).parent().attr("mode")!="wrap"){
						$(this).wrap("<p mode='wrap'>");
					}
		    	}else{	// 空白やdisplay iosだとinlineになるっぽい
if($(this).parent().attr("mode")=="wrap"){
						$(this).unwrap();
					}
		    	}
	    	}
	    }
	});
});
</script>
```

しかし、なんでoptionをpタグでwrapすると消えるんだろう？？
Terraform でスペースなどを含んだユニークキーのリソースを import する


[`aws_budgets_budget`](https://www.terraform.io/docs/providers/aws/r/budgets_budget.html) を terraform  import しようとしていました。
[`aws_budgets_budget`](https://www.terraform.io/docs/providers/aws/r/budgets_budget.html) の import の例文は以下の通りです。

```
terraform import aws_budgets_budget.myBudget 123456789012:myBudget
```

この `myBudget` というのは Budget Name を指します。つまり、 Budget におけるユニークキーは Budget Name であるということになります。
運の悪いことに、私は Budget Name にスペースを含んだ日本語を設定していました。とても嫌なユニークキーですね。ですが、作り直すのも面倒なのでこのまま import してしまいましょう。

```
terraform import aws_budgets_budget.myBudget 123456789012:"これは Alert だよ"
```

ダブルクオートで囲むといい感じに Terraform が解釈してくれます。やりましたね！
TerraformのCIについての覚書

以前から気になっていたterraformのCIを設定したときの所見と今後やりたいことの覚書。

# お手本

[GitHub Actionsで Terraformをplan&applyしてみた / I tried to plan and apply Terraform with GitHub Actions \- Speaker Deck](https://speakerdeck.com/tomohide_tanaka/i-tried-to-plan-and-apply-terraform-with-github-actions)
とそこからリンクが貼られているhashicorp公式のterraform-github-actions。

# 設定したCI

## PRタイミングでのfmt, validate, init, plan

ここはお手本通り。基本的にplanで問題ないことまでチェックできれば良いと思う。
PRは変更を加えることが前提なのでplanで -detailed-exitcode にする必要はない。

この段階でのslackへの通知は重要性が低くて鬱陶しいだけなので無効を推奨。

PRだけではなくすべてのコミットに対してこのCIを実行してもよい。planだけなら数十秒で終わるので
Github Actionsのコンピューティングコストが気にならないならちょっとだけ助かるケースがある
(PRする前のコミット段階でテストが実行・終了するのでPRを作らなくてもステータスが確認できたりする。
PRにしないとテストが走らない場合、PRにしてすぐWIPを外してレビューを頼む、みたいなことができずテストが終わるまで一拍待つ手間が発生する)。

## masterへのpushタイミングでのapply

ここもお手本通り。CIでapplyすることが怖いという意見はわかるがmasterへのpush/mergeプロテクションをgithubで設定すればいいと思う。

このCIはslackへ通知したほうが良いと思う。少なくとも失敗したときはslackへ通知するようにすると便利。

このCIで注意するべき点は、仮に前段のPRタイミングでのplanが成功していてもapplyが成功するとは限らないこと。
terraformはすべての依存性解決などをよしなにやってくれるわけではない。
依存性などを自分で注意して書いてやったり予めterraform state xxxやAWSで手動にての変更などが必要になるケース、失敗してから個別にそれらをやらないと行けないケースは常にある。
なのでGithub Actionsからのみしかapplyをしない、というのは幻想。
基本的にCIでapplyをするにしても手元からも常に実行できるようにしておくこと。

# 設定したいCI

※ これはまだ設定していないのでどこかに落とし穴があるかも

## 一日一回(または定期)でのplan

masterブランチの状態と実際のインフラ状態がずれていないかをチェックするために一日一回程度planする。
その際はplanに`-detailed-exitcode`オプションを設定して差分が発生したときもstatus code 0以外を出すようにする。

## PR段階でのworkspaceとapplyを使っての適用テスト

[Terraform Workspacesの基礎と使い方について考えてみた！ \#AdventCalendar ｜ Developers\.IO](https://dev.classmethod.jp/cloud/how-to-use-terraform-workspace/)
こちらの記事にインスピレーションを受けて考えた、インフラコードの適用テストCI。
いわばTerraformコンフィギュレーションの単体テストにあたる。
実際の手順は以下。

CIの事前にやっておくこと

1. Workspace機能でdefaultとは別のworkspace `test`を作成
2. そのテストworkspaceの対象を別のAWSアカウントなどにしておく
3. 一旦testワークスペースは作らないでおく

PR CIでやること

1. マージ対象のブランチの最新コミットの状態で testワークスペースをinit, apply
2. マージするブランチの最新コミットの状態でtestワークスペースにapply
3. 成否に関わらずtestワークスペースのすべてをdestroy

このCIが成功する = 理論上defaultワークスペースへのapplyも必ず成功する、ということになり、上の方で書いたplanのみのテストよりも一歩踏み込んだテストができる。
またterraformのapplyはあくまで差分適用なのでterraformコンフィギュレーションを育てていくと実はある時点でリソースが全くない状態からのapplyが失敗するようになっていた、というようなケースもある。
このテストを回すと毎回１から作るためその点も副次的に毎回テストできることになる。

このCIのデメリット:

1. テストに時間がかかる。１からすべてのインフラを作るのでCloudFrontなどがある場合数十分コースは確定である
2. 専用のAWSアカウントなどを用意する必要がある。なくてもいいがより安全に実行したり混乱を避けるためアカウントは分けておいたほうがいい
3. 多少のコストが掛かる。ただしワークスペースを立てっぱなしにするのではなくテスト中しかリソースは使用しないのでテストの利得と比較すると正直無視していいコストだと思う
4. 同時に２個以上のテストを実行するときは工夫が必要。おそらくワークスペースを実行前に用意するのではなくCIテストごとにランダムな名前などで生成すればよいが、AWSアカウントまで毎回作るわけにも行かないのでTerraformコンフィギュレーション側でリソース名がかぶらない工夫などは必要。
WEB開発におけるDockerの使い道を超初心者なりに整理した

## この記事を読むにあたっての注意
- **初心者**が備忘録として、Dockerを利用したWEB開発の流れについてまとめたものです。
- 普段、業務などでDockerを利用し、WEB開発を行っている人などには情報として**価値の無い**記事です。
- Dockerのコマンドや、Dockerfile、docker-compose.ymlなどについては一切書いておりません。

## 本題
### Dockerをなぜ使う？
開発環境について
開発環境を開発メンバーごとに手動で用意すると、環境に少なからず差異が生まれてしまう。
これを防ぐために、Dockerを利用し、開発環境のコード実行環境を統一する。
これによって、コードやデータベースのシードデータなどさえ同じならば、コード(実行ファイル)は同じように実行できる。

本番環境について
本番環境(端末など)が複数存在する場合、少なからず環境には差異がある。
どの本番環境(端末)でも同じように動作することを保証するために、Dockerを用いて環境を構築し、実行するコードや実行ファイルを置くなどの最低限の作業(git pullなど)で、動作させる。

## 開発環境について
Dockerで統一するのは、コードの実行環境(ローカルのテスト環境)。
なので、コードはホストOS側で、好きなエディタなどを用いて書いて、コードが書けたら、必要なものだけをDockerコンテナ内にコピーし(.dockerignoreを利用しても良い)動作確認を行う。

## Dockerfileについて
Dockerイメージは開発環境用と本番環境用の2つ用意するのが一般的。故に、Dockerfileを開発環境用と本番環境用の２つを管理するか、マルチステージビルド機能を利用して、単一のDockerfileにまとめる必要がある。
ただし、環境でイメージを使い分けるので、開発環境で正常に動作するからといって、本番環境で正常に動作すると限らない。
したがって、可能な限り、本番環境の動作を保証するための手段を取る必要がある。
対策：
1. 静的コード解析ができるエディタを使用する。
2. 静的コード解析の自動化
3. テストを書く
4. テストの自動化
5. デプロイの自動化(Dockerに対応しているCIツールもある)

他にも、少し話がずれるかもしれないが、権限管理、手入力で行う定型的なコマンドのシェルスクリプト化、作業内容を作業表にまとめておくなどの対策も必要かもしれない
【python】mock.patchでクラス関数を置き換える際にselfパラメータが通常引数扱いとなる

## はじめに
mock.patchを使ってクラス関数をテスト用に作成したクラス関数に置き換えたいのだが、
テスト用クラス関数のselfが通常引数扱いされ、引数の数が合わずTypeErrorが発生して詰まった。

解決したのでメモ

## 失敗例

``` test_human.py
import unittest
from unittest.mock import patch

class Human:

    def set_name(self, name):
        self.name = name

    def get_name(self):
        return self.name

class TestHuman(unittest.TestCase):
    def test_human(self):
        """Human クラスの get_name を常に "しげる" を返す関数に置き換える"""
        with patch('test_human.Human.get_name') as get_name_mock:
            def custom_get_name(self):
                return "しげる"

            get_name_mock.side_effect = custom_get_name
            human = Human()
            human.set_name("たけし")
            self.assertEqual(human.get_name(), "しげる")

if __name__ == '__main__':
    unittest.main()


```

``` 結果
TypeError: get_name() missing 1 required positional argument: 'self'
```

## 成功例
autospec=Trueを設定することで、selfは本来のselfとして扱われる。

``` test_human.py修正後
class TestHuman(unittest.TestCase):
    def test_human(self):
        """Human クラスの get_name を常に "しげる" を返す関数に置き換える"""
        with patch('test_human.Human.get_name', autospec=True) as get_name_mock:
            def custom_get_name(self):
                return "しげる"

            get_name_mock.side_effect = custom_get_name
            human = Human()
            human.set_name("たけし")
            self.assertEqual(human.get_name(), "しげる")

```

``` 結果修正後
Ran 1 test in 0.003s

OK
```
【備忘録】LINE WORKS版Trello Botの動作確認をPostmanで行う

先日、他部署のLINE WORKS版Trello Botユーザーから**「作って貰ったTrello Botの更新通知がLINE WORKSに来なくなった」**という連絡が来た。Trelloからも「Webhookの1つが失敗し、無効になる可能性があります」という件名でメールが来ているとのこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/f1174105-0c9e-79c6-b3ce-844231f755cc.png)

しかし、
- こちらでHerokuにデプロイしたBotアプリのソースコードをいじったわけではない
- LINE WORKSのAPI情報をいじったわけでもない
- Trelloから「Webhookの仕様変えるよ」という連絡が来た記憶はない
ということを考えると、「ユーザー側で何かした」としか思えなかったので確認したところ、「ボードを一つ追加しただけ」とのこと。

何はともあれ、原因究明のため、動作確認をする必要が出てきたが、動作確認のためには**LINE WORKS版Trello Botのデプロイ先（Heroku）に対してPOSTリクエストをする**必要がある。

しかし、
- 他部署のTrelloボードへのアクセス権限は貰えないため、WebhookによるPOSTリクエストはできない
- 会社のPCにcURLを入れるための説明をISMS担当者にするのもめんどくさい
と億劫な気持ちになっていたら、**Chrome ウェブストアでPostmanを発見！**
Postmanで解決できた。

以下、再度、動作確認しなければならなくなったときの為、やったことを記録しておく。

# やったこと
### 1. PostmanをGoogle Chromeに追加
リンクはこちら（↓）
[Postman - Chrome ウェブストア](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=ja)
なお、PostmanはGoogleアカウントで利用登録できた。

### 2. JSONダミーデータを作成
Trelloのカードにコメントを入力すると、Webhook生成時にコールバックURLで指定したLINE WORKS版Trello Botのデプロイ先（Heroku）にJSONデータが飛ぶ（POSTメソッド）。
そのJSONデータを処理してLINE WORKSのトークルームに送信するソースコード（抜粋）は以下のようになっている。

```Python:app.py
@app.route('/webhook', methods=['GET', 'HEAD', 'POST'])
def webhook():
    if request.method == 'GET':
        return 'Start', 200
    elif request.method == 'HEAD':
        return '', 200
    elif request.method == 'POST':
        action_type = request.json['action']['display']['translationKey']
        if action_type == 'action_comment_on_card':
            card_name = request.json['action']['data']['card']['name']
            user_name = request.json['action']['memberCreator']['fullName']
            comment = request.json['action']['data']['text']
            message = user_name + "さんがコメントしました。\n【カード】" + card_name + "\n【コメント】" + comment
            talkbot.send_text_message(send_text=message)
            return '', 200
        else:
            pass
    else:
        abort(400)
```

このPOSTリクエストをPostmanで再現したいので、JSONダミーデータを作成した。

```json
{
    "action":{
        "display":{
            "translationKey":"action_comment_on_card"
        },
        "data":{
            "card":{
                "name":"カード名"
            },
            "text":"コメント"
        },
        "memberCreator":{
            "fullName":"ユーザー名"
        }
    }
}
```

### 3. PostmanからPOSTリクエストを送信
- HTTPメソッドを「POST」に変更
- URLにコールバックURL（HerokuアプリのURL）を入力
- Bodyでリクエストボディは「row」を選択し、Content-typeは「JSON(application/json）」に変更、2のJSONダミーデータを入力

この状態でSendボタンを押下すると、Postリクエストが送信される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373977/d8d0e69c-5b85-156c-40cf-6f6fdd31175e.png)


# 動作確認した結果
ステータスコード200のレスポンスが返ってきて、LINE WORKSにも更新通知が飛んだ。そして、以降はTrello更新通知がLINE WORKSに飛ぶようになった。結局、原因不明だがめでたしめでたし。
JSで要素同士に線や矢印を引けるライブラリ"LeaderLine"

#LeaderLineとは
矢印や線の描画、範囲の描画が簡単に行えるオープンソース・ソフトウェアです。

>https://anseki.github.io/leader-line/

#使用方法
####１、ホームページでフォルダのダウンロードを行います
####２、ダウンロードしたフォルダの"leader-line.min.js"をwebページに埋め込みます
```html:test.html
<script src="leader-line.min.js"></script>
```
####３、矢印や線でつなぎたい要素をLeaderLineのコンストラクタに渡す
```js:test.js
new LeaderLine(
  document.getElementById('要素1'),
  document.getElementById('要素2')
);
```

#使用例を一部紹介します
####１、ノーマル
```js:test.js
new LeaderLine(
  document.getElementById('start'),
  document.getElementById('end')
);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/60f2a735-b617-516f-44c5-9b9878b17221.png)

####２、サイズや形、色の変更
```js:test.js
new LeaderLine(element1, element2, {
  startPlugColor: '#1a6be0',
  endPlugColor: '#1efdaa',
  gradient: true
});
new LeaderLine(element2, element3, {dash: {animation: true}});
new LeaderLine(element4, element5, {dropShadow: true});
new LeaderLine(element5, element6, {dash: true});
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/229815b6-deba-0c4c-3ecf-26846f30a438.png)

####３、一定条件に矢印がひかれる
```js:test.js
new LeaderLine(LeaderLine.mouseHoverAnchor(startElement), endElement);
```
![ex-110.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/a3169022-66db-49dd-9251-04c56b022fdd.gif)

####４、範囲を描画できる
```js:test.js
new LeaderLine(startElement, LeaderLine.areaAnchor(endElement));
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/96aea473-d589-3115-42a7-530eaaba4545.png)


#最後に
この他にもスクロールによる要素の位置の変更にも対応できたり、
div要素だけでなくbutton,ul,text,circle,,,などにも線をつなげることができます。詳しくは[こちら](https://anseki.github.io/leader-line/)
使ってみて便利だったので紹介させていただきました。
転移学習とは何ですか？


通常、画像分類モデルのトレーニングには数日かかる場合がありますが、転移学習は、関連タスクのために既にトレーニングされたモデルを取得し、それを新しいモデルを作成するための開始点として使用する手法です。通常、これには1時間もかかりません。 （このプロセスは、モデルの「微調整」とも呼ばれます。）

#### 転移学習は、次の2つの方法で実行できます:

- 最終層のみの再トレーニング：このアプローチでは、最終分類が行われるモデルの最後の数層のみを再トレーニングします。これは高速で、小さなデータセットで実行できます。

- 完全なモデルの再トレーニング：このアプローチでは、新しいデータセットを使用してニューラルネットワークの各レイヤーを再トレーニングします。その結果、モデルはより正確になりますが、時間がかかります。また、モデルの過剰適合を避けるために、かなりのサンプルサイズのデータ​​セットを使用して再トレーニングする必要があります。

転移学習は、事前に訓練されたモデルで学習された機能が一般的であり、高度に専門化されていない場合に最も効果的です。たとえば、家庭用品を認識できる事前トレーニング済みモデルは、新しい事務用品を認識するように再トレーニングされる場合がありますが、異なる犬種を認識するよう事前トレーニングされたモデルはそうでない場合があります。

新しいクラスのセットを認識するために画像分類モデルを再トレーニングする方法は？


転送学習を使用して既存のモデルを再トレーニングし、Edge TPUデバイスで実行するようにコンパイルします（Googleグローバル販売代理店-Gravitylinkオンラインストアから取得できます: https://store.gravitylink.com/global）。再トレーニングしたモデルは、Coral Dev Boardまたは Coral USBアクセラレータ。
NativeScript + Vue でフォントアイコン(FontAwesome)を使う

NativeScript VueでFontAwesomeのアイコンを使う方法。
FontAwesome以外の他のフォントアイコンでも同様の方法が使える。

# ダウンロード

まず、FontAwesomeのttfファイルを入手する。
以下からダウンロード。

https://fontawesome.com/v4.7.0/

注意するべき点としては、2020/2/5現在、v5系は使えないので、v4.7をダウンロードすること。

# 配置

ダウンロードした font-awesome-4.7.0.zip を解凍し、`fonts/fontawesome-webfont.ttf` というファイルを、NativeScript Vueプロジェクトの `app/assets/fonts` フォルダ内にコピーする
コピーしたファイルを、 `FontAwesome.ttf` にリネームする(これが重要)

# 使うための前準備

グローバルのスタイルシートである app/app.scss に以下を記述。

```scss:app/app.scss
.fa {
  font-family: FontAwesome;
}
```

# 使い方

まず、使いたいアイコンフォントのユニコード文字列を知る必要がある。
FontAwesomeであれば、FontAwesomeで使いたいアイコンフォントのページを開くと、以下に表示されている。

<img width="734" alt="Cog_Icon___Font_Awesome.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170712/2f0f082b-81ee-c3fd-8b7f-60b869e6438a.jpeg">


ここでは、歯車のアイコンフォントが使いたい。 
`\u`をプレフィックスとしてつければユニコード指定できる。
歯車アイコンの文字コードが f013 なので、ここでは、以下のように`\uf013`と指定する。

```vue:components/App.vue

<Button :text="'\uf013'" class="fa"></Button>

```

以下のように、アイコンフォントが表示されればOK。
<img width="60" alt="IMG_086308BB428F-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170712/2266a48b-1b87-8577-d48e-fb2f3deca356.jpeg">

#
fputcsvのダブルクォーテーション問題をスッキリ解決する

# 経緯

文字列をダブルクォーテーションできっちりくくった状態でcsvに吐き出す必要があった。
SQL側で文字列結合とかquote_identとかでダブルクォーテーション付けて結果を取得し、fputcsvで書き出すと下記状態になってしまっていた。

( ﾟдﾟ) ・・・ (つд⊂)ｺﾞｼｺﾞｼ (；ﾟдﾟ)

```
"""文字列""","""文字列""",....
```

どうやらfputcsvが残念仕様でPHP的には良くある話のようだ。
割とfputcsvを再発明して関数とかで何とかしてる人が多い気がする。

**ワイはそんなのやりたく無い**

# どうやったか

文字列にして乗り切った

前

```php
fputcsv($file, 文字列);
```

後

```php
file_put_contents($file,implode(",",文字列).PHP_EOL,FILE_APPEND);
```
SSH認証するための鍵をBitbucketに設定する。

##そもそも鍵とは...
そもそも鍵はなぜ必要なのか。
リポジトリにアクセスするために、SSH認証キーを使う。
SSH認証することで、
・セキュリティ向上（言わずもがな）
・アクセス時に毎回パスワードを聞かれなくてストレスフリー
私が今回この記事を書こうと決めたのは、パスワードを毎回聞かれ、
ストレスがやばかったから。
では、そのSSH認証するための鍵の生成について見ていきましょう。


***
#SSH認証するための鍵をBitbucketに設定する
1.SSH認証の公開鍵/秘密鍵を作成
2.公開鍵をクリップボードにコピー
3.Bitbucketに公開鍵を登録

***
###SSH認証の公開鍵/秘密鍵を作成
ターミナル上で以下コマンドを叩いて、公開鍵と秘密鍵を生成。

```Bash:bash
$ cd ~/.ssh
$ ssh-keygen -t rsa -C hoge@example.com  # 自分のメールアドレス
```
以下コマンドを叩いて、生成されたファイルを確認。

```Bash:bash
$ ls -l 
合計 12
-rw------- 1 hoge 1831  2月 5 18:00 id_rsa
-rw-r--r-- 1 hoge  405  2月 5 18:00 id_rsa.pub
```
各ファイル名は下記です。
秘密鍵：id_rsa
公開鍵：id_rsa.pub

#公開鍵をクリップボードにコピー
cat(またはless)コマンドで公開鍵の内容をクリップボードにコピー。

```Bash:bash
$ cat id_rsa.pub
```
#Bitbucketに公開鍵を登録
1.Bitbucketにログイン後、左下のユーザアイコンをクリックし、view profileをクリック。

2.「設定」をクリックし、「セキュリティ」の中の「SSH　鍵」をクリック。

3.「鍵を追加」をクリックし、「Label」に適当な名前を入力し、「Key」に先ほどクリップボードにコピーした公開鍵の中身をペースト。

4.「鍵を追加」をクリックして設定完了。

これで、リポジトリにプッシュ！！！
【Laravel】24時間以内に作成されたユーザーの数を集計する【指定範囲のデータ取得】

# 1日
```php
use DB;

DB::table('users')
  ->orderBy('created_at','desc')
  ->whereRaw('created_at > NOW() - INTERVAL 1 DAY')
  ->count()
```

# 30分

```php
  ->whereRaw('created_at > NOW() - INTERVAL 30 MIN')
```

# リファレンス

* [MySQL :: MySQL 5\.6 リファレンスマニュアル :: 12\.7 日付および時間関数](https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-functions.html)

この記事が作成されている時点では、以下のリファレンスが用意されていたのですが、バージョンアップで参照できなくなるとおもうので、適宜環境にあったリファレンスを参照してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/871f30de-9612-8b78-d969-ea7cdb3acbe8.png)


筆者のサーバー環境はMySQL 5.5だったのだけど、実行環境依存だとおもうので、`MIN`とかが使えないバージョンなどもあったりするのだろうか。。。 :thinking:
スマートカード三行まとめ

#はじめに
スマートカード（ICカード）について調査したので、メモしておく。
Linux機でソニー以外のICカードリーダを使用したかったため。

#はじめに概要をつかむ
[EternalWindows スマートカード]
(http://eternalwindows.jp/security/scard/scard00.html)
スマートカードの技術仕様について幅広く記述されている。
ざっと目を通す。

#APDUとは
Application Data Unit
スマートカードへの命令とデータのプロトコル。

#pyscard
[pyscard]
(https://github.com/LudovicRousseau/pyscard)
[公式サンプルコード]
(https://pyscard.sourceforge.io/pyscard-wrapper.html#wrapper-samples)

Linux、pythonで動かせた。
2019.11時点でver1.9.9であり、開発期間も長いので候補。

#pcscd
[DebianでICカードリーダSCR3310を使って住基カードが認識するか見てみる]
(http://www.nofuture.tv/diary/20130927.html)

Linuxでpcscd,pcsc-toolsでpcsc_scanコマンドが確認できた。
しかし当コマンド以外の使い方がよくわからない。
深堀すれば使えそうだが、複雑な用途に使わないならpyscardでいいと思う。

#Windowsで試す
[WindowsでOpenSCを使ってカードのIDmを確認する方法]
(https://qiita.com/gebo/items/eb76d2b83041cdb47ec3)
Windowsで簡単に試せた。
ただし、verが0.xなので開発途上なのかも。

#ソニーのPaSoRiなら情報が多い
[raspberrypi nfcpy]
(https://qiita.com/carpenders/items/14f15807a9dca15f5fde)
[Python3でnfcpy]
(https://qiita.com/Electro35/items/9a220c005f6b3a78131d)
[nfcpy で複数の System Code を持つ NFC タグを扱う方法]
(http://uchan.hateblo.jp/entry/2016/11/18/190237)

カードリーダー選定でPaSoRiを選べるならあり。
機種バージョン違いでソフトが使えなくなることもあるらしいので留意する。

#キーワードの備忘録
libpafe(pasori felica?)
nfcpy
pc/sc(Windows)
pc/sc lite(Linux,Mac)
libccid
linux nfc subsystem
pyscard
opensc
LinuxでAnacondaインストール中に固まった場合の対処

#はじめに
CentOSにAnacondaをインストール中にトラブったのでメモ


#環境
- CentOS 7
- Anaconda 2019.10-Linux-x86_64.


#現象
Anaconda3-2019.10-Linux-x86_64.shでインストール中に以下のUnpacking payloadのところで固まった状態になった。

```
Anaconda3 will now be installed into this location:
/home/kimisyo/anaconda3

  - Press ENTER to confirm the location
  - Press CTRL-C to abort the installation
  - Or specify a different location below

[/home/kimisyo/anaconda3] >>>
PREFIX=/home/kimisyo/anaconda3
Unpacking payload ...
```

#対応
シングルコアの場合に発生するらしい。仮想環境の場合は仮想マシンのCPUのコア数を2以上にするとうまくいった。

#参考
https://github.com/ContinuumIO/anaconda-issues/issues/11466
作業中のブランチに、マスターの変更を適用する[Github Desktop]

##What
githubを利用して、複数名共同でアプリケーションを作成する際に、
新たにgemを入れて全員で使用したいときのための github desktop の活用方法。

##why
上記の方法がわからず、一度マスターにマージしてからgemを共有したところ、
プルリクエストする際に苦心したため。

##方法

####手順 1
共有したいマスターへの変更(例：gemを入れたい、mixinファイルに変数を定義したいなど)
を作成するためのブランチを作成する。

####手順 2
手順1で作成したブランチの作業をマスターにマージする。

####手順 3
Github Desktop メニューバーの Branch から Update from master を選択

画面上部のこんな感じのところ↓
![alt](https://gyazo.com/95e933277803cf948026ac8a54c8ca82.alt)



以上を行うとマスターの内容を作業中のブランチに適用できるらしい。
CentOS7 + Python3 + netmikoでCisco Catalystにssh接続してローカルにコンフィグを保存する

# 概要

Ciscoのスイッチ（Catalyst2960など）にsshアクセスしコンフィグを自動で取得するプログラムを書く必要が生じ情報収集すると、どうもnetmikoというpythonライブラリで実現できそうなので環境構築しプログラムを作成してみました。

なおCentOS7にデフォルトのリポジトリでyumインストールできるpythonのヴァージョンは2系でそのままではnetmikoが動作しないため、python3をインストールする手順も記載します。

### インポート

IUSリポジトリを追加します。

```
# yum install -y https://centos7.iuscommunity.org/ius-release.rpm
```

### 確認

以下コマンドを実行しインストール可能なマイナーヴァージョンを確認します。

```
# yum search python3
```

### インストール

現時点で最新のpython3.6（本体＋ライブラリ、開発、パッケージ管理等）をインストールします。

```
# yum install -y python36u python36u-libs python36u-devel python36u-pip

# python -V
Python 3.6.8

# pip -V
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
```

### netmikoのインストール

netmikoライブラリをインストールします。

```
# pip install netmiko
```

# サンプルプログラム

サンプルプログラムとしてIPアドレスとパスワードをカンマ区切りで記載したcsvファイルを読み込み
running-configを指定ディレクトリに保存するpythonコードを記載します。

```:devices.csv
192.168.1.254,password1234
172.16.1.254,password5678
```

```python:backup.py
#!/usr/bin/env python

from netmiko import ConnectHandler
import csv
import datetime

# コンフィグのバックアップファイルに日付を含ませるための日付取得処理
now = datetime.datetime.now()
today = now.strftime('%Y%m%d')

with open('devices.csv') as f:
        reader = csv.reader(f)

        # csvファイルを1行読み込んでIPアドレスとパスワードを取得し処理を回す
        for row in reader:
                cisco_ios = {
                        'device_type': 'cisco_ios', # sshの場合左記を指定
                        'ip': row[0],               # csvファイルの1カラム目
                        'username': 'user_name',    # 実際のユーザー名
                        'password': row[1],         # csvファイルの2カラム目
                        'port' : 22,                # ポート番号
                        'secret': row[1],           # enable secretのパスワード
                        'verbose': False,
                        }

                net_connect = ConnectHandler(**cisco_ios)

                # 特権モードに移行
                net_connect.enable()

                # write memoryコマンドでrunning configをstartup configに保存
                net_connect.send_command('wr')
                # running-configの取得
                output = net_connect.send_command('show running-config')
                # ホスト名の取得
                prompt = net_connect.find_prompt()
                hostname = prompt[:-1]

                # 先頭の不要行を除外
                list = output.split('\n')
                list = list[3:]
                config = '\n'.join(list)

                # ファイル名の作成
                file = 'store/' + hostname + '-' + today + '.txt'

                # ファイルをstoreディレクトリに保存
                with open(file, 'w') as backup:
                        backup.write(config)
                        print(hostname + ' : ' + 'succeeded')

                net_connect.disconnect()
```

またコンフィグファイルの保存先ディレクトリを作成しておきます。

```
# mkdir store
```

pyファイルとcsvファイル、storeディレクトリを同じディレクトリに設置しpyファイルを実行するとstoreディレクトリに「ホスト名-年月日.txt」の形式でrunning configが保存されます。

```
# ls
backup.py  devices.csv  store

# python backup.py
switch1 : succeeded
switch2 : succeeded

# ls store/
switch1-20200205.txt  switch2-20200205.txt
```
RaspberryPiにPS3コントローラーを接続する

##libusb
```
% sudo apt install libusb-dev
```

##sixpair
sixpairをダウンロードして、コンパイルする。

```
% mkdir Sixaxis
% cd Sixaxis
% wget "https://help.ubuntu.com/community/Sixaxis?action=AttachFile&do=get&target=sixpair.c" -O sixpair.c
% gcc -o sixpair sixpair.c -lusb
```
##必要なライブラリのインストール
```
--- pyuic4 ---
% sudo apt install python-qt4 pyqt4-dev-tools qt4-designer
--- jack.h ---
% sudo apt install libjack-jackd2-dev
--- bluetooth.h ---
% sudo apt install libbluetooth-dev
```

##qtsixaのインストール
```
% git clone https://github.com/falkTX/qtsixa.git
% cd qtsixa
% make
% sudo make install
```

##PS3コントローラーの接続
```
% sudo sixad -start &
```
この後にPS3コントローラーをラズパイにUSBケーブルで接続し"PS"ボタンを押すと接続できる。
うまくPS3コントローラーを認識出来るようになった。
本当はこのままUSBケーブルを抜くとRaspberryPiとPS3コントローラーの間がBlueToothで繋がって使えるようになるらしいが、家ではUSBケーブルを抜くとPS3本体の電源が入ってコントローラーがそっちと繋がってしまった。
PS3コントローラーのリセットボタンを押すと対応できるらしいが試してない。

PS3コントローラーが繋がったので、ラズパイ起動時にデーモンが動くようにしておく。

```
% sudo systemctld enable sixad
```
ラズパイを再起動する

```
% sudo reboot
```
##PS3コントローラー情報の取得
こんな感じでPS3のボタンの情報を取得できる[githubのソースはこちら](https://github.com/roxa-delphi/microbit/blob/master/js_watch.py)

```python:js_watch.py
import struct

device_path = "/dev/input/js0"

EVENT_FORMAT = "LhBB"
EVENT_SIZE   = struct.calcsize(EVENT_FORMAT)

with open(device_path, "rb") as device :
  event = device.read(EVENT_SIZE)
  while event :
    (ds3_time, ds3_val, ds3_type, ds3_num) = struct.unpack(EVENT_FORMAT, event)
    print("{0}, {1}, {2}, {3}".format(ds3_time, ds3_val, ds3_type, ds3_num))

    event = device.read(EVENT_SIZE)
```
実行する

```
% python3 js_watch.py
```
各ボタンを押して調べた結果がこれ[githubにも置いてある](https://github.com/roxa-delphi/microbit/blob/master/js_watch.log)
type=1 だとボタンがデジタル値で　0か1の2値
type=2 だとボタンはアナログ値で -32767〜32767　の値
で取得できる。

```text:js_watch.log
up         : num=13, type=1, val=1 or 0
down       : num=14, type=1, val=1 or 0
left       : num=15, type=1, val=1 or 0
right      : num=16, type=1, val=1 or 0

x          : num=0, type=1, val=1 or 0
circle     : num=1, type=1, val=1 or 0
triangle   : num=2, type=1, val=1 or 0
squre      : num=3, type=1, val=1 or 0

L1         : num=4, type=1, val=1 or 0
L2         : num=2, type=2, val=-32767:32767
             num=6, type=1, val=1 or 0
R1         : num=5, type=1, val=1 or 0
R2         : num=5, type=2, val=-32767:32767
             num=7, type=1, val=1 or 0

stop       : num=8, type=1, val=1 or 0
start      : num=9, type=1, val=1 or 0

left stick
left&right : num=0 , type=2, val=-32767:32767
up&down    : num=1 , type=2, val=-32767:32767
push       : num=11, type=1, val=1 or 0

right stick
left&right : num=3 , type=2, val=-32767:32767
up&down    : num=4 , type=2, val=-32767:32767
push       : num=12, type=1, val=1 or 0
```

##いつのまにかBlueToothが使えない
ラズパイを再起動してもBluetoothがうまく使えなくなっていた。
しばらく調べていると、デーモンファイルの実行権がなくなっていたことに気づいた。
実行権をつけることでうまく動くようになった。

```
% sudo chmod +x /usr/lib/bluetooth/bluetoothd
```
原因は不明だが、このsixadをインストールしたとにapt upgradeでシステムの更新をしたときに、
うまくアップデートできなくて実行権がなくなった? かもしれない。。。
Python3でgcloudコマンドを動かせるようにする

# tl;dr;
```bash
export CLOUDSDK_PYTHON=python3
```

# 説明

`pyenv` 等でpython3, gcloudをインストールした環境では、gcloud実行時に以下のようなエラーが出ることがある。

```
$ pyenv local
3.7.4
$ gcloud
pyenv: python2: command not found
The `python2' command exists in these Python versions:
  2.7.17
```
gcloudがpython2でしか動作しないのかというとそうではなく、
ドキュメントにはGoogle Cloud SDK version 274.0.0以降であればpython3.5以上で動作する(GA)と書いてある。
https://cloud.google.com/sdk/docs/?hl=en
> As of Cloud SDK version 274.0.0, the gcloud CLI has GA support for running using a Python 3.5 and up interpreter. For exclusions and more information on configuring your Python interpreter, run `gcloud topic startup`.

`gcloud topic startup` を読んでみると……

```
NAME
    gcloud topic startup - supplementary help for gcloud startup options

DESCRIPTION
Choosing a Python Interpreter

    The gcloud CLI runs under Python. On Windows, you have the option of
    installing a bundled Python interpreter, but on Mac and Linux you must have
    a Python interpreter available somewhere on your system. gcloud will
    attempt to locate an interpreter on your system PATH by looking for the
    following binaries (in this order):

      ▪ python2
      ▪ python27
      ▪ python
      ▪ python3

    Currently gcloud requires Python version 2.7.x or 3.5 and up.

    Other Python tools shipped in the Cloud SDK do not yet support Python 3,
    including:

      ▪ dev_appserver
      ▪ endpointscfg

    If you have multiple Python interpreters available or if you don't have one
    on your PATH, you can specify which interpreter to use by setting the
    CLOUDSDK_PYTHON environment variable. For example:

        # Use the python3 interpreter on your path
        $ export CLOUDSDK_PYTHON=python3

        # Use a python you have installed in a special location
        $ export CLOUDSDK_PYTHON=/usr/local/my-custom-python-install/python

    gsutil now supports Python 3.5 and up in addition to Python 2.7.x. To use a
    different interpreter for gsutil than for the other Python tools, you can
    set the desired interpreter by setting the CLOUDSDK_GSUTIL_PYTHON
    environment variable.

    bq now supports Python 3.5 and up in addition to Python 2.7.x. To use a
    different interpreter for bq than for the other Python tools, you can set
    the desired interpreter by setting the CLOUDSDK_BQ_PYTHON environment
    variable.
    
```
すなわち、

- `python2` にpathが通っていると、python2が優先的に使おうとする。
- `python2` にpathが通っていなければpython3が使われる
- 環境変数 `CLOUDSDK_PYTHON=python3` を指定しておくとpython3が使われる
- 一部のCloud SDK toolはpython3に未対応
    - `dev_appserver` と `endpointscfg`


とのことなので、python2とpython3が共存している環境では、 `CLOUDSDK_PYTHON=python3` を設定しておくとgcloudがpython3を使ってくれるようになる。

世の中には [python2を使わせる設定をする記事](https://qiita.com/kadokusei/items/b2ff3d372f95af57a15a)はたくさんあるものの、python3を使わせる設定についてはヒットしなかったのでメモ。
- python3がGAになったgcloud 274.0.0のリリース日は[2019年12月18日](http://console.cloud.google.com/storage/browser/cloud-sdk-release?authuser=0&prefix=google-cloud-sdk-274.0.0)。まだ1ヶ月半くらいだった。
JavaScriptのつまずきやすいとこ

# オブジェクト

## 配列とオブジェクトの違い

どちらも複数の値をひとまとめにし、key-valueの形になっている。
配列はkeyが番号だが、オブジェクトはkeyが名前を持っている。
(実は配列もオブジェクトの一種)

## オブジェクトの作り方

new演算子を使うか、オブジェクトリテラルかの2パターン。 

## new演算子

new演算子を使うとコンストラクタ(ある種の関数)が呼び出される。
コンストラクタがnewで呼び出された場合、新しいオブジェクトが作成され、それがthisになる。
newにより作成されたオブジェクトのことをコンストラクタから見てインスタンスと呼ぶ

## 関数=オブジェクト

**関数定義とは、作った関数を変数に入れる作業である。**

```javascript
function hello(){
  alert("hello");
}
console.log(typeof(hello));//functionと表示
```
functionと表示されているが、オブジェクトである。
ただ`()`をつけると呼び出せるというのは関数だけの特徴である。

```javascript
const a = {};
a.hello = greeting;
a.hello();

function greeting(){
    alert("hello");
}
```
関数定義は**実行される場所より後ろに書いてあっても機能する**
HTMLをPDFに変換するやり方

#はじめに
業務上HTMLの画面をPDFにしてダウンロードしたい場合があります。
利用者は手動でツール、コマンドなどを使ってPDFに変換する場面があるし、
プログラムでPDF作成してダウンロードする場面もあります。

やり方を簡単にまとめてみます。

#1. 利用者手動でPDF生成
##1.1 ブラウザの機能を使ってPDFとして保存
Chromeの場合は、印刷の画面の送信先を「PDFに保存」選択し、保存ボタンを押すとPDFファイルとして作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/9e1e2f4e-f4c6-dd11-e9ba-b4f34a52ecb4.png)

##1.2 Chromeの拡張機能の利用
いくつかありますが、例えば：Print Friendly & PDF
https://chrome.google.com/webstore/detail/print-friendly-pdf/ohlencieiipommannpdfcmfdpjjmeolj?hl=ja

##1.3 コマンドでPDF生成
###1.3.1 wkhtmltopdf
wkhtmltopdfはとても有名だと思います。サポートするCSSはちょっと古いみたいです。CSS3のものは効かない場合があります。
https://wkhtmltopdf.org/

使い方は簡単です。
例：`wkhtmltopdf http://google.com google.pdf`

また、wkhtmltoimageで画像に変換するのも可能です。

###1.3.2 WeasyPrint 
Pythonの環境があればWeasyPrintも利用できます。
https://weasyprint.readthedocs.io/en/latest/index.html

ただし、Vue.jsなどSPAのページは描画できないようです。

###1.3.3 ヘッドレスのChrome
利用例：`chrome --headless --print-to-pdf https://yahoo.co.jp/`

実行結果は、`C:\Program Files (x86)\Google\Chrome\Application\79.0.3945.130\output.pdf` になります。

#2. プログラムでPDF作成
##2.1 ライブラリの利用
###2.1.1 openhtmltopdf
openhtmltopdf: https://github.com/danfickle/openhtmltopdf

>An HTML to PDF library for the JVM. Based on Flying Saucer and Apache PDF-BOX 2. With SVG image support. Now also with accessible PDF support (WCAG, Section 508, PDF/UA)!

厳密なHTML構成でないとエラーになりますので、ちょっと使いにくいと思います。

例えば、<script async はエラーで、<script async="true" のようにする必要があります。

###2.1.2 Selenium
selenium: https://selenium.dev/
テストフレームワークとして有名ですが、ブララザのエビデンス取るのはとても便利です。
PDFとして保存することも可能です。

chromedriverダウンロード: https://sites.google.com/a/chromium.org/chromedriver/downloads

##2.2 プログラムからコマンドを呼び出してPDF生成
###2.2.1 wkhtmltopdf
wkhtmltopdf: https://wkhtmltopdf.org/

###2.2.2 ヘッドレスのChrome
参考URL：https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md

##2.3 Nodeモジュールの利用
いつくかのモジュールがありますが、HeadlessのChromeを利用しているのは多いです。
###2.3.1 chrome-pdf
chrome-pdf: https://www.npmjs.com/package/chrome-pdf

###2.3.2 html-pdf-chrome
html-pdf-chrome: https://www.npmjs.com/package/html-pdf-chrome

###2.3.3 chrome-headless-render-pdf
chrome-headless-render-pdf: https://www.npmjs.com/package/chrome-headless-render-pdf

コード例：

```javascript
const RenderPDF = require('chrome-headless-render-pdf');
RenderPDF.generateSinglePdf('http://google.com', 'outputPdf.pdf');
```

###2.3.4 Puppeteer
Puppeteer: https://github.com/puppeteer/puppeteer

PDFの出力例：

```javascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://qiita.com/', {waitUntil: 'networkidle2'});
  await page.pdf({path: 'qiita.pdf', format: 'A4'});

  await browser.close();
})();
```

以上
WebWorker

WebWorkerのお勉強。

まずは最小限のコードでWebWorkerを動かしてみる。
任意のデータをワーカーに渡して、オウム返しして表示するだけ。

```js:メインスレッド
const worker = new Worker('worker.js')
worker.onmessage = event => console.dir(event.data)
worker.postMessage([1,2,3])
```

```js:worker.js
onmessage = event => postMessage(event.data)
```

## インラインworker

worker.jsが外部ファイルなのが気に入らない場合は、内部化できる。

クラスを文字列化し、それをBlob・URL化すれば、worker.jsの代わりになる。
クラスは、ワーカーのコンテキストで動作することに注意すれば普通に書ける。

ワーカーは非同期処理なので、プロミス化するのが好手。
データはクラスのコンストラクタに渡され、コンストラクタの戻り値がプロミスの値となる。

これら一連の処理を関数化したのが、次の関数である。

```js:使い方
const workerが返す値 = await inlineWorker(worker化するクラス, workerに渡すデータ)
```

```js
function inlineWorker(fn, data){
    const code = `onmessage = event => postMessage(new ${fn.toString()}(event.data))`
    const blob = new Blob([code], {type: 'text/javascript'})
    const url  = URL.createObjectURL(blob)

    function async(ok, ng){
        const worker = new Worker(url)
        worker.onmessage = event => ok(event.data)
        worker.onerror   = event => ng(event)
        worker.postMessage(data)
    }
    return new Promise(async)
}
```
メモ：/bin/shで使えないオペレーターがあるんですね


シェルスクリプト実行時にこんなエラーが。

```sh
sh -c "if [ a == b ]; then echo hello ; fi"
sh: 1: [: a: unexpected operator
```

エラーメッセージを見ると`[`が使えないのかな？とかおもったけど違って、
`==`が使えないのが原因だった。

変なところでハマった。

```sh
sh -c "if [ a != b ]; then echo hello ; fi"
hello
```

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
ここに色々書いてあるが、POSIX準拠のShellのtestコマンドの文字列比較オペレーターは `==`ではなく`=`でした。

Bash使えば？って話でもあるが。
[ AndroidStudio ] PMD解析結果の見方


少し前にPMDを導入した。
https://qiita.com/QiitaD/items/7c1e635ff0cc2115d969

見方を調査してみた。

##解析結果
以下が解析結果である。
![スクリーンショット (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506451/b50fd921-8e6f-cabd-9979-ae8bd57b69ad.png)

例ではperformanceというところを見ている。これを開くと冗長な初期化がされていると書いてある。
その下、ビックリマークの横に発生しているクラスと行が書かれている。
試しにスクショの上半分のコードを見て頂くと、TitleActivityの11行目にボタンをnullで初期化しており、これが冗長な分だと示している。

##感想
pmdについて調べてみたが、参考になるサイトはほとんどなかった。どうやらbuildフォルダのoutputに解析結果出す方法がありそうなのだが、見つからず…
今回紹介したものでも役立ちそうなので、しばらくはこれで行きたい。
Power Apps でゲーム作成をして学んだノウハウ -3- ゲーム内タイマーを使ってパラパラアニメーションを作ろう

さて、以前の記事ではゲーム内タイマーを作りました。

[Power Apps でゲーム作成をして学んだノウハウ -1- ゲーム内タイマーを作ろう](https://qiita.com/hrfmjp/items/0470bef6fd4db0694527)

今回はこのタイマーを利用して、パラパラ漫画のようなアニメーションを作成してみたいと思います。

#コマの切り替えタイミングを制御する
以前の記事で作成したゲーム内タイマーは秒間 20 コマ（1 コマ 50ms）を刻むことができます。パラパラアニメーション用にもっと秒間のコマ数を少なくしたい場合には、パラパラアニメーション用に調整したタイマーを作成します。

##アニメーション用タイマーを作成する
アニメーション用タイマーの値を保持するために、画面上に「スライダー」コントロールを追加します。そして、そのスライダーコントロールの「Default」と「Max」にそれぞれ次のように指定します。

```
RoundDown(GameTimer.Value/3,0)
```

GameTimer は、タイマーコントロールの値を元に作成したゲーム内タイマー（スライダーコントロール）です。今回追加したスライダーコントロールに RoundDown 関数から得られる値を指定することで、ゲーム内タイマーの 1/3 倍速で数字が 1 ずつ増えていくアニメーション用タイマーが完成です。

画面上には下図のように 1 つのタイマーコントロールと 2 つのスライダーコントロールが存在することになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/c0f3845c-69fd-b9ff-15df-95c081f0f09b.png)

このようにして作成したアニメーション用タイマーの値を利用して、パラパラアニメーションを作成していきます。

#パラパラアニメーションを作成する
さて、パラパラアニメーションを作成していきましょう。

##画像を用意する
まずは、パラパラアニメーションの各コマになる画像を用意し、アプリの「メディア」としてアップロードしておきます。今回は次のようなものを作成しました。

ball1
![ball1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/4ee4792e-a8ef-19c7-d70e-5317a57ff91d.png)

ball2
![ball2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/54722bd9-40d5-525c-c91e-a38982d97ed2.png)

ball3
![ball3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/c41f84f8-0311-bb89-98e0-386c2b5436de.png)

ball4
![ball4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/dff11abc-fce0-2400-68ea-cdeec9f5c140.png)

ボールが弾むようなイメージの 4 コマです。この 4 コマを、ball1 ⇒ ball2 ⇒ ball3 ⇒ ball4 ⇒ ball3 ⇒ ball2 ⇒ ball1 ⇒ ball2 ⇒ ball3 ⇒ ・・・ のように切り替えていきたいと思います。

##画像コントロールを設定する
アプリ上に画像を表示するには、「画像」コントロールを配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/48c910ca-ab47-c1c6-082f-8341ff93636e.png)

この画像コントロールの「Image」パラメーターにメディアに追加した画像名を指定すると、画面上にその画像が表示されるというものです。今回はこの「Image」パラメーターに次のように指定します。

```
Switch(
    Mod(AnimationTimer,6),
    0,
    ball1,
    1,
    ball2,
    2,
    ball3,
    3,
    ball4,
    4,
    ball3,
    5,
    ball2
)
```

ボールが弾むアニメーションには 6 コマ必要なので、Mod 関数を利用してアニメーション用タイマーの値を 6 で割った余剰を求め 0 から 5 に順に変化する値を算出します。その値を Switch 関数を利用して場合分けを行い画像を順に切り替えていきます。

ここまで設定を行ってからタイマーを動かすと次ように画像が表示されるはずです。

![ballanimation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/f27b116f-5f19-1f5a-634a-cdb640f65c55.gif)

パラパラアニメーションができましたね。早さを調整するには、アニメーション用タイマーに指定した RoundDown 関数内の GameTimer.Value の値を割る数を変更すれば良いわけです。

#なぜこのような実装にしたか
今回はアニメーション用タイマーを作成しましたが、なぜこのようにしたかが大切なところです。単純に考えると、画像コントロールの「Image」パラメーターに次のように設定することでも同様の効果が得られます。

```
Switch(
    Mod(RoundDown(GameTimer.Value/3,0),6),
    0,
    ball1,
    1,
    ball2,
    2,
    ball3,
    3,
    ball4,
    4,
    ball3,
    5,
    ball2
)
```
これならわざわざアニメーション用タイマーを画面上に追加する必要もありません。ただし、他の画像も同期させて動かしたい場合には、他の画像にも同じような関数を書くことになってしまい、アニメーションの速度変更を行いたい場合などは画像コントロール毎に関数を書き直す必要が出てきてしまいます。

また、Power Apps で作成するアプリを効率よくデバッグするためには、動作が目で見えるかたちで実装しておくことがキモです。そのため、後々のことを考えてわざわざアニメーション用タイマーを作成することにしました。

#まとめ
今回のようなかたちで簡易的ではありますが、パラパラアニメーションを作成することができます。また、ここまで理解できれば、ゲーム内タイマーを利用したゲーム内での時間制御の方法も理解できてきたかと思います。
X, Y, Zが互いに独立なとき、特に独立になるか？

## Introduction : 「独立」と「互いに独立」
事象$A_1,\cdots,A_n$が**独立(mutually independent)**であるとは、積事象$A_1\cap\cdots\cap A_n$の確率が各事象の確率の積で計算できること : 

```math
\begin{eqnarray*}
\mathbb{P}[A_1\cap\cdots\cap A_n] &=& \mathbb{P}[A_1]\times\cdots\times\mathbb{P}[A_n] 
\end{eqnarray*}
```
だと定義されます。特に確率変数$X_1,\cdots,X_n$が独立であるとは、どんな実数$x_1,\cdots,x_n$に対しても、事象$X_1\leq x_1,\cdots,X_n\leq x_n$が独立になることです。

一方で、事象$A_1,\cdots,A_n$が**互いに独立(pairwise independent)**であるとは、どの事象のペアも必ず独立であることを言います。要するに、2つの事象$A_i,A_j$, ($i\neq j$)は選び方によらず独立です。確率変数$X_1,\cdots,X_n$の「互いに独立」も同様に定義されます。


## 1. 問題
独立の定義から、「互いに独立」と「独立」の間の関係について、以下の命題を難しくなく確認することが出来ます。

**命題** : 確率変数$X_1,\cdots,X_n$が独立なら、特に互いに独立である。

**証明** : $X_1,\cdots,X_n$が独立ならば、$X_1,\cdots,X_{n-1}$が独立であることを示せば十分です。それぞれの累積分布関数を$F_{X_1,\cdots,X_n}(x_1,\cdots,x_n)$, $F_{X_1,\cdots,X_{n-1}}(x_1,\cdots,x_{n-1})$、各確率変数$X_i$の累積分布関数を$F_{X_i}(x_i)$と書くことにします。このとき、

```math
\begin{eqnarray*}
F_{X_1,\cdots,X_{n-1}}(x_1,\cdots,x_{n-1}) &=&\lim_{x_n\rightarrow\infty}F_{X_1,\cdots,X_n}(x_1,\cdots,x_n) \\
&=& \lim_{x_n\rightarrow\infty}\left(F_{X_1}(x_1)\times\cdots\times F_{X_n}(x_n)\right)\\
&=& F_{X_1}(x_1)\times\cdots\times F_{X_{n-1}}(x_{n-1})\times \lim_{x_n\rightarrow\infty}F_{X_n}(x_n)\\
&=& F_{X_1}(x_1)\times\cdots\times F_{X_{n-1}}(x_{n-1})
\end{eqnarray*}
```
が成り立つので、$X_1,\cdots,X_n$が独立ならば、$X_1,\cdots,X_{n-1}$が独立であることがわかります。■

今回はこの命題の逆が成り立つかを考えてみましょう。

**問題** : $n$は$3$以上の整数とします。確率変数$X_1,\cdots,X_n$が互いに独立ならば、特に独立になるか？


## 2. 解答

結論から言うと**成り立ちません**。次のような反例を構成することが出来ます。

**反例** : $x,y,z=0,1$のいずれかの値をとる確率変数$X, Y, Z$の同時確率質量関数を次のように定義します。

|X|Y|Z|確率|
|:-:|:-:|:-:|:-:|
|1|1|0|1/4|
|1|0|1|1/4|
|0|1|1|1/4|
|0|0|0|1/4|

このとき、$\mathbb{P}[X=1]=\mathbb{P}[Y=1]=\mathbb{P}[Z=1]=1/2$であることに注意すれば、$X,Y,Z$が互いに独立であることを確認できますが、

* $\mathbb{P}[(X,Y,Z)=(1,1,1)]=0$
* $\mathbb{P}[X=1]\mathbb{P}[Y=1]\mathbb{P}[Z=1]=1/8$

が成り立つので独立ではありません。


## 3. 考察
$x,y,z=0,1$のいずれかの値をとる確率変数$X,Y,Z$の同時分布に対して、互いに独立な場合と独立な場合の同時確率質量関数の自由度の違いを比較しておきましょう。独立な場合、同時確率質量関数は3つのパラメータ$t_1=\mathbb{P}[X_1=1],t_2=\mathbb{P}[X_2=1],t_3=\mathbb{P}[X_3=1]$を用いて、次の形で尽くされます。

|X|Y|Z|確率|
|:-:|:-:|:-:|:-:|
|1|1|1|$t_1t_2t_3$|
|1|1|0|$t_1t_2(1-t_3)$|
|1|0|1|$t_1(1-t_2)t_3$|
|1|0|0|$t_1(1-t_2)(1-t_3)$|
|0|1|1|$(1-t_1)t_2t_3$|
|0|1|0|$(1-t_1)t_2(1-t_3)$|
|0|0|1|$(1-t_1)(1-t_2)t_3$|
|0|0|0|$(1-t_1)(1-t_2)(1-t_3)$|

一方で、互いに独立の場合は4つのパラメータ$t_1=\mathbb{P}[X_1=1],t_2=\mathbb{P}[X_2=1],t_3=\mathbb{P}[X_3=1],t_{111}=\mathbb{P}[(X,Y,Z)=(1,1,1)]$を用いて、次の形で尽くされます。

|X|Y|Z|確率|
|:-:|:-:|:-:|:-:|
|1|1|1|$t_{111}$|
|1|1|0|$t_1t_2-t_{111}$|
|1|0|1|$t_1t_3-t_{111}$|
|1|0|0|$t_1(1-t_2-t_3)+t_{111}$|
|0|1|1|$t_2t_3-t_{111}$|
|0|1|0|$t_2(1-t_3-t_1)+t_{111}$|
|0|0|1|$t_3(1-t_1-t_2)+t_{111}$|
|0|0|0|$1-(t_1+t_2+t_3)+(t_1t_2+t_2t_3+t_3t_1)-t_{111}$|

要するに、互いに独立な同時分布のパラメータ空間は4次元あり、このうち$t_{111}=t_{1}t_{2}t_{3}$をみたす3次元の部分空間が特に独立な同時分布になっています。なお、2で挙げた例は$t_{1}=\frac{1}{2}$, $t_{2}=\frac{1}{2}$, $t_{3}=\frac{1}{2}$, $t_{111}=0$に対応するわけです。

## Acknowledgement
忙しいなか3日連続で更新できたのは、みなさんが前の記事をリツイートしてくれたり、伊集院先生から激励してもらえたおかげです。みなさまに感謝を申し上げます。またご質問を頂いたすうがくぶんかの生徒さんに感謝申し上げます。また、<a href="https://twitter.com/norihitoishida">Norihito Ishida</a>さんに2.解答の反例にある同時確率質量関数に間違いがある旨をご指摘いただきました（2/5修正済み）。ありがとうございます。