OmniAICreator/Qiita-1.07M huggingface dataset:
【SeleniumBasic】キャプチャした画像をエクセルファイルに貼りつける

# 記事の内容
VBAでブラウザ自動操作を行える、SeleniumBasicを使ってwebページにアクセス、画面のキャプチャ、エクセルに貼りつけるまでの流れを紹介します。
seleniumでキャプチャした画像をそのままエクセルファイルに貼りつけて保存したい！って方のざっくりとした参考資料になれば…

**検証環境**
windows8.1
Microsoft Excel 2013
google chrome バージョン: 74.0.3729.169
chromedriver chrome対応バージョン 

### なぜVBAで？
キャプチャした画像をどこかのディレクトリに保存するのではなく、直接エクセルファイルに貼りつけて保存したかった。

## VBAでSeleniumBasicを使用するための準備
こちらのサイトが参考になりました。（丸投げ）
https://sugiyamatatsuya.com/vba-selenium-setup/

## 実際のコードと解説コメント
ﾍﾟﾁｮﾘ…

```

Option Explicit

' Sleep するために使用
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
'  webDriverの生成
Public driver As New ChromeDriver
' 画像を貼りつける位置を設定するために使用。nowHeightPoint はセルの行の位置を表している。
Public nowHeightPoint As Long


' 新規エクセルファイルを開いて、webページにアクセスしてスクショ、それをエクセルファイルに貼りつけて保存して閉じる。
Sub main()

    ' 新規でファイルを開いた時のワークシートの数を1に設定
    Application.SheetsInNewWorkbook = 1
    
    ' てはじめにgoogleへアクセス
    driver.Get "https://www.google.com/?hl=ja"
    driver.Window.Maximize

    Dim wb As Workbook
    ' 新規ワークブックを開く
    Set wb = Workbooks.Add
    
    ' 最初に貼りつける画像を位置を格納
    nowHeightPoint = 1

    'qiitaにアクセスしてスクショ、それをエクセルファイルに貼りつける。
    screenShotFunction ("https://qiita.com/")
    '楽天にアクセスしてスクショ、それをエクセルファイルに貼りつける。
    screenShotFunction ("https://www.rakuten.co.jp/")
    
    ' webDriverの終了
    driver.Close
    driver.Quit


    ' マクロがあるパスと同じ階層に選択したファイル名で保存する。
    Dim macroFilePath As String: macroFilePath = ThisWorkbook.Path
    wb.SaveAs Filename:=macroFilePath & "\testCapture.xlsx"
    MsgBox "保存先：" & macroFilePath & "\testCapture.xlsx"
    wb.Close
End Sub

' 受け取ったURLへアクセス、スクショを取って取ったImageをpasteFunctionへ渡す。
Sub screenShotFunction(url As String)
    
    ' 引数で受け取ったURL へアクセス
    driver.Get url
    Sleep 2000

    Dim captureImage As Image
    ' driver.TakeScreenshotで画面を実際にキャプチャしている
    Set captureImage = driver.TakeScreenshot
    
    ' 画像をリサイズしてエクセルファイルに貼りつけるsub関数を呼ぶ
    Call pasteFunction(captureImage)

End Sub

' Imageを受け取ってリサイズしてアクティブシートに貼りつける
Sub pasteFunction(captureImage As Image)
    Dim resizeImage As Image
    ' スクショした画像が大きいのでリサイズ
    Set resizeImage = captureImage.Resize(900, 450)
    ' ここでイメージをクリップボードにコピーしている。
    resizeImage.Copy
    Sleep 1000

    ' クリップボードにある画像を　nowHeightPoint行　1列目を始点に貼りつける。
    ActiveSheet.Paste Destination:=Cells(nowHeightPoint, 1)
    
    ' 次に画像を貼りつける位置をセル20個下の位置にしている。
    nowHeightPoint = nowHeightPoint + 20

End Sub

```
## コード抜粋（↑のコードを抜き出しただけ。肝の部分的な感じです。）
```
Dim captureImage As Image
' driver.TakeScreenshotで画面を実際にキャプチャしている
Set captureImage = driver.TakeScreenshot
```

```
' スクショした画像が大きいのでリサイズ
Set resizeImage = captureImage.Resize(900, 450)
' ここでイメージをクリップボードにコピーしている。
resizeImage.Copy
' クリップボードにある画像を　nowHeightPoint行　1列目を始点に貼りつける。
ActiveSheet.Paste Destination:=Cells(nowHeightPoint, 1)
```

## 課題

2枚目以降に貼りつける画像の高さを調節するいい方法が分からなかった。
ImageクラスのToExcel Methodを使ってできそうだったが、読み方がよくわからず死亡… 
ToExcel Methodを使えればわざわざクリップボードにコピーして画像をエクセルファイルに貼りつける必要もなくなりそうです。
[shell] ディレクトリ内にある画像ファイルをpdfにまとめて{ディレクトリ名}.pdfとして出力する

# やりたいこと
以下のようにカレントディレクトリの中に複数のディレクトリがあり、
さらにそのディレクトリの中に複数の画像ファイルが格納されています。

```
ディレクトリ01/
　- picture01-01.jpg
　- picture01-02.jpg 
ディレクトリ02/
　- picture02-01.jpg
　- picture02-02.jpg
ディレクトリ03/
　- picture03-01.jpg
　- picture03-02.jpg
  ...
```

この状況下で、シェルを実行し、各ディレクトリ内の画像ファイルを１つのpdfにまとめて、
以下のように出力をします。

```
ディレクトリ01.pdf (picture01-01.jpg + picture01-02.jpg)
ディレクトリ02.pdf (picture02-01.jpg + picture02-02.jpg)
ディレクトリ03.pdf (picture03-01.jpg + picture03-02.jpg)
```

# シェル

```sh

PRE_IFS=$IFS; 
IFS=$'\n'; 

for dir in `ls` 
 do 
  convert $dir/*.jpg $dir.pdf
done
```

これで終わり。

# ワンライナー　

これくらいならワンライナーでもいいでしょう。

```terminal
$ PRE_IFS=$IFS; IFS=$'\n'; for dir in `ls` ; do convert $dir/*.jpg $dir.pdf ; done
```
Burp Suiteでのセキュリティテスト[導入編]

前回の投稿に引き続きBurpSuiteの設定と実際の動作を見ていこうと思います。
まずローカルプロキシの設定をPCにします。
これにより、ブラウザとサーバとの通信に、一旦自身のローカルプロキシをかませることにより通信の傍受することが可能になります。


インターネットのプロパティからプロキシサーバーの設定をします。
Windwos 10で開き方が変わったようです。
https://win10labo.info/win10-internet-options/

クロームからも開けます。
LANの設定→プロキシサーバー
<img width="175" alt="burp9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/e9c5cca7-d082-2bd5-0314-97a609aee449.png">


<img width="524" alt="burp2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/b3ff97be-2cb5-f127-4775-0e04d44f5299.png">






<img width="223" alt="burp3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/cacb27ea-ccee-7dfb-c814-f98ecc69edde.png">



ローカルホストをプロキシに設定します。
localhost または 127.0.0.1  
port には 8080を設定します。なんでもok
（127.0.0.1はlocalhostのことです。  ）

<img width="316" alt="burp4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/c3007808-420a-b9d3-9f93-e24957328a9b.png">

ブラウザで適当なサイトにアクセスしてみます。　たとえばーyahoo.co.jp
プロキシ（代理サーバ）との通信なのでブラウザが証明書エラーを発生させています。。

<img width="522" alt="burp10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/67233504-c1bd-0732-4bda-478df930ff07.png">

詳細設定をクリックすることで、　プロキシが返しているyahooにアクセスすることができます。
<img width="500" alt="burp11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/ee70d07e-b8db-b920-f703-e2cff70d4e8c.png">


<img width="560" alt="burp15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/b36b16d9-dc64-d058-a51d-bc43613db8a8.png">



次回、通信内容についてみていこうと思います。
Gradleが反応しない　効かない　読めない

Spring Boot でネット検索で見つかったクラスを使おうとした時import文だけ書いても
反応しない。

で、gradleに記述するのですが、そのあと正しくrefreshしないとimport出来ずハマったのでメモ。

buil.gradleを右クリックするとrefreshメニューが見えているがこっちはimport分には関係ない。
下の写真のようにGradleに合わせてそのサブメニューのRefresh Gradle Projectを選ぶとbuild.gradleに追記した分がライブラリとしてインストールされて使えるようになる。

また、ライブラリはプロジェクトごとに入れなおさないと、gradleに記述したプロジェクトでしか動かない。

<img width="506" alt="スクリーンショット 2019-06-04 22.26.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/9cf75ed1-5132-63c2-c41c-fd98911ea688.png">
php://outputが書き込みの途中で出力される

調べたのでメモ。
※信憑性は自信なし。

**※コメントを読んでください。**

```php
<?php
$array = getArray();    // BDとから取得

$file = new SplFileObject('php://output', 'w');

foreach($array as $row) {
  $file->fputcsv($row);
}

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=sample.csv');
header('Content-Transfer-Encoding: binary');

$file->fflush();
```

$arrayの中身が大きくなると
Warning: Cannot modify header information - headers already sent by がでた。
しかも環境によって出たり出なかったり。

output_buffering に値が設定されていたことが原因のようでした。

```:php.ini
output_buffering=4096
```

https://www.php.net/manual/ja/outcontrol.configuration.php#ini.output-buffering
>output_buffering boolean/integer
このディレクティブを 'On' と設定することにより、全てのファイルに 関して出力バッファリングを有効にすることができます。 特定の大きさにバッファの大きさを制限したい場合、このディレクティブの 値として 'On' の代わりに最大バイト数(例:output_buffering=4096) を使用することができます。 PHP-CLI ではこのディレクティブが常に Off となります。

output_bufferingに'on'もしくは最大バイト数をあげればエラーが消えました。

https://www.php.net/manual/ja/wrappers.php.php

>php://output 
php://output は書き込み専用のストリームで、 print および echo と同じ方法での出力バッファへの書き込みを許可します。

出力バッファへの書き込んでいたけれど、設定されていたバッファの最大バイト数に達したので出力されていたよう
※予想の範疇を出ていません。違ったら教えてください。

# 修正

```php
<?php
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=sample.csv');
header('Content-Transfer-Encoding: binary');

$array = getArray();    // BDとから取得

$file = new SplFileObject('php://output', 'w');

foreach($array as $row) {
  $file->fputcsv($row);
}

$file->fflush();
```

なぜ初めからこう書いていなかったのか...？
でもおかげで調べたのでよし。
エンジニアが「アウトプット大全」を読んだ感想

#本の紹介
[『アウトプット大全』](https://www.amazon.co.jp/dp/4801400558)　樺沢紫苑（著）

今から1年ほど前に出たビジネス書です。エンジニア視点で大事だと思ったポイントを抜き出していきたいと思います。

#インプットとアウトプットの黄金比は「３：７」
多くの学生や社会人はインプットの割合の方が多いと思います。この本が社会人を対象に行った調査では、インプットとアウトプットの比は「７：３」という結果だったそうです。

僕自身も学生時代の勉強では、資格の勉強ばかりで教科書を読むことが多かったです。確かに知識は身に付いたのですが、今となってはほとんど忘れてしまいました。なぜなら覚えた知識を使うことがなかったからです。知識をもとに何かを作ったり仕事をすることで、エピソード記憶となって脳に残りやすくなるのですが、それがなかったということですね。ほかにもプログラミングの勉強ばかりしていて、作品を作らない、知識を披露しないなども同じ例だと思います。おかげで何も作れないプログラマーの出来上がりです。

知識を使いこなすためには「３：７」とアウトプットを重視する必要があります。具体的なアクションとしては学んだ技術をブログに書く、SNSに書く、人に説明するなどでしょうか。作品を作るのも手っ取り早いですね。

インプットの量を減らしていいのか？という意見もあると思います。確かにそうなのですが、インプットしても結局忘れてしまっては意味がないです。特にプログラミングに関しては、仮に忘れてもその都度調べればいいと思います。たとえば「JavaScriptの配列の使い方忘れた」ならググってドキュメント見ればいいですね。むしろいかにググれるかが重要かもしれません笑

#紙に書く・絵や図を書く
本では紙に書いて整理することで、記憶定着やアイデアが思いつきやすくなると書かれていました。また口頭よりも視覚を使った説明の方が6倍以上記憶に残るとも書かれています。

これは勉強でもそうですし、仕事でも例えば設計図を作ることは多いと思います。最終的にはPC上で図を書くことになると思いますが・・・。まずはアナログで紙に図を書いて整理することは有効でしょう。エンジニアだからこそアナログ手法が脳の刺激になるはずです。

#楽しむ
本では楽しいと脳内で「ドーパミン」が出て、集中力やモチベーション、学習能力を高めるとあります。一方嫌々やることでは、「コルチゾール」が出て、楽しいの真逆の効果が出るとあります。

ぶっちゃけ好きじゃないとエンジニアやってられないですよね。なんとなく楽しいからエンジニアをやっている人は多いと思います。だからこそプライベートでも自己研鑽ができるはずです。これだけ努力が報われる職業って他に無いですよね。比較的運要素が少なく、才能もそこまで必要じゃないですし。

楽しむ→自己研鑽する→成長する→好きな仕事ができる→楽しむ
この無限ループが最強でしょう。

それでも楽しくない仕事をしている人もいるはずです。そのような人は「楽しいことを探して自己研鑽する」がベストだと思います。ある程度自分で勉強して「これをやりたくて勉強してきました！」と申し出れば、相手もそれならやらせてあげようとなって、好きなことができる可能性が上がりますね。

#その他
###完成させる
良いものを作ろうとせず、まずは30％作るべきです。そのあとに細かいところを直していけばいいですね。完璧主義はNG。
###説明する
人に説明することで理解度が90%に達するそうです。学んだ技術を周りに説明しましょう。
###運動する
エンジニア運動不足になりやすいですからね！脳が活性化するのでリフレッシュにも最適です。

#まとめ
全体としてアナログ手法が多いですが、PC作業が多いエンジニアだからこそ有効なのでオススメしたいです。
僕も今後はQiitaなどを通してアウトプットしていきたいと思います。
Sign in with Apple 用の Ruby Gem をリリースして Rails でサンプル実装してみました

iOS App に Apple ID でログインできたらいいのになぁ〜と思い続けてはや数年、ついにそんな時代がやってきましたね！

ということで、FB Connect 登場時の fb_graph gem リリース以来のスピード感で、Sign in with Apple 用の ruby gem をリリースしてみました。
[github.com/nov/apple_id](https://github.com/nov/apple_id)

ついでに Rails のサンプルアプリも。
[github.com/nov/signin-with-apple](https://github.com/nov/signin-with-apple)

このサンプルアプリはこちらで動かしてるので、試したい方はどうぞ。
[signin-with-apple.herokuapp.com](https://signin-with-apple.herokuapp.com/)

Sign in with Apple は OpenID Connect を採用してるんですが、現状では Native SDK でしか email や fullName は取れないようです。

そのうち UserInfo API が出てくると思うんで、出てきたら apple_id gem でもサポートしようかと思います。

ps.
とりあえず Terminal で動かすだけでいいよって方はこちらのサンプルをどうぞ。
https://gist.github.com/nov/993a303aa6badd8447f7b96fb952088e
Kantu Browser Automationを使って自動テストをしてみる

##1 概要

システムのテストを行っているとき、同じ作業を何度も行って疲弊することが多いと思います。
また、バグの発生などでテストをやり直しになったり、回帰テストとして同じケースを何度も実行することもあると思います。

そんな場合にはテスト自動化が有効になります。

テスト自動化ツールとしてSeleniumが有名ですが、Seleniumの知見をすべて習得してからでは少し時間がかかってしまいます。

Kantu Browser Automationは、Seleniumによる自動テストを簡単に実行したり、Excelのマクロのようなイメージで画面操作を記録するということが簡単に行えるツールです。

Google Chromeの拡張機能としてインストールすれば、ブラウザで動くシステムをすぐに自動テストを記録することができます。

今回、Kantu Browser Automationのインストール、テストの記録と実行方法について簡単にご説明します。

##2 インストール

Google Chromeがすでにインストールされている前提で進めます。
インストールされていない方は、インストールをお願いします。

###1 Kantu Browser Automationのインストール

###1 Chromeから下記のサイトを開きます。

https://chrome.google.com/webstore/detail/uivision-kantu-for-chrome/gcbalfbdmfieckjlnblleoemohcganoc?hl=ja

###2 「Chromeに追加」をクリックします。

![pic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/ab0a8f18-fa2d-5616-f4cb-53313166551a.png)

###3 拡張機能として追加される以下のアイコンをクリックすると、Kantu Browser Automationが開かれます。

![pic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/593ff342-338b-a566-de75-713fc5cbec0f.png)

![pic3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/9078d6a6-ff3a-46f2-fa13-50a2572efa9b.png)

##3 テストを記録するためのサンプルサイトを確認する

テスト手順を記録するために、サンプルサイトにアクセスしてみます。

下記のサイトは日本Seleniumユーザーコミュニティさんが作成したSelenium動作用のサイトで、ブログ・書籍・Web記事用のサンプルやデモ用途など自由に使用して良いこととなっております。

http://example.selenium.jp/reserveApp/

サイトを開くと、以下のような予約システムの入力フォームが出てきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/bffb29e1-92ec-a4e1-3dc3-8e6019868ec2.png)

ここで、何か入力して「次へ」を押下すると、確認画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/23a821d1-294f-2343-4678-20a189df5a54.png)

完了を押すと、完了画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/b98e93b5-361d-f904-ac3d-51ac275b1165.png)

この一連の流れを、Kantu Browser Automationを使って記録してみたいと思います。

##4 テストを記録してみる

では、テストを記録する方法についてです。

まず、マクロの作成を行います。
手順は簡単で、この「+Macro」ボタンを押して、名前を入力するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/4736ba94-eb45-440a-e440-e4f2c9997652.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/fd88e9ab-ed27-3b58-a338-680bdf67e49c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/3960ada9-2106-52ff-9d13-9d52ed8ae27b.png)

その後、下記のRecordボタンを押下すると、マクロの記録が開始されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/f5915189-5c57-96e8-3ba8-ebbf9dae28b8.png)

記録が開始されたら、先ほどの動作確認用サイト（http://example.selenium.jp/reserveApp/ ）を開いて適当に入力し、完了画面まで進んでみましょう。

記録を終了したいときは、Stop Recordをクリックすれば終了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/26ef6053-ccd4-5d18-d4d3-df6b248377d8.png)

##5 記録したマクロを実行する

保存したマクロを開き、「Play Macro」をクリックすればマクロが実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337185/dee5471f-26d9-bd71-af71-0003a4842ba4.png)

##6 テスト内容を変えたい場合

マクロを記録する場合、少し余計な処理が記録されたり、タイミングによってはうまく記録されなかったりと言うことが発生します。
その場合、手動で修正が必要になります。

また、作成したマクロの内容を変更したり、追加で処理を作成することが多いと思います。

次回、マクロの記録で作成されるスクリプトの内容については下記の時期で解説しています。

https://qiita.com/gevanni/items/04101aed2907b87be0bb
Excel で他のブックへのリンクが紛れ込む場所

## はじめに

Excel を開くと「セキュリティ警告　リンクの自動更新が無効にされました」が表示されるようになる。
他のブックへの参照ができちゃったのは分かるのですが、どこに設定されたが見つからずに苦しんだことありませんか？

## 数式の中に紛れている

### 発生するケース

別シートの値を参照しているセルを含むシートを別の Excel にシートのコピーをするとコピー元の Excel への参照になります。

うちの会社だと設計書のヘッダーが最初のシートの値を参照していてて、新規の設計書を作る際に、他の設計書のシートをまるっとコピーする奴がいると発生してます。

### 探し方

Ctr + F で「.xl」に対してブックの検索をすると見つけられます。

## 「データ入力規則」の中に紛れている

### 発生するケース

別シートの値を参照している「データ入力規則」を設定してあるセルを別の Excel にコピペすると発生します。

うちの会社だと管理表の取り合いっこで、コピーした管理表に書き込んでおいた内容をオリジナルにコピーする奴がいると発生してます。

### 探し方

怪しそうなセル（リスト選択ができるようになっているセル）の「データ入力規則」の設定画面を開き、「同じ入力規則が設定されているすべてのセルに適用する」にチェックを入れると、他のブックへのリンクになってしまっているセルは同じ入力規則ではなくなっているので、選択状態になりません。

## 「条件付き書式」の中に紛れている

### 発生するケース

別シートの値を参照している「条件付き書式」を設定してあるセルを別の Excel にコピペすると発生します。

うちの会社だと入力値を変えるたびに色々とセルの色を変えることを生き甲斐しているPMが作った管理表でたまに発生してます。

### 探し方

[ホーム]-[条件付き書式]-[ルールの管理]から書式ルールの範囲で各シートのルールを表示し、ルールに「C:\...」「D:\...」のような値を探します。

## 他のブックへのリンクを作らない工夫

### 値の貼り付け

数式をコピペする必要がないのなら、値を張り付ければリンクは紛れ込みません。
（リンクがよく紛れ込む管理表は、なぜかセル結合がされていてコピペがしづらくなっていたりする。）

### INDIRECT

数式の INDIRECT を使うと、文字列をセルのアドレスとして認識させることができ、コピペした場合も値が変わりません。当然、コピペした先に Excel の同じ参照先にコピー元と同じように値が設定されている必要があります。

http://yiaowang.web.fc2.com/programing/vba_xls_tips/formula_indirect.html

## おわりに

今回は、イケてないドキュメントを使わざるを得ない環境に対する愚痴が半分です。しかもリンクを作る奴は、リンクの警告が出てても一向に気にしないし。

「他の場所にもリンクが紛れ込むことがある」とか「リンクはこうやって探すと見つかる」みたいなものがあれば、ぜひともコメントお願いします。
【CSS】backgroundで画像を扱うときに便利な記述

## CSSでbackground-imageを扱うときに画像のポジションをいい感じの位置にする
メモ書きです。
cssで画像の場所をええ感じにしたい時には大体以下のように記述しておけばなんと綺麗に見れる。

```css
background-image: url(../img/sample.jpg);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
```
ええ加減、ちょっとずつでもScalaの基礎を理解する　lazy　

# ええ加減、理解しないと
業務でScalaを書けるようにならなければいけない初心者が、あんま分かってなかった、というか本読んで流し読みだった概念を、
（ほぼ本と同じではあるが）自分で書いてみて、理解したことをまとめていきます。
だいぶざっくりなので、間違いがあれば指摘をいただけると大変ありがたいです。

ひとつの記事のサイズ小さめで行きます。

基本的には、『技術評論社　実践Scala入門』に沿って、気になる点を適宜記事にしていく方向です。

# lazy "怠け者"
* 計算の一部を遅らせるための修飾子（すでに構文的には成り立っている式に、意味を足すために記述するもの）
　　　　　　　private、protectedとかも修飾子
* コンピュータに大きな負担がかかるような計算を、呼ばれたときに、計算するようにしたいって時に使う。
　（呼ばれないと動きださないから、Lazy（"怠け者"）
「えーそれ、だるくねえ？本当に使うときだけにしてよ。呼ばれたらちゃんとやれるように準備はしとくからさ」って感じか。
* 計算は（一つのインスタンスにつき）一回しか行われない

## 実際にやってみる

```scala
object LazyStudy extends App {

  class LazyCircle(x: Int) {
    var radius: Int = x　// radius: 半径　　　※後で更新してみたいので、varで定義
    lazy val area = radius * radius * math.Pi // コンストラクタに、面積を記述。普通はインスタンス生成時に計算されるが、lazyがついているので、呼び出されたときに計算される。しかも一度きり。

    def printArea(): Unit = { // こちらが面積を呼ぶメソッド
      println("面積は、" + this.area)
    }
  }
}
```

以上をコンソールでRun

```console
scala> val crcl = new LazyStudy.LazyCircle(5)
crcl: LazyStudy.LazyCircle = LazyStudy$LazyCircle@892af0e //　インスタンス生成

scala> crcl.printArea() // 面積が必要なメソッドを実行。だるいけど、呼び出されたので仕方なく面積を求めてくれた。「でも、もうやらねえよ」
面積は、78.53981633974483

scala> crcl.radius = 10 // 半径を更新してみる
crcl.printArea()
crcl.radius: Int = 10

scala> 面積は、78.53981633974483 // 変わらない... 「一回きりしかやんねえから。よろしく」

```

ちなみに、別のインスタンスを作れば、ちゃんと改めて動いてくれます。

```console
scala> val crcl2 = new LazyStudy.LazyCircle(7)
crcl2.printArea()
crcl2: LazyStudy.LazyCircle = LazyStudy$LazyCircle@42150951

scala> 面積は、153.93804002589985 // ちゃんと、半径7に対して計算してる。
```


## 使いどころ
最初にも書いたが、大きな計算やクエリを行う場合で、その処理によって得られた値が毎回、頻繁には使われないとき。（？）
Scalaはコンパイル言語なので、通常はファイルを動かすときに計算を行っておくが、例えばWebサイトで、クライアントが押したら取得される計算があったりしたら、毎回ページを表示するたびに計算するよりは、呼ばれた時だけでよいよね、って感じか？？
matplotlibの極座標プロットで,北が0度・時計回りのグラフを描く

# 概要

極座標のプロットを描くには

```python
ax = plt.subplot(111, polar=True)
```

のように polar=true を指定すればよいのですが、
デフォルトでは東が0度、反時計回りのプロットが描かれます。

![polar1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244405/182d9d1b-c930-1c84-ea12-fbe50a1f32d0.png)

方角ごとのデータを扱いたい場合などは北を0度、時計回りにしたいこともあります。
以下の通り設定すればOKです。

```python
ax.set_theta_direction(-1)
ax.set_theta_zero_location("N")
```

# コード
```python:polar.py
import matplotlib.pyplot as plt
import numpy as np

theta = np.linspace(0, 2*np.pi, 100) 
r = np.linspace(0, 120, 100) 

tt, rr = np.meshgrid(theta,r) 
z = rr 

ax = plt.subplot(111, polar=True)

ax.set_theta_direction(-1)
ax.set_theta_zero_location("N")

ctf = plt.contourf(tt, rr, z, 100)

plt.colorbar()
plt.show()
```

# 出力
![polar2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244405/c0dbcecc-3ebc-942d-0865-dd8885d32b05.png)

素晴らしい。
1803を適用後のWindows 10で.NET Framework 3.5を有効にする

## 事象
.NET Framework 3.5を使いたかったが、有効化しようとするとエラーが発生した

## 前提
* Windows 10 (1803)
* エラー(0x800f0954)が発生した ※必ずしも同一のエラーコードとは限らない

## 問題
Windows Update (1803)以降、WSUS(Windows Server Update Services)への接続でエラーになる模様

## 解決
1. `Windows Key + R` → `gpedit.msc`を実行し、
2. コンピューターの構成 → 管理用テンプレート → システム を開く
3. オプションコンポーネントのインストールおよびコンポーネントの修復のための設定を指定する を編集する
4. 有効にし、オプションでWindows Updateから〜直接ダウンロード を選択して適用
5. `Windows Key + R` → `cmd`でコマンドプロンプトを立ち上げる
6. `gpupdate /force`を実行する（ローカルグループポリシーの更新）
7. 3.5の有効化を再び実施する

以上です
【Swift5】動画をループ再生する

##環境
- x-code10.2.1
- Swift5

##要件
- 動画をループ再生する(動画終了時に巻き戻す)
- 動画のアスペクト比は維持する
- 動画の拡張子は、m4v、mp4、movのいずれかとする


##実装

```ViewController.swift

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    /// AVPlayerViewを乗せるView
    @IBOutlet weak var videoView: UIView!
    
    private let playerView = AVPlayerView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // playerViewをUIViewに追加
        playerView.frame = CGRect(x: videoView.frame.origin.x ,
                                  y: videoView.frame.origin.y,
                                  width: videoView.frame.width,
                                  height: videoView.frame.height)
        // 動画の終了時に巻き戻し再生する
        NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
        
        if let playURL = URL(string: "hoge.mp4") {
            self.playerView.player = AVPlayer(url: playURL)
            self.playerView.player?.actionAtItemEnd = AVPlayer.ActionAtItemEnd.none
            // アスペクト比を維持
            self.playerView.setVideoFillMode(mode: AVLayerVideoGravity.resizeAspect.rawValue)
            self.videoView.addSubview(self.playerView)
            // 動画を再生
            self.playerView.player?.play()
        }
    }

    /// リピート
    @objc func endVideo() {
        playerView.player?.currentItem?.seek(to: CMTime.zero, completionHandler: nil)
    }
    
    /// 動画終了時
    ///
    /// - Parameter notification: Notification
    @objc private func playerItemDidReachEnd(_ notification: Notification) {
        // 動画を最初に巻き戻す
        self.playerView.player?.currentItem?.seek(to: CMTime.zero, completionHandler: nil)
    }
}

final class AVPlayerView: UIView {
    
    var player: AVPlayer? {
        get {
            let layer: AVPlayerLayer = self.layer as! AVPlayerLayer
            return layer.player
        }
        set(newValue) {
            let layer: AVPlayerLayer = self.layer as! AVPlayerLayer
            layer.player = newValue
        }
    }
    
    // MARK: - OverrideMethod
    
    override public class var layerClass: Swift.AnyClass {
        return AVPlayerLayer.self
    }
    
    // MARK: - Public Method
    
    /// アスペクト比を維持
    ///
    /// - Parameter mode: AVLayerVideoGravity
    func setVideoFillMode(mode: String) {
        let layer: AVPlayerLayer = self.layer as! AVPlayerLayer
        layer.videoGravity = AVLayerVideoGravity(rawValue: mode)
    }
}
```

## 参考
- https://aska.hatenablog.com/entry/2015/09/15/035827
- https://qiita.com/Ryosuke-Hujisawa/items/263bec5f11a62f403298
Backlogの課題一覧をGoogleAppsScriptでSpreadSheetに張り付ける

Backlogの課題一覧をSpreadsheetに張り付けることがよくあるのでメモしておく:writing_hand:

# スプレッドシートへの準備 :footprints:
下表のように、2行目にBacklogのレスポンスのキーを予め記述しておき、課題の値を3行目以降に記述していくこととする。
カスタムフィールドの場合、1つ目はcustomFields1、2つ目はcustomFields2...とする。

#### 一括取得前のイメージ

|概要|期限日|ステータス|3番目のカスタムフィールド|
|---|---|---|---|---|
|summary|dueDate|status|customFields3|
|　||||
|　||||

:point_down_tone1::point_down_tone2::point_down_tone3::point_down_tone4::point_down_tone5:

#### 一括取得後のイメージ

|概要|期限日|ステータス|3番目のカスタムフィールド|
|---|---|---|---|---|
|summary|dueDate|status|customFields3|
|xxxの件|2019/06/06|処理中|xxxxxx|
|yyyの件|2019/07/07|未対応|yyyyyy|

# Backlogの課題を取得する :red_car:
ここにメモった。
https://qiita.com/rubyfmzk/items/1c594819134258d1c4e3

# SpreadSheetに張り付ける :spider:

### SpreadSheetに張り付けるメイン関数 :dancer:
```main.js
function writeSpreadsheet(array) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート名");//シート名を指定
  var key_row = 2;//キーの行を指定
  var write_issues = [];//書き込み内容を格納する配列

  //SpreadSheetで使用するキー一覧
  var keys = sheet.getRange(key_row, 1, 1, sheet.getLastColumn()).getValues()[0];

  for(var i in array){
    var issue = array[i];
    var write_issue = [];

    //無効と重複は表示しない
    if(issue["resolution"] && (issue["resolution"]["id"] === 2 || issue["resolution"]["id"] === 3)){
      continue;
    }
    
    for(ii in keys){
      var key = keys[ii];
      if(!key) break;

      //値を配列から取得
      var val = issue[key];
 
      //カスタムフィールドの値を取得
      if(key.match(/^customFields/)) val = val["customFields"][key.match(/\d+$/) - 1]["value"];
      
      //配列の場合は値に変換する関数
      val = val2str(val);
      
      //日付の場合、フォーマットを変更する関数
      val = dateFormat(val);
      
      //書き込み用の配列に追加
      write_issue.push(val);
    }
    //書き込み用の配列に追加
    write_issues.push(write_issue);
  }

  //データをシートに書き込む
  if(write_issues){
    sheet.getRange(key_row + 1, 1, write_issues.length, write_issues[0].length).setValues(write_issues);
    Browser.msgBox("書き込み完了しました。");
  }
  else{
    Browser.msgBox("データはありませんでした。");
  }
}
```

### 型が不明な値を再帰的に文字列に変換 :arrows_counterclockwise:
配列の場合は/で区切り連結するようにする。

```util.js
function val2str(val){
  if(val === null) return "";

  if(typeof val === "object"){
    if(val["name"]) return val["name"];
    
    if(val[0]){
      var val2 = val2str(val[0]);
      for(i in val){
        val2 += "/" + val2str(val[i])
      }
      return val2;
    }
  }
  return val;
}
```

#### SpreadSheetの日付型に変換 :clock1:
YYYY-MM-DDTHH:MM:SSZ を YYYY/MM/DD に変換。
SpreadSheetにYYYY/MM/DDで入力してあげると、日付として認識してくれる:v:

```util.js
function dateFormat(date){
  if(!date) return date;
  if(typeof date !== "string") return date;

  var regex_date = /^\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
  if(date.match(regex_date)) return date.slice(0,4) + "/" + date.slice(5,7) + "/" + date.slice(8,10);
  return date;
}
```
Tkinterでファイル選択をGUIで行う。

#本当はドラッグアンドドロップがしたい
ファイルを指定する際、エクスプローラからドラッグアンドドロップして指定できたらすごく楽だなぁ・・・と思っていたら、なんとTkinterは標準では別アプリケーションからのドラッグアンドドロップに対応していないとの事。
(頑張ればできるらしいが面倒くさいので)今回はダイアログボックスを使うことにする。
※Pythonのバージョンは3.7.2です。

#コード
```python:pori.py
import os, shutil, sys
from tkinter import filedialog as tkFileDialog

```
これでインポートして

```python:pori.py

def dialog_action(event):
    dir_entry.delete(0, tkinter.END)
    dir_=tkFileDialog.askdirectory()
    dir_entry.insert(tkinter.END, dir_)

dialog = tkinter.Button(text=form1_dialog_text, font=btn_font)
dialog.bind("<Button-1>",dir_dialog_action)
dialog.pack(anchor = 'w')

```
イベントとボタンの実装はこんな感じ。ダイアログで選択したディレクトリのパスをエントリーに入力する。入力する前にエントリーの中身を消しておかないと、入力済みの内容の後ろにパスが入力される。

#完成品
前回作ったアプリにこのボタンを追加。
![c06ac7eb7bda91ff62fa839c59d425e5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425022/2f7bfe1c-94f8-bc04-6268-a042f3c5602a.png)

使いやすくなっていくのが楽しい。

#おまけ
前回の投稿でもらったコメントにあったこのコード

```python:pori.py
dir_ = input() or dir_
```
**すげえ（語彙力が無い）**
1行で書けることに衝撃を受けました。
future Branchを作成した直後に空コミットを入れると分岐点がわかりやすい

#なぜ、空コミットを入れるのか？
**branchの分岐点がわかりやすくなる**

#空コミットを入れないとどうなるのか？
**branchの分岐点がわかりにくくなる**

#どうわかりにくくなるのか？
空コミット入れない場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/b427eeb6-1008-d448-6131-e3fa2f5bc4b8.png)

空コミット入れた場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/c8dd3e43-63a9-45d0-a0db-b37422207327.png)

#どうして気づいたのか？
先輩「branchなんかカオスな事になってない？、masterからbranchきってない？」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/b427eeb6-1008-d448-6131-e3fa2f5bc4b8.png)
確かにそう見える

けど
そんな事してない

#これまでのbranchからmergまで流れ
1. MasterからFutuerBranch(リリース単位)を作成
2. FutuerBranch（リリース単位）をリモートへプッシュ
3. FutuerBranchから各開発用のbranch（A-branch、B-branch、C-branch、...）を作成
4. A-branchに対してソースを修正、コミット
5. A-branchからFutuerBranchへのプルリク
6. マージ完了

これだと
こうなってしまう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/b427eeb6-1008-d448-6131-e3fa2f5bc4b8.png)

#これからのbranchからmergまで流れ
1. MasterからFutuerBranch（リリース単位）を作成
2. FutuerBranch（リリース単位）に対して空コミット
3. FutuerBranch（リリース単位）をリモートへプッシュ
4. FutuerBranchから各開発用のbranch（A-branch、B-branch、C-branch、...）を作成
5. 各開発用のbranch（A-branch、B-branch、C-branch、...）に対してソースを修正、コミット、リモートへプッシュ
6. 各開発用のbranch（A-branch、B-branch、C-branch、...）からFutuerBranchへのプルリク
7. マージ完了

これで分岐点がわかりやすくなる
空コミットから枝が分かれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/c8dd3e43-63a9-45d0-a0db-b37422207327.png)

#空コミットの方法
このコマンドで空コミット
`git commit --allow-empty -m "ブランチの分岐点"`
空コミットの方法は下記の記事を参照
https://qiita.com/lni_T/items/36abcff16256282a1a6e
Wikipediaがわからなかった人へのクロージャ解説

ウェブ上の記事でクロージャを調べても不十分であったりわかりにくいと感じたので，これを読めば Wikipedia が読めるくらいの内容を目指して書いてみました．


# クロージャとは何か
クロージャとは，少し厳密ではありませんが，
「関数の中の関数で，外側の関数の引数やローカル変数を使うもの」
です．
例えば，下のコードの無名関数 `(e) => y * z * e` がクロージャです(Scala で書いてしまいましたが，読めると思います)．

```scala:closure.scala
def example(x: Int, y: Int): List[Int] = {
    var z = f(x)
    List(0, 1, 2).map((e) => y * z * e)
    // 三つの要素を持つリストのすべての要素に対して `y` と `z` をかけている
    // この無名関数 `(e) => y * z * e` は外側の関数 `example` の引数 `y` やローカル変数 `z` を使っているのでクロージャ
}
```

この例ではわからないと思いますが，そのような関数は `y` や `z` のような変数がどういう値であるかを覚えるという，通常の関数とは異なる処理をする必要があります．
そこで，そのような関数のことを特別扱いし，クロージャと呼んでいるのです．


# どういうときに使うか
では，クロージャはどういうときに出てくるか，使うかというと，典型的な例を二つ挙げます．

## 例1: 関数の引数に無名関数
一つは，上の例のように，高階関数の引数に無名関数を渡すときです．
その無名関数の本体に外側の関数の引数やローカル変数を使っているとき，その無名関数はクロージャとして処理されています．
これは，無意識に使ったことがあるかもしれません．

## 例2: 状態を持った関数を作る
もう一つは，例えばカウンタ(呼び出された回数を返す関数)のような，呼び出すたびに違う振る舞いをする関数を作りたいときです．
そういうとき，普通はグローバル変数を使うかそれ用のクラスを作ると思いますが，クロージャを使うともっと綺麗に実装することができます．
カウンタの例だと，下のコードのように書きます．

```scala:count.scala
var count = (() => {
    var x = 0
    () => {x += 1; println(x)}
})() // 無名関数の実行結果を変数 count に代入している

count() // 1 が出力される
count() // 2 が出力される
```

これは何してるかというと，
内側の無名関数 `() => {x += 1; println(x)}` がクロージャです．
そして，外側の無名関数はクロージャを返す関数なので，最終的に変数 `count` にはその実行結果であるクロージャが入っています．
ここで，クロージャの特徴として，関数の呼び出しが終わった後も `x` の値は保存されます．
なので，最後の行では期待通り，2 が出力されます．

もう少し実用的な例としては[こちら](http://dqn.sakusakutto.jp/2012/02/javascript_13.html)の二回注文を押されると警告を出すボタンが面白いと思いました．

### グローバル変数やクラスではダメなのか
このような関数はグローバル変数やクラスでも実装できます．
では，クロージャを使うと何が良いかというと，
まず，グローバル変数を使う方法と比べるとグローバル変数の数を減らせます．
グローバル変数がたくさんあると名前が衝突するなどバグになる可能性があり，減らせると嬉しいです．
また，クラス作る方法と比べると，クロージャを使う方が簡単かと思います．


# レキシカルスコープとクロージャ
クロージャをどういうときに使うかを説明しましたが，元々クロージャはレキシカルスコープというものを実現するためのものです．

## 自由変数
ある関数に対して，引数やローカル変数以外の変数，外で定義された変数のことを自由変数といいます．

## スコープ
自由変数の扱い方には，レキシカルスコープとダイナミックスコープという二つの方法があります．

- レキシカルスコープ: 自由変数が出てきたときは，定義されたときの変数を参照する．下の例では 1 (1 行目で定義された方の `x`．5 行目で `1` が再代入されている)を出力する．
- ダイナミックスコープ: 自由変数が出てきたときは，実行時のその名前の変数を参照する．下の例では 2 (8 行目(`main` 関数内)で定義された方の `x`)を出力する．

```scala:scope.scala
var x = 0

def print_x() = print(x) // この `x` が自由変数

x = 1

def main() = {
    var x = 2 // この `x` は上の `x` とは別物
    print_x()
}
```

この二つのどちらを採用するかはプログラミング言語によって異なりますが，普通はレキシカルスコープが採用されます．
これは，[Wikipedia](https://ja.wikipedia.org/wiki/%E5%8B%95%E7%9A%84%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97) によるとミスを招きやすいためだそうです．
確かに，一番最初の例で `y` や `z` は明らかに外側のローカル変数を参照しており，違う変数の値を使われてしまったら困ると思います．

ダイナミックスコープでは，名前でどの変数を使えばいいか判別できますが，レキシカルスコープを採用するとどの変数を使えばいいか関数ごとに覚えておかなければいけません．
そこで，クロージャが必要になります．

## 環境
では，どのように覚えているかというと，コンパイラなどの言語処理系内部では，クロージャは関数本体と環境というもののペアとして処理されます．
環境とはそれぞれの自由変数がどの変数を参照しているか(自由変数の名前とポインタの対応)です．

ただ，グローバル変数やクラス変数，インスタンス変数などは特別扱いされるので，それらを使うだけではクロージャの仕組みはいりません．
必要になるのは関数の中に関数を使えるなど，入れ子のような仕組みを備えているときです．


# 参考
[Closure (computer programming) - Wikipedia](https://en.wikipedia.org/wiki/Closure_(computer_programming))
[クロージャ再考 - Qiita](https://qiita.com/pebblip/items/2ed30f59cd5981513908)
[クロージャって結局何なのか - Qiita](https://qiita.com/eg_19_/items/949747037030d8e171f4)
[[JavaScript] 猿でもわかるクロージャ超入門 まとめ · DQNEO起業日記](http://dqn.sakusakutto.jp/2009/01/javascript_5.html)
無料にされたデバッギングの拡張機能のRevDeBug

はじめまして、
私はRevDeBugから来ましたが、開発者向けの製品は現在無料になった際、プログラミングをしている日本人の方にもぜひお試ししていただきたいと思います。

<a href="https://marketplace.visualstudio.com/items?itemName=RevDeBug.RecordReplayforNET-RevDeBug">開発者向けのRevDeBugは無料でダウンロード</a>

日本語で書かれているRevDeBugについての記事がこちら：
http://kkamegawa.hatenablog.jp/entry/2018/03/22/094039
Linux で Unity Hub をインストール

# はじめに

Linux に Unity Hub をインストールする。


# 環境

- Manjaro Linux 18.0.4 illyria
- kernel: 4.19.45-1-MANJARO
- i3wm


# 手順

## ダウンロード

[Forum](https://forum.unity.com/forums/unity-hub.142/?_ga=2.13359223.1319993524.1559644252-1922675265.1559644252) にある [Unity Hub v2.0.0 Release](https://forum.unity.com/threads/unity-hub-v2-0-0-release.677485/) から `Hub 2.0.0 for Linux` をクリックして、 `UnityHubSetup.AppImage` をダウンロード。


## インストール

`UnityHubSetup.AppImage` に実行権限を追加して、実行。

```
chmod u+x ~/Downloads/UnityHubSetup.AppImage
./UnityHubSetup.AppImage
```


## HiDPI の起動方法

HiDPI のディスプレイを使用しているときは、以下のように起動することで解決。

```
GDK_SCALE=2 GDK_DPI_SCALE=0.5 /path/to/my/editor -projectpath /path/to/project
```

# 参考

- [Unity Hub and HiDPI - Unity Forums](https://forum.unity.com/threads/unity-hub-and-hidpi.604378/)
WP mail SMTPでAWS Workmailを利用する

## やりたいこと
WordPressのWP mail SMTPというプラグインを利用して、問い合わせフォームに入力された内容を、Workmailのメールに送信したい。

## 前提
以下が準備されている前提になります。
- WordPressの環境が用意されている
- WP mail SMTPがインストールされている
- AWSアカウントがある
- Workmailのセットアップが終わっている

## 作業内容
WordPressの管理画面の「設定＞WP mail SMTP」から、WP mail SMTPの設定画面を開きます。
下記のように設定項目を入力します

メーラー: Other SMTP
SMTPホスト: smtp.mail.us-east-1.awsapps.com (リージョン名はWorkmailを利用するリージョン名を入力)
暗号化: SSL
SMTPポート: 465

次に、認証をONにして、以下を入力します。

SMTP Username: workmailで作成したユーザーのメールアドレス
SMTP Password: workmailで設定したユーザーのパスワード

## 確認
「Email Test」からメールが送信できることを確認します。

## 参考
[[新機能]Amazon WorkMailがSMTPプロトコルをサポート ｜ DevelopersIO](https://dev.classmethod.jp/cloud/aws/amazon-workmail-smtp-support/)
【Matplotlib入門】３D Scatter Plotを試してみる♬

何度も3dのScatterPlotでミスをするので、ここで一度基本を押さえておこうと思う。
元ネタは参考①のとおりですが、ミスする箇所はちょっと異なるので記事にしておきます。

元々の使い方は参考②のMatplotlibのドキュメントにあります。
そして、参考③はnp.reshape(X[:,0],-1)の表現のために引用しています。つまり、引数は1次元の変数である必要があります。

【参考】
①[matplotlibで3Dプロット](https://qiita.com/kazetof/items/c0204f197d394458022a)
②[scatter(xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs)@mplot3d API@ matplotlib](https://matplotlib.org/mpl_toolkits/mplot3d/api.html#mpl_toolkits.mplot3d.axes3d.Axes3D.scatter)
③[matplotlib.scatter() not working with Numpy on Python 3.6](https://stackoverflow.com/questions/46746839/matplotlib-scatter-not-working-with-numpy-on-python-3-6)
###今回のコードは以下のとおり
```py
import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import matplotlib

print(matplotlib.__version__)
# 3.0.3
#for 3D plotting
from mpl_toolkits.mplot3d import Axes3D

if __name__ == '__main__':
    N = 100
    X = np.random.rand(N, 3)
    y = np.random.rand(N) * 2 - 1
    
    fig = plt.figure()
    ax1 = fig.add_subplot(211 , projection='3d')
    sc = ax1.scatter(X[:, 0], X[:, 1],zs=X[:, 2],zdir='z', s=50, vmin=0, vmax=1, c=y, cmap=plt.cm.jet) 
    plt.colorbar(sc)
    
    ax2 = fig.add_subplot(212, projection='3d')
    sc2=ax2.scatter3D(np.ravel(X[:, 0]), np.ravel(X[:, 1]), zs=X[:, 2],zdir='z',s=50, vmin=0, vmax=1, c=y, cmap=plt.cm.jet)
    plt.colorbar(sc2)
    plt.show()
```
ここまでのグラフは以下のとおり、同じ絵が描けました。
![Figure_1_3dscatter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/9d72fada-1c57-8dbc-d954-96260ea54e8b.png)

```py
    fig = plt.figure()
    ax3 = fig.add_subplot(211)
    sc3 = ax3.scatter(np.reshape(X[:,0],-1), np.reshape(X[:,1],-1), c=np.reshape(X[:,2],-1), cmap=plt.cm.jet) #cmap=plt.cm.jet cm.seismic plt.cm.Spectral
    plt.colorbar(sc3)

    ax4 = fig.add_subplot(212, projection='3d')
    sc4=ax4.scatter3D(X[:, 0], X[:, 1],c=np.reshape(X[:,2],-1), cmap=plt.cm.jet)
    plt.colorbar(sc4)
    plt.show()
```
上記の上のコードが通常よく使う二次元のプロットにカラーで３次元目を表すコードです。
そして、最後のコードでprojection='3d'を指定しないとエラーで描画できません。
※ここが通常のscatterとscater3Dの異なる部分のようです
![Figure_2_scatter3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/b4962d35-cb44-4736-13da-1557d3f29bac.png)
###まとめ
・3d Scatter Plotについて試してみた
・描画の仕方としてscatterとscatter3Dは3dプロットだと同じ振る舞いをするが、2dプロットの場合はscatterを使う方が見やすい
・おまじないとしてfrom mpl_toolkits.mplot3d import Axes3Dとprojection='3d'がないと3dプロットはできない
・引数はX,Y,Zとcは1ーDである必要があり、np.ravel(X[:, 0])やnp.reshape(X[:,0],-1)などで変換することができる
[Linux] 特定SSHホストのフィンガープリントのチェックを省略する

一度SSH接続した後に、OSを再インストールして繋ぎなおすと `REMOTE HOST IDENTIFICATION HAS CHANGED` のWARNINGが出て、接続できなくなる

```
$ ssh localhost
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:x+3G7YmVt74mJbrp2YDCdo9N5uv4Q9fb4m2U2jzYBNA.
Please contact your system administrator.
Add correct host key in /home/suzutsuki/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/suzutsuki/.ssh/known_hosts:7
ECDSA host key for localhost has changed and you have requested strict checking.
Host key verification failed.
```

これは、SSHクライアントが前回繋いだホストとは異なっていることをユーザーに知らせるためのもので、偽装ホストへの接続を防ぐための仕組みである

`ssh-keygen -R HOST_NAME` で `~/.ssh/known_hosts` にキャッシュされているフィンガープリントを削除することで解決するが、VM や Dockerコンテナのように頻繁に作り直すホストに対して毎回行うのは煩わしい

`/etc/ssh/ssh_config` で `StrictHostKeyChecking` を `no` に設定すればフィンガープリントの確認が省略できるが、全てのホストに対して無効にするのはセキュリティーレベルを緩くしすぎである

そこで、特定のホスト(今回はlocalhostのみ)のSSH接続だけをチェックしないように設定したい

`~/.ssh/config` を開き、以下のように設定を記述する

```
Host localhost
    StrictHostKeyChecking no
```

Hostには `*` (0 個または以上の任意の文字に一致する)や `?` (任意の 1 文字だけに一致する) も使える

複数のホストを書くには半角スペースで区切る

```
Host host1 host2 ...
```

設定した後は、WARNINGは出るが接続できるようになる

```
$ ssh localhost
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:MJJBD6MuXKz1tQ13ADlJfNZp4au6KqaY61L7BCtlHiU.
Please contact your system administrator.
Add correct host key in /home/suzutsuki/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/suzutsuki/.ssh/known_hosts:7
Password authentication is disabled to avoid man-in-the-middle attacks.
Keyboard-interactive authentication is disabled to avoid man-in-the-middle attacks.
```
【Mastodon+Apache httpd】そのProxyPassではストリーミングが正常に動かない

# 概要
Apache httpdでMastodonを動かす設定をググると、大体↓みたいなのが出てくるが、これだとWebUI以外の一部のクライアントでストリーミングが使えない。

```conf:mastodon-NG.conf
# ProxyPass以外は省略
   ProxyPass /api/v1/streaming/ ws://localhost:4000/
   ProxyPassReverse /api/v1/streaming/ ws://localhost:4000/
   ProxyPass / http://localhost:3000/
   ProxyPassReverse / http://localhost:3000/
```
Mastodon公式の旧ドキュメント
https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Alternatives.md
でもこうなってしまっている。

↓のようにすると正常に動作する。

```conf:mastodon-OK.conf
# ProxyPass以外は省略
  <LocationMatch "^/api/v1/streaming/?$">
     ProxyPass ws://localhost:4000/api/v1/streaming
     ProxyPassReverse ws://localhost:4000/api/v1/streaming
  </LocationMatch>
   ProxyPass /api/v1/streaming/ http://localhost:4000/api/v1/streaming/
   ProxyPassReverse /api/v1/streaming/ http://localhost:4000/api/v1/streaming/
   ProxyPass / http://localhost:3000/
   ProxyPassReverse / http://localhost:3000/
```

# 何が起きるの？

- WebSocket( /api/v1/streaming?... )を使おうとすると、リダイレクトループが起きて死ぬ
 - なおWebUIはどういうわけか /api/v1/streaming/?... ("?"の直前に"/"がある)というURLを使っていて、こちらは正常に動作する
- Server-sent events ( /api/v1/streaming/public など)は全く動作しない

# 原因っぽいの

現象が2つなので原因も2つに分けて書く。

## WebSocketが死ぬ方

/api/v1/streaming?... へのアクセスが mastodon-web (http://localhost:3000/api/v1/streaming?...) に飛ばされてしまうのが原因。
そしてこれが HTTP 301(Moved Permanently)で全く同じURLにリダイレクトしてしまいループして死ぬ。
これはWebSocket接続で mastodon-streaming (ws://localhost:4000/... ) に飛ばす必要がある。
さらに /api/v1/streaming/?... ("/"がついている)も同様にWebSocket接続で mastodon-streaming に飛ばす必要がある。
ちなみにWebSocket接続時は、mastodon-streaming がURL("?"より前の文字列)を無視するので、こんな風にしても問題なく動く(少なくともVer 2.8.4ではそうだった)。

```conf:mastodon-OK2.conf
  <LocationMatch "^/api/v1/streaming/?$">
     ProxyPass ws://localhost:4000/
     ProxyPassReverse ws://localhost:4000/
  </LocationMatch>
```

## Server-sent eventsが使えない方

/api/v1/streaming/xxxx (publicなど) がWebSocket接続で mastodon-streaming (ws://localhost:4000/...) に飛ばされてしまうのが原因。
これは **HTTP接続で** mastodon-streaming (http://localhost:4000/...) に飛ばす必要がある。
さらに、mastodon-streamingに投げるURLには "/api/v1/streaming/" を残しておく必要がある。

# にゃーん

Mastodon公式にもあるnginxの設定はもっとスマートだし、Apache httpdでももう少し綺麗に書けないかなとは思う。

# にゃーん2

どういうわけかPawooからのトゥがまともに送られてこない不具合が発生したのでnginxに戻したorz
FetchAPIの詰まりどころ

# FetchAPIの詰まりどころ

## そもそもFetchAPIとは？
XMLHttpRequestの後継技術で、javascriptから非同期通信をするためのAPIです。
一昔前はjavascriptによる非同期通信というとjQuery.ajaxが主流でしたが、
普通に書いてしまうとコールバック地獄に陥りますし、今更jQuery.Defferedなど使いたくありません。

その点、fetchはPromiseをベースに作られているので、非常に簡潔に書くことができます。
例えば、特定のURLにアクセスしてJsonを取ってくる処理などはわずか2行です。

```javascript
//async function内　
const resp = await fetch(url);
const json = await resp.json();

```
一度使い始めると最早手放せません。
某IEとかいう化石ブラウザが対応していませんが、そこはpollyfillで何とかしましょう。

https://github.com/github/fetch

## 癖のある動作
しかし、このfetch癖のある仕様が何か所かあります。

### 500や404でもRejectしない
fetchによって投げたRequestが、500エラーや404になった場合、
fetchが返すPromiseはresolve,rejectどちらになるでしょうか。
普通に考えるとrejectされそうなものですが、このfetchはそれくらいではrejectしません。
クロスオリジン制約にかかるなど、まともにリクエストすら投げられない状態がrejectであり
ステータスコードが帰ってくるのはresolveです。

#### ではどうやってリクエストの成功を確かめればいいのか？
とはいえHttpStatusがエラーかどうかはきちんと判別できないと困ります。
そういう場合は、Response.status　または Response.okを使いましょう。
Response.statusはその名の通りHttpStatusを返し、Repsonse.okはStatusが200番台の時にtrueを返します。

```javascript
const resp = await fetch(url);
if(!resp.ok){
  //エラー処理
  return;
}
const json = await resp.json();

```

### デフォルトではCookieが乗らない
fetchAPIはデフォルトではCookieなどの認証情報が乗りません。
認証を必要とするAPIで利用する場合は、以下のようにオプションを渡してやる必要があります。

```javascript
const resp = await fetch(url,{
            credentials: 'same-origin'  //同一オリジンの場合に認証情報を乗せる
        });

```

## まとめ
* fetchAPIは非常に便利
* 一方でちょっと癖のある仕様も多いのできっちり確認しておくべき

## 参考
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API
ー初心者でもわかるエラー解決ー　#<モデル名:0x00007fb0b9c165a8> とは？

# "#<モデル名:0x00007fb0b9c165a8> "

こんなメッセージが出てきたことはありませんか？

実はこのメッセージはレコード一つを表しています。

色々なエラーの中で表示されますが、エラー以外でも表示されます。

### params{...id{#<モデル名:0x00007fb0b9c165a8>}}
要は、直前のビューの中でカラムを指定しないことで、レコード全体を指定してしまっている、ということです。

このようなエラーが発生したら、直前のビューでカラムを指定しましょう。
【npm】root権限で「npm install -g 〇〇」すると『Permission denied』エラーで怒られる時

※linux環境想定

```sh
root@hoge:/home# npm i -g hogehoge
```

で

```
# 中略
sh: 1: node: Permission denied
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
# 中略
```

みたいな時


## 解決
```sh
npm config set user 0
npm config set unsafe-perm true
# をそれぞれ実行してから、npm i -g XXX
```

参考~~(というか丸々引用)~~ : https://stackoverflow.com/questions/51811564/sh-1-node-permission-denied

~~こまけぇ事はいいからとにかく~~
ローカルの仮想開発環境とかでrootで何でもすませちゃいたいものぐさマン(私)はどうぞお試しください
aws cliが動きません😭 と言われたときに試してもらうリスト【随時更新】

# キャッシュと環境変数のセッショントークンを削除してもらう

```
rm -f ~/.aws/cli/cache/*
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
```


# どこに設定されている認証情報でAWSのAPIを叩いているかをチェックする

```
aws configure list

# スイッチロールありの場合
aws configure list --profile ${PROFILE}
```

参考: https://dev.classmethod.jp/cloud/aws/how-to-configure-aws-cli/

# どのユーザーとして認証情報を叩いているかチェックする

```
aws sts get-caller-identity

# スイッチロールありの場合
aws sts get-caller-identity --profile ${PROFILE}
```

[awscli-alias](https://github.com/awslabs/awscli-aliases) を設定すると `aws whoami`で呼び出せるようになります。
参考: https://dev.classmethod.jp/cloud/aws/aws-cli-alias/


# 設定されいているIAMポリシーをチェックする

```
aws iam list-attached-user-policies --user-name ${USERNAME} --query "AttachedPolicies[*].PolicyArn" --output text | xargs -n1 -I {} aws iam get-policy --policy-arn {}

aws iam get-policy-version \
  --policy-arn <↑で取得したIAMポリシーのARN> \
  --version-id <↑で取得したバージョンID>

# スイッチロールする場合
PROFILE=YOUR_PROFILE
ROLE_NAME=YOUR_ROLE_NAME
aws iam list-attached-role-policies --role-name ${ROLE_NAME} --profile ${PROFILE} --query "AttachedPolicies[*].PolicyArn" --output text | xargs -n1 -I {} aws iam get-policy --policy-arn {} --profile ${PROFILE}

aws iam get-policy-version \
  --policy-arn <↑で取得したIAMポリシーのARN> \
  --version-id <↑で取得したバージョンID> \
  --profile=${PROFILE}
```
react-navigationタブをタップした時に、Stackをリセットする。

![alt](https://user-images.githubusercontent.com/26253721/39765058-e8d0eae4-531b-11e8-9305-4c852f269517.png)

react-navigationでは、タブを切り替えても、タップしても、Stackは保存される。
使いにくいんじゃ！

そこで、
resetOnBlur: true
を設定する。

```
const TabNavigator = createBottomTabNavigator(
  {
    HomeScreen,
    SettingsScreen,
  },
  {
    resetOnBlur: true
  }
)
```

タブをタップすると、各Tabの初期Screenが表示されるようになる。


役に立ったらいいねください
Backlogの課題を一括取得してGoogleAppsScriptで配列や連想配列として扱う

BacklogAPIで課題を一括取得してJSやGASで配列や連想配列として扱うことがよくあるのでメモしておく。

# Backlogの仕様書
https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/

# GoogleAppsScriptで一括取得
最大100件しか取得できないので、何度もコールします。
パラメータは適宜変更します。

```getBacklogIssues.js
function getBacklogIssues(){
  var space_id   = "スペース名";
  var api_key    = "APIキー";
  var project_id = "プロジェクトID";
  var count = 100;//最大取得数100件
  var params = "&order=asc";//その他パラメータをご自由に
  var issues = [];//結果を格納

  while(true){
    //課題を取得
    var response = UrlFetchApp.fetch("https://" + space_id + ".backlog.jp/api/v2/issues?apiKey=" + api_key + "&projectId[]=" + project_id + "&count=" + count + "&offset=" + issues.length + params);

    //エラーの場合は終了
    if(response.getResponseCode() != 200) return false;
    
    //配列に追加
    issues = issues.concat(JSON.parse(response));
      
    //取得が100件未満ならループから抜ける。
    if(JSON.parse(response).length < count) break;
  }
  return issues;
}
```

### issueKeyがキーの連想配列に変換
PHPのarray_column()的なことをして、単純な配列を連想配列に変える。

```arrayColumn.js
function arrayColumn(array, key){
  var new_array = {};
  for(row in array) new_array[array[row][key]] = array[row];
  return new_array;
}

var issues = arrayColumn(getBacklogIssues(), "issueKey");
```
【VSC】VSCを入れたら入れる拡張機能【チラ裏】

## 背景
- 現場が変わったり何だでVisual Studio Codeを入れ直した時、拡張機能を**いっつも忘れる**ので自分用にメモ

## 拡張機能紹介

### Japanese Language Pack for Visual Studio Code
- URL
    - https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja
- 目的
    - UIを日本語化する
- 適用方法
    - 拡張機能をインストール後、VSCを再起動する

### indent-rainbow
- URL
    - https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow
- 目的
    - ソースのインデント部分が七色になり深さが視認しやすくなる
- 適用方法
    - 拡張機能をインストール後、VSCを再起動する

### Keyboard Macro Beta
- URL
    - https://marketplace.visualstudio.com/items?itemName=tshino.kb-macro
- 目的
    - キーボードマクロの記録と実行による入力支援をする
- 適用方法
    - 拡張機能をインストールする
- 使用方法
    - ①マクロを記録開始（Ctrl-Alt-R）する
    - ②任意のキーボード操作をする
    - ③マクロの記録を停止（Ctrl-Alt-R）する
    - ④任意のカーソル位置で、マクロを実行（Ctrl-Alt-P）する

### change-case
- URL
    - https://marketplace.visualstudio.com/items?itemName=zhengxiaoyao0716.intelligence-change-case
- 目的
    - キャメルケース、スネークケース等の一括変換
- 適用方法
    - 拡張機能をインストール
        - 同名の拡張機能があるのでご注意！作者はWater Zheng氏
    - 「ファイル＞基本設定＞設定」を開く
    - 検索ボックスで「change-case」と入力し「Change-case.Default」の「setting.jsonで編集」をクリック
    - 以下のように編集して保存。使用しないケースがある場合は除外してOK
    ```json
    {
        "change-case.default": [
            "camelCase",
            "PascalCase",
            "param-case",
            "snake_case",
            "CONST_CASE"
        ]
    }
    ```
- 利用方法
    - 変換したいキーワードを選択状態にして、「Ctrl + U」押下

### Raindow CSV
- URL
    - https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv
- 目的
    - CSVファイルの視認性を上げる
    - 変にグリッド表示にしたくない場合なんかはオススメ
- 適用方法
    - 拡張機能をインストール後、VSCを再起動する
TypeScriptでよく作るClass

サーバーサイド(Cloud Functions)でしかTypeScriptを書いた事が無いのでクライアントサイドは謎。

```typescript
export type DogData = {
    id?: string;
    name: string;
    race?: string;
}

//Type Guard
export const dataIsDogData = (data: any): data is DogData => {
    const d = data as DogData;
    if (typeof d.name !== 'string') return false;
    return true
}

export class Dog implements DogData {

    readonly id: string;
    readonly name: string;
    readonly race?: string;

    constructor(data: any) {
        if (!dataIsDogData(data)) throw new Error(data is not DogData `${JSON.stringify(data)}`);
        Object.assign(this, data);
        this.id = generateId(data);
        this.name = data.name;
    }
}
```

メソッドが欲しくならない限りtype定義だけして済ませる事が多いのだけれど、欲しくなったらこういうの用意して

```typescript
//Barrel
import * as entity from '../Entity';

createDog = (incomingData: any): entity.Dog | undefined => {
    const dogData: entity.dogData = {
        ...incomingData,
        name: 'Dogmeat',
    };
    if (!entity.dataIsDogData(dogData)) return undefined;
    return new entity.Dog(dogData);
}

createDog({
  race: ''
})

```

みたいな感じでよく使ってる。プロパティが増えるとやや煩雑なので、どうしようかなと思ってる。あとconstructorでanyを受けちゃうのはちょっとお行儀悪い。