OmniAICreator/Qiita-1.07M huggingface dataset:
【Laravel】ファイルアップロードのテスト


Laravel6.0

ファイルアップロードのテストで詰まったのでメモ。

## ファイルアップロード

https://readouble.com/laravel/6.x/ja/filesystem.html

```php

    public function update(Request $request)
    {
        $path = $request->file('avatar')->store('avatars');

        return $path;
    }
```

`filesystems.php`が下記の場合、
ファイルが保存される場所は`storage/app/avatar/`


```php:filesystems.php
'default' => env('FILESYSTEM_DRIVER', 'local'),

 'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/html'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
        ],

    ],


```

## ファイルアップロードのテスト

https://readouble.com/laravel/6.x/ja/mocking.html

```php
    public function testAlbumUpload()
    {
        Storage::fake('photos');    // ここの記述が間違っていた

        $response = $this->json('POST', '/photos', [
            UploadedFile::fake()->image('photo1.jpg'),
            UploadedFile::fake()->image('photo2.jpg')
        ]);

        // ひとつ以上のファイルが保存されたことをアサート
        Storage::disk('photos')->assertExists('photo1.jpg');
        Storage::disk('photos')->assertExists(['photo1.jpg', 'photo2.jpg']);

        // ひとつ以上のファイルが保存されなかったことをアサート
        Storage::disk('photos')->assertMissing('missing.jpg');
        Storage::disk('photos')->assertMissing(['missing.jpg', 'non-existing.jpg']);
    }
```

`storage/app/avatar`に保存されるファイルのテストをしたくて
`Storage::fake('avatar');`と記述していた。

正しくは
`Storage::fake('local');`と記述する必要がある。

書き直すと下記のようになる。

```php
public function testAlbumUpload()
    {
        Storage::fake('local'); 

        $response = $this->json('POST', '/photos', [
            UploadedFile::fake()->image('photo1.jpg'),
            UploadedFile::fake()->image('photo2.jpg')
        ]);

        Storage::disk('photos')->assertExists('avatar/photo1.jpg');

        Storage::disk('photos')->assertMissing('avatar/missing.jpg');

    }
```
Arduinoで筋電センサを使う

この記事は、arduinoで筋電センサ（MyoWare）を使うためのものです。１個当たり5500円以下で購入出来ます。直下に筋肉がある程度ないと、反応しません。また、アースとして、肘など筋肉のないところを基準点として使います。
https://www.switch-science.com/catalog/2682/

#接続方法
_ + <->5V
_ - <->GND
_ SIG <->A0
![MYO.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/bd426572-21fe-57fb-809a-abddf00a2798.jpeg)


#プログラム
A0端子の値を表示するシリアルプロッタで表示するプログラムです。

```java:myo.ino
void setup() {
  Serial.begin(9600);
}

void loop() {
  int value = analogRead(0);
  Serial.println(value);
  delay(20);
}


```
rails s 時のエラー「Address already in use - bind(2) for "0.0.0.0" port 3000」の解決法【初心者】

環境


## 結論：別のポートで立ち上げるのが早い

```rails s -p 3001```というコマンドを入力すればOKです。

サーバーを立ち上げる際のlocalhost:3000は実は3000以外にも数字があるので3001番などで立ち上げるのが手っ取り早いです。


## エラー内容

rails sをすると以下のようなエラーが出ます。

```
/Users/shogo/environment/sample_app/vendor/bundle/ruby/2.6.0/gems/puma-3.9.1/lib/puma/binder.rb:269:in initialize': Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE)
```


## 解決方法

localhost:3000が使われているという意味なので、localhost:3001番でサーバーを立ち上げてあげます。

以下のコマンドをターミナルに入力します。
```rails s -p 3001```

これで解決です。

どうしても3000番でサーバーを立ち上げたいということであれば以下のURLを参考にしてください。

備忘録として手短に。何かあれば追記します。


[もっと詳しくみるにはこちら→rails sが通らない](http://hyottokoaloha.hatenablog.com/entry/2015/09/17/144100)
IntelliJでMavenアーティファクトのダウンロードが終わらない(めちゃめちゃ時間がかかる)

去年の夏ぐらいより開発環境をEclipseからIntelliJに移行したけど、Eclipseの時よりも頻繁にMavenアーティファクトのダウンロードが終わらない事象に遭遇するようになりました。
環境は以下です。

* CentOS 7.7
* IntelliJ IDEA Community Edition 常に最新(2020年1月現在は2019.3.1)

正確にはIntelliJ上の表示で、アーティファクトはダウンロード完了になっているものの、処理経過時間はカウントアップを続け、約15分くらい経つと次の処理に移ります。

この[約15分で思いつくのは、ソケット通信の送信タイムアウト](https://int128.hatenablog.com/entry/20100514/1273865819)なので、
Mavenリポジトリに使用している社内のNexusとか、通信経路上のリバースプロキシ等々を疑いました。

しかし、mvnコマンドを使用した場合では事象が発生しないので、IntelliJ側に何らかの問題があるように思えます。

なのでIntelliJ側の設定をいろいろ試してみた結果、設定画面の```ビルド、実行、デプロイ > ビルド・ツール > Maven > ランナー```にある```バックグラウンドで実行```のチェックを外したところ、解消されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387890/8559f6a4-898d-dcf7-366e-250494684258.png)


* プロジェクト毎に設定するのは面倒なので、新規プロジェクトの設定画面の方で```バックグラウンドで実行```のチェックを外しておきました。


継続して様子を見て、また再発するようだったら報告します。
Arduinoでサーボモータを使う

この記事は、arduinoでサーボモータ（SG90）を使うためのものです。１個当たり200円以下で購入出来ます。電力的にはarduino１台で１個フルに使っても大丈夫なモーターです。そんなにパワーは出ません。


#接続方法
赤<->5V
茶<->GND
橙<->4(Digital)
![SERVO.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/88d60645-1ede-d14c-57e2-fee7e7c26b64.jpeg)

#プログラム

```java:servo.ino
#include<Servo.h>
 
Servo servo;
 
void setup(void){  
  servo.attach(4);
}
 
void loop(void){
  servo.write(0);
  delay(500);
  servo.write(30);
  delay(500);
  servo.write(60);
  delay(500);
  servo.write(100);
  delay(500);
}


```
【iOS】APNS証明書登録手順 2020年版

# 概要
定期的にUIが変わってどれをどう選んで良いのか分からなく
なる場合もあるので2020年版の登録手順についてまとめました。

# 登録手順

## 1. キーチェーンで証明書署名要求の作成

こちらは他にいっぱい記事があると思うので割愛。

## 2. iOS Dev Centerで作成

### Apple Push Notification service SSL (Sandbox & Production)を選ぶ

もはやここを書きたくて記事にしたと言っても過言ではない。
どれを選べば良いのか分からなかったのですが、こちらです。
![スクリーンショット 2020-01-27 11.57.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11800/1fd1d17d-188f-973e-6c34-0c3fb9368f36.png)

### 対象となるApp IDを選択
![スクリーンショット_2020-01-27_11_57_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11800/b0114c14-c2ed-ad3d-a11c-25beaced0f33.png)

### 作成した証明書署名要求ファイルのアップロード
![スクリーンショット 2020-01-27 11.57.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11800/d45f8a34-9f95-1127-c3a1-329e29aa9910.png)

あとはダウンロードするだけです。

誰かのお役に立てば。
Arduinoで２軸ジャイロセンサを使う

この記事は、arduinoで２軸ジャイロセンサ（）を使うためのものです。１個当たり400円以下で購入出来ます。小さいのが特徴です。
http://akizukidenshi.com/catalog/g/gK-04912/
※ジャイロセンサとは角速度を求めるセンサです。重力に方向に対して絶対的な角度は出せません。単位時間あたりの角度の変化を調べられます。


#接続方法
1<->A0
2<->A1
7<->GND
8<->5V
![vib.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/f61a51a2-d44e-74d3-3ee8-f62166c72a38.jpeg)

#プログラム
説明書によると1.35Vが基準値なので、5Vで動くArduinoの値に変換します。
1.35/5.0*1024 = 276.48
実際には少しずれるようです。

シリアルプロッタで確認するプログラム例です。

```java:jyro2axis.ino
float x,y;

//1.35/5.0*1024

void setup() {
  Serial.begin(9600);
}

void loop(){
  x += analogRead(0)-296.46;
  y += analogRead(1)-292.9;
  Serial.print(x);
  Serial.print(",");
  Serial.println(y);
  delay(10) ;
}


```
Arduinoで加速度センサを使う

この記事は、arduinoで加速度センサ（KXR94-2050）を使うためのものです。X,Y,Zそれぞれの軸の加速度を計測できます。１個当たり850円で購入出来ます。
http://akizukidenshi.com/catalog/g/gM-05153/
※静止状態において重力加速度がわかるので、姿勢がわかります。動いているときには、動きの加速度が加わるので、絶対的な姿勢はわかりません。

#接続方法
![IMG_5685.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/c0615d93-df5c-7eb6-9663-e4b041ad2c64.jpeg)

1<->5V
2<->5V
3<->GND
5<->GND
6<->A2
7<->A1
8<->A0

#プログラム
説明書によると1.65Vが基準値（ゼロＧ）です。

シリアルプロッタで確認するプログラム例です。
３つの値の場合、x,y,zとなるように出力すると、シリアルプロッタで３つのグラフが表示できます。print命令は改行なし、println命令は改行ありで、最後のzだけ、改行します。

```java:acce.ino
void setup() {
  Serial.begin(9600);
}

void loop() {
  int x = analogRead(0);
  int y = analogRead(1);
  int z = analogRead(2);
  Serial.print(x);
  Serial.print(",");
  Serial.print(y);
  Serial.print(",");
  Serial.println(z);
  
  delay(20);
}


```
ChatWorkでファイル添付のタイムライン表示順が変更。良いアップデート！

2020年1月27日より
タイムラインでのファイルの表示位置が変わるそうです。（私はまだ反映されておりませんが）

今までは``ファイル添付``→``メッセージ``でしたが
今回のアップデートで``メッセージ``→``ファイル添付``として表示順が変わるそうです。

![202001_timeline_change_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452135/589f6849-bfbb-c257-7f0a-4fed1da71184.png)

これはタイムライン上も添付するモーダル上も一緒になるようです。

![202001_timeline_change_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452135/f5885be3-50f1-39e4-22a5-4fb344c70657.png)

覚えている限りで、今までのアップデートの時系列では
最初は、ファイル添付のみ
次に、ファイル添付とメッセージも一緒に送れるように
で今回、メッセージとファイル添付という形になったと記憶しています。

すごく細かい内容ですが、メッセージを送信して確認してもらってからファイル添付という使い方をすることが多いのでユーザのことを意識したすごくいいアップデートだなと思いました。

https://blog-ja.chatwork.com/2020/01/sendfile.html
プログラミング学生のノマド場所の紹介

福岡近郊からプログラミング学校の通っている者です。ノマド作業場所を探している人向けに僕がオススメな場所を紹介します。混雑時や長時間の利用は、お店やお客さんの迷惑になりかねないので、配慮して活用しましょう。

# オススメのノマドカフェ
|場所  |県名  |Wifi  |電源  |飲食  |備考  |
|---|---|---|---|---|---|
|ジョイフル空港店／蒲田店 |福岡県|○<br><br>30Mbps程度  |○<br><br>電源位置はお店によって異なる  |モーニング・ランチ・ドリンクバーがあるお手頃|<br>郊外のジョイフルだと比較的空いているので長時間の利用が可能。集中できる。
|コメダ珈琲店土井店  |福岡県|○<br><br>70Mbps程度  |△<br><br>２〜３席程度  |モーニングはオススメ！ |wifiスピードが速いのでe-Learningなど動画の勉強ができる  |
|ドトールコーヒーショップ 地下鉄博多駅筑紫口店  |福岡県|○<br><br>2Mbps程度  |×  |モーニングはオススメ！ |通学前にちょろっと作業するのに最適！<br>wifiはFukuoka_city_wifiなので速度は期待できない  |
|福岡空港3Fフードコートエリア |福岡県|○<br><br>30Mbps程度  |×  |飲食したことがない |空港から地下鉄を使う前にちょろっと作業するのに最適！<br>wifiはAriportWifi。時間帯により快適性が変わる<br>人の行き来が多いので集中できない。  |
|福岡空港カードラウンンジ |福岡県|○<br><br>90Mbps程度  |○<br><br>電源のある作業スペースが広い  |フリードリンクは飲み放題 |空港から地下鉄を使う前にちょろっと作業するのに最適！<br>wifiはAriportWifi。時間帯により快適性が変わる |

# 福岡以外のノマドカフェ
イベントや遊びで遠方に出掛けた時に活用したノマド作業場所を紹介します。

|場所  |県名  |Wifi  |電源  |飲食  |備考  |
|---|---|---|---|---|---|
|セントレアカードラウンジ |愛知県  |○<br><br>5Mbps程度  |○<br><br>電源のある作業スペースが広い  |なんとビールが飲み放題！！！<br>トマトジュースもオススメ！ |出入り自由なので空港内の飲食店で食べるのもOK！<br> 愛知に行く時はよく利用する<br>飲み過ぎ注意です！！！ |
|コメダ珈琲店 |愛知県  |○<br><br>70Mbps程度  |△<br><br>２〜３席程度  |愛知に来たらコメダでシロノワールを食べよう（笑） |モーニングで利用する人が多い。朝から混んでいることもある。 |
|ドトールコーヒーショップ |愛知県  |○<br><br>30Mbps程度  |△<br><br>お店によっては電源がないところもある  |モーニングがお手頃 |モーニングで利用する人が多い。朝から混んでいることもある。 |

これからもいろんなノマド作業ができそうな場所を探して、良い場所があれば紹介していきたいと思います。
homebrewでyarnインストール

# 環境

`macOS Mojave 10.14.6`

# 準備

Homebrewをインストールしておく。

参照：[macOSにHomebrewをインストール](https://qiita.com/pypypyo14/items/4bf3b8bd511b6e93c9f9)

# 実装
```:ターミナル
$ brew install yarn --ignore-dependencies
```


`--ignore-dependencies`をつけておくと、複数nodeの依存関係を無視させることができる。

nodeの管理を予めnodebrewで行なっていて、nodebrewとyarnをhomebrewでインストールするとお互いのnodeに依存関係が生まれてしまいエラーが起きるようです。

というのもyarnをインストールするとnodeも一緒にインストールされてしまい、nodebrewが使うnodeのPATHをyarnが使うnodeのPATHに変更されてしまいnodebrewのnodeが使われなくなってしまうようです。

```:ターミナル
$ brew list
yarn

$ yarn -v
1.21.1
```

インストール完了。
OCI 大阪リージョンリリース

# OCI 大阪リージョンリリース

2020/1/24からOracle Cloudの大阪リージョンが利用できるようになりました。
AD数は東京と同じく1です。
https://docs.cloud.oracle.com/en-us/iaas/releasenotes/changes/b792b6a2-b78f-463e-9af9-5494960c302d/
https://docs.cloud.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm

## 東阪リージョン間の差異

基本的なサービスは揃っていますが、一部差異があります。

### 東京にあって、大阪にない

||Japan East (Tokyo)|Japan Central (Osaka)|
|---|:-:|:-:|
|Oracle Cloud Infrastructure API Gateway|○|×|
|Oracle Cloud Infrastructure Compute GPU|○|×|
|Oracle Cloud Infrastructure Compute HPC|○|×|
|Oracle Analytics Cloud|○|×|
|Oracle Blockchain Platform|○|×|
|Oracle Content and Experience|○|×|
|Oracle Developer Cloud Service|○|×|
|Oracle Digital Assistant|○|×|
|Oracle Identity Cloud|○|×|
|Oracle Integration|○|×|
|Oracle Java Cloud Service|○|×|
|Oracle Mobile Hub|○|×|
|Oracle NoSQL Database|○|×|
|Oracle SOA Suite Cloud Service|○|×|
|Oracle Visual Builder|○|×|
|Oracle WebCenter Portal Cloud Service|○|×|

### 大阪にあって、東京にない

||Japan East (Tokyo)|Japan Central (Osaka)|
|---|:-:|:-:|
|Oracle Cloud Infrastructure Storage Gateway|×|○|
|Oracle Database Cloud Service|×|○|
|Oracle Database Exadata Cloud Service|×|○|

※メニューに出てこないもの、メニューに出てくるけど使えないものがあります

全体の利用可能サービス一覧はこちら
https://www.oracle.com/cloud/data-regions.html#apac
Cloud RunでNode.jsのconsole.log, debug, warn, errorでログ出力するとどのように表示されるか

[公式に記載の通り](https://cloud.google.com/run/docs/logging?hl=en)Cloud RunのログはStackdriver Logging に自動的に送信されます。

下図のデフォルトのログ出力を確認すると500エラーで左のアイコンが `!!` になっていたり、404エラーで `!` になっていたりします。

<img width="453" alt="スクリーンショット 2020-01-27 11.20.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40689/e05ac31d-03ca-af10-9c5f-7cb6a6c4fa66.png">

[Stackdriverのドキュメント](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity)を確認すると9つのレベルが用意されており、Node.jsで以下のログ出力を行った場合にどのように表示されるのか確認しました。

```js
    console.log('This is log.')
    console.debug('This is debug.')
    console.warn('This is warn.')
    console.error('This is error.')
```

結果は下図の通りで、全て同じレベルで表示されました。

<img width="337" alt="スクリーンショット 2020-01-27 11.28.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40689/cd55fda9-60ba-c976-122f-945cac397e13.png">

レベルで制御する場合は[Stackdriver Logging クライアント ライブラリを使用して](https://cloud.google.com/logging/docs/reference/libraries)出力する必要があるかもしれません。
Laravelでデプロイの都度キャッシュを飛ばすのはcache:clearではだめ

だめと書いてますがサーバーが1台の場合は特に問題ないと思います。
また、Blue-GreenDeployにおいてもあまり気にする必要はないかもしれません。

今回はローリングアップデートでデプロイした際に`php artisan cache:clear`で駄目だったのでその回避方法を紹介します。

## ローリングアップデートで死ぬ
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89213/8b3e6244-4b1f-e7b7-f918-9cb5bc23cbb8.png)

今回はサーバー（インスタンス）が２台あり、それぞれをローリングアップデートでデプロイしているケースです。
１台目のデプロイ時に`php artisan cache:clear`でキャッシュを消していました。
このとき、２台目のまだリリースが完了していないアプリケーションにリクエストが流れ、そのキャッシュが作られたことにより、１台目のアプリケーションでキャッシュから取得したデータがロジック変更によりエラーになってしまいました。

ではどうしたらよかったか。

## 違うキャッシュキーを参照するようにする
１台目と２台目でキャッシュキーが異なれば１台目ではキャッシュが取得できないので新たに取得処理・キャッシュ生成が行われます。また、そもそもキャッシュをクリアする必要すら不要になります。
デプロイする都度、その世代のキャッシュキーを生成することで問題は解消されます。

Laravelの`config/cache.php`にはprefixという項目があり、`CACHE_PREFIX`という環境変数で変更できます。

```php:cache.php
'prefix' => env(
    'CACHE_PREFIX',
    str_slug(env('APP_NAME', 'laravel'), '_') . '_cache'
),
```
※CACHE_PREFIXはキャッシュを`file`や`array`指定時には利用されません。

## デプロイの都度一意のキャッシュキーを生成
今回はCircleCIでの例です。

```bash
echo -n "CACHE_PREFIX=" > .env | echo $CIRCLE_SHA1 | cut -c -10 >> .env
```

CircleCIでは`$CIRCLE_SHA1`で最終コミットのハッシュが取得できます。これを利用し、この先頭から10桁を.envに書き出しました。
これでデプロイする都度キャッシュキーはリフレッシュされます。

同じことでお困りの方がいたら参考にどうぞ。

## 追記
DBのキャッシュとセッションキャッシュが両方消えて困った！という方は次の方法をご検討ください。

まずはmemcachedの設定をDB向けとセッション向けで分離します。

```php:config/cache.php
'db_memcached' => [
  // 内容はmemcached項目を参照
],
'session_memcached' => [
  // 内容はmemcached項目を参照
],
```

そして`.env`のDBのキャッシュドライバとセッションストアの指定を変更

```file:.env
CACHE_DRIVER=db_memcached
SESSION_STORE=session_memcached
```

これでDBのキャッシュとセッションのキャッシュを分離できました。
続いて`db_memcached`のみprefixを与えます。

```php:config/cache.php
'db_memcached' => [
  // 内容はmemcached項目を参照
  'options' => [
    Memcached::OPT_PREFIX_KEY => env('DB_CACHE_PREFIX', '')
  ]
],
```

あとは先程のデプロイ手順同様にDB_CACHE_PREFIXを生成してあげることでデプロイ毎にDBキャッシュだけ更新されます。
めでたしめでたし。
Dockerfile書いてみた

[この前の記事](https://qiita.com/sfead/items/0ff1c84b33b944d82319)で作成した環境をDockerfileで書いてみたので、メモ。

# まず書いて動かしてみた
[効率的に安全な Dockerfile を作るには](https://qiita.com/pottava/items/452bf80e334bc1fee69a)、実際にshell上で動かしたコマンドをそのままDockerfileにすれば良いとのことで、メモから抽出して作ったのがこちら。


    FROM ubuntu:18.04

    ENV https_proxy "xxxxxx"
    ENV http_proxy "xxxxxx"

    RUN apt -y update
    RUN apt -y install vim
    RUN apt -y install python3.8
    RUN apt -y install curl
    RUN apt -y install python3-pip
    RUN pip3 install numpy
    RUN pip3 install torch

## Warningが出てくるが無視してOKらしい
dockerbuild下にDockerfileを配置して、

    docker image build -t myubuntu dockerbuild
すると、何やら色々動いてくれるが、ところどころ以下のWarningが出てくる…

    WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
    debconf: delaying package configuration, since apt-utils is not installed

[この記事](https://tech-blog.cloud-config.jp/2019-09-09-dockerfile-apt-apt-get-source-tips/)によると全然無視して良いっぽい。

## Torchのinstallでkillが発生する
いい感じに動いてくれていると思ったら、Torchのinstall中にいきなりkillで終了してしまい、最後でうまくいかなかった。

[こちらの記事](https://qiita.com/bwtakacy/items/35fe33c7abc88b9314a3)がすでに通った道で、OOMでのkillが走っていた模様。
こちらはdocker for Windowsだが、解決策は一緒で「setting」「Advanced」からMemoryの部分をいじる。
自分は2048MBから4096MBまで上げたところ、docker imageのbuildは無事終了。

    docker image ls
でmyubuntuが追加されていることを確認してrun。

    docker run -it -d --name ubuntu1804 myubuntu
    docker exec -it ubuntu1804 /bin/bash

bashからpython3, torchの確認までできたので、[この前の記事](https://qiita.com/sfead/items/0ff1c84b33b944d82319)と同じ環境がDockerfileで作れたはず！
Play Console デバイス一括除外スクリプト

注意：11/2からは新しいPlay Consoleを使わないといけなくなるため、下記の方法ではデバイスを一括除外できなくなります

Androidアプリ開発において、公開対象のデバイスを制限したい場合があります。
今までは[このページ](https://qiita.com/kookaa/items/1c4e2d674b67fb911250)のスクリプトで一括で行えていたのですが、最近アクセスすると方法が変わっていたのでスクリプトを記載します。（2020/01/27）

まずは画面を切り替える必要がありますので、下記の画面の右端の黒になっているレイアウト変更ボタンをタッチして画面を切り替えます。

<img width="1001" alt="スクリーンショット 2020-01-29 17.41.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56144/dc78bbe6-532f-06b4-3378-b8aeaf6ddb84.png">

切り替えると下記のような画面になると思います。
チェックがついているのは既に除外しているためで、デフォルトではチェックがついていないはずです。
<img width="940" alt="スクリーンショット 2020-01-27 11.14.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56144/8a431b4c-5953-ace8-b367-6a9d1d8a90a2.png">

<img width="941" alt="スクリーンショット 2020-01-27 11.14.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56144/abdd66d0-dff6-f63e-0c14-885138838d76.png">

この状態で、コンソール画面を開いて下記のスクリプトを実行します。

```javascript
let max_page = 257 // 切り替えるページ数

for (var i = 1; i < max_page; i++) {
	document.getElementById('gwt-uid-221').click();　// 除外ボタン
	document.getElementsByClassName('GNVPVGB-f-b')[1].click(); // 次へボタン
}
```

[getElementByClassName](https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByClassName)

forの条件はページ数によって変更してください。
これで少し時間は掛かりますが一括で変更できるようになります。

尚、Javascriptを実行するためには下記URLが参考になります。
基本的にはコンソールログに直打ちで実行させます。

[デバッグのお供に！javascriptでコンソールログを出力する方法を解説](https://www.sejuku.net/blog/87923)

＜追記：2020/01/29＞
一括除外した後にサポート対象の端末が増えると上記の方法が使えなくなりますので、新しくスクリプトを作成しました。
下記でサポート対象のデバイスを見つけたらアラートを出して、サポート対象から除外を手動で行うスクリプトです。

＜修正：2020/03/18＞

```javascript

page_num = document.getElementsByTagName("strong")[1].innerHTML;    // 最大ページ数
page_num -= 1;

for (var i = 0; i < page_num; i++) {
   // document.getElementById('gwt-uid-221').click();　// 除外ボタン
    if (check_in_page()) {
        break;
    }
    // 「次へボタン」をクリックして次のページに遷移する
    document.getElementsByClassName('GNVPVGB-f-b')[1].click();
}
alert("Check Done")

// 各ページでのスクリプト
function check_in_page() {

    // ページ内のデバイス数
    // 基本的には30デバイスで固定されているため変更しないこと
    device_num_in_page = 30;

    // ページ内に記載のデバイスを上から順にチェック
    for (var i = 0; i < device_num_in_page; i++) { 

        // ステータスを取得してチェック
        // １行が長いため何とかしたい
        var status = document.getElementsByTagName("tbody")[11].getElementsByTagName("tr")[i].getElementsByTagName("td")[4].getElementsByTagName("div")[0].innerHTML;
        if (status == "サポート対象") {
            var device_name = document.getElementsByTagName("tbody")[11].getElementsByTagName("tr")[i].getElementsByTagName("td")[1].innerHTML;
            if (device_name.match(/sense2/)) {
              // sense2がサポート対象でも何もしない
            } else {
                // どの行がサポート対象（チェックが入っていない）かアラートする
                alert((i+1) + " row detect !!");
                return true;
            }
        }
    }
    return false;
}
```
継承など

##【継承】
→すでに作成したクラスをもとに新たなクラスを作成すること（クラスを拡張すること）
→継承のもとになるクラスをスーパークラス、新しいクラスをサブクラスという。
→extendsというキーワードを使う
→サブクラスはスーパークラスのメンバを引き継ぎ新たに追加したメンバと同じように呼び出せる
→サブクラスのコンストラクタの先頭にスーパークラスの引数のないコンストラクタが呼び出される
→コンストラクタ内で```super(引数);```を記述するとスーパークラスのコンストラクタを指定して呼び出すことができる


```
class Super{} //スーパークラス

class Sub extends Super{} //サブクラス
```

##【メンバへのアクセス】
→スーパークラスのprivateメンバにはサブクラスからもアクセスできない
→```protected```メンバにすることでサブクラスからもアクセス可能

##【オーバーライド】
→スーパークラスと同名のメンバをサブクラスで定義し新たな処理を記述するとスーパークラスを引き継いだ新たなメンバを使える
######オーバーロードとの違い
※オーバーロード→引数の形式が異なる同名メソッドの定義
※オーバーライド→サブクラスで同名かつ同形式の引数を持つメソッドを定義すること

##【final】
→メソッドにつけるとサブクラスでのオーバーライドができなくなる
→フィールドにつけると値の変更が不可能になる
→クラスにつけるとクラスを拡張できなくなる

##【Objectクラス】
→すべてのクラスはObjectクラスを受け継いでいて、スーパークラスを指定しないクラスは自動でObjectクラスのサブクラスとなる。
####Objectクラスがもつメソッド
①```boolean equals(object obj)```
→オブジェクトが引数と同じものであるかを調べる
②```Class getClass()```
→オブジェクトのクラスを返す
③```String toString()```
→オブジェクトをあらわす文字列を返す
【備忘録】Office365の各グループの機能まとめ　その2

Office365の各グループはややこしい。ってことで前回、[【備忘録】Office365の各グループの機能まとめ　その1　](https://qiita.com/hisssa0102/items/1a75c39d5d18cb20386a)にまとめてみた。ユーザー目線でまとめてみたけど、管理者目線でも使い分けしたほうがいい部分があり、まとめてみた。

切り口も別物なのですが、ご容赦を。

2020/08/08ネストに関して加筆しました。


#Intuneでの、アプリケーション配布

Intuneで管理しているデバイスに、クライアントアプリをインストールを設定できる（強制、任意とか）。メールが可能なセキュリティグループ、セキュリティグループ、それからOffice365グループも使える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/ffd5ec01-536b-08d9-7cc9-43dbc021ae15.png)

ネストされているグループでも配布可能対象に設定できます。親グループにアプリケーション配布を設定すれば、配下のユーザーのデバイスにもアプリのインストールを構成できます。


#AzureADでの、条件付きアクセス

メールが可能なセキュリティグループ、セキュリティグループ、Office365グループ、配布リストもも使える。

配布リストも割り当て出来て、対象ユーザーのサインインのレポートにも表示されてた。驚き。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/7f8eb046-30af-3ca6-9062-21c7c1fc6730.png)

ネストされているグループでは、入れ子になっているグループには付与できない。
個別に設定する必要があります。


#AzureADでの、グループベースのライセンス付与

特定のグループのメンバーには、特定のライセンスを自動付与できる。
メールが可能なセキュリティグループ、セキュリティグループが使えるけど、Office365グループは使えない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/d73f888a-1f18-6460-932f-abcaa4998c9c.png)

ネストされているグループでは、入れ子になっているグループには付与できない。
個別に設定する必要があります。


#AzureADでの、エンタープライズアプリケーションへのアクセス権付与

Azure AD AppProxyでのアプリケーション割り当てや、外部SaaSの割り当てもグループベースで割り当ても、グループベースで行える。

先ほどのライセンス付与と同じく、メールが可能なセキュリティグループ、セキュリティグループが使えるけど、Office365グループは使えない。

ネストされているグループでは、入れ子になっているグループには付与できない。
個別に設定する必要があります。


#Azureポータルでのグループ作成
Azure Portalでは、セキュリティグループとOffice365グループしか作成できない。
配布リストやメールが可能なセキュリティグループをつくりたいばあいは、Microsoft365管理センターであれば作成できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/6d6db922-27ae-e086-4a4c-750dd5a34bff.png)


#まとめてみた

|配布リスト|セキュリティグループ|メールが可能なセキュリティグループ|Office365<br>グループ|SharePointグループ|備考| 
|:-:|:-:|:-:|:-:|:-:|:-:|
|-|Intuneでのアプリ配布|Intuneでのアプリ配布|Intuneでのアプリ配布|-|-| 
|条件付きアクセス割り当て|条件付きアクセス割り当て|条件付きアクセス割り当て|条件付きアクセス割り当て|-|ネストしている場合、子グループには適用されない| 
|-|グループベースのライセンス付与|グループベースのライセンス付与|-|-|ネストしている場合、子グループには適用されない| 
|-|エンタープライズアプリケーションの割り当て|エンタープライズアプリケーションの割り当て|-|-|ネストしている場合、子グループには適用されない|  
|-|Azureポータルでの作成|-|Azureポータルでの作成|-|

#所感

その2で書いた機能をユーザーが設定することはあまりなくて、管理者側が設定することがほとんど。

とはいえメンバーのメンテナンスをユーザー側に渡すケースも多いはず。ユーザー目線だと、１つであれもこれもできたほうがいいのだけど、エンタープライズアプリケーションの割り当てには365グループ(=Teams）は使えない。残念。


たとえば、ある部門が導入したSaaSとかAzure AD AppProxyの対象ユーザーの割り当て（条件付きアクセスを含む）をその部門で実施させたい場合は、「メールが可能なセキュリティグループを作成し、メンテナンスしてもらう」とするのが最上。利用者全体にメールでの一斉周知にも利用できるし、Outlookからメンバーメンテナンスも委任できる。
「必要なグループをすべて指定してもらう」というのも手ですが。

AzureADに関連するアクセス権のメンバー管理する場合は、メールが可能なセキュリティグループがベターではないだろうか。


配布リストで条件付きアクセスを割り当てられることは意外とはいえ、ライセンス付与や条件付きアクセスには使えませんから、に配布リストで管理するメリットはあまりありませんね。

365グループ単位でライセンス割り当てとか、条件付きアクセスとか構成出来たらなぁ・・・。
遅いクエリーをチェック方法(How to check slow query) in Mysql

皆さん、こんにちは！
![slow-query.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244597/c2a71119-54ba-e7c4-caba-6ba6e600d317.png)


#問題
開発の時、データがあまりなくて、パフォーマンスに気にしない人がいらっさいすか？
今回、スピード改善プロジェクトに参加しました。私のタスクはウェブサイトが遅くロードの原因を調べて、改善法を研究することでした。


一般的に、僕も
・データベース構造から
・複雑Joinクエリーをチェックし
・採番（Index）したところをチェックし
・等を調べました

この以外にSlowQueryを探すために、Myqlのコンフィグを設定しました。

#Slowクエリーをチェック方法
```
# Enable slow query log 
SET GLOBAL slow_query_log = 'ON';
# 遅い時間を定義する。1秒に設定した。
SET GLOBAL long_query_time = 1;
# Slowクエリーログはどこでほぞんされるかをチェックする 
SELECT @@GLOBAL.slow_query_log_file;
# SlowクエリーログPathを再設定する。
SET GLOBAL slow_query_log_file = '/path/to/filename';
```

さらに、ログクエリーを有効して、実行されたクエリー数を確認できたのがよいと思います。

```
SET GLOBAL general_log = 'ON';
# クエリーログはどこでほぞんされるかをチェックする
SELECT @@GLOBAL.general_log_file;
```

以上です。
読んでいただき、ありがとうございました。
【Laravel6.8以降】認証関連のリダイレクト先の設定変更がDRYになったよ

## TL;DR

Laravel6.8以降では認証関連のコントローラーの`RedirectTo`プロパティ等の内容について、個々のクラスで持つのではなく、`RouteServiceProvider`の定数`HOME`に集約されました。

## Before

```php:app/Http/Controllers/auth/LoginController.php
<?php
// 略　
class LoginController extends Controller
{
    // 略
    protected $redirectTo = '/home';
    // 略
}
```

## After

```php:app/Http/Controllers/auth/LoginController.php
<?php
// 略　
class LoginController extends Controller
{
    // 略
    protected $redirectTo = RouteServiceProvider::HOME;
    // 略
}
```

```php:app/Providers/RouteServiceProvider.php
<?php
// 略
class RouteServiceProvider extends ServiceProvider
{
    // 略　
    public const HOME = '/home';
```

## 変更された対象

この変更が行われた対象は、`app/Http/Controllers/auth`配下の以下5コントローラーと、

```
.
├── ConfirmPasswordController.php
├── LoginController.php
├── RegisterController.php
├── ResetPasswordController.php
└── VerificationController.php
```

ミドルウェアの`RedirectIfAuthenticated`です。

```php:app/Http/Middleware/RedirectIfAuthenticated.php
<?php
// 略
class RedirectIfAuthenticated
{
    // 略
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect(RouteServiceProvider::HOME);
        }

        return $next($request);
    }
}
```

## 所感

個人で新規にLaravelのプロジェクトを作成するときなどは、まずログイン後のリダイレクト先を`'/home'`ではなく、`'/'`にしていますが、ログイン後以外も含めたリダイレクト先の設定変更が一箇所で済むようになったのは良いですね。

Laravelの認証のような、もう完成仕切っているイメージのあるコードでも、まだまだDRYにできる余地があるというのが個人的には驚きでした。

## 参考

- [DRY up path to /home (#5173)](https://github.com/laravel/laravel/pull/5173)
Excelで郵便番号と住所を同時に記入する方法　

プログラミングではなく関数ですが、
打ち込みの時間短縮かつ正確性を少し上げることが出来たので、
記録しておきます。

郵便番号と住所の不一致が何件か見つかったりしたので、
会社の事務の人にも便利なはず。
今回は、はがき印刷ウィザード用の住所録名簿の打ち込み作業で使用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/ccd3cac7-1e2e-24e7-547f-39c593dd69dd.png)



ここの 郵便番号欄と住所_1欄を同時に入力する小技。
２ステップだけです。


###①郵便番号欄に関数を入力(連続データを作成しておく)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/a3089416-52be-dfe1-125d-a914cba5b0c7.png)

PHONETIC(指定セル)
→変換前の入力文字を表示

ASC()
→半角で表示



###②住所_1欄に郵便番号を入力し変換する
全角でも半角でもOK
※全角の場合は変換時にスペースキーではなく変換キー使用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/4716c04e-c20a-4716-27c7-83b4851ee112.png)

確定後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/bb2689c5-68a8-abda-2b68-fcd868577409.png)


連続データを作成しておけば連続して打ち込めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/0a6a9878-e3cc-ac3f-a39a-a9c0e59ef74b.png)
プロキシ環境下でのUnityインストール方法

今回は、Windows 7にUnityをインストールしたいと思います。

# Unityのインストール方法

[こちら](https://store.unity.com/ja/download-nuo)のページの`はじめよう`ボタンを押し、`Unity Hub`をダウンロードします。

# Unity Hubの起動
画面の指示に従い、サインインした後にインストールが始まった場合は、正常にインストールできているので、問題ありません。

# Unity Hubでインストールができない場合
Unity Hubでインストールを何回か試みたが、`Personal ライセンスが作成できませんでした。`と表示されインストールできませんでした。
調べたところ、プロキシの設定に問題ある事が分かりました。

## プロキシーを設定してUnity Hubを開く方法

※ Unity Hubを既に１回でも起動した場合は、Windows タスクマネージャーでUnity Hubを選択し、`プロセスの終了`をしてください。

下記のようなバッチファイルを作成し、起動してください。

```sh:Unity起動.bat
@echo off
rem プロキシの設定
set HTTP_PROXY=http://ユーザー名:パスワード@ドメイン名:8080
set HTTPS_PROXY=http://ユーザー名:パスワード@ドメイン名:8080

rem Unity Hubのパスを指定し起動
start "" "E:\Unity Hub\Unity Hub.exe"
```

上記の方法で自分はインストールすることができました。
QRコードからファジングする(sQRCodeFugging.exe{sWebTool})

ver5.2.5.0 から sQRCodeFugging.exe(sWebTool) を同梱した。

# はじめに

私はWebアプリケーションのセキュリティ診断業務を生業にしていますが、、、稀に

- 入力インターフェイスがQRコードがなんですけど・・・

などという相談を受ける時があったりなかったり・・・

まぁ、大抵は、QRコードリーダーを迂回して、サーバ側のWebAPIに直接アクセスすることで、Webアプリケーションのセキュリティ診断テクニックを応用できるので、そうすることで作業(診断サービスの提供)はできるのだけど・・・

- QRコードリーダーを迂回する経路がない
- QRコードリーダーとサーバ間は http ではない(CorbaとかRMIとかDCOMとかRPCとかgRPCとか)ので、サーバに直接って無理(もう、Webアプリケーション診断のサービス対象ではないのだが・・・(>_<))

・・・という際に、このツールを使って、QRコードの画像から、ベースの文字列を抽出し、それに応じたファジングしたQRコードを複数生成できます。

# 画面説明

![sQRCodeFugging1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/9e1bea86-5098-5f53-c036-dd1bd5434ed5.png)

1. ベースとなるQRコードの画像を読み取り(または元となる文字列を直接入力する)
2. 置換パータンを設定する
3. QRコード画像の出力先ディレクトリを設定して
4. 各種設定して・・・
5. 「Create」ボタンで、QRコードの画像が指定されたディレクトリに出力される
6. あとは、印刷などして、QRコードリーダーにひとつずつ読み込ませればいいでしょう

以下、いくつか注意点

- 右上の「ソースとなる文字列」のテキストボックスはURLデコードしてからQRコード作成をするので、「%」とか「+」とかはURLエンコードしておいてくれ
- この URL エンコード/デコードの関係で、文字コードを指定する必要があって、上記のサンプル画像では「shift_jis」になっているけど、大抵は ASCII 系のみだろうから、文字コード系でトラブルことはないと思う
- リストボックスと、その上での置換パターンについては「%s%」が「ソースとなる文字列」を示すマクロ文字になっている(上記のサンプル画像だと「%s%」が「Test」に置換される)

# Android アプリ

手動で、少しずつ試したい場合は、こちら(↓)

- [QRコードを編集ツール Androidアプリ(sQRCodeEditer)](https://qiita.com/tomoki0sanaki/items/1927f53ba69a8f1500b3)

# 画面説明2(QRコード認証のクライアントのQRコードリーダーとして・・・)

ver5.3.0.0 から「sAuthenticator.exe」の同梱に伴い、QRコードリーダー的側面が強くなってきた。
→
QRコードを読み取り、otpauthスキームのURIの場合、「sAuthenticatior.exe」を呼び出すことができるようになった。
デスクトップ/画像ファイル/カメラ
(ver6.0.0.6まで未実装)
から、QRコード認証のQRコードを読み取り、「sAuthenticator.exe」へ渡すとパスコードを取得できるようになった。

ver6.0.3.8からカメラからも取得できるようになった([USBカメラを使ってみよう](https://qiita.com/secile/items/21b7da5d32bc44dbb947)の[UsbCamera.cs](https://github.com/secile/UsbCamera)を使用しています)。

![sQRCode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/0dcf9c1c-64ee-1175-b2e8-ca5bc76e0849.png)

# 利用に際して

当然ですが、本ツールは、デバグ用、開発用であり、悪用厳禁ですよ。

# インデックスへ戻る

[sWebTool Manual index](https://qiita.com/tomoki0sanaki/items/b8f571ae296a32f7b434)

# 以上
【ふくだ学習録】SQLアンチパターン part5【19日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)
[PHPフレームワーク CakePHP 3入門](https://www.amazon.co.jp/dp/4798048577/ref=cm_sw_r_tw_dp_U_x_.YIjEbS1K4JY2)

### 今読んでいる本
[SQLアンチパターン](https://www.amazon.co.jp/dp/4873115892/ref=cm_sw_r_tw_dp_U_x_XlokEbJQK2N7P )

# SQLアンチパターンを読んで

### ２１：シュードキー・ニートフリーク（擬似キー潔癖症）
欠番を気にしすぎる時に発生するもの。

#### アンチパターン：隙間を埋める
欠番を埋めるために、最も小さい欠番から情報を埋めていくのはアンチパターン。
不要なクエリ（何番が欠番になっているのか）を投げる必要が出てきてしまう。
また既存行に番号を振り直すのもアンチパターン。番号の振り直しには、競合状態を引き起こす可能性が高く、欠番が多い場合は、さらにその可能性が上がってしまう。また擬似キージェネレータが作成する番号は、最後に作成したキー番号に＋１したものなので、結局は欠番が発生してしまう。

#### 解決策：擬似キーの欠番は埋めない
行番号と主キーは同意ではない。行番号には欠番が発生しない（結果セットに対しての行の順序番号を示すものだから）が、主キーには欠番が発生する。この特性を十分理解した上で活用すべし。

また従来の擬似キージェネレータを使用する代わりに、GUID（グローバル意識別子）を使用することも検討する。GUIDを使用することで、複数のデータベースサーバー間で重複した値を生成することなく、並行して擬似キー作成できるようになったり、欠番を気にすることもなくなる。（ただし１６バイト必要なので、実行時間が長くなるなどのデメリットはある）

### シー・ノー・エビル（臭いものに蓋）
データベースAPIの戻り値を無視したり、アプリケーションコード内に点在するSQLしか読まないことで発生しがちな問題。

#### アンチパターン：SQL文字列を組み立てるアプリケーションコードの側からデバックを開始すること。
最終的に投げられているSQLに対してのエラーから徐々に紐解いていくほうが、結果的に早く解決できる。

#### 解決策：エラーから優雅に回復する
データベースからエラーが返ってくることを想定して、エラー発生時もブランクページを表示させないような処理を書いておく。

### ディプロマティック・イミュニティ（外交特権）
SQLに対してだけ、ベストプラクティスを実施しないがために生まれる技術的負債のことなどを指して使われる言葉。
SQLもGit管理を行なったり、テストコードを記載したりすべき。

#### 解決策：包括的に品質問題に取り組む
ER図を用いた文書化、バージョン管理、テスティングを行う。

### マジックビーンズ（魔法の豆）
アクティブレコード機能に頼りすぎて、それ以外の解決策（技術）を使用しなくなること。柔軟性を失った開発をしてしまうこと。

#### アンチパターン：モデルがアクティブレコードそのもの


#### 解決策：モデルがアクティブレコードを「持つ」ようにする
MVCアーキテクチャとしてのモデルの特性は、「リレーショナルDBに保存してあるデータをオブジェクト指向でのモデルで扱えるようにする」ことである。なので複数のテーブルに対してアクティブレコードを行い、ビジネスロジックを持ったオブジェクトを作成する、といったようにモデルがアクティブレコードを持つ（利用している）状態にすることが重要。

### 砂の城
天災などによって起こりうる影響（事故）に関して、事前に対策を行なっておくべき。という考え方。

#### アンチパターン：想定不足



# 今日の一言
24章はめちゃめちゃためになった！
モデルはドメイン単位で作成すべきやなぁ、って感じたけどCakePHPなら逆にドメイン単位でモデル作成しにくくない？？って感じてしまった。どうなんやろ？
今度Larabvel使ってドメイン単位でモデル作ってみよ！
curl で Cloud Firestore のデータを削除

データのひとつを削除します。
>project-aaa の cities の t0924 を削除

```bash
export GOOGLE_APPLICATION_CREDENTIALS="***.json"
#
ACCESS_TOKEN=`gcloud auth application-default print-access-token`
#
project_id=`jq .project_id $GOOGLE_APPLICATION_CREDENTIALS | sed "s/\"//g"`
echo $project_id
URL='https://firestore.googleapis.com/v1/projects/'$project_id'/databases/(default)/documents/cities'
#
curl -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE $URL"/t0924"
#
```
資料d

DFS探索のつもり。
再帰使いたくなかったので、再帰使わないDFS探索。
クラス使ったやり方のがいいのかもしれないけど、よく分からなかったのでとりあえず。

```cs:Program.cs
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sanc
{
    class Program
    {
        private static int _Idx;

        public static int Idx
        {
            get => _Idx;
            set
            {
                _Idx = value;
                Console.WriteLine(value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            var ExeTree = new Dictionary<int, List<int>>();
            ExeTree.Add(1, new List<int>() { 2, 3});
            ExeTree.Add(2, new List<int>() { 6 });
            ExeTree.Add(3, new List<int>() { 4, 5, 7});
            ExeTree.Add(4, new List<int>() { 8, 9 });
            ExeTree.Add(7, new List<int>() { 10 });

            //A⇒Bを記録
            var MemoryPlace = new List<KeyValuePair<int, int>>();
            Idx = 1;
            var LastIdxes = new List<int>() { 1 };
            int LastIdx;

            while (LastIdxes.Any())
            {
                while (ExeTree.ContainsKey(Idx))
                {
                    var LastIdxInLoop = Idx;
                    var Values = ExeTree[Idx];
                    foreach(var Value in Values)
                    {
                        //行ったことある道でなければif内実行
                        if(!MemoryPlace.Contains(new KeyValuePair<int, int>(Idx, Value)))
                        {
                            MemoryPlace.Add(new KeyValuePair<int, int>(Idx, Value));
                            Idx = Value;
                            LastIdxes.Add(Idx);
                            break;
                        }
                    }

                    //変更があればもう一回ループ.
                    //なければIdxに対して全て行ったValueなのでbreakで抜ける.
                    if (LastIdxInLoop == Idx) break;
                }

                if (LastIdxes.Count > 1)
                {
                    LastIdx = LastIdxes.SkipLast(1).Last();
                    LastIdxes.Remove(LastIdxes.Last());
                    Idx = LastIdx;
                }
                else if(LastIdxes.Count == 1)
                {
                    break;
                }
            }
        }


    }
}

```
e2eテストでタイムアウトさせたい 

e2eテストを書いていて外部サーバーでタイムアウトを発生させる
テストケースを確認したいことがあり
すこしハマったので書きとめておきたい


プラグインはmockttpを使用

```
//外部サーバーを実行しているラッパーメソッド
function method() {
  await api.post(path, request).catch(err => {
    if (err.code === 'ECONNABORTED') {
      console.log('タイムアウト');
    }  
  });
}

function main() {
  method();
}
```

上のような感じで（例がうまくかけないですが）タイムアウトのときになにか処理させるということをしたく
E2Eテストで外部サーバーでの処理をタイムアウトさせたい、ということがあった

外部サーバーの部分を以下のようにモックしてテストを実行
```
const endPoint = await mock.post(path).thenTimeout();
```
こうすると外部サーバーはタイムアウトを返してくれるようになった

ただ、外部サーバーへのリクエストパラメータや呼び出し回数を確認するため
`endPoint.getSeenRequests()`
をしてリクエストの情報を取得しようとしたが、タイムアウトに・・・
endPointをログにだしてみたが`request`に要素は入っている、Countも1でカウントされている


リクエストの情報も確認したいので`thenCallback()`を使うようにした

```
const endPoint = await mock.post(path).thenCallback(async req => {
  await sleep(ms);
  return {
    statusCode: 200
  }
});
```
sleepは引数の時間分スリープするメソッド
テストのタイムアウト時間より長く設定することで、タイムアウトエラーが発生
`endPoint.getSeenRequests()`でリクエスト情報を取得できるようになった


`thenTimeout()`がどういう感じで動いているか
`getSeenRequests()`でどうしてタイムアウトになってしまうのか
まだ理解しきれていないのでまた確認しておきたい
Windows : Apacheをサービス登録として自動起動させる

ApacheをWindowsのサービスに登録し、PC起動時に自動起動させる手順について説明していきます。
※ApacheMonitor.exeをワンクリックでApacheの起動も可能！！！

# 目次
1. Apacheをサービスに登録する
2. 「Apacheを起動」が実施済であること

# 1. Apacheをサービスに登録する
Apacheをサービスに登録するためにはコマンドプロンプトを使います。

![apache-service-launch-windows10-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/4a5ac32f-0871-e428-91ae-da769185035b.png)
コマンドプロンプトを「管理者として実行」で起動します。

![apache-service-launch-windows10-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/293213ce-edeb-aed9-c172-fddd178fece3.png)
まずはApacheディレクトリのbinディレクトリの中に移動します。ディレクトリの移動にはcdコマンドで以下のように実行します。

### ディレクトリを移動するコマンド
```
cd c:¥Apache2.4¥bin
```

![apache-service-launch-windows10-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/9d07ff14-6c8e-d47a-34c7-ad75ceae8926.png)
ディレクトリを移動した後は、以下のコマンドを実行してApacheをWindowsのサービスに登録します。

 
### Apacheをサービス登録するコマンド
```
httpd -k install
```

![apache-service-launch-windows10-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529910/50fe2f61-668b-69dd-8c3f-7e7901c6bc20.png)
設定から「サービス」を表示させるとApacheがサービスに登録されていることが確認できます。

Apacheをサービス登録させるための手順は以上になります。
CSSのgridを使うとSafariで崩れる問題

##環境
- macOS 10.15.2
- Chrome 79.0.3945.130（Official Build)
- Safari 13.0.4 (15608.4.9.1.3)
- Firefox 72.0.2 (64 ビット)

##問題点
下の記事の様にCSSで親要素のサイズを``grid``でのみ指定し明示的に指定しない状態で、子要素でサイズを親要素の最大値に設定すると、ブラウザによって表示のされ方が違う。

###記事
>https://entotsu44.hatenablog.com/entry/2020/01/27/070000

##解決方法
下の様に親要素にも明示的にサイズを指定すると解決する。

```css
.cell {
  width: 100%;
  height: 100%;
  border: solid 2px;
}
```
チャットでコマンドをやり取りして惨劇が起きかけた話

# はじめに
サーバ管理をしていて少しヒヤッとしたことがあったので
ほんとに恥ずかしいし、バカバカしい話なのですが自分への戒めのために記事を書きました。

# TLDL;
- 当たり前だが、チャット上でコードスニペットやコマンドを送るときはちゃんと `` `(バッククオート) ``を使おう。でないと、記号がMarkdownと認識され大変なことになるかも。　※記法によっては`~(チルダ)`でもOK
- 当たり前だが、実行するOSのコマンドは実行前にしっかり内容を確認しよう
- 当たり前だが、ログローテーションはしよう

# 起きた出来事
部内で利用している、Jiraサーバが起動しなくなったので2人で原因調査をしたところ
Jiraのログファイルの肥大化によってストレージを食いつぶしていました。

そこで、Jiraのログ内容を見てみるとログローテーションがしっかりされておらず
ファイルの圧縮や削除がされていませんでした。

```bash:lsの結果
[root@jira ~]# ls -ahl /opt/atlassian/jira/logs/
total 59G
drwx------  2 jira root  68K Jan 24 03:45 .
drwxr-xr-x 15 root root 4.0K Feb 25  2016 ..
-rw-r--r--  1 jira jira 1.2K Jul  1  2019 catalina.2019-07-01.log
-rw-r--r--  1 jira jira 3.8K Jul  2  2019 catalina.2019-07-02.log
-rw-r--r--  1 jira jira 1.5K Jul  5  2019 catalina.2019-07-05.log
-rw-r--r--  1 jira jira 1.5K Jul  5  2019 catalina.2019-07-05.log
-rw-r--r--  1 jira jira    0 Jan 24 03:45 catalina.out
```
※ログは一部のみ表示

そこで

1. 暫定対応として、溜まったログファイルの内「30日前以前に作成されたcatalina.xxxxx.logファイルの削除」
2. 本格対応として、ログローテーションの導入(ファイルの圧縮・削除)

を行うことにしました。

1の対処を行うときにヒヤッとすることが起きました。

```bash:打ちたかったコマンド
[root@jira ~]# find /opt/atlassian/jira/logs/*.*.* -mtime +30 | xargs rm
```
/opt/atlassian/jira/logs/配下の30日前以前に作成された(厳密には変更された)
`*.*.*(e.g. catalina.2019-07-05.logなど)`の削除。

一緒に作業していたメンバーが対象ファイルを削除するコマンドを、チャットで書いて送ってくれたのですが

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254318/0d442edd-c1ae-d88f-c137-8bb831b72b12.png)

となっていました。
コマンド打つ前に気付きましたが、このまま打つと`/opt/atlassian/jira/logs/`の上位ディレクトリを吹き飛ばして大変なことになるとこでした...

# 何が起きたのか
チャット上で

`find /opt/atlassian/jira/logs/*.*.* -mtime +30 | xargs rm`

を打つと、`*.*.*`の前半の`*.*`部分がMarkdownの[強調](https://qiita.com/tbpgr/items/989c6badefff69377da7#-%E5%BC%B7%E8%AA%BFem)と判定されて、斜体になっていました。

ただ、

|通常のドット|斜体のドット|
|:--:|:--:|
| . | *.* |

ん？？
間違い探し？？

ドットはパット見で斜体かどうかもわかりませんｗ

ちゃんとコマンド見たから良かったものの、脳死してコマンド流していたらどうなっていたか...
※まぁ、脳死してコマンド流すことはないですが :innocent:

# おわりに
コードやコマンドにはMarkdownでも利用される様々な記号が登場します。

チャット上でコードスニペットやコマンドをサクッと送るシーンで
しっかりと、`` `(バッククオート) ``を使わないといずれ大変なことになるかもしれないなーと
実感しました。
※`~(チルダ)`など別の記法もありますが。
FullCalendar 月・週・日カレンダーを表示する方法

# はじめに
FullCalendar という素晴らしい強力なライブラリを見つけました。（とても有名だと思いますが、知りませんでした・・・。）
英語のドキュメントばかりなので、日本語で誰かに役に立てばと思いまとめさせていただきました。

今回は月・週・日カレンダーのそれぞれに切り替える方法をまとめました。

#### 関連リンク
関連リンクを下記に載せておくので、必要であれば参考にしてください。。

* 【Rails】 5分でFullCalendar実装する方法
    * https://qiita.com/syukan3/items/68280ce4ff45aa336363


# 前提条件

FullCalendarをアプリケーションに実装済みであること。

Railsアプリケーションで実装ができていない方は上記の記事を参考にしてみてください。
Railsを使ったことがない人でも簡単に実装することができますので、この機会にRuby と Railsをインストールして使ってみてください。


# 実装

javascript に 2箇所ほど追記をすれば実装することができます。


```javascript:app/assets/javascripts/application.js
    $('#calendar').fullCalendar({
        // ***省略***

        // month: "月",  agendaWeek: "週", agendaDay: "日"
        // 不要なテーブルは month, agendaWeek, agendaDay を消すと選択肢が消える。
        header: {
            // ここ
            left: 'month, agendaWeek, agendaDay',
            center: 'title',
            right: 'today prev,next'
        },

        // デフォルトで表示させたいテーブル（この場合は、週のカレンダーを表示させる）
        // ここ
        defaultView: 'agendaWeek',

        // ***省略***
```

## イメージ
こちらは完成イメージとなります。
月・週・日と書かれたボタンを押すことで、それぞれのカレンダー表記に切り替える事ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308256/6f17c4d7-8ed4-ed76-c17a-647f30f482f2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308256/e845fd84-17dc-c133-7089-2b15914d1a1e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308256/e7e77a2b-eccc-0a2a-12a8-563eb1a84fc5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308256/f645939b-a254-fdf1-90c0-88e41fb3513d.png)


# まとめ
公式ドキュメントに載っている事ですが、探すのに時間がかかったためまとめました。
しばらく、このFullCalendar関連の記事をまとめたいと思います。


# 参考
* FullCalendar 公式ドキュメント
    * https://fullcalendar.io/

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
中古パーツでDeepLearning専用の自作PCを組み立てみた

# Background
[yolov3開発者が使っているPCの価格を算出したった。](https://qiita.com/satsukiya/items/ffe303a0e1bd5b46be31) の続きです。
夜1時間や土日に実際にDeepLearningで学習させてみたかったので、自作でPCを組み立ててみました。
普通だったら高めのグラボ積んでWindowsOSでゲームでもくもくを遊ぶヨコシマな目的でパーツを買うものですが、メインではMacBookを使っているのでコストは最小限にしたいと最終的には思い、結局のところは中古パーツで揃えることにしました。

# Parts & Price

|type| Parts | new or used| Price | if new|
|:--:|:--|:--:|--:|--:|
|CPU|AMD Ryzan 5 1400|used|9190|17199|
|GPU|GeForce GTX960|used|9490|56055|
|Mother Board|~~ASUS PRIME B450M-A~~ <br> MSI B450 GAMING PLUS MAX B450|used|~~7460~~ <br> 6480|~~8631~~ <br> 7980|
|Memory|~~DDR4 8G~~ <br> DDR4 8G × 4枚|used|~~2990~~ <br> 2480 * 4 = 9920| 3500 * 4 = 14000 |
|SSD|SSD 2.5 SATA|used|2490||
|PCケース|| used | 3980 ||
|電源|玄人志向 KRPW-BK 750W| new | 7638 ||
||グリス| new | 1320 ||
||自作PC工具セット| new | 1078 ||
||USB| new | 320 ||
||マウス| new | 330 ||
||キーボード| new | 990 ||
||Bluetooth USB| new | 1980 | |
||合計|  | ~~49256~~ <br> 55206 | 新品買うより 60154 オトク |

~~ちょうど、5万円くらいに予算が収まりました。~~
DDR4メモリを8GBから32GBに増設しました。マザボもmicroATXからATXに変更しました。理由は内臓のTVチューナーを取り付けたいためです。(まだ動かん:sweat:)
(2020/11〜)


# Outer

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/UyPwDHGlfWg/0.jpg)](http://www.youtube.com/watch?v=UyPwDHGlfWg)

な、なんだと、、ブ、、ブルジョアめー:angry:

<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/FrameBreaking-1812.jpg/500px-FrameBreaking-1812.jpg" width=50%>
(※　脳内想像図)


macとnvidiaは相性悪そうです（妄想）。


# Reference
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/-oAF9l4MiJE/0.jpg)](http://www.youtube.com/watch?v=-oAF9l4MiJE)
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/rg4WPhnOf1U/0.jpg)](http://www.youtube.com/watch?v=rg4WPhnOf1U)
こっちの方が参考になります！
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発

#モダンなアプリケーション開発
###モダンなアプリケーション開発とは
ソフトウェア業界が培ったベストプラクティスやツールを活用して開発の品質とスピードを向上させることです。

#Salesforce DX
###Salesforce DXとは
Salesforce DXはモダンなアプリ開発をするためツール群です。ですので、いわゆる要件定義、設計、コーディング、ビルド、テスト、リリースといったような流れを包括するようなツールを提供しているものです。

###Salesforce DXが提供しているツール
- ソース駆動開発
- 新しいSalesforceCLI
- IDEやエディタの拡張
- 揮発的なスクラッチ組織
- Pipelinesによる継続的デリバリー
- 継続的インテグレーション
- Partial/Full Sandbox
- 新しい概念のパッケージング

###Salesforce CLI
####Salesforce CLIとは
各種自動化や他のツールとの統合のためのインターフェースです。

####Salesforce CLIを利用してできること
- Salesforceの制御をCLIコマンドで行う
    - 開発およびCI用の組織の生成・破棄
    - ソースを双方向で同期
    - 開発およびテスト用のデータのインポート
    - テスト作成と実行
    - パッケージのライグサイクルの制御

- sfdxコマンドを利用
- シェルスクリプトの中に用意に容易に統合可能

####DevHub環境の作成
Enterprise, Performance, Unlimited エディションの場合、DevHubの機能を有効にできますが、
個人など、DevHub環境を持っていない場合は[こちら](https://developer.salesforce.com/promotions/orgs/dx-signup)からトライアル組織を作成します。

####Salesforce CLIのインストール
[https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm](https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm)

####sfdx コマンド
#####`sfdx force:auth:web:login` --- ブラウザを開いて組織にログイン

```
$ sfdx force:auth:web:login -a MyDevOrg
```
#####`sfdx force:auth:web:login` --- ブラウザを開いて組織にログイン

```
$ sfdx force:auth:web:login -a MyDevOrg
```

20:57
寿司打を自動化してみた【RPA×OCR】

##はじめに

皆さんは[寿司打](http://typingx0.net/sushida/)というタイピングゲームをご存知でしょうか？

回転寿司のように問題が次々に流れてきて、それをどんどんタイピングして点数を稼いで行くというゲームになります。
![寿司打紹介.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431306/d2234136-bf6f-635f-917b-938362dd2f7a.png)

おそらくタイピングゲームでは一番有名？なのではないでしょうか。
(私もブラインドタッチの練習をしていた頃に大変お世話になりました)

私が現在参画しているプロジェクトでは、飲み会の幹事をこの寿司打で決めるという面白い習慣があります。
新卒の子達が先輩にボコボコにされ、その子達が訓練を積んで、次の後輩達をボコボコにする(結果的にみんなタイピングが速くなる)という事ですね。

もはや本来の趣旨を外れているのですが、「これすぐ自動化できそうだな」と思ったので、RPA(UiPath)とOCRで自動化してみました。

■使用環境
OS：Windows
ブラウザ：Chrome
RPA：UiPath
OCR：UiPathデフォルトのtesseractエンジン

■開発時間
2時間程度

##結果

最適化すればもっと速くなりそうですが、しっかりとタイプしてくれています。
![ezgif.com-crop.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431306/746438ca-8694-5c40-de12-e9ab2341176f.gif)
全体の動画は右記参照：[寿司打を自動化してみた](https://youtu.be/7l9FiPtPftw)(YouTube)

アルゴリズムとしては、スクショを撮る→OCRで文字読み取り→読み取り結果をタイピングという単純なもので、正規表現でのマッチングとリプレイス、読み取りエラーのハンドリングを5箇所程度入れています。

最終スコアがどうなるか楽しみにしていたのですが、ここで一つ大きな誤算がありました。。
制限時間の減少速度を、連打ボーナスによる時間の増加が上回り、いつまでも終わらないのでスコアが出ないという状態になりました。
とりあえず放置してみた所、500円皿が100皿を超えたあたりでシステムエラー？によるポップアップが出て強制終了に。

スコアが出ないのはそれはそれで困るので、試しに強制終了となる手前でRPAを止めた所、合計300皿で12万円程度でした。これで新卒の子達に負ける心配はなさそうです。
![寿司打.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431306/39a3c65c-1482-188b-5f98-b7fab2981e96.png)
※380円皿は2週目(180皿)

##まとめ

過去に使用した際の経験上、tesseractの読み取り精度を心配していたのですが、この程度の問題設定なら十分に読み取ってくれました。

最初Pythonでやろうかと思ったのですが、UiPathは画面をクリックすればセレクタを自動で取ってきてくれるので楽ですね。小中規模程度の実装なら、フローチャート形式で書ける可読性の高さのメリットも大きいです(後から見た時にすぐわかる)。

今回は割と問題設定が易しかったので、「これ自動化してみて欲しい」という面白い課題がありましたら教えて頂けると幸いです。

<参考>
Qiita記事
・[RPAは誰でも簡単に作れるという罠](https://qiita.com/jw-automation/items/78d823a6cb278f7015b5) 
・[VBAが組める人ならRPAは簡単に作れるという罠](https://qiita.com/jw-automation/items/38c28016bf5162e76c59)
・[UiPathのコーディングチェックツールを作ってみた【RPA】](https://qiita.com/jw-automation/items/003dd0ef116cf968c3a8)
・[RPAへの理解がぐっと深まる、RPAがよくこける理由](https://qiita.com/jw-automation/items/836391dfde3fb1ac83d6)
・[RPAのオススメ書籍](https://qiita.com/jw-automation/items/3c141c50c7a163943fd9)
・[RPAの開発に向いている人、向いていない人](https://qiita.com/jw-automation/items/828933731611b9ec601f)
・[RPAの推進に必須なRPAOpsという考え方](https://qiita.com/jw-automation/items/53c45b7dfc7a5865c5ff)
・[【AI】Deep Metric Learning](https://qiita.com/jw-automation/items/7bbe1c872fcec7fa6c1d)
・[【AI】Deep Learning for Image Denoising](https://qiita.com/jw-automation/items/f942ea0c6a02e8e50fa2)
・[Deep Convolutional Autoencoderベースの教師なし異常箇所検知](https://qiita.com/jw-automation/items/aea08a5c915d0627803a)

デモ
・[UiPathCodingChecker](https://jw-automation.com/rpa/uipathcodingchecker)：UiPathのxamlファイルからコードを分析
・[AI Demos](https://jw-automation.com/ai/demos)：DeepLearningによる手書き文字認識・異常検知・画像のデノイズ
・[寿司打自動化(YouTube)](https://youtu.be/7l9FiPtPftw)：タイピングゲーム寿司打のRPA×OCRでの自動化
言語処理100本ノック-98(pandas使用):Ward法によるクラスタリング

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の98本目「Ward法によるクラスタリング」の記録です。
前回の非階層型クラスタリングと異なり、階層型クラスタリングをします。ノック結果はクラスタが階層型となる下図の形です(238ヶ国なので大きい・・・)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/bc314831-49e8-0bae-6b43-2544e831576f.png)

# 参考リンク

|リンク|備考|
|:--|:--|
|[098.Ward法によるクラスタリング.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/098.Ward%E6%B3%95%E3%81%AB%E3%82%88%E3%82%8B%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0.ipynb)|回答プログラムのGitHubリンク|
|[素人の言語処理100本ノック:98](https://qiita.com/segavvy/items/5efe20750b643a2d49cb)|言語処理100本ノックで常にお世話になっています|
|[PythonによるDendrogramの作成とlinkageの要素について](https://qiita.com/sho-matsuo/items/cd7f2b66e572bf60048b)|PythonでのWard法とデンドログラム実装方法|

# 環境

|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.01 LTS|仮想で動かしています|
|pyenv|1.2.15|複数Python環境を使うことがあるのでpyenv使っています|
|Python|3.6.9|pyenv上でpython3.6.9を使っています<br>3.7や3.8系を使っていないことに深い理由はありません<br>パッケージはvenvを使って管理しています|

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

|種類|バージョン|
|:--|:--|
|matplotlib|3.1.1|
|pandas|0.25.3|
|scipy|1.4.1|

# 課題
## [第10章: ベクトル空間法 (II)](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch10)
> 第10章では，前章に引き続き単語ベクトルの学習に取り組む．

### 98. Ward法によるクラスタリング
> 96の単語ベクトルに対して，Ward法による階層型クラスタリングを実行せよ．さらに，クラスタリング結果をデンドログラムとして可視化せよ．

#### 課題補足(階層的クラスタリング)
今回は階層的クラスタリングです。その詳細は[リンク先](https://www.albert2005.co.jp/knowledge/data_mining/cluster/hierarchical_clustering)が非常にわかりやすかったです。
上位階層で分けることで、クラスタ数を任意に設定できます。

# 回答
## 回答プログラム [098.Ward法によるクラスタリング.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/098.Ward%E6%B3%95%E3%81%AB%E3%82%88%E3%82%8B%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0.ipynb)

```python
import matplotlib.pyplot as plt
import pandas as pd
from scipy.cluster.hierarchy import dendrogram, linkage

country_vec = pd.read_pickle('./096.country_vector.zip')
print(country_vec.info())

clustered = linkage(country_vec, method='ward')

plt.figure(figsize=(20, 50), dpi=100, facecolor='c')
_ = dendrogram(clustered, labels=list(country_vec.index), leaf_font_size=8, orientation='right')
plt.show()
```

## 回答解説
全般的に記事[「PythonによるDendrogramの作成とlinkageの要素について」](https://qiita.com/sho-matsuo/items/cd7f2b66e572bf60048b)を参考にしています。
関数`linkage`を使ってクラスタリングをします。パラメータ`method`を`ward`にすることでWard法でのクラスタリングになります。

```python
clustered = linkage(country_vec, method='ward')
```

あとは結果を表示します。表示したデンドログラム(樹形図)は上の方に載せています。わざわざ背景色を`c`(シアン)に設定したのは、なぜかデフォルトの白だとラベルがimageファイルにしたときに見えなくなったからです。

```python
plt.figure(figsize=(20, 50), dpi=100, facecolor='c')
_ = dendrogram(clustered, labels=list(country_vec.index), leaf_font_size=8, orientation='right')
plt.show()
```

上の方だけ見てみます。K-Meansと違って、個々の国の類似度もわかるのがいいですね。
海洋国家が並んでいるかと思えば、JapanとChinaが近い位置にある。なんでなのでしょうかね。イラクとアフガニスタン、イスラエルなんかは物理的な距離は近いですが、意味が似ているのでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/1e34431e-c900-ebd7-2370-c845dec75957.png)