OmniAICreator/Qiita-1.07M huggingface dataset:
[Win10 Home Docker環境メモ(WSL2 or vagrant)] localhostのローディング時間が異常に長い問題の対処法

----
[追記]
環境構築手順のまとめを [Windows 10 Home WSL2でDockerを使う](https://qiita.com/wakki_haya/items/da1a4e15b1d347ef3c1e) に更新しました

----

当Qiitaは、Dockerの環境作りをしようと試みた過程と結果のメモです。

結論から言うと、 **WSL2をきちんと設定して使う**ことが重要でした。 

### 環境
- Windows 10 Home
- WSL2(ubuntu 18.04)
- CPU: Core-i7
- RAM: 16GB
- Docker for windows

### やりたかったこと
激オモなrailsプロジェクトをDocker環境で実行したい。

## [やったこと1] Vagrant操作でDocker環境を作る
WSL2を使うと何かと厄介な問題に引っかかりまくることが分かったので、VM wareでVirtual環境を作ることにした。

### 手順(雑)
1. Vagrantをインストール
2. Virtual Boxをインストール
3. `vagrant up` , `vagrant ssh` 
4. sshログイン先で、`docker` コマンド

### 結論
`rails s` してから、localhostにアクセスし、トップページを表示するまでに、4,5分くらいかかる


## [やったこと2-1] WSL2でDocker for windows part-1
Windows 10 Home はHype-Vの環境がありませんが、WSL2をうまく使えば、Dockerを使えるとのことでやってみた。

### 手順(雑)
1. Docker for Windows をインストール
2. WSL2のintegrationを許可する
3. 使えた
 
### 発生した問題
vagrantと同じく、localhostにアクセスするloading時間が異常に長い…（5,6分)

## [やったこと2-2] WSL2でDocker for windows part-2
上記で発生した課題として、loading時間が異常に長いというのがあった。

### 原因
調べてみると、これの原因はディスクアクセスに時間がかかっているぽい。

具体的には、上記の[やったこと2-1]において、**ubuntuターミナル上から `/mnt/c`で(windowsディレクトリを見にいき)、runしたいプロジェクトを指定したため**、loading時間が異常に長くなることがわかった

### 解決策
**`/mnt/c` でwindowsディレクトリを見に行くのではなく、ubuntu上に、dockerをrunしたいプロジェクトを作成し、実行する。**

loading時間は、10sくらいになった。

## まとめ
Windows 10 Homeでdocker環境構築するのは本当に面倒くさい :thumbsdown: 

が、WSL2の設定をちゃんとやれば、VMよりも断然早く環境構築することができる
【GAS】ガントチャートの進捗が変更されたらChatworkに送信したかった

①スプレッドシートでガントチャートを作る
②ガントチャートに管理上必要なカラムを追加
③進捗が即全体に周知できるように、Chatworkに通知したい

③にあたり、進捗が更新されたら任意の内容をChatworkに飛ばすbotをGASを使って作成した。

その時のメモ。
大体コピペさせていただいた。

```javascript:gas

var status_column = 7; //スプレッドシートのG列が編集された時のみ通知したい。

/**
 * メイン処理
 *
 * 取り出したデータをCWに送信する
 * トリガーは更新時
 *
 */
function postSheetChange(){
  const value = getValue();
  var client = ChatWorkClient.factory({token:"cw_API_token"}); //Chatwork API
  
  if (value) {
   client.sendMessage({  //メッセージの投稿を行う
   room_id: roomID, // room_ID
   body:value }); 
   }

}

/**
 * スプレッドシートから必要なデータを取り出す
 *
 */
function getValue(){  
  var notifySheet = SpreadsheetApp.getActiveSpreadsheet();
  var active_sheet = SpreadsheetApp.getActiveSheet();
  var my_cell = active_sheet.getActiveCell();
  var active_sheet_column = my_cell.getColumn();
  var rowNum = my_cell.getRow();
  
  var data =
'WBS：'+ notifySheet.getRange('A' + rowNum).getValue()+ '\n' 
+'タスク：' + notifySheet.getRange('B' + rowNum).getValue() + notifySheet.getRange('C' + rowNum).getValue() + '\n' 
+'ステータス：' + (notifySheet.getRange('G' + rowNum).getValue())*100 + '%' + '\n'
+'該当のスプレッドシートのURL';

  if (active_sheet_column !== status_column){
    return ;
  }

  return data;

}

function all() { //複数の関数を順番に実行するための関数を用意
  getValue();
  postSheetChange();
  
 }




```






#参考
[ガントチャートアドオン](https://boxil.jp/mag/a65/)

[Chatworkライブラリ](https://qiita.com/saitotakashi/items/376414263ef9dd607b4b)

[更新時、Slackに通知する方法](https://github.com/matsukazu1112/spreadsheet_notification/blob/master/spreadsheet_notification.gs)
Virtual box 6.1（Windows10）へのUbuntu20.04のインストールが「Error 5 Input / output error」で失敗する場合の対処メモ

自宅学習用のUbuntu環境構築に手間取ったので、
今後のためにメモを残します。

##前提環境
Windows10 Pro
VirtualBox 6.1
Ubuntu 20.04 (を入れたい）

##インストール失敗
ISOダウンロードから仮想マシン作成までは特に語る内容が無いので割愛。
[こちらの記事](https://qiita.com/HirMtsd/items/225c20b77a7cd5194834)に詳しいやり方が書いてあります。

起動ハードディスクを選択してインストールを進めると、
コンピュータ名等の入力フォームが表示された直後に以下のエラーがでました。

![2Rkar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265074/9680f111-4cbe-6c1b-4a7d-9208f7f12d8f.png)

[Errno 5] Input/output errorはどうやらCD/DVDドライブの欠陥に伴う入出力エラーのようです。
対処法は「ディスクドライブの清掃」......Virtual Boxなんですけど...?

##解決方法
askUbuntuにエントリーがありました。
どうやらVirtualBoxのバグっぽい？
[Error when installing Ubuntu 20.04 in VirtualBox](https://askubuntu.com/questions/1239382/error-when-installing-ubuntu-20-04-in-virtualbox)

1. Windowsの機能の有効化または無効化を開く<br>
※[コントロールパネル]→[プログラム]→[Windowsの機能の有効化または無効化]）
2. hyper-v, Windowsハイパーバイザープラットフォーム, 仮想マシンプラットフォームのチェックを外す<br>
※ない場合もあります。自環境ではhyper-vは無く、ハイパーバイザープラットフォームは元々無効でした。
3. 管理者権限でコマンドプロンプトを起動
4. ```bcdedit /set hypervisorlaunchtype off```を実行<br>
※[bcdedit](https://docs.microsoft.com/ja-jp/windows-hardware/manufacture/desktop/bcdedit-command-line-options)はブート構成データ(Boot Configuration Data, BCD)を管理するコマンドラインツール。
5. PCを再起動

これで無事インストールを完了させることができました。
Herokuアドオンで自動で作られるアカウントについて

Herokuアドオン(例えばAuth0)を使うと、自動的にそのサービスのアカウントが作られることが多いです。

ただ、そのアカウントにはHerokuのダッシュボードからしかログインできないし、Herokuを使わない時もそのAuth0使うかもしれないから、管理が煩雑になってしまう、、

そこで以下の方法を思いつきました。

```
アドオン追加
→ダッシュボードからAuth0の管理画面に移動
→Auth0からログアウト
→ログイン画面でパスワードを忘れたをクリック
→Herokuに登録しているメールアドレスを入力する
→メールを確認してパスワードを設定
```

こうすることで、Herokuのダッシュボードからも、Auth0のログイン画面からもログインできて、Herokuを使わない時にも同じアカウントで別プロジェクト?を作成できるようになります。

## 注意
Herokuに詳しい方にこの方法について意見を伺ったのですが、ライセンス的に微妙らしいです。「Heroku以外で使う場合とアカウントをシェアして良いよ」というアドオンと、そうでないアドオンがあるみたい。アドオン詳細ページの`SHAREABLE DETAILS` を確認するとわかるみたいです。(Auth0はOK)
![ 2020-09-04 12.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/f07444f1-c72f-70e5-b443-9697e00cc4c7.png)
[Elements Marketplace: Auth0](https://elements.heroku.com/addons/auth0)

## 他の方法
Herokuアドオンを追加する時に、コマンドラインから`$ heroku addons:attach hoge`として追加すると、既存の(Auth0等の)アカウントを利用してHerokuアドオンを追加できるみたいです。(試してはいないです)

## 所感
いちいちライセンスを確認するのも面倒だし、アドオンが何をやってくれているかを理解した上でサービスのドキュメントを解釈しないといけないから、Herokuでしか使わなそうなもの以外はアドオンなしで使おうと思いました。
Material UI でのテーマ切り替えがReact.StrictModeで動かない

## 背景
[Material-UIでテーマを切り替えられるようにする](https://coders-shelf.com/material-ui-select-theme/)
を参考にさせていただきテーマ切り替えを実装したのですが上手く動かず *1、
その原因を突き止めるのに時間がかかったので、メモとして残しておきます。

*1 即時反映されず、ページをリロードする必要がありました

## 結論
題名の通り、`<React.StrictMode>`が原因でした
**ですが、**
本番環境では`<React.StrictMode>`がそもそも機能しないので、実際には何もする必要はありません。
（dev環境でテーマを切り替えるときはリロードする手間があるだけです）

`create-react-app`で作成した場合、`index.tsx`は以下のようになっています。

```tsx:index.tsx
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);
```

この`<React.StrictMode>`を取り除くと、テーマの切り替えがdev環境でも即時反映されます。
arr.splitメソッドを使って多次元配列の子要素を配列化する

#####paizaラーニングのレベルアップ問題を解いていて、「あっ、これそろそろ覚えとかないと！」と感じたので、これを機にQiitaにメモ書きしておきます。

#####具体的には、arr.mapの引数内にコールバック関数としてarr.splitを配置。
#####下記のようになります。

 ```JavaScript:qiita.js
let arr = [ 'Kiri 1', 'Kyo 2' ]
let splited = arr.map((value) => value.split(" "));
console.log(splited);

// 結果：[ [ 'Kiri', '1' ], [ 'Kyo', '2' ] ]
 ```
WSL2環境のDockerコンテナにVS Codeでリモート接続してPythonプログラムをデバッグする方法

Windows 10でVisual Studio Codeをお使いの方を対象に
WSL2環境のDockerコンテナにリモート接続してPythonプログラムをデバッグする方法について記載します。
WSL2環境でdocker desktopを利用できるようにする方法については予め別サイトで確認して、セットアップしておいてください。
さらにVisual Studio Codeの拡張機能でRemote Developmentをインストールしてください。
Remote Developmentについては下記を参照しました。
[VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview "VS Code Remote Development")

ここまで準備ができたところで本題に入ります。
まず、VS Codeを立ち上げて、左下のこのマークをクリックしてださい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640503/e611c44a-6b02-2a15-0607-17c5fdc17d4b.png)
そうすると上部に*Remote-...*がたくさん表示されると思います。
そのうち*remote-containers open folder in container*を選択し、
所望のプロジェクトのフォルダを選択します。
初回起動時は、どの設定を参照してコンテナを立ち上げるかを確認されるので、例えば*docker-compose.yml*を選択します。
そうすると、その設定に従ってコンテナが立ち上がり、VS Codeはそのコンテナにリモート接続して、対象のフォルダが左ペインに表示されます。
下記を参考にしました。
[Developing inside a Container](https://code.visualstudio.com/docs/remote/containers "Developing inside a Container")

VS Code内で開かれたーターミナル(デフォルトだと右下側)に

```sh
cat /etc/*release
```


とかを入力してOSのバージョンを確認してみてください。
Dockerfileで指定したOSが起動していますよね (^^♪

そして、左ペインから起動したいPythonプログラムを選択します。
すると、下記のメッセージが右下に表示されますので、お勧め通りインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640503/9177ac33-0e8f-97ac-9711-980bdefa4089.png "Python extension for Visual Studio Code")
*Dev Container: Existing...*と出るのでクリック、さらに[再読み込みが必要です]と出るのでクリック。

あとは、先ほどのPythonプログラムを選択して、BreakPointを張って、**F5**でデバッグ実行して、BreakPointで止めるいったデバッグ動作が可能となります。

終了するときは、このマークを選択して、[リモート接続を終了する]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640503/e611c44a-6b02-2a15-0607-17c5fdc17d4b.png)

コンテナ自体は終了しないようなので、現時点では自分で*docker-compose down*とかで落とさないとダメなようです。
また、コンテナをdownさせるとVisual Studio Codeの拡張機能として、上記の*Python extension for Visual Studio Code*を毎回インストールしないといけないようです。(要調査)

以上によって、大幅な開発効率の向上が見込めますし、何よりコンテナ内に入って作業ができることに安心感が得られます。
Windowsのメモリダンプ取得方法

#はじめに
特にWindowsの場合、メモリダンプを取得して調査することにより、ディスクにない情報やディスクからは発見困難な情報を得られる可能性があります。そのためWindowsのフォレンジック調査では、可能な限りメモリダンプを取得することが推奨されます。
#メモリダンプ取得ツール
DumpitやFTK Imagerを使うことが多いようです。Dumpitは実行するだけで取得できますので、ここではFTK Imager Liteで取得する手順を紹介します。ちなみにFTK Imager Liteはディスクの保全も可能です。[こちらの記事](https://qiita.com/log0417/items/55b7e42bb5af67a4acec)をご参照ください。

FTK Imager Liteは以下からダウンロードできます。必要事項を入力すると、メールでダウンロードするためにリンクが送られてきます。ダウンロードし、Zipを解凍したものをUSBメモリや外付けHDDに保存してください。
https://accessdata.com/product-download/ftk-imager-lite-version-3-1-1

#メモリダンプ取得
1. FTK Imager Liteの起動
準備ができたのでメモリダンプを取得しましょう。メモリダンプを取得したいマシンにUSBメモリや外付けHDDを挿入し、FTK Imager Liteを実行します。もし起動時にエラーが出る場合は下記の手順を実施してください。無事に起動すると以下のような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/949d27c6-dd56-b6eb-d815-5bf62a864142.png)

###FTK Imager Liteの実行時にエラーが出る場合
FTK Imager Liteの実行時に環境によっては「このアプリの実行は管理者によってブロックされています。」というエラーが出て起動できないことがあります。その場合は以下の手順で起動してください。

1-1. コマンドプロンプトを管理者権限で起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/889e471f-5c3f-bc83-1278-2de8043f7aca.png)

1-2. 以下のようにUSBメモリまたは外付けHDDのドライブに移動し、FTK Imager Liteを起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/1c481902-0e58-5412-df2d-3db810228a73.png)

1-3. これでFTK Imager Liteが起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/b4736754-0d2b-720b-74ee-a132cfb0864c.png)

2.画面上部にある緑色のメモリのアイコンをクリックします。
カーソルを合わせるとCapture Memoryと表示されるアイコンです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/2e47a3ae-2a21-7874-120a-532dd040f5f9.png)

アイコンをクリックすると以下の画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/e6018e7f-29ba-f31b-4fa1-a8a63fbd199e.png)

3.Browseをクリックし、メモリダンプを保存する場所を選択します。必ずUSBメモリや外付けHDDを選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/fc1558b9-0a90-d52c-883f-2db8d43681e0.png)

4.「Capture Memory」をクリックします。メモリのサイズにもよりますが、数分程度で完了すると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/a229fdd4-dda9-4c92-3ca8-40139e4f5943.png)

以下の画面になったら完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/5b07a505-df79-9eb4-7ea1-0b0975d5bb11.png)

念のためUSBメモリや外付けHDD内にメモリダンプが作成されていることを確認します。メモリのサイズと同じサイズの「memdump.mem」が作成されているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/8b8d39fa-a2de-60fc-f5cc-bc278485593d.png)

#まとめ
メモリダンプの取得手順について解説しました。参考になれば幸いです。
windows forfilesコマンド　ディレクトリ操作　動作確認環境構築

forfilesコマンドを使って、最終更新日時の異なるフォルダとファイルに対し、いろいろ動作を確認してみたかったので、powershell にて試験用のディレクトリ構成を簡易に作り出すコマンドを作りました。
powershell にて下図の構成を一発で作れます。
※("yyyy/mm/dd")は、最終更新日時

```ruby:こんな感じの動作環境を即興で作れます。

test/
 ├FOLDER_1/("2020/06/25 00:00:00")
 │     └FORDER_A/("2020/06/25 00:00:00")
 │     │    └text_a.txt("2020/06/25 00:00:00")
 │     │    └text_b.txt("2020/07/25 00:00:00")
 │     │    └text_c.txt("2020/08/25 00:00:00")
 │     └FORDER_B/("2020/07/25 00:00:00")
 │     └FORDER_C/("2020/08/25 00:00:00")
 │     └text_A.txt("2020/06/25 00:00:00")
 │     └text_B.txt("2020/07/25 00:00:00")
 │     └text_C.txt("2020/08/25 00:00:00")
 ├FOLDER_2/("2020/07/25 00:00:00")
 ├FOLDER_3/("2020/08/25 00:00:00")
 └text_1.txt("2020/06/25 00:00:00")
 └text_2.txt("2020/07/25 00:00:00")
 └text_3.txt("2020/08/25 00:00:00")

```

```ruby:作成の為のpowershell用コマンド
New-Item FOLDER_1 -itemType Directory
New-Item FOLDER_2 -itemType Directory
New-Item FOLDER_3 -itemType Directory
New-Item text_1.txt -type file
New-Item text_2.txt -type file
New-Item text_3.txt -type file
New-Item FOLDER_1\FOLDER_A -itemType Directory
New-Item FOLDER_1\FOLDER_B -itemType Directory
New-Item FOLDER_1\FOLDER_C -itemType Directory
New-Item FOLDER_1\text_A.txt -type file
New-Item FOLDER_1\text_B.txt -type file
New-Item FOLDER_1\text_C.txt -type file
New-Item FOLDER_1\FOLDER_A\text_a.txt -type file
New-Item FOLDER_1\FOLDER_A\text_b.txt -type file
New-Item FOLDER_1\FOLDER_A\text_c.txt -type file
Set-ItemProperty FOLDER_1  -Name LastWriteTime -Value "2020/06/25 00:00:00"
Set-ItemProperty FOLDER_2  -Name LastWriteTime -Value "2020/07/25 00:00:00"
Set-ItemProperty FOLDER_3  -Name LastWriteTime -Value "2020/08/25 00:00:00"
Set-ItemProperty text_1.txt -Name LastWriteTime -Value "2020/06/25 00:00:00"
Set-ItemProperty text_2.txt -Name LastWriteTime -Value "2020/07/25 00:00:00"
Set-ItemProperty text_3.txt -Name LastWriteTime -Value "2020/08/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_A -Name LastWriteTime -Value "2020/06/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_B -Name LastWriteTime -Value "2020/07/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_C -Name LastWriteTime -Value "2020/08/25 00:00:00"
Set-ItemProperty FOLDER_1\text_A.txt -Name LastWriteTime -Value "2020/06/25 00:00:00"
Set-ItemProperty FOLDER_1\text_B.txt -Name LastWriteTime -Value "2020/07/25 00:00:00"
Set-ItemProperty FOLDER_1\text_C.txt -Name LastWriteTime -Value "2020/08/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_A\text_a.txt -Name LastWriteTime -Value "2020/06/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_A\text_b.txt -Name LastWriteTime -Value "2020/07/25 00:00:00"
Set-ItemProperty FOLDER_1\FOLDER_A\text_c.txt -Name LastWriteTime -Value "2020/08/25 00:00:00"
```
同一PCで本番・開発環境を同じホスト名でブラウズする方法

## やりたいこと
ブラウザで本番環境を開きつつ、同一PCで**同じホスト名**の開発環境・ステージング環境の内容をブラウズしたい。

### hostsの書き換えは困る
- hostsファイルを書き換えればできるけど、そうすると本番環境が見に行けない。
- 毎回書き換えるのが面倒。
- 書き換えを戻すのを忘れてしまう。
- 同じPCで右画面は本番、左画面は開発ってしたい。

## 結論
- Windowsサンドボックス内に自動インストールしたChrome + hosts書き換えでいい感じにする。
- サンドボックス起動→Chromeインストール終了で20秒程度。
- サンドボックス内のhostsを書き換えても、ホスト側に影響は無い。

### Windowsサンドボックス ?
- 10秒程度で起動するWindows10 標準の仮想環境
- 設定ファイル（xml）を作ると、環境ごとにあれこれ切り替えられる
- 上記設定ファイルで起動スクリプトを指定できる（これで自動インストール等をする）
- ただし Windows10 Proが必要。Hyper-Vを有効にしてないと駄目。

入れ方など
https://www.tipsfound.com/windows10/01016

### サンドボックスの設定ファイル
こんな感じにした。
`C:\Develop\WinSandbox\chrome_hosts\`に下記の３つのファイルと、chromeのスタンドアロンインストーラー(ChromeStandaloneSetup64.exe)をおいた。

chrome_hosts.wsb

```xml
<Configuration>
  <VGpu>Disable</VGpu>
  <MappedFolders>
    <MappedFolder>
      <HostFolder>C:\Develop\WinSandbox\chrome_hosts</HostFolder>
      <SandboxFolder>C:\Users\WDAGUtilityAccount\Desktop</SandboxFolder>
      <ReadOnly>true</ReadOnly>
    </MappedFolder>
  </MappedFolders>
  <LogonCommand>
    <Command>C:\users\WDAGUtilityAccount\Desktop\chrome_hosts\install_chrome.cmd</Command>
  </LogonCommand>
</Configuration>
```

install_chrome.cmd

```
@echo off
set dir=C:\Users\WDAGUtilityAccount\Desktop\chrome_hosts

copy /y %dir%\hosts C:\Windows\System32\drivers\etc\

# install chrome
start %dir%\ChromeStandaloneSetup64.exe

# open hosts
start notepad C:\Windows\System32\drivers\etc\hosts

exit
```

ホストからは↓を起動する
start_chrome_sandobx.cmd

```
copy /y C:\Windows\System32\drivers\etc\hosts .
start chrome_hosts.wsb
```

### wsbファイルのオプションなど
Windows サンドボックスの構成
https://docs.microsoft.com/ja-jp/windows/security/threat-protection/windows-sandbox/windows-sandbox-configure-using-wsb-file

## その他 試したこと
### chromeの機能拡張
一見下記で解決しそうだったのですが、私の環境では動きませんでした。

Virtual Hosts
https://chrome.google.com/webstore/detail/virtual-hosts/fbkigokjancnolojmhcgcfhgeeljolkh?hl=ja


## 教えて下さい
いやいや、他にもっと良い方法があるよと言うことであれば、コメントで教えて下さい。
【Embulk】MacにEmbulkとプラグインをインストールする

# はじめに
MacでEmbulkと、必要なプラグインをインストールするまでを記載します。

# 環境
```
$ sw_vers
ProductName:    Mac OS X
ProductVersion:    10.15.6
BuildVersion:    19G2021

$ java -version
openjdk version "1.8.0_265"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_265-b01)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.265-b01, mixed mode)
```

# インストール
## install java
Embulkは、Javaアプリケーションです。
すでにJavaが入っていれば、ここは読み飛ばしてください。

```
# 確認
$ which Java

# インストール
$ brew cask install homebrew/cask-versions/adoptopenjdk8
```

## install embulk
brewコマンドで、Mac上にインストールしてみます。

```
# インストール
$ brew install embulk

# 確認
$ which embulk
$ embulk --version
embulk 0.9.23
```

## install Embulk plugins

Rubyのgemコマンドを使ってインストールします。
プラグインの一覧はこちらにありますので、プロダクトで必要なものをチョイスしてください。
https://plugins.embulk.org/

```
# インストール
ex) embulk gem install <plugin name>

embulk gem install embulk-input-mysql
embulk gem install embulk-input-s3
embulk gem install embulk-input-firestore

embulk gem install embulk-output-s3
embulk gem install embulk-output-bigquery
embulk gem install embulk-output-elasticsearch
```

# さいごに

これだけでEmbulkの準備は完了です。かんたんでしたね。
このあと実際にEmbulkを動かすまでをやっていみたいと思います。
Macのデスクトップ通知をPythonから表示する

Macの通知をPythonスクリプトから出したい局面があったので、

- AppleScriptをコマンドで実行する
- 上記のコマンドをPythonから実行する

という流れで作成しました。

## AppleScriptでデスクトップ通知を表示する

AppleScriptでは、

```AppleScript:notification.scpt
display notification "こんにちは世界"
```

でデスクトップ通知を表示できます。下図では、ScriptEditor.appから実行しています。

| ![notification_applescript.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162670/d0680d1e-1f7a-5d39-f453-17da2086aeef.png) |
|--------|



## コマンドからAppleScriptを実行する

`osascript`コマンドを使用します。

terminal.appにて、

```sh
$ osascript -e 'display notification "こんにちは世界"'
```

で、先程と同じ結果が得られます。

## Pythonスクリプト内でコマンドを呼び出す

`os`モジュールの`system`メソッドの引数に、前述のコマンドを文字列として渡すことで実行できます。

```python:notification.py
import os

os.system("osascript -e 'display notification \"こんにちは世界\"'")
```

## 実行環境がMacのときだけ上記の処理を実行したい

PythonスクリプトがMac以外の環境でも実行される可能性がある場合、デスクトップ通知の表示は環境によっては行わないようにする必要が出てきます。

Pythonの標準ライブラリに[platform](https://docs.python.org/ja/3/library/platform.html)というモジュールがあるので、こちらを利用しました。

`platform.system()`を実行すると、システムの名前が`'Linux'`, `'Darwin'`, `'Java'`, `'Windows'`のような文字列で返ってきます。不明な場合は空文字が返ってきます。

## まとめ

以上をまとめると次のようになりました。

```python:notification_matome.py
import os
from platform import system

pf = system()
if pf == "Darwin":
    os.system("osascript -e 'display notification \"こんにちは世界\"'")
```

## 今後の展望

通知が「スクリプトエディタ」発になっているので、できれば変更したい。

# 環境

- macOS 10.15.6
- zsh 5.7.1 (x86_64-apple-darwin19.0)
- Python 3.8.0

# Reference

[pythonからmacOSの通知センターを操る方法 - アウトプットして苦悩する](http://atc.hateblo.jp/entry/2018/06/25/python%E3%81%8B%E3%82%89macOS%E3%81%AE%E9%80%9A%E7%9F%A5%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC%E3%82%92%E6%93%8D%E3%82%8B%E6%96%B9%E6%B3%95)

[platform --- 実行中プラットフォームの固有情報を参照する — Python 3.8.5 ドキュメント](https://docs.python.org/ja/3/library/platform.html)
jupyterで仮想環境に入るならnb_conda_kernelsがおすすめ

# 概要
タイトル通り。日本語で検索すると[jupyter_environment_kernels](https://github.com/Cadair/jupyter_environment_kernels)を使った方法ばかりがヒットするが、Anaconda公式が開発している[nb_conda_kernels](https://github.com/Anaconda-Platform/nb_conda_kernels)を使った方が簡単かつ確実。

# 導入
jupyterを起動する環境下で以下のコマンドを実行するだけ。

`conda install -c conda-forge nb_conda_kernels`

jupyterを開いて"カーネル"→"カーネルの変更"から好きな環境を選択する。

# 詳細
jupyter notebookやjuypter labを実行する際の環境をanacondaの仮想環境に変更したいという需要は非常に高いと思います。
日本語で「jupyter 仮想環境」と検索すると、[jupyter_environment_kernels](https://github.com/Cadair/jupyter_environment_kernels)を用いた方法を紹介している記事が多くヒットします。ですが、configの書き換えなどinstall以外にも操作が必要です。また、このレポジトリを見ると最終コミットが2018/2になっていることから、メンテナンス面でも不安が残ります。
そこで代替案として、[nb_conda_kernels](https://github.com/Anaconda-Platform/nb_conda_kernels)をおすすめします。これはAnaconda公式が開発しているもので、installするだけでjupyter内での仮想環境を変更できるようになります。
configの書き換え等も不要のため、こちらの方が断然おすすめです。
2つのBuild Typeで同じsrcを参照したい

例えば、`debug build type`と全く同じコードを利用する`develop build type`を作成したい場合があるとする。

その場合、普通に作ると同じコードをそれぞれのbuild type毎に用意する必要があるが、`sourceSets`を使うとbuild typeが実際に参照するソースを制御できる。

通常`develop build type`は`src/develop`ディレクトリ以下を見にいくが、それを`src/debug`以下を見にいくように変更してしまう。

```groovy
android {
    sourceSets {
        develop {
            manifest.srcFile 'src/debug/AndroidManifest.xml'
            java.srcDirs = ['src/debug/java']
            res.srcDirs = ['src/debug/res']
        }
    }
}
```

また、AndroidManifest.xmlだけ`src/develop`ディレクトリに置いておきたいなら次のようにすれば良い。

```groovy
android {
    sourceSets {
        develop {
            java.srcDirs = ['src/debug/java']
            res.srcDirs = ['src/debug/res']
        }
    }
}
```

`develop build type`の`src/develop`以下にあるAndroidManifest.xmlから`src/debug`以下のApplicationクラスを使用したい場合でも問題なく参照できる。



## 参考
- https://developer.android.com/studio/build/build-variants?hl=ja#sourcesets
- https://developer.android.com/studio/build/gradle-tips?hl=ja#change-default-source-set-configurations
Power BI Premiumを触ってみるシリーズ

## はじめに

Power BI Premiumについて色々まとめてみようと思います。

## コンテンツ

### Power BI Premiumについて機能差などを整理してみた

まずはPower BI Premium特有の機能などの整理から

[Power BI Premiumについて機能差などを整理してみた](https://qiita.com/ryoma-nagata/items/b0d82a33d4eb74c07f3d)


### Power BI Premium専用機能を従量課金でテストする方法

ライセンス月額払うにはハードルがあるので、時間課金で機能を利用する方法があります。

[Power BI Premium専用機能を従量課金でテストする方法](https://qiita.com/ryoma-nagata/items/08b1e54627853e679fd1)

### Power BI データフローにPremiumu容量を割り当てて、性能向上するか試してみる

Premium専用機能である、[拡張コンピューティング エンジン](https://docs.microsoft.com/ja-jp/power-bi/transform-model/service-dataflows-enhanced-compute-engine)について、どれくらいパフォーマンスが変わるか**超**簡単にテストします。

**作成中**
Spatial Transformer Networks のメモ

- Max Jaderberg Karen Simonyan Andrew Zisserman Koray Kavukcuoglu
- Deepmind, 2015年
- https://arxiv.org/pdf/1506.02025.pdf

### 概要
- CNN ではmax poolingとかでshift invarianceを入れているが、回転とかは弱い。(普通Data Augmentationで入れるような)
- Spatial Transformer と呼ぶ層をCNNの中に混ぜる。この層はtrainableである。Transformerはインスタンスごとに適切な変換を行うように学習する。どうもある種の正規化みたいなことを画像に対して行うことが期待されているようだ。

- STはConv層の間に挟む。普通に作ると全結合になりそうでパラメータ増えそうだが、どうなっているのかな？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412142/6ab9cee1-4390-5c71-0ad9-fe8ffe49d062.png)


### 評価
評価はMNIST, SVHN などの文字とCUB200 という鳥類画像で行っている。
基本的には分類精度の向上で評価しているようだ。
違うコントローラーのページにredirectするときのパス指定

サイトにコメント機能の実装をする際、
comments controllerに

```ruby:qiita.rb
class CommentsController < ApplicationController
  def create
    Comment.create(comment_params)
    redirect_to item_path(item.id)
  end

  private
  def comment_params
    params.require(:comment).permit(:text).merge(user_id: current_user.id, item_id: params[:item_id])
  end
end
```

と記述したところ、データベース上に値は保存されてるけど、redirectがエラーとなり、「undefined local variable or method `item' for #< CommentsController:0x00007f7ef315cdd0 >」
と表示された。

[解決策]
 redirect_to item_path(item.id)
のitemが何かわかりませんと言われているので、
item = Item.find(params[:id])を追加記述。
そうすると、「idが何かわかりません」と言われたので、item = Item.find(params[:item_id])と書き直したところ通りました。
Mockkであるクラスのstaticなメソッドをmockしたい場合

あるFooクラスのstaticなメソッドをmockしたい場合、Mockk1.8.1以降では`mockkStatic`を使用する。

```kotlin
// Fooクラス
class Foo {
    @JvmStatic
    fun bar(): Boolean {
        return false
    }
}
```

Fooクラスのbarメソッドをmockしたい場合次のようにする。

```kotlin
// テストコード
@RunWith(AndroidJUnit4::class)
class FooBarTest {

    @Before
    fun init() {
        mockkStatic(Foo::class)
    }

    @Test
    fun test() {
        every { Foo.bar() } returns true
        .
        .
        .
    }
}
```

## 参考
- https://github.com/mockk/mockk
- https://stackoverflow.com/questions/49762409/mock-static-java-methods-using-mockk
シェルスクリプトで文字数を指定して文字列を初期化する方法

文字列の長さを指定しつつ、特定の文字で初期化したい時は`printf`を使うとよい

```bash
len=100
c="*"
word=$(printf "%${len}s" | tr " " "$c")
```

半角スペースで埋める場合は`tr`は不要

文字数が少ないときはfor文で連結するほうが早かったりするが、こっちのほうが1行ですむので見やすいと思う。
ワンライナーズンドコチェック

**今朝、ズンドコチェックなるものと邂逅した。１行にした。**
セミコロンは甘え。

```python
print((lambda f, z:f(f, z))(lambda f, z:z + 'キ・ヨ・シ！' if z[-10:] == 'ズンズンズンズンドコ' else f(f, z + __import__('random').choice(['ズン', 'ドコ'])), ""))
```

```
ズンズンドコズンズンドコズンドコドコズンドコドコドコズンドコズンド コドコドコズンズンドコズンズンズンズンズンズンズンドコキ・ヨ・シ！
```
flutter/providerで状態管理を引き継ぐ方法

個人の備忘録として

前提条件
flutter 1.20.2
Dart 2.9.1
provider: ^4.3.1(画面の状態管理のプラグイン)

投稿時点での推奨状態管理の方法であるproviderにて

 Widget build(BuildContext context) {
    return ChangeNotifierProvider<ProviderModel>(
        create: (_) => ProviderModel(),
        child: Consumer<ProviderModel>(
          builder: (context, model, child) {
          },
        ));
  }

このように状態を作りこれらを別画面でも共有したい場合、上記を再度行うと
もう一つ同じ名前のproviderができるだけで共有できません。
ではどうするか

Widget build(BuildContext context) {
    final Model = Provider.of<ProviderModel>(context);
    return ChangeNotifierProvider.value(
        value: Model,
        child: Consumer<ProviderModel>(builder: (context, model, child) {

final Model = Provider.of<ProviderModel>(context);
ここで引き継いでいます。<>の中の名称は一致させましょう。
また引き継ぐ側は決められた部分を上記のように変更することで引き継げます。
ScrollViewの中のListView

ScrollViewの中にいろいろ部品を突っ込んでその中にListViewも含まれる場合、普通に書くとスクロールされないんですよ。
ListViewの中でスクロールされてしまう感じ...
下のイメージ参照。

![movie1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678917/3b1c2b22-8d86-4cc4-fd09-401acf8ab6db.gif)


これをスクロールできるように画面に表示するにはカスタマイズすれば良いらしいです！

▼カスタムListView

```

class CustomListView : ListView {

    private val MAX_SIZE = 99

    constructor(context: Context?) : super(context) {
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        var newHeight = 0
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        if (heightMode != MeasureSpec.EXACTLY) {
            val listAdapter: ListAdapter? = adapter
            if (listAdapter != null && !listAdapter.isEmpty) {
                var listPosition = 0
                listPosition = 0
                while (listPosition < listAdapter.count
                    && listPosition < MAX_SIZE
                ) {
                    val listItem: View = listAdapter.getView(listPosition, null, this)
                    if (listItem is ViewGroup) {
                        listItem.setLayoutParams(
                            LayoutParams(
                                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
                            )
                        )
                    }
                    listItem.measure(widthMeasureSpec, heightMeasureSpec)
                    newHeight += listItem.getMeasuredHeight()
                    listPosition++
                }
                newHeight += dividerHeight * listPosition
            }
            if (heightMode == MeasureSpec.AT_MOST && newHeight > heightSize) {
                if (newHeight > heightSize) {
                    newHeight = heightSize
                }
            }
        } else {
            newHeight = measuredHeight
        }
        setMeasuredDimension(measuredWidth, newHeight)
    }
}
```

▼レイアウト

```
<ScrollView
  android:id="@+id/scroll_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

                    ・・・略・・・

    <jp.co.sample.ui.CustomListView
      android:id="@+id/list_view"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent" />
  </LinearLayout>

</ScrollView>
```

こんな感じになりました〜
![movie2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678917/5516dfff-9e59-3cbe-4347-09869f751e31.gif)
Storybookでcomponentに任意のクエリパラメータを参照させる

# この記事は何？
クエリパラメータを参照して挙動が変わるcomponentをStorybookで確認したい、といった場合が稀にあると思います。
素直に[addon](https://www.npmjs.com/package/@storybook/addon-queryparams)を使えばいいんですが、導入するほどでもないなという時に使うといいかもです。

# 実装
`Vue.js`のstoryで実装した例を載せます。
reactはわからないですが同じようにライフサイクルフックの中でやれば多分うまく行くと思います。

```AnyStory.stories.js
export initial = (args, { argTypes }) => {
  ...
  created() {
    // 任意のクエリパラメータをセット
    history.replaceState('', '', `${window.location.href}&any_params=hogehogehugahuga`);
  },
  ...
};
```

# 注意
- すでにstorybookによるクエリパラメータが設定されているので`&`始まりでパラメータを追加する必要があリます。
- `replaceState`の仕様的にoriginの異なるurlに差し替えることはできないです。

# 参考URL
https://qiita.com/nightyknite/items/b350dc95f7da089a516a
https://developer.mozilla.org/ja/docs/Web/API/History/replaceState
OkHttp InterceptorのUnitTest


リクエスト時にあるHeaderを付与する`SampleInterceptor()`を書いた場合、OkHttpのMockWebServerを使って次のようにテストを書ける。

```kotlin
@RunWith(AndroidJUnit4::class)
class SampleInterceptorTest {
  
    @get:Rule
    val server: MockWebServer = MockWebServer()
      
    @Before
    fun init() {
        server.enqueue(MockResponse())
    }
     
    @Test
    fun test() {
        val client: OkHttpClient = OkHttpClient().newBuilder()
            .addInterceptor(SampleInterceptor())
            .build()
		val response = client.newCall(Request.Builder().url(server.url("/")).build()).execute()
		        
		response.request().run {
            Truth.assertThat(header("HEADER_NAME")).isNotNull()
        }
    }
}
```

これだけでMockWebServerのstartとshutdownをやってくれるの便利。

```kotlin
@get:Rule
val server: MockWebServer = MockWebServer()
```

## OkHttp Authenticatorのテスト

OkHttp Authenticatorでのtokenの更新処理とUnitTestについても書いた。

https://qiita.com/Horie1024/items/dec5ec6508f8fc5aea3f

## 参考
- Interceptorの概要
    - https://square.github.io/okhttp/interceptors/
- okhttp3プロジェクトに含まれるInterceptorのテスト
    - https://github.com/square/okhttp/blob/master/okhttp/src/test/java/okhttp3/InterceptorTest.java		
- https://jordifierro.com/android-http-interceptor-testing
[GCP] Cloud Runでデプロイした時にメモリ上限を越えていて失敗した時のgcloudコマンドでの対処法

## 経緯

Goで書いた簡単なバックエンドのDockerコンテナをCloud Runで動かそうとしてデプロイしたら失敗した。
ログを見たらメモリ上限を越えているとのこと。


```console
Memory limit of 256M exceeded with 277M used. Consider increasing the memory limit, see https://cloud.google.com/run/docs/configuring/memory-limits
```

ログには[https://cloud.google.com/run/docs/configuring/memory-limits](https://cloud.google.com/run/docs/configuring/memory-limits)を見ろと書いてある。

見てみると、Cloud Runにおけるメモリの扱いについて説明されている。

> 許容されるメモリ上限を超える Cloud Run コンテナ インスタンスは終了します。
>
> コンテナ インスタンスの使用可能なメモリは次のとおりです。
> 
> アプリケーション実行可能ファイルを実行する（実行可能ファイルをメモリに読み込む必要があるため）
> アプリケーション プロセスでメモリを割り当てる
> ファイル システムへのファイルの書き込み
> デプロイされたコンテナ イメージのサイズは、使用可能なメモリにはカウントされません。

つまり、「コンテナ内で実行するプログラムに必要なメモリサイズ」がデフォルトの設定上限を越えているということらしい（デフォルトは256MB）。

同ページにはGUI上での対処法は書いてあるが、`gcloud run`コマンドではどうするのか調べたくて[gcloud runのリファレンス](https://cloud.google.com/sdk/gcloud/reference/run)を見てみる。**見事に書いてない。困った。**

## 解決法

[Google Cloud Run の運用 - Qiita](https://qiita.com/t-otsuka/items/7c074a2c8a0b033f1d56)に書いてた。

`gcloud run`コマンドには`--memory`フラグがあるのでこれを使う。

```console
gcloud run deploy --project [ProjectID] gcr.io/[ProjectID]/[ServiceName] --memory 512
```
2D Lidar( RPLIDAR A3)でAutoware waypointを使って自動走行

2D Lidar( RPLIDAR A3)でAutoware waypointを使って自動走行します。

# 目次

1. [Ubuntu18.04にAutoware自動運転シミュレータLGSVLをインストール](https://qiita.com/k-koh/items/7c7f90c1d9b61adf958b)
2. [Ubuntu18.04にAutoware.AIをインストール](https://qiita.com/k-koh/items/90647b1cb140b4b75c91)
3. [LGSVL SimulatorでAutoware vector mapを使って自動走行](https://qiita.com/k-koh/items/10e0259764426e41cf47)
4. [2D Lidar( RPLIDAR A3)でAutoware waypointを使って自動走行](https://qiita.com/k-koh/items/db88bbd6923a668c3164)

# 環境
- AsRock DeskMini GTX1060(Z370)
- Core i9-9900 (3.10GHz 8core 16thread)
- メモリー32GB
- NVIDIA GeForce GTX 1060 Mobile(6GB GDDR5)
- Ubuntu 18.04.5
- ROS Melodic
- Qt Creator 4.9.2
- Autoware 1.14.0
- LGSVL 2020.05

# Autowareを起動

```
roslaunch runtime_manager runtime_manager.launch
```

# RPLIDAR A3のROS packageを起動

```
roslaunch rplidar_ros rplidar_a3.launch
```

RPLIDAR A3のROS packageを改造したので、PointCloud2のTopicデータが出力されます。

```
frame_id : velodyne
topic_name : points_raw
```

今回は、確認のために、代わりに[記録したRPLIDAR A3のRosbag](https://qiita.com/k-koh/items/0e492a0ae032a5ab034d)を使います。

ROSBAGを選択してplay → Pause で一時停止

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/bf4fe99a-ed57-ad9a-0af5-472a70bc544b.png)

# Setup Tab

TFとVehicle Modeを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/b32d4516-35e6-122b-68fc-a398c56db96b.png)

# Map Tab

[生成したPCD地図](https://qiita.com/k-koh/items/0e492a0ae032a5ab034d)とロカールTFを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/e1f3858d-8d95-d07e-89d2-8ff693e442d9.png)

# Sensing Tab

voxel_grid_filterを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/334f8cf4-6bad-de24-e915-3569c30a82d5.png)

# Computing Tab

waypoint_loaderのappに[生成したWaypoint経路ファイル](https://qiita.com/k-koh/items/0e492a0ae032a5ab034d)を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/ebdc3652-b0b6-1ac5-8774-a2e294c2c898.png)


下記ノードを起動します。
ndt_matching, vel_pose_connect,
waypoint_loader,
astar_avoid, velocity_set,
pure_pursuit, twist_filter

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/4a2d86be-767c-d18c-59e7-05cf7eb4deb3.png)


# rvizを起動

ロードしたWaypoint経路が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/4808456c-3a9e-4593-6bd1-a5c8d392588f.png)

# 自動走行を開始

twist_filterを起動すると、自動に自動走行が開始されます。

今回ROSBAGを使っているので、一時停止したROSBAGを再開すると、自動走行が開始されます。

自動走行開始

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/d3c8b7c7-cb59-425a-a63b-cac383c73a2e.png)

自動走行完了

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/42c67b73-911f-2a63-06e2-d0acbb74a1f6.png)
UIImage.cgImageがnilを返す場合

CIImageから作ったUIImageからCGImageを作ると、nilを返すようです。

UIImage経由しなければ回避できますね。

```swift
let context = CIContext(options: nil)
let cgImage = context.createCGImage(ciImage, fromRect: ciImage.extent())
```

****
Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[MLBoysチャンネル]
(https://www.youtube.com/channel/UCbHff-wfjTnB3rtXIP6y0xg)
[Medium](https://medium.com/@rockyshikoku)

[相棒](https://twitter.com/oka_yuuji)
[note](https://note.com/oka_yuuji)
iOS14のIDFA制限が延期

※本記事は、 Appleで一般公開されている情報 を元に作成しています。

**訂正(2020/9/4 11:17)**

すみません、同日リリースされた最新のiOS14 betaの細かな挙動について公開して良いのか怪しいため、
自らご確認ください。

27:37
https://developer.apple.com/videos/play/wwdc2020/10676/

![スクリーンショット 2020-09-03 18.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308423/88b1bd69-86da-a538-e65f-b68b896fa9f7.png)

上記のようにプライバシーの配慮によりiOS14からユーザーの許可を得ないとIDFAを取得できなくなる予定でしたが、
IDFAの制限が来年はじめ(early next year)まで延期されたようです！！
https://developer.apple.com/news/?id=hx9s63c5
https://techcrunch.com/2020/09/03/apple-delay-ios-14-privacy-ad-tracking/
StackViewでどのデバイスでもレイアウトが崩れない十字キーを作成する

##できること
<img width="200" alt="IMG_A6DABE312A3B-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/6e07192d-6b8f-ba1c-6e92-f783b81c4913.jpeg">
ゲーム等で十字キーを再現したい...けどレイアウトが崩れてしまう！
そんな時にはStackViewで絶対に崩れないレイアウトを作成しましょう。

##方法
<img width="250" alt="IMG_B53D09532B14-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/770744cd-3014-b575-e6e0-9e79c491f104.jpeg"> 
StackViewで水平方向にView Button View を配置し、それらをさらにStackViewで鉛直方向に配置します。
StackViewの設定でViewとButtonが同じ大きさになるように設定することも、直接width = heightとなるように設定することもできます。
ラズパイのVNC Viewer化

ラズパイを[VNC](https://ja.wikipedia.org/wiki/Virtual_Network_Computing)クライアント(Viewer)化する手順です。ラズパイ依存の部分が無いのでUbuntu, Debianでも同様にできます。サウンドもpulseaudio経由でちゃんと出ます。

# ラズパイ側準備
## ラスパイSDカードの下準備

1. https://www.raspberrypi.org/downloads/ からSDカードイメージをダウンロードし起動する。デスクトップ環境が含まれるSDカードイメージを選択すること。32bit版でも64ビット版でもどちらでもよい。
2. ネットワークへの接続（有線でも無線でもよい）とキーボードの設定などを行い普通に使えるようにする
3. ターミナル（など）から `sudo apt-get install pulseaudio tigervnc-viewer` で PulseAudioとTiger VNC Viewerパッケージをインストールする
4. 音を鳴らしたいなら、以下の作業に進む前に音が鳴ることを確認する。USB接続マイクスピーカーなども使え、録音もできます。
5. VNCサーバーのほうは、以下のラズパイの設定前に普通に使えるようにしておいて下さい

## VNC ViewerとPulseaudio自動起動ファイル作成

下記の２つのファイルを作る

```config:/mnt/etc/systemd/system/tigervncviewer.service
[Unit]
Description=Tiger VNC Viewer
After=network-online.target
Wants=network-online.target

[Service]
Type=exec
# 次の行の192.168.1.72:1をVNCサーバーのホスト名とディスプレイ番号に置き換える
ExecStart=/usr/bin/xinit /usr/bin/xtigervncviewer -FullScreen -RemoteResize 192.168.1.72:1
Restart=always

[Install]
WantedBy=multi-user.target
```

次の`auth-ip-acl` にはウェブブラウザなどを実行する計算機のIPアドレスが含まれるように書く

```config:/mnt/etc/systemd/system/pulseaudio.service
[Unit]
Description=PulseAudio system server
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/pulseaudio --load="module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.1.0/24" --daemonize=no --system --disallow-exit --disallow-module-loading=no

[Install]
WantedBy=multi-user.target
```

ラズパイのターミナルから `sudo systemctl set-default multi-user.target;` `sudo systemctl enable tigervncviewer pulseaudio` を実行する

# 音声の送り方
これだけだと音が出ないので、ウェブブラウザなどを実行する計算機から音声をラズパイに送るように、を下記のファイルを設置することで指示する。

```$HOME/.xsessionrc
export PULSE_SERVER=ラズパイのIPアドレスかホスト名
```

# Could not acquire name on session bus
というメッセージがMATEで出るときには上記の`/etc/X11/Xsession.d/` に適当なファイルを作成してその中で `unset DBUS_SESSION_BUS_ADDRESS` する。このメッセージは、キーボードとリモートホストの両方から同時にログインしようとしたときに生じるが、そういう使い方は基本的にサポート外だと思われる…

[OpenBox](https://packages.debian.org/sid/openbox) はキーボードとXDMCPからの同時ログインで一応動作する。

# ラズパイX端末の電源の切り方など
`CTRL + ALT + ファンクションキー` でログインプロンプトが出てくるので、ユーザー `pi` でログインして `sudo systemctl poweroff` などとする。`sudo apt-get update; sudo apt-get dist-upgrade` でインストール済みのラズパイLinuxカーネルやXサーバーなどの更新もできる。
ライトニングトークのススメ（意義編）

# LTとは

>ライトニングトーク（英: Lightning Talks）とはカンファレンスやフォーラムなどで行われる短いプレゼンテーションのこと。様々な形式があるが、持ち時間が5分という制約が広く共有されている。

引用：[ライトニングトーク - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%88%E3%83%8B%E3%83%B3%E3%82%B0%E3%83%88%E3%83%BC%E3%82%AF)

# 結論

LTはエンジニアとしてのスキルアップに繋がるので、積極的に登壇しましょう!

# インプットとアウトプットの話

技術力向上のために、日々何をしていますか？

気をつけるべき点は、インプット偏重になっていないか？ということです。
技術書を読んだりネット記事を読むだけで、手を動かす『アウトプット』を軽視していませんか？

料理本をひたすら読むだけの一流料理人はいませんし、
イメージトレーニングしかしない野球の3割打者もいないはずです。

インプットも重要ですが、それと同じぐらいアウトプットの機会も積極的に作っていく必要があります。

# 学習効率

ラーニングピラミッドという考えがあります。
結論から言うと根拠のない理論らしいのですが、感覚的になんとなく正しいように感じませんか？

![learning.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/4a1f3a13-2ca6-d463-2028-1857aa5b08a3.png)

また、マネジメントの父として知られる経営学者のピーター・ドラッカーは、以下の名言を残しています。

**人に教えることほど、勉強になることはない。**
**人の成長の助けとなろうとすることほど自らの成長になることはない。**

実際教える側に立つと、うろ覚えの部分が不安で追加で調べたり、理解しきれていない・言語化できていないところが浮き彫りになります。

LT未経験の方からすると、登壇者は「高い知識を持っていて、視聴者にそれを分け与える」印象かもしれません。
もちろんその側面もあるのですが、実は登壇者自身のスキルアップにも大きく貢献することになります。

# アウトプットを怠らない

アウトプットを怠ってインプットに偏重した勉強法は、成長という観点で効率が悪いです。
インプットだけでもスキルアップはできますが、そのスピードは当然遅くなります。

RPGに例えるなら、インプット専門の勉強法は最初のダンジョンでスライムを倒し続けているようなもの。
経験値効率が悪いのでレベルアップスピードが遅く、後発の勇者にドンドン追い抜かれてしまいます。

# アウトプットの手段

人に教える手段として、LTが何も唯一の手段でも完璧な手段でもありません。

社外カンファレンスだったり、ブログやnote, Qiita記事であったりYoutube等多種多様に渡ります。
しかし一番ハードルが低いのは社内でのLTではないでしょうか。
もしエンジニア組織でありながら社内LTが無いのであれば、実施を提案してみると良いでしょう。

# 結論

LTはエンジニアとしてのスキルアップに繋がるので、積極的に登壇しましょう！

[ライトニングトークのススメ（テクニック編）](https://qiita.com/rf_p/items/b8a0c5e92529bbf7efd1)へ続きます
【Javascript】if文をワンライナー（1行）で書ける三項演算子とは？

Javascript 三項演算子（if文を一行で書く）
# なにこれ
Javascriptを学習中に、下記のコードを見て「ワンライナー？何これ？」と思ったので、
備忘録として記事化しました。（確か前にも同じ箇所でつまずいた）

```
count += todo.done ? 100 : 1;
```

# 答えは三項演算子
if文をワンライナー（一行）で書く方法の一つ
構文は下記

```
条件式 ? trueの時 : falseの時
```

# 例文
trueの場合

```test.js
test = true;
console.log(test ? 100 : 1);
  // 表示結果：100
```
falseの場合

```test.js
test = false;
console.log(test ? 100 : 1);
  // 表示結果：1
```

# 余談
紛らわしいのでif文で書きたい（本音）
でもワンライナーで書いた方がコードが短くなって可読性上がる。この葛藤。
Git環境開発リンクまとめ

#Git

Sourcetree
https://ics.media/entry/4969/
https://qiita.com/nnishimura/items/b5410e35f3a292a55244

Git
https://www.granfairs.com/blog/staff/git-mistake-parent-branch
https://reasonable-code.com/sourcetree-invalid-error/
https://qiita.com/o_msyk/items/6a74623903e392ce92a3

コンフリクト
https://qiita.com/hkengo/items/f47b9f50ac2dca407d12

vi
https://qiita.com/pe-ta/items/0510bee10bcfd88afeee
herokuのmongoのダンプリストア

```
mongodump -h ds335648.mlab.com:35648 -d heroku_j12xcpbw -u <user> -p <password> -o <output directory>
```
![lw毛fんlクェfんlウェ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/f1724d36-73da-efcd-ee66-76c387f37dec.png)

https://www.mlab.com

## 02

```
mongorestore -d db_name /path/
```

https://stackoverflow.com/questions/6770498/how-to-import-bson-file-format-on-mongodb

## 03

```
heroku config
```

https://qiita.com/master-of-sugar/items/23774fe3a483bda0e696
Rails6で複数チェックボックスを使う！

オリジナルアプリのユーザー登録機能実装中複数チェックボックスを使いました！
初心者のため備忘録として初投稿します！
間違えていたらコメントで指摘をお願いします笑


<h1>チェックボックスの書き方</h1>
チェックボックスといっても書き方は色々あります。
今回は関連するモデルがあるのでcheck_boxメソッドを使いました。

```
 <%= f.check_box  :food, {multiple: true}, food, nil %>
```
こんな感じです。
foodの部分はそれぞれ指定したいオブジェクト名を入れてください。
ちなみにカラムの型はtext型で指定しています。
複数選択を可能にする為に、{multiple: true}を書きます。

<h1>キーのパラメーターを許可する</h1>
今回のアプリ製作ではユーザー登録にdeviseを使用しているので、application_controller.rbにのprivateメソッド内にチェックボックスのパラメーターを許可する為の記述をします。

```
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname, food:[]])
  end
```
  [ ]を忘れないように。

<h1>form画面の書き方</h1>

こんな感じです。

```
<div class="field">
    <% %w(ステーキ ハンバーグ 寿司 オムライス).each.with_index do |food,i| %>
    <label>
      <%= f.check_box  :food, {multiple: true}, food, nil %>
      <%= food %>
    </label>
    <% end %>
  </div>
```

チェックボックスの項目は％記法を使い配列の中に入れてあげます。
そしてそれをeach.with_indexを使い、配列の要素を変数foodに格納して番号も振っています。
lebelタグでフォームの項目の関連付けをすることを忘れないように


以上です！！
formは難しいですね笑
初心者なので書き方がわからず、理解できないところもありましたが、使えるようになると便利だとおもいます！
間違えやもっといい書き方がありましたら教えていただけると幸いです！
他のサイトを参考に見よう見まねでやりましたが実装はうまくできたと思います！
参考にしたサイトはこちらです！⇓⇓
https://www.sejuku.net/blog/27132
UIFlow で RoverC とToF Unitを同時に使う方法

# 概要
UIFlowでRoverC HATとToF Unitを同時に使うと不安定になる問題の解決方法。
文章は短いですが、結構大変だったのでメモ書きです。

# 経緯と問題
M5Stack(M5SickC)のプログラムをMakecode風にビジュアルに開発できる[UIFlow](https://m5stack.github.io/UIFlow_doc/ja/)を試しています．これはM5StickCのHATやGroveのUnit用のライブラリが組み込まれていて大変便利です。

迷路探索ロボットの実験のために[RoverC](https://www.switch-science.com/catalog/6206/)と[ToF距離センサユニット](https://www.switch-science.com/catalog/5219/)を組み合わせて次のような簡単なテストプログラムで試してみました。
![2020-09-04-09-27-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71087/04f75d41-9fb9-9103-5663-be2c7e4d7f3b.png)
事前にUnitsでToFを、HatでRoverCを追加し、数値を表示するためにLabelを追加しています。

しかしこれだけのプログラムでも、"I2C bus error (19)"と出て同時に使えません．距離センサの読み取りとRoverCへの動作命令の間に50ミリ秒程度のウェイトをいれるとうまくいく場合はありますが，エラーが出ることもあり，どうにも不安定です．

# 解決方法

調べてみても，なかなか同じような問題に当たっている人がいないようです．[ソースコードらしきもの](https://github.com/m5stack/UIFlow-Code/blob/master/units/_tof.py)を発見してみてみると、ToFユニットとの通信が、70ミリ秒ごとのタイマー割り込みで値の取得をしているようです。どうもこのタイマー割り込みが怪しいと思って、tof1.deinit()でタイマーをとめて，tof1._update()をしてから値を取得するようにすると．．．ビンゴ！。エラーが出なくなり、さらにセンサの値の更新も高速になりました．
![2020-09-04-09-30-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71087/00542b2f-27e1-d599-8cee-8be5cd87ce5b.png)

最終的にこの_tof.pyを参考にしながら、タイマー割り込みを使わないCustom Blockを作成しました。
【LINEWORKS API】新機能！BOT でファイルを送受信！

ver 2.9 で（個人的に）待望の BOT でのファイル受信が追加されました！ヾ(´∀｀)ﾉ
[[リリース] アップデートのお知らせ (8月25日)](https://developers.worksmobile.com/jp/notice?lang=ja&detailUrl=https%3A%2F%2Fjp1-notice.worksmobile.com%2Fview%2F%23%2Fdetail-view%2F497%3Fusess%3D1%26serviceType%3D12%26serviceLanguage%3Dja_JP)

ではではさっそく使ってみましょう！

# ngrok を使って Callback を受信

おなじみ ngrok さんの登場です！
もう 2年の付き合いになりますか…長いような短いような。
本当に色々助かっております。今回もよろしくお願いしますね！

・・・え、ngrok さんを知らない！？Σ( ﾟДﾟ)
ngrok さんはローカル PC の外部公開用 URL を取得してくれるステキモジュールなんですよ！
細かい設定は、過去の記事になりますがこちらの記事をどーぞ(*_ _)
[ローカル環境で LINEWORKS Bot を動かす話](https://qiita.com/kunihiros/items/c9a5340f4512149e580d#%E5%A4%96%E9%83%A8%E5%85%AC%E9%96%8B%E7%94%A8%E3%81%AE-url-%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6-bot-%E3%81%AE-callback-url-%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B)

# Bot にファイルを送信する

ファイルの送信はとっても簡単です。
LINEWORKS のトークサービスを開いて、ファイルをクリック＆ドロップするだけ！

![1599125206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/9e21273f-b3d9-9889-60c9-f8b513b432e8.png)


すると、Bot がファイルを受信します。

```js
{ type: 'message',
  source: { accountId: 'name@domain.xyz' },
  createdTime: 1599112511707,
  content:
   { type: 'file',
     resourceId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' } }
```

受信内容の `resourceId` を使って LINEWORKS のメンバーにファイルを転送することができます。

## 別のメンバーに File を送信

これは従来のメッセージ送信 API とほぼ変わりませんね。
[LINEWORKS API - メッセージ送信 (File)](https://developers.worksmobile.com/jp/document/100500810?lang=ja)

`content` の `type` を `file` に指定します。

```js
const request = require('request');
const options = {
  'method': 'POST',
  'url': 'https://apis.worksmobile.com/r/API ID/message/v1/bot/botNo/message/push',
  'headers': {
    'consumerKey': 'xxxxxxxxxxxxx',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
  },
  body: JSON.stringify({
    "accountId":"name@domain.xyz",
    "content":{
        "type":"file",
        "resourceId":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
  })
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
```

![1599125265.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/8daa6f84-bdbd-7cf6-874b-de5a6c77d12a.png)


別のユーザに転送できました！
これで、色々なファイルのやりとりができますね～♪

# おわりに
ここまでお付き合いいただきありがとうございました。

待ちに待った新機能！
ファイル扱えるとなると、Bot の利用幅が凄く広くなると思うんですよね～。
音声や動画ファイルとかもいけるのかな？
色々試してみたいですね！

ではまた！(^^)/

# 参考にさせていただきましたm(_ _)m
[LINEWORKS Developers](https://developers.worksmobile.com/jp/?lang=ja)
[JavaScript]addEventListener('load'）が発火してくれない問題

問題・window.addEventListener('load', change)と記述しているのに
更新ボタンを押さないとイベントが発火してくれない

前提
changeは変数自分で命名する

```
change.jsの記述内容
function change(){
  item.addEventListener('keyup', function(){
 keyupした時の処理内容
  })
}
window.addEventListener('load', change)
```
window.addEventListener('load', change)と記述すれば
windowがloadされた時にchangeの内容が処理されるようになる


#解決方法
app/javascript/packs/application.jsの内容を書き換える

```
require("@rails/ujs").start()
require("turbolinks").start()#消す
require("@rails/activestorage").start()
require("channels")
require("../change")
```

require("turbolinks").start()
この記述を消すと解決される

#解説
turbolinksとは？
TurbolinksはRails4.0からデフォルトで導入されたgem
js, cssの読み込みを初回時に行い次回以降の読み込み処理を省略することで高速化する。


#Turbolinksの問題点
(document).ready()が発火しない
(window).load()が発火しない←今回の問題
metaタグが更新されない


#まとめ
過去保存したjs、cssをいち早く表示するようにrequire("turbolinks").start()が動作している。なのでページを開いた時、新しく追加したchange.jsを反映してくれない。
その後更新ボタンを押すとwindow.addEventListener('load', change)が発火しchange.jsで設定した処理を行ってくれる。

よってページを開いた時から追加したjsの処理を実行して欲しかったらrequire("turbolinks").start()を消す。これで過去保存したcss、jsの情報を表示しなくなり、新しく記述したデーターを読み取り表示できるようにする。
それって deno ではどうやるの？ (バレル編)

# バレルってなんだっけ

バレル(Barrel)とは、複数のモジュールから1つのモジュールにエクスポートをロールアップする方法です。
`node.js` であれば

```example_nodejs.ts
import { SpecA } from './specifications/spec_a';
import { SpecB } from './specifications/spec_b';
import { SpecC } from './specifications/spec_c';
```

と書いているものを

```example_nodejs.ts
import { SpecA, SpecB, SpecC } from './specifications';
```
と書けるようにする仕組みである。

```./specifications/index.ts
export * from './spec_a'; 
export * from './spec_b';
export * from './spec_c';
```

というファイルを用意すればランタイムが勝手に判断してくれる機構である。

# deno ではどうするの？
しかし。`deno` では `index.{js,ts}` による魔法のようなモジュールの依存関係の解決はやめようと、この仕組みは用意されていない。deno で`node.js` のように以下の

```example_deno.ts
import { SpecA, SpecB, SpecC } from './specifications.ts';
```

ように書きたい場合は、`index.ts` を用意するのではなく

```./specifications.ts
export * from './specifications/spec_a'; 
export * from './specifications/spec_b';
export * from './specifications/spec_c';
```
というファイルを用意することになるであろう。もちろん、今まで通り `index.ts` を用意して

```example_deno_index.ts
import { SpecA, SpecB, SpecC } from './specifications/index.ts';
```

という形でインポートすることも可能である。しかし、`index.ts` は「誤解のもとだから使うな」と `deno` のスタイルガイドに書いてあり、わざわざ茨の道を進まなくても良いと思う。
** is not available. please reconnect the device.　対処法

#実機テストができなくなった！
BigSurベータアップデートあたりからそういうことがちらほらあるようです。

**心配しないで。いくつかの方法を試せば、なんとかなります（たぶん）。**

+ macOSをアップデートする（ぼくこれで解決しました）。
+ Xcodeをアップデートする。
+ iOSをアップデートする。
+ デバイスとmacのペアリングを一度解除してみる。
+ プロジェクトの対応iOSバージョンを変えてみる。
+ macを再起動する。
+ シミュレーターで実行してからデバイスを試す。
+ クリーンビルドフォルダ。
+ デバイスサポートファイルをダウンロードしてみる。 https://github.com/iGhibli/iOS-DeviceSupport/blob/master/DeviceSupport/

 （デバイスサポート参考記事：[【Xcode】実機で動かそうとしたらこんなエラーが出た時](https://qiita.com/solabito331/items/17ee51d954fb3f87b37c)）
+ ライトニングケーブルのUSBのポートを変えてみる。
+ デバイスのアプリを一回消してみる。
+ デバイスを再起動。

こういうのをやっているうちに、解決するはずです（たぶん）。

****
Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[MLBoysチャンネル]
(https://www.youtube.com/channel/UCbHff-wfjTnB3rtXIP6y0xg)
[Medium](https://medium.com/@rockyshikoku)

[相棒](https://twitter.com/oka_yuuji)
[note](https://note.com/oka_yuuji)